From bf403a8f97f9a83383dba6c23705da2864acbf65 Mon Sep 17 00:00:00 2001 From: NIMFER Date: Sun, 14 Aug 2022 03:55:25 +0200 Subject: [PATCH] Ducktaped together a FishNet version of the Transport Ducktaped together a FishNet version of the Transport, now I need to edit the LoadBalancer and Server so it connects and actually trades information --- Dockerfile | 39 - FishBait.png | Bin 0 -> 265164 bytes LRM.png | Bin 11146 -> 0 bytes .../LRM_LoadBalancer/Config.cs | 1 - .../LRM_LoadBalancer/Program/Program.cs | 2 - .../LRM_LoadBalancer/Program/ProgramExtra.cs | 5 +- README.md | 2 +- .../Dockerfile | 15 + .../LRM/Config.cs | 14 +- .../LRM/Program/Program.cs | 34 +- .../LRM/RelayHandler/RelayHandler.cs | 31 +- .../LRM/RelayHandler/RelayHandlerCallbacks.cs | 17 +- .../RelayHandler/RelayHandlerRoomMethods.cs | 25 +- .../Ignorance/Core/IgnoranceClient.cs | 288 -- .../Ignorance/Core/IgnoranceServer.cs | 303 -- .../Ignorance/Dependencies/ENet.cs | 1385 ------ .../MultiCompiled/Ignorance/Ignorance.cs | 510 --- .../Ignorance/IgnoranceDefinitions.cs | 94 - .../Ignorance/Plugins/Linux/libenet.so | Bin 60144 -> 0 bytes .../Ignorance/Plugins/Windows/README.txt | 3 - .../Ignorance/Plugins/Windows/enet.dll | Bin 124928 -> 0 bytes .../Ignorance/Plugins/readme.txt | 35 - .../MultiCompiled/KCP/KcpTransport.cs | 19 +- .../Assets/{Ignorance.meta => FishBait.meta} | 2 +- UnityProject/Assets/FishBait/BiDictionary.cs | 56 + .../BiDictionary.cs.meta} | 2 +- .../Ignorance => FishBait}/Editor.meta | 2 +- .../FishBait/Editor/FishBaitInspector.cs | 310 ++ .../Editor/FishBaitInspector.cs.meta} | 2 +- .../FishBait/FishBaitDirectConnectModule.cs | 180 + .../FishBaitDirectConnectModule.cs.meta} | 2 +- UnityProject/Assets/FishBait/FishBaitTools.cs | 201 + .../FishBaitTools.cs.meta} | 2 +- .../FishBaitTransport.meta} | 2 +- .../FishBaitTransport/FishBaitTransport.cs | 200 + .../FishBaitTransport.cs.meta | 11 + .../FishBaitTransportDirectConnect.cs | 71 + .../FishBaitTransportDirectConnect.cs.meta | 11 + .../FishBaitTransportVariables.cs | 77 + .../FishBaitTransportVariables.cs.meta | 11 + .../Resources.meta} | 2 +- .../Assets/FishBait/Resources/FishBait.png | Bin 0 -> 265164 bytes .../FishBait/Resources/FishBait.png.meta | 92 + UnityProject/Assets/FishBait/SocketProxy.cs | 68 + .../Assets/FishBait/SocketProxy.cs.meta | 11 + UnityProject/Assets/FishNet.meta | 8 + .../Assets/FishNet/CodeGenerating.meta | 8 + .../FishNet/CodeGenerating/Extension.meta | 8 + .../Extension/TypeDefinitionExtensions.cs | 96 + .../TypeDefinitionExtensions.cs.meta | 11 + .../Extension/TypeReferenceExtensions.cs | 24 + .../Extension/TypeReferenceExtensions.cs.meta | 11 + .../FishNet/CodeGenerating/FN_README.txt | 9 + .../CodeGenerating/FN_README.txt.meta} | 2 +- .../FishNet/CodeGenerating/Helpers.meta | 8 + .../CodeGenerating/Helpers/AttributeHelper.cs | 94 + .../Helpers/AttributeHelper.cs.meta | 11 + .../CodeGenerating/Helpers/CodegenSession.cs | 221 + .../Helpers/CodegenSession.cs.meta | 11 + .../Helpers/CreatedSyncVarGenerator.cs | 121 + .../Helpers/CreatedSyncVarGenerator.cs.meta | 11 + .../CodeGenerating/Helpers/Extension.meta | 8 + .../Extension/CustomAttributeExtensions.cs | 54 + .../CustomAttributeExtensions.cs.meta | 11 + .../Helpers/Extension/Diagnostics.cs | 41 + .../Helpers/Extension/Diagnostics.cs.meta | 11 + .../Extension/FieldReferenceExtensions.cs | 32 + .../FieldReferenceExtensions.cs.meta | 11 + .../Helpers/Extension/GetConstructor.cs | 191 + .../Helpers/Extension/GetConstructor.cs.meta | 11 + .../Extension/ILProcessorExtensions.cs | 169 + .../Extension/ILProcessorExtensions.cs.meta | 11 + .../Extension/InstructionExtensions.cs | 12 + .../Extension/InstructionExtensions.cs.meta | 11 + .../Extension/MethodDefinitionExtensions.cs | 55 + .../MethodDefinitionExtensions.cs.meta | 11 + .../Extension/MethodReferenceExtensions.cs | 123 + .../MethodReferenceExtensions.cs.meta | 11 + .../Extension/ModuleDefinitionExtensions.cs | 65 + .../ModuleDefinitionExtensions.cs.meta | 11 + .../ParameterDefinitionExtensions.cs | 24 + .../ParameterDefinitionExtensions.cs.meta | 11 + .../Extension/TypeDefinitionExtensions.cs | 468 ++ .../TypeDefinitionExtensions.cs.meta | 11 + .../Extension/TypeReferenceExtensions.cs | 137 + .../Extension/TypeReferenceExtensions.cs.meta | 11 + .../CodeGenerating/Helpers/GeneralHelper.cs | 941 ++++ .../Helpers/GeneralHelper.cs.meta | 11 + .../Helpers/GenericReaderHelper.cs | 143 + .../Helpers/GenericReaderHelper.cs.meta | 11 + .../Helpers/GenericWriterHelper.cs | 197 + .../Helpers/GenericWriterHelper.cs.meta | 11 + .../Helpers/NetworkBehaviourHelper.cs | 441 ++ .../Helpers/NetworkBehaviourHelper.cs.meta | 11 + .../CodeGenerating/Helpers/ObjectHelper.cs | 90 + .../Helpers/ObjectHelper.cs.meta | 11 + .../CodeGenerating/Helpers/ReaderGenerator.cs | 494 +++ .../Helpers/ReaderGenerator.cs.meta | 11 + .../CodeGenerating/Helpers/ReaderHelper.cs | 478 ++ .../Helpers/ReaderHelper.cs.meta | 11 + .../Helpers/TimeManagerHelper.cs | 51 + .../Helpers/TimeManagerHelper.cs.meta | 11 + .../CodeGenerating/Helpers/TransportHelper.cs | 36 + .../Helpers/TransportHelper.cs.meta | 11 + .../FishNet/CodeGenerating/Helpers/Typed.meta | 8 + .../CodeGenerating/Helpers/Typed/Comparers.cs | 34 + .../Helpers/Typed/Comparers.cs.meta | 11 + .../Helpers/Typed/CreatedSyncType.cs | 49 + .../Helpers/Typed/CreatedSyncType.cs.meta | 11 + .../Helpers/Typed/GeneratorHelper.cs | 180 + .../Helpers/Typed/GeneratorHelper.cs.meta | 11 + .../Helpers/Typed/QOLAttributeType.cs | 12 + .../Helpers/Typed/QOLAttributeType.cs.meta | 11 + .../Helpers/Typed/SerializatierType.cs | 19 + .../Helpers/Typed/SerializatierType.cs.meta | 11 + .../Helpers/Typed/SyncIndexData.cs | 17 + .../Helpers/Typed/SyncIndexData.cs.meta | 11 + .../CodeGenerating/Helpers/Typed/SyncType.cs | 14 + .../Helpers/Typed/SyncType.cs.meta | 11 + .../CodeGenerating/Helpers/WriterGenerator.cs | 504 +++ .../Helpers/WriterGenerator.cs.meta | 11 + .../CodeGenerating/Helpers/WriterHelper.cs | 557 +++ .../Helpers/WriterHelper.cs.meta | 11 + .../Assets/FishNet/CodeGenerating/ILCore.meta | 8 + .../CodeGenerating/ILCore/FishNetILPP.cs | 498 +++ .../CodeGenerating/ILCore/FishNetILPP.cs.meta | 11 + .../CodeGenerating/ILCore/ILCoreHelper.cs | 38 + .../ILCore/ILCoreHelper.cs.meta | 11 + .../ILCore/PostProcessorAssemblyResolver.cs | 139 + .../PostProcessorAssemblyResolver.cs.meta | 11 + .../ILCore/PostProcessorReflectionImporter.cs | 22 + .../PostProcessorReflectionImporter.cs.meta | 11 + ...PostProcessorReflectionImporterProvider.cs | 12 + ...rocessorReflectionImporterProvider.cs.meta | 11 + .../FishNet/CodeGenerating/Processing.meta | 8 + .../Processing/CustomSerializerProcessor.cs | 296 ++ .../CustomSerializerProcessor.cs.meta | 11 + .../NetworkBehaviourPredictionProcessor.cs | 1878 ++++++++ ...etworkBehaviourPredictionProcessor.cs.meta | 11 + .../Processing/NetworkBehaviourProcessor.cs | 681 +++ .../NetworkBehaviourProcessor.cs.meta | 11 + .../NetworkBehaviourSyncProcessor.cs | 1408 ++++++ .../NetworkBehaviourSyncProcessor.cs.meta | 11 + .../Processing/QOLAttributeProcessor.cs | 164 + .../Processing/QOLAttributeProcessor.cs.meta | 11 + .../CodeGenerating/Processing/Rpc.meta | 8 + .../Processing/Rpc/AttributeData.cs | 68 + .../Processing/Rpc/AttributeData.cs.meta | 11 + .../Processing/Rpc/Attributes.cs | 166 + .../Processing/Rpc/Attributes.cs.meta | 11 + .../Processing/Rpc/CreatedRpc.cs | 58 + .../Processing/Rpc/CreatedRpc.cs.meta | 11 + .../Processing/Rpc/RpcProcessor.cs | 1052 +++++ .../Processing/Rpc/RpcProcessor.cs.meta | 11 + .../CodeGenerating/Processing/Typed.meta | 8 + .../Processing/Typed/ProcessedSync.cs | 24 + .../Processing/Typed/ProcessedSync.cs.meta | 11 + .../Unity.FishNet.CodeGen.asmdef | 18 + .../Unity.FishNet.CodeGen.asmdef.meta | 7 + .../FishNet/CodeGenerating/cecil-0.11.4.meta | 8 + .../cecil-0.11.4/Directory.Build.props | 30 + .../cecil-0.11.4/Directory.Build.props.meta} | 2 +- .../CodeGenerating/cecil-0.11.4/LICENSE.txt | 21 + .../cecil-0.11.4/LICENSE.txt.meta} | 2 +- .../cecil-0.11.4/Mono.Cecil.Cil.meta | 8 + .../cecil-0.11.4/Mono.Cecil.Cil/Code.cs | 234 + .../cecil-0.11.4/Mono.Cecil.Cil/Code.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs | 663 +++ .../Mono.Cecil.Cil/CodeReader.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs | 651 +++ .../Mono.Cecil.Cil/CodeWriter.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/Document.cs | 123 + .../Mono.Cecil.Cil/Document.cs.meta | 11 + .../Mono.Cecil.Cil/ExceptionHandler.cs | 71 + .../Mono.Cecil.Cil/ExceptionHandler.cs.meta | 11 + .../Mono.Cecil.Cil/ILProcessor.cs | 291 ++ .../Mono.Cecil.Cil/ILProcessor.cs.meta | 11 + .../Mono.Cecil.Cil/Instruction.cs | 296 ++ .../Mono.Cecil.Cil/Instruction.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs | 426 ++ .../Mono.Cecil.Cil/MethodBody.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs | 439 ++ .../Mono.Cecil.Cil/OpCode.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs | 894 ++++ .../Mono.Cecil.Cil/OpCodes.cs.meta | 11 + .../Mono.Cecil.Cil/PortablePdb.cs | 591 +++ .../Mono.Cecil.Cil/PortablePdb.cs.meta | 11 + .../Mono.Cecil.Cil/SequencePoint.cs | 76 + .../Mono.Cecil.Cil/SequencePoint.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs | 1226 ++++++ .../Mono.Cecil.Cil/Symbols.cs.meta | 11 + .../Mono.Cecil.Cil/VariableDefinition.cs | 29 + .../Mono.Cecil.Cil/VariableDefinition.cs.meta | 11 + .../Mono.Cecil.Cil/VariableReference.cs | 42 + .../Mono.Cecil.Cil/VariableReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Metadata.meta | 8 + .../Mono.Cecil.Metadata/BlobHeap.cs | 54 + .../Mono.Cecil.Metadata/BlobHeap.cs.meta | 11 + .../Mono.Cecil.Metadata/Buffers.cs | 499 +++ .../Mono.Cecil.Metadata/Buffers.cs.meta | 11 + .../Mono.Cecil.Metadata/CodedIndex.cs | 29 + .../Mono.Cecil.Metadata/CodedIndex.cs.meta | 11 + .../Mono.Cecil.Metadata/ElementType.cs | 55 + .../Mono.Cecil.Metadata/ElementType.cs.meta | 11 + .../Mono.Cecil.Metadata/GuidHeap.cs | 36 + .../Mono.Cecil.Metadata/GuidHeap.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs | 24 + .../Mono.Cecil.Metadata/Heap.cs.meta | 11 + .../Mono.Cecil.Metadata/MetadataToken.cs | 94 + .../Mono.Cecil.Metadata/MetadataToken.cs.meta | 11 + .../Mono.Cecil.Metadata/PdbHeap.cs | 32 + .../Mono.Cecil.Metadata/PdbHeap.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Metadata/Row.cs | 152 + .../Mono.Cecil.Metadata/Row.cs.meta | 11 + .../Mono.Cecil.Metadata/StringHeap.cs | 59 + .../Mono.Cecil.Metadata/StringHeap.cs.meta | 11 + .../Mono.Cecil.Metadata/TableHeap.cs | 101 + .../Mono.Cecil.Metadata/TableHeap.cs.meta | 11 + .../Mono.Cecil.Metadata/TokenType.cs | 49 + .../Mono.Cecil.Metadata/TokenType.cs.meta | 11 + .../Mono.Cecil.Metadata/UserStringHeap.cs | 36 + .../UserStringHeap.cs.meta | 11 + .../Mono.Cecil.Metadata/Utilities.cs | 649 +++ .../Mono.Cecil.Metadata/Utilities.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE.meta | 8 + .../Mono.Cecil.PE/BinaryStreamReader.cs | 53 + .../Mono.Cecil.PE/BinaryStreamReader.cs.meta | 11 + .../Mono.Cecil.PE/BinaryStreamWriter.cs | 88 + .../Mono.Cecil.PE/BinaryStreamWriter.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs | 335 ++ .../Mono.Cecil.PE/ByteBuffer.cs.meta | 11 + .../ByteBufferEqualityComparer.cs | 47 + .../ByteBufferEqualityComparer.cs.meta | 11 + .../Mono.Cecil.PE/DataDirectory.cs | 30 + .../Mono.Cecil.PE/DataDirectory.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/Image.cs | 169 + .../cecil-0.11.4/Mono.Cecil.PE/Image.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs | 793 ++++ .../Mono.Cecil.PE/ImageReader.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs | 860 ++++ .../Mono.Cecil.PE/ImageWriter.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/Section.cs | 22 + .../Mono.Cecil.PE/Section.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.PE/TextMap.cs | 106 + .../Mono.Cecil.PE/TextMap.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil.Tests.props | 16 + .../cecil-0.11.4/Mono.Cecil.Tests.props.meta} | 2 +- .../cecil-0.11.4/Mono.Cecil.meta | 8 + .../cecil-0.11.4/Mono.Cecil.nunit | 9 + .../cecil-0.11.4/Mono.Cecil.nunit.meta | 7 + .../cecil-0.11.4/Mono.Cecil.nuspec | 42 + .../cecil-0.11.4/Mono.Cecil.nuspec.meta | 7 + .../cecil-0.11.4/Mono.Cecil.sln.meta | 7 + .../cecil-0.11.4/Mono.Cecil/ArrayType.cs | 145 + .../cecil-0.11.4/Mono.Cecil/ArrayType.cs.meta | 11 + .../Mono.Cecil/AssemblyDefinition.cs | 189 + .../Mono.Cecil/AssemblyDefinition.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs | 24 + .../Mono.Cecil/AssemblyFlags.cs.meta | 11 + .../Mono.Cecil/AssemblyHashAlgorithm.cs | 22 + .../Mono.Cecil/AssemblyHashAlgorithm.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs | 22 + .../Mono.Cecil/AssemblyInfo.cs.meta | 11 + .../Mono.Cecil/AssemblyLinkedResource.cs | 37 + .../Mono.Cecil/AssemblyLinkedResource.cs.meta | 11 + .../Mono.Cecil/AssemblyNameDefinition.cs | 32 + .../Mono.Cecil/AssemblyNameDefinition.cs.meta | 11 + .../Mono.Cecil/AssemblyNameReference.cs | 269 ++ .../Mono.Cecil/AssemblyNameReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/AssemblyReader.cs | 3889 +++++++++++++++++ .../Mono.Cecil/AssemblyReader.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs | 3336 ++++++++++++++ .../Mono.Cecil/AssemblyWriter.cs.meta | 11 + .../Mono.Cecil/BaseAssemblyResolver.cs | 406 ++ .../Mono.Cecil/BaseAssemblyResolver.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/CallSite.cs | 105 + .../cecil-0.11.4/Mono.Cecil/CallSite.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/Consts.cs | 4 + .../cecil-0.11.4/Mono.Cecil/Consts.cs.meta | 11 + .../Mono.Cecil/CustomAttribute.cs | 221 + .../Mono.Cecil/CustomAttribute.cs.meta | 11 + .../Mono.Cecil/DefaultAssemblyResolver.cs | 61 + .../DefaultAssemblyResolver.cs.meta | 11 + .../Mono.Cecil/EmbeddedResource.cs | 98 + .../Mono.Cecil/EmbeddedResource.cs.meta | 11 + .../Mono.Cecil/EventAttributes.cs | 21 + .../Mono.Cecil/EventAttributes.cs.meta | 11 + .../Mono.Cecil/EventDefinition.cs | 156 + .../Mono.Cecil/EventDefinition.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/EventReference.cs | 40 + .../Mono.Cecil/EventReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/ExportedType.cs | 238 + .../Mono.Cecil/ExportedType.cs.meta | 11 + .../Mono.Cecil/FieldAttributes.cs | 41 + .../Mono.Cecil/FieldAttributes.cs.meta | 11 + .../Mono.Cecil/FieldDefinition.cs | 281 ++ .../Mono.Cecil/FieldDefinition.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/FieldReference.cs | 68 + .../Mono.Cecil/FieldReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/FileAttributes.cs | 17 + .../Mono.Cecil/FileAttributes.cs.meta | 11 + .../Mono.Cecil/FunctionPointerType.cs | 111 + .../Mono.Cecil/FunctionPointerType.cs.meta | 11 + .../Mono.Cecil/GenericInstanceMethod.cs | 77 + .../Mono.Cecil/GenericInstanceMethod.cs.meta | 11 + .../Mono.Cecil/GenericInstanceType.cs | 75 + .../Mono.Cecil/GenericInstanceType.cs.meta | 11 + .../Mono.Cecil/GenericParameter.cs | 360 ++ .../Mono.Cecil/GenericParameter.cs.meta | 11 + .../Mono.Cecil/GenericParameterAttributes.cs | 27 + .../GenericParameterAttributes.cs.meta | 11 + .../Mono.Cecil/GenericParameterResolver.cs | 175 + .../GenericParameterResolver.cs.meta | 11 + .../Mono.Cecil/IConstantProvider.cs | 44 + .../Mono.Cecil/IConstantProvider.cs.meta | 11 + .../Mono.Cecil/ICustomAttributeProvider.cs | 44 + .../ICustomAttributeProvider.cs.meta | 11 + .../Mono.Cecil/IGenericInstance.cs | 47 + .../Mono.Cecil/IGenericInstance.cs.meta | 11 + .../Mono.Cecil/IGenericParameterProvider.cs | 58 + .../IGenericParameterProvider.cs.meta | 11 + .../Mono.Cecil/IMarshalInfoProvider.cs | 38 + .../Mono.Cecil/IMarshalInfoProvider.cs.meta | 11 + .../Mono.Cecil/IMemberDefinition.cs | 82 + .../Mono.Cecil/IMemberDefinition.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/IMetadataScope.cs | 23 + .../Mono.Cecil/IMetadataScope.cs.meta | 11 + .../Mono.Cecil/IMetadataTokenProvider.cs | 17 + .../Mono.Cecil/IMetadataTokenProvider.cs.meta | 11 + .../Mono.Cecil/IMethodSignature.cs | 56 + .../Mono.Cecil/IMethodSignature.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/Import.cs | 816 ++++ .../cecil-0.11.4/Mono.Cecil/Import.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/LinkedResource.cs | 42 + .../Mono.Cecil/LinkedResource.cs.meta | 11 + .../Mono.Cecil/ManifestResourceAttributes.cs | 21 + .../ManifestResourceAttributes.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/MarshalInfo.cs | 153 + .../Mono.Cecil/MarshalInfo.cs.meta | 11 + .../Mono.Cecil/MemberDefinitionCollection.cs | 73 + .../MemberDefinitionCollection.cs.meta | 11 + .../Mono.Cecil/MemberReference.cs | 102 + .../Mono.Cecil/MemberReference.cs.meta | 11 + .../Mono.Cecil/MetadataResolver.cs | 391 ++ .../Mono.Cecil/MetadataResolver.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/MetadataSystem.cs | 431 ++ .../Mono.Cecil/MetadataSystem.cs.meta | 11 + .../Mono.Cecil/MethodAttributes.cs | 48 + .../Mono.Cecil/MethodAttributes.cs.meta | 11 + .../Mono.Cecil/MethodCallingConvention.cs | 22 + .../MethodCallingConvention.cs.meta | 11 + .../Mono.Cecil/MethodDefinition.cs | 558 +++ .../Mono.Cecil/MethodDefinition.cs.meta | 11 + .../Mono.Cecil/MethodImplAttributes.cs | 36 + .../Mono.Cecil/MethodImplAttributes.cs.meta | 11 + .../Mono.Cecil/MethodReference.cs | 202 + .../Mono.Cecil/MethodReference.cs.meta | 11 + .../Mono.Cecil/MethodReferenceComparer.cs | 144 + .../MethodReferenceComparer.cs.meta | 11 + .../Mono.Cecil/MethodReturnType.cs | 97 + .../Mono.Cecil/MethodReturnType.cs.meta | 11 + .../Mono.Cecil/MethodSemanticsAttributes.cs | 25 + .../MethodSemanticsAttributes.cs.meta | 11 + .../Mono.Cecil/MethodSpecification.cs | 83 + .../Mono.Cecil/MethodSpecification.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/Modifiers.cs | 112 + .../cecil-0.11.4/Mono.Cecil/Modifiers.cs.meta | 11 + .../Mono.Cecil/ModuleDefinition.cs | 1353 ++++++ .../Mono.Cecil/ModuleDefinition.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/ModuleKind.cs | 55 + .../Mono.Cecil/ModuleKind.cs.meta | 11 + .../Mono.Cecil/ModuleReference.cs | 49 + .../Mono.Cecil/ModuleReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/NativeType.cs | 55 + .../Mono.Cecil/NativeType.cs.meta | 11 + .../Mono.Cecil/PInvokeAttributes.cs | 44 + .../Mono.Cecil/PInvokeAttributes.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs | 120 + .../Mono.Cecil/PInvokeInfo.cs.meta | 11 + .../Mono.Cecil/ParameterAttributes.cs | 27 + .../Mono.Cecil/ParameterAttributes.cs.meta | 11 + .../Mono.Cecil/ParameterDefinition.cs | 146 + .../Mono.Cecil/ParameterDefinition.cs.meta | 11 + .../ParameterDefinitionCollection.cs | 60 + .../ParameterDefinitionCollection.cs.meta | 11 + .../Mono.Cecil/ParameterReference.cs | 57 + .../Mono.Cecil/ParameterReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/PinnedType.cs | 35 + .../Mono.Cecil/PinnedType.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/PointerType.cs | 43 + .../Mono.Cecil/PointerType.cs.meta | 11 + .../Mono.Cecil/PropertyAttributes.cs | 23 + .../Mono.Cecil/PropertyAttributes.cs.meta | 11 + .../Mono.Cecil/PropertyDefinition.cs | 245 ++ .../Mono.Cecil/PropertyDefinition.cs.meta | 11 + .../Mono.Cecil/PropertyReference.cs | 43 + .../Mono.Cecil/PropertyReference.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/ReferenceType.cs | 43 + .../Mono.Cecil/ReferenceType.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/Resource.cs | 58 + .../cecil-0.11.4/Mono.Cecil/Resource.cs.meta | 11 + .../Mono.Cecil/SecurityDeclaration.cs | 201 + .../Mono.Cecil/SecurityDeclaration.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/SentinelType.cs | 35 + .../Mono.Cecil/SentinelType.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TargetRuntime.cs | 19 + .../Mono.Cecil/TargetRuntime.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/Treatments.cs | 61 + .../Mono.Cecil/Treatments.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeAttributes.cs | 63 + .../Mono.Cecil/TypeAttributes.cs.meta | 11 + .../Mono.Cecil/TypeComparisonMode.cs | 11 + .../Mono.Cecil/TypeComparisonMode.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeDefinition.cs | 618 +++ .../Mono.Cecil/TypeDefinition.cs.meta | 11 + .../Mono.Cecil/TypeDefinitionCollection.cs | 98 + .../TypeDefinitionCollection.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeParser.cs | 531 +++ .../Mono.Cecil/TypeParser.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeReference.cs | 352 ++ .../Mono.Cecil/TypeReference.cs.meta | 11 + .../TypeReferenceEqualityComparer.cs | 253 ++ .../TypeReferenceEqualityComparer.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeResolver.cs | 220 + .../Mono.Cecil/TypeResolver.cs.meta | 11 + .../Mono.Cecil/TypeSpecification.cs | 66 + .../Mono.Cecil/TypeSpecification.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/TypeSystem.cs | 330 ++ .../Mono.Cecil/TypeSystem.cs.meta | 11 + .../cecil-0.11.4/Mono.Cecil/VariantType.cs | 37 + .../Mono.Cecil/VariantType.cs.meta | 11 + .../Mono.Cecil/WindowsRuntimeProjections.cs | 959 ++++ .../WindowsRuntimeProjections.cs.meta | 11 + .../Mono.Collections.Generic.meta | 8 + .../Mono.Collections.Generic/Collection.cs | 427 ++ .../Collection.cs.meta | 11 + .../ReadOnlyCollection.cs | 101 + .../ReadOnlyCollection.cs.meta | 11 + .../Mono.Security.Cryptography.meta | 8 + .../CryptoConvert.cs | 290 ++ .../CryptoConvert.cs.meta | 11 + .../CryptoService.cs | 202 + .../CryptoService.cs.meta | 11 + .../CodeGenerating/cecil-0.11.4/Mono.meta | 8 + .../cecil-0.11.4/Mono/Disposable.cs | 45 + .../cecil-0.11.4/Mono/Disposable.cs.meta | 11 + .../CodeGenerating/cecil-0.11.4/Mono/Empty.cs | 62 + .../cecil-0.11.4/Mono/Empty.cs.meta | 11 + .../cecil-0.11.4/Mono/MergeSort.cs | 66 + .../cecil-0.11.4/Mono/MergeSort.cs.meta | 11 + .../cecil-0.11.4/MonoFN.Cecil.asmdef | 15 + .../cecil-0.11.4/MonoFN.Cecil.asmdef.meta | 7 + .../cecil-0.11.4/ProjectInfo.cs | 20 + .../cecil-0.11.4/ProjectInfo.cs.meta | 11 + .../CodeGenerating/cecil-0.11.4/README.md | 17 + .../cecil-0.11.4/README.md.meta | 7 + .../CodeGenerating/cecil-0.11.4/cecil.snk | Bin 0 -> 596 bytes .../cecil-0.11.4/cecil.snk.meta | 7 + .../CodeGenerating/cecil-0.11.4/rocks.meta | 8 + .../cecil-0.11.4/rocks/Mono.Cecil.Rocks.meta | 8 + .../rocks/Mono.Cecil.Rocks/AssemblyInfo.cs | 15 + .../Mono.Cecil.Rocks/AssemblyInfo.cs.meta | 11 + .../rocks/Mono.Cecil.Rocks/DocCommentId.cs | 261 ++ .../Mono.Cecil.Rocks/DocCommentId.cs.meta | 11 + .../rocks/Mono.Cecil.Rocks/Functional.cs | 41 + .../rocks/Mono.Cecil.Rocks/Functional.cs.meta | 11 + .../rocks/Mono.Cecil.Rocks/ILParser.cs | 228 + .../rocks/Mono.Cecil.Rocks/ILParser.cs.meta | 11 + .../rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs | 411 ++ .../Mono.Cecil.Rocks/MethodBodyRocks.cs.meta | 11 + .../Mono.Cecil.Rocks/MethodDefinitionRocks.cs | 72 + .../MethodDefinitionRocks.cs.meta | 11 + .../Mono.Cecil.Rocks/ModuleDefinitionRocks.cs | 32 + .../ModuleDefinitionRocks.cs.meta | 11 + .../ParameterReferenceRocks.cs | 11 + .../ParameterReferenceRocks.cs.meta | 11 + .../SecurityDeclarationRocks.cs | 157 + .../SecurityDeclarationRocks.cs.meta | 11 + .../Mono.Cecil.Rocks/TypeDefinitionRocks.cs | 65 + .../TypeDefinitionRocks.cs.meta | 11 + .../Mono.Cecil.Rocks/TypeReferenceRocks.cs | 87 + .../TypeReferenceRocks.cs.meta | 11 + UnityProject/Assets/FishNet/DOCUMENTATION.txt | 3 + .../Assets/FishNet/DOCUMENTATION.txt.meta | 7 + UnityProject/Assets/FishNet/Example.meta | 8 + UnityProject/Assets/FishNet/Example/All.meta | 8 + .../FishNet/Example/All/Authenticator.meta | 8 + .../All/Authenticator/Authenticator.unity | 375 ++ .../Authenticator/Authenticator.unity.meta | 7 + .../Example/All/Authenticator}/Scripts.meta | 2 +- .../All/Authenticator/Scripts/Broadcasts.cs | 17 + .../Authenticator/Scripts/Broadcasts.cs.meta | 11 + .../Scripts/PasswordAuthenticator.cs | 114 + .../Scripts/PasswordAuthenticator.cs.meta | 11 + .../FishNet/Example/All/CustomSyncType.meta | 8 + .../CustomSyncType/Component State Sync.meta | 8 + .../Component State Sync/AMonoScript.cs | 17 + .../Component State Sync/AMonoScript.cs.meta | 11 + .../ComponentStateSync.cs | 157 + .../ComponentStateSync.cs.meta | 11 + .../ComponentSyncStateBehaviour.cs | 43 + .../ComponentSyncStateBehaviour.cs.meta | 11 + .../CustomSyncType/Custom Struct Sync.meta | 8 + .../Custom Struct Sync/StructSyncBehaviour.cs | 44 + .../StructSyncBehaviour.cs.meta | 11 + .../Custom Struct Sync/StructySync.cs | 332 ++ .../Custom Struct Sync/StructySync.cs.meta | 11 + .../FishNet/Example/All/Prediction.meta | 8 + .../All/Prediction/CharacterController.meta | 8 + .../CharacterControllerPrediction.unity | 1264 ++++++ .../CharacterControllerPrediction.unity.meta | 7 + .../CharacterController/Prefabs.meta | 8 + .../CharacterControllerPrediction.prefab | 221 + ...CharacterControllerPrediction.prefab.meta} | 2 +- .../CharacterController/Scripts.meta | 8 + .../Scripts/CharacterControllerPrediction.cs | 115 + .../CharacterControllerPrediction.cs.meta | 11 + .../Example/All/Prediction/Materials.meta | 8 + .../All/Prediction/Materials/BlueMat.mat | 77 + .../Prediction/Materials/BlueMat.mat.meta} | 4 +- .../All/Prediction/Materials/GroundMat.mat | 77 + .../Prediction/Materials/GroundMat.mat.meta} | 4 +- .../All/Prediction/Materials/PurpleMat.mat | 77 + .../Prediction/Materials/PurpleMat.mat.meta | 8 + .../All/Prediction/Materials/YellowishMat.mat | 77 + .../Materials/YellowishMat.mat.meta | 8 + .../Example/All/Prediction/Rigidbody.meta | 8 + .../All/Prediction/Rigidbody/Prefabs.meta | 8 + .../Prefabs/RigidbodyPrediction.prefab | 459 ++ .../Prefabs/RigidbodyPrediction.prefab.meta | 7 + .../Rigidbody/RigidbodyPrediction.unity | 759 ++++ .../Rigidbody/RigidbodyPrediction.unity.meta | 7 + .../All/Prediction/Rigidbody/Scripts.meta | 8 + .../Rigidbody/Scripts/RigidbodyPrediction.cs | 161 + .../Scripts/RigidbodyPrediction.cs.meta | 11 + .../Example/All/Prediction/Transform.meta | 8 + .../All/Prediction/Transform/Prefabs.meta | 8 + .../Prefabs/TransformPrediction.prefab | 246 ++ .../Prefabs/TransformPrediction.prefab.meta | 7 + .../All/Prediction/Transform/Scripts.meta | 8 + .../Transform/Scripts/TransformPrediction.cs | 197 + .../Scripts/TransformPrediction.cs.meta | 11 + .../Transform/TransformPrediction.unity | 736 ++++ .../Transform/TransformPrediction.unity.meta | 7 + .../FishNet/Example/All/SceneManager.meta | 8 + .../Example/All/SceneManager/Materials.meta | 8 + .../All/SceneManager/Materials/Black.mat | 78 + .../All/SceneManager/Materials/Black.mat.meta | 8 + .../All/SceneManager/Materials/Blue.mat | 78 + .../All/SceneManager/Materials/Blue.mat.meta | 8 + .../All/SceneManager/Materials/Green.mat | 78 + .../All/SceneManager/Materials/Green.mat.meta | 8 + .../All/SceneManager/Materials/Red.mat | 78 + .../All/SceneManager/Materials/Red.mat.meta | 8 + .../Example/All/SceneManager/Prefabs.meta | 8 + .../All/SceneManager/Prefabs/Player.prefab | 342 ++ .../SceneManager/Prefabs/Player.prefab.meta | 7 + .../SceneManager Event Diagram.png | Bin 0 -> 45367 bytes .../SceneManager Event Diagram.png.meta | 92 + .../Example/All/SceneManager/Scenes.meta | 8 + .../All/SceneManager/Scenes/Additive.meta | 8 + .../Scenes/Additive/AdditiveConnection.unity | 264 ++ .../Additive/AdditiveConnection.unity.meta | 7 + .../Scenes/Additive/AdditiveGlobal.unity | 264 ++ .../Scenes/Additive/AdditiveGlobal.unity.meta | 7 + .../Scenes/Additive/AdditiveMain.unity | 1261 ++++++ .../Scenes/Additive/AdditiveMain.unity.meta | 7 + .../All/SceneManager/Scenes/Replace.meta | 8 + .../Scenes/Replace/ReplaceConnection.unity | 617 +++ .../Replace/ReplaceConnection.unity.meta | 7 + .../Scenes/Replace/ReplaceGlobal.unity | 593 +++ .../Scenes/Replace/ReplaceGlobal.unity.meta | 7 + .../Scenes/Replace/ReplaceMain.unity | 1234 ++++++ .../Scenes/Replace/ReplaceMain.unity.meta | 7 + .../Example/All/SceneManager/Scripts.meta | 8 + .../SceneManager/Scripts/PlayerController.cs | 75 + .../Scripts/PlayerController.cs.meta | 11 + .../Scripts/SceneLoaderExample.cs | 147 + .../Scripts/SceneLoaderExample.cs.meta | 11 + .../Scripts/SceneUnloaderExample.cs | 91 + .../Scripts/SceneUnloaderExample.cs.meta | 11 + .../FishNet/Example/FishNet.Example.asmdef | 15 + .../Example/FishNet.Example.asmdef.meta | 7 + .../Assets/FishNet/Example/Prefabs.meta | 8 + .../Example/Prefabs/NetworkHudCanvas.prefab | 529 +++ .../Prefabs/NetworkHudCanvas.prefab.meta | 7 + .../Example/Prefabs/NetworkManager.prefab | 208 + .../Prefabs/NetworkManager.prefab.meta | 7 + .../Assets/FishNet/Example/Scripts.meta | 8 + .../Example/Scripts/NetworkHudCanvases.cs | 248 ++ .../Scripts/NetworkHudCanvases.cs.meta | 11 + UnityProject/Assets/FishNet/LICENSE.txt | 35 + UnityProject/Assets/FishNet/LICENSE.txt.meta | 7 + .../Ignorance => FishNet}/Plugins.meta | 2 +- .../Assets/FishNet/Plugins/Addressables.meta | 8 + .../Addressables/AddressablesExtensions.cs | 24 + .../AddressablesExtensions.cs.meta | 11 + .../Assets/FishNet/Plugins/CodeAnalysis.meta | 8 + .../FishNet.CodeAnalysis.Analyzers.dll | Bin 0 -> 22016 bytes .../FishNet.CodeAnalysis.Analyzers.dll.meta} | 20 +- .../CodeAnalysis/FishNet.CodeAnalysis.dll | Bin 0 -> 5120 bytes .../FishNet.CodeAnalysis.dll.meta} | 13 +- .../FishNet/Plugins/CodeAnalysis/LICENSE.txt | 4 +- .../Plugins/CodeAnalysis/LICENSE.txt.meta | 7 + .../FishNet/Plugins/CodeAnalysis/README.txt | 2 + .../Plugins/CodeAnalysis}/README.txt.meta | 2 +- UnityProject/Assets/FishNet/Runtime.meta | 8 + .../FishNet/Runtime/Authenticating.meta | 8 + .../Runtime/Authenticating/Authenticator.cs | 44 + .../Authenticating/Authenticator.cs.meta | 11 + .../Assets/FishNet/Runtime/Broadcast.meta | 8 + .../FishNet/Runtime/Broadcast/Helping.meta | 8 + .../Broadcast/Helping/BroadcastHelper.cs | 19 + .../Broadcast/Helping/BroadcastHelper.cs.meta | 11 + .../FishNet/Runtime/Broadcast/IBroadcast.cs | 8 + .../Runtime/Broadcast/IBroadcast.cs.meta | 11 + .../Assets/FishNet/Runtime/Config.json | 1 + .../Assets/FishNet/Runtime/Config.json.meta | 7 + .../Assets/FishNet/Runtime/Connection.meta | 8 + .../FishNet/Runtime/Connection/Buffer.cs | 244 ++ .../FishNet/Runtime/Connection/Buffer.cs.meta | 11 + .../Connection/NetworkConnection.Buffer.cs | 115 + .../NetworkConnection.Buffer.cs.meta | 11 + .../Connection/NetworkConnection.PingPong.cs | 104 + .../NetworkConnection.PingPong.cs.meta | 11 + .../Connection/NetworkConnection.QOL.cs | 29 + .../Connection/NetworkConnection.QOL.cs.meta | 11 + .../Runtime/Connection/NetworkConnection.cs | 308 ++ .../Connection/NetworkConnection.cs.meta | 11 + .../Runtime/DefaultPrefabObjects.asset | 21 + .../Runtime/DefaultPrefabObjects.asset.meta | 8 + .../Assets/FishNet/Runtime/Documenting.meta | 8 + .../FishNet/Runtime/Documenting/Attributes.cs | 8 + .../Runtime/Documenting/Attributes.cs.meta | 11 + .../Assets/FishNet/Runtime/Editor.meta | 8 + .../FishNet/Runtime/Editor/CodeStripping.cs | 118 + .../Runtime/Editor/CodeStripping.cs.meta | 11 + .../FishNet/Runtime/Editor/Configuration.meta | 8 + .../Editor/Configuration/SettingsProvider.cs | 1 + .../Configuration/SettingsProvider.cs.meta | 11 + .../FishNet/Runtime/Editor/Configuring.meta | 8 + .../Editor/Configuring/ConfigurationData.cs | 124 + .../Configuring/ConfigurationData.cs.meta | 11 + .../Editor/Configuring/ConfigurationEditor.cs | 86 + .../Configuring/ConfigurationEditor.cs.meta | 11 + .../Runtime/Editor/Configuring/Configuring.cs | 95 + .../Editor/Configuring/Configuring.cs.meta | 11 + .../Editor/Configuring/SettingsProvider.cs | 86 + .../Configuring/SettingsProvider.cs.meta | 11 + .../FishNet/Runtime/Editor/Constants.cs | 13 + .../FishNet/Runtime/Editor/Constants.cs.meta | 11 + .../Runtime/Editor/DefaultPrefabsFinder.cs | 126 + .../Editor/DefaultPrefabsFinder.cs.meta | 11 + .../Assets/FishNet/Runtime/Editor/Finding.cs | 216 + .../FishNet/Runtime/Editor/Finding.cs.meta | 11 + .../FishNet/Runtime/Editor/PlayModeTracker.cs | 51 + .../Runtime/Editor/PlayModeTracker.cs.meta | 11 + .../Editor/PrefabCollectionGenerator.meta | 8 + .../PrefabCollectionGenerator/Generator.cs | 557 +++ .../Generator.cs.meta | 11 + .../PrefabCollectionGenerator/Settings.cs | 103 + .../Settings.cs.meta | 11 + .../SettingsProvider.cs | 230 + .../SettingsProvider.cs.meta | 11 + .../FishNet/Runtime/Editor/PrefabProcessor.cs | 85 + .../Runtime/Editor/PrefabProcessor.cs.meta | 11 + .../Runtime/Editor/ScriptingDefines.cs | 50 + .../Runtime/Editor/ScriptingDefines.cs.meta | 11 + .../Runtime/Editor}/Textures.meta | 2 +- .../FishNet/Runtime/Editor/Textures/Icon.meta | 8 + .../Editor/Textures/Icon/fishnet_light.png | Bin 0 -> 41016 bytes .../Textures/Icon/fishnet_light.png.meta | 92 + .../FishNet/Runtime/Editor/Textures/UI.meta | 8 + .../UI/Button_Dark_Client_Background.png | Bin 0 -> 7098 bytes .../Button_Dark_Client_Background.png.meta} | 28 +- .../Textures/UI/Button_Dark_Indicator.png | Bin 0 -> 2891 bytes .../UI/Button_Dark_Indicator.png.meta} | 41 +- .../UI/Button_Dark_Server_Background.png | Bin 0 -> 9320 bytes .../UI/Button_Dark_Server_Background.png.meta | 116 + .../FishNet/Runtime/FishNet.Runtime.asmdef | 17 + .../Runtime/FishNet.Runtime.asmdef.meta | 7 + .../Assets/FishNet/Runtime/Generated.meta | 8 + .../FishNet/Runtime/Generated/Component.meta | 8 + .../Generated/Component/NetworkAnimator.meta | 8 + .../Component/NetworkAnimator/Editor.meta | 8 + .../Editor/NetworkAnimatorEditor.cs | 184 + .../Editor/NetworkAnimatorEditor.cs.meta | 11 + .../NetworkAnimator/NetworkAnimator.cs | 1332 ++++++ .../NetworkAnimator/NetworkAnimator.cs.meta | 11 + .../Generated/Component/NetworkTransform.meta | 8 + .../Component/NetworkTransform/Editor.meta | 8 + .../Editor/NetworkTransformEditor.cs | 135 + .../Editor/NetworkTransformEditor.cs.meta | 11 + .../NetworkTransform/NetworkTransform.cs | 1743 ++++++++ .../NetworkTransform/NetworkTransform.cs.meta | 11 + .../NetworkTransform/SynchronizedProperty.cs | 13 + .../SynchronizedProperty.cs.meta | 11 + .../Generated/Component/Observing.meta | 8 + .../Observing/DistanceCondition.asset | 18 + .../Observing/DistanceCondition.asset.meta | 8 + .../Component/Observing/MatchCondition.asset | 15 + .../Observing/MatchCondition.asset.meta | 8 + .../Observing/OwnerOnlyCondition.asset | 15 + .../Observing/OwnerOnlyCondition.asset.meta | 8 + .../Component/Observing/SceneCondition.asset | 17 + .../Observing/SceneCondition.asset.meta | 8 + .../Observing/ServerOnlyCondition.asset | 15 + .../Observing/ServerOnlyCondition.asset.meta | 8 + .../Generated/Component/Prediction.meta | 8 + .../Component/Prediction/DesyncSmoother.cs | 11 + .../Prediction/DesyncSmoother.cs.meta | 11 + .../Component/Prediction/Editor.meta | 8 + .../Editor/PredictedObjectEditor.cs | 93 + .../Editor/PredictedObjectEditor.cs.meta | 11 + .../Component/Prediction/OfflineRigidbody.cs | 298 ++ .../Prediction/OfflineRigidbody.cs.meta | 11 + .../Prediction/PredictedObject.Rigidbodies.cs | 408 ++ .../PredictedObject.Rigidbodies.cs.meta | 11 + .../Component/Prediction/PredictedObject.cs | 441 ++ .../Prediction/PredictedObject.cs.meta | 11 + .../Prediction/PredictedRigidbody.cs | 17 + .../Prediction/PredictedRigidbody.cs.meta | 11 + .../Prediction/PredictedRigidbody2D.cs | 17 + .../Prediction/PredictedRigidbody2D.cs.meta | 11 + .../Prediction/PredictedRigidbodyBase.cs | 17 + .../Prediction/PredictedRigidbodyBase.cs.meta | 11 + .../Component/Prediction/RigidbodyState.cs | 90 + .../Prediction/RigidbodyState.cs.meta | 11 + .../Runtime/Generated/Component/Spawning.meta | 8 + .../Component/Spawning/PlayerSpawner.cs | 158 + .../Component/Spawning/PlayerSpawner.cs.meta | 11 + .../Runtime/Generated/Component/Utility.meta | 8 + .../Component/Utility/DefaultScene.cs | 203 + .../Component/Utility/DefaultScene.cs.meta | 11 + .../Component/Utility/PingDisplay.cs | 91 + .../Component/Utility/PingDisplay.cs.meta | 11 + .../Generated/FishNet.Generated.asmdef | 15 + .../Generated/FishNet.Generated.asmdef.meta | 7 + .../Runtime/Generated/ReaderAndWriters.meta | 8 + .../ConnectionReaderWriters.cs | 53 + .../ConnectionReaderWriters.cs.meta | 11 + .../ReaderAndWriters/ScenedReaderWriters.cs | 425 ++ .../ScenedReaderWriters.cs.meta | 11 + .../Assets/FishNet/Runtime/InstanceFinder.cs | 178 + .../FishNet/Runtime/InstanceFinder.cs.meta | 11 + .../Assets/FishNet/Runtime/Managing.meta | 8 + .../FishNet/Runtime/Managing/Client.meta | 8 + .../Client/ClientManager.Broadcast.cs | 180 + .../Client/ClientManager.Broadcast.cs.meta | 11 + .../Runtime/Managing/Client/ClientManager.cs | 472 ++ .../Managing/Client/ClientManager.cs.meta | 11 + .../Runtime/Managing/Client/Editor.meta | 8 + .../Client/Editor/ClientManagerEditor.cs | 46 + .../Client/Editor/ClientManagerEditor.cs.meta | 11 + .../Runtime/Managing/Client/Object.meta | 8 + .../Client/Object/ClientObjects.RpcLinks.cs | 87 + .../Object/ClientObjects.RpcLinks.cs.meta | 11 + .../Managing/Client/Object/ClientObjects.cs | 746 ++++ .../Client/Object/ClientObjects.cs.meta | 11 + .../Managing/Client/Object/ObjectCaching.cs | 548 +++ .../Client/Object/ObjectCaching.cs.meta | 11 + .../FishNet/Runtime/Managing/Debugging.meta | 8 + .../Managing/Debugging/DebugManager.cs | 20 + .../Managing/Debugging/DebugManager.cs.meta | 11 + .../Runtime/Managing/Debugging/ParseLogger.cs | 77 + .../Managing/Debugging/ParseLogger.cs.meta | 11 + .../FishNet/Runtime/Managing/Editor.meta | 8 + .../Managing/Editor/NetworkManagerEditor.cs | 72 + .../Editor/NetworkManagerEditor.cs.meta | 11 + .../FishNet/Runtime/Managing/Logging.meta | 8 + .../Managing/Logging/LoggingConfiguration.cs | 127 + .../Logging/LoggingConfiguration.cs.meta | 11 + .../Runtime/Managing/Logging/LoggingType.cs | 25 + .../Managing/Logging/LoggingType.cs.meta | 11 + .../Managing/NetworkManager.Logging.cs | 124 + .../Managing/NetworkManager.Logging.cs.meta | 11 + .../Runtime/Managing/NetworkManager.Pro.cs | 32 + .../Managing/NetworkManager.Pro.cs.meta | 11 + .../Runtime/Managing/NetworkManager.QOL.cs | 55 + .../Managing/NetworkManager.QOL.cs.meta | 11 + .../Runtime/Managing/NetworkManager.cs | 538 +++ .../Runtime/Managing/NetworkManager.cs.meta | 11 + .../FishNet/Runtime/Managing/Object.meta | 8 + .../Runtime/Managing/Object/DualPrefab.cs | 16 + .../Managing/Object/DualPrefab.cs.meta | 11 + .../Runtime/Managing/Object/ManagedObjects.cs | 380 ++ .../Managing/Object/ManagedObjects.cs.meta | 11 + .../Managing/Object/ObjectSpawnType.cs | 12 + .../Managing/Object/ObjectSpawnType.cs.meta | 11 + .../Managing/Object/PrefabObjects.meta | 8 + .../PrefabObjects/DefaultPrefabObjects.cs | 104 + .../DefaultPrefabObjects.cs.meta | 11 + .../Object/PrefabObjects/DualPrefabObjects.cs | 144 + .../PrefabObjects/DualPrefabObjects.cs.meta | 11 + .../Object/PrefabObjects/PrefabObjects.cs | 24 + .../PrefabObjects/PrefabObjects.cs.meta | 11 + .../PrefabObjects/SinglePrefabObjects.cs | 136 + .../PrefabObjects/SinglePrefabObjects.cs.meta | 11 + .../Managing/Object/SpawnParentType.cs | 10 + .../Managing/Object/SpawnParentType.cs.meta | 11 + .../Runtime/Managing/ObserverManager.cs | 167 + .../Runtime/Managing/ObserverManager.cs.meta | 11 + .../FishNet/Runtime/Managing/Scened.meta | 8 + .../Runtime/Managing/Scened/Broadcast.meta | 8 + .../Scened/Broadcast/SceneBroadcasts.cs | 38 + .../Scened/Broadcast/SceneBroadcasts.cs.meta | 11 + .../Managing/Scened/DefaultSceneProcessor.cs | 155 + .../Scened/DefaultSceneProcessor.cs.meta | 11 + .../Runtime/Managing/Scened/Events.meta | 8 + .../Events/ClientPresenceChangeEventArgs.cs | 34 + .../ClientPresenceChangeEventArgs.cs.meta | 11 + .../Scened/Events/LoadSceneEventArgs.cs | 78 + .../Scened/Events/LoadSceneEventArgs.cs.meta | 11 + .../Scened/Events/UnloadSceneEventArgs.cs | 42 + .../Events/UnloadSceneEventArgs.cs.meta | 11 + .../Managing/Scened/LoadUnloadDatas.meta | 8 + .../Scened/LoadUnloadDatas/LoadOptions.cs | 33 + .../LoadUnloadDatas/LoadOptions.cs.meta | 11 + .../Scened/LoadUnloadDatas/LoadParams.cs | 19 + .../Scened/LoadUnloadDatas/LoadParams.cs.meta | 11 + .../Scened/LoadUnloadDatas/LoadQueueData.cs | 51 + .../LoadUnloadDatas/LoadQueueData.cs.meta | 11 + .../Scened/LoadUnloadDatas/ReplaceOption.cs | 25 + .../LoadUnloadDatas/ReplaceOption.cs.meta | 11 + .../Scened/LoadUnloadDatas/SceneLoadData.cs | 180 + .../LoadUnloadDatas/SceneLoadData.cs.meta | 11 + .../Scened/LoadUnloadDatas/SceneScopeTypes.cs | 18 + .../LoadUnloadDatas/SceneScopeTypes.cs.meta | 11 + .../Scened/LoadUnloadDatas/SceneUnloadData.cs | 112 + .../LoadUnloadDatas/SceneUnloadData.cs.meta | 11 + .../Scened/LoadUnloadDatas/UnloadOptions.cs | 36 + .../LoadUnloadDatas/UnloadOptions.cs.meta | 11 + .../Scened/LoadUnloadDatas/UnloadParams.cs | 19 + .../LoadUnloadDatas/UnloadParams.cs.meta | 11 + .../Scened/LoadUnloadDatas/UnloadQueueData.cs | 53 + .../LoadUnloadDatas/UnloadQueueData.cs.meta | 11 + .../Managing/Scened/SceneLookupData.cs | 324 ++ .../Managing/Scened/SceneLookupData.cs.meta | 11 + .../Runtime/Managing/Scened/SceneManager.cs | 2054 +++++++++ .../Managing/Scened/SceneManager.cs.meta | 11 + .../Managing/Scened/SceneProcessorBase.cs | 93 + .../Scened/SceneProcessorBase.cs.meta | 11 + .../Runtime/Managing/Scened/SceneSpawner.cs | 356 ++ .../Managing/Scened/SceneSpawner.cs.meta | 11 + .../FishNet/Runtime/Managing/Server.meta | 8 + .../Server/ClientConnectionBroadcast.cs | 22 + .../Server/ClientConnectionBroadcast.cs.meta | 11 + .../Runtime/Managing/Server/Editor.meta | 8 + .../Server/Editor/ServerManagerEditor.cs | 61 + .../Server/Editor/ServerManagerEditor.cs.meta | 11 + .../Runtime/Managing/Server/Object.meta | 8 + .../Server/Object/ServerObjects.Observers.cs | 468 ++ .../Object/ServerObjects.Observers.cs.meta | 11 + .../Server/Object/ServerObjects.Parsing.cs | 45 + .../Object/ServerObjects.Parsing.cs.meta | 11 + .../Managing/Server/Object/ServerObjects.cs | 764 ++++ .../Server/Object/ServerObjects.cs.meta | 11 + .../Server/ServerManager.Broadcast.cs | 470 ++ .../Server/ServerManager.Broadcast.cs.meta | 11 + .../Managing/Server/ServerManager.QOL.cs | 206 + .../Managing/Server/ServerManager.QOL.cs.meta | 11 + .../Managing/Server/ServerManager.RpcLinks.cs | 78 + .../Server/ServerManager.RpcLinks.cs.meta | 11 + .../Runtime/Managing/Server/ServerManager.cs | 679 +++ .../Managing/Server/ServerManager.cs.meta | 11 + .../FishNet/Runtime/Managing/Statistic.meta | 8 + .../Managing/Statistic/NetworkTrafficArgs.cs | 21 + .../Statistic/NetworkTrafficArgs.cs.meta | 11 + .../Statistic/NetworkTrafficStatistics.cs | 199 + .../NetworkTrafficStatistics.cs.meta | 11 + .../Managing/Statistic/StatisticsManager.cs | 22 + .../Statistic/StatisticsManager.cs.meta | 11 + .../FishNet/Runtime/Managing/Timing.meta | 8 + .../Runtime/Managing/Timing/Editor.meta | 8 + .../Timing/Editor/TimeManagerEditor.cs | 65 + .../Timing/Editor/TimeManagerEditor.cs.meta | 11 + .../Runtime/Managing/Timing/MovingAverage.cs | 86 + .../Managing/Timing/MovingAverage.cs.meta | 11 + .../Runtime/Managing/Timing/PhysicsMode.cs | 23 + .../Managing/Timing/PhysicsMode.cs.meta | 11 + .../Runtime/Managing/Timing/PreciseTick.cs | 47 + .../Managing/Timing/PreciseTick.cs.meta | 11 + .../Runtime/Managing/Timing/SceneComparer.cs | 18 + .../Managing/Timing/SceneComparer.cs.meta | 11 + .../Runtime/Managing/Timing/TickRounding.cs | 23 + .../Managing/Timing/TickRounding.cs.meta | 11 + .../Runtime/Managing/Timing/TickType.cs | 10 + .../Runtime/Managing/Timing/TickType.cs.meta | 11 + .../Runtime/Managing/Timing/TimeManager.cs | 1051 +++++ .../Managing/Timing/TimeManager.cs.meta | 11 + .../Runtime/Managing/Transporting.meta | 8 + .../Managing/Transporting/LatencySimulator.cs | 352 ++ .../Transporting/LatencySimulator.cs.meta | 11 + .../Managing/Transporting/SplitReader.cs | 87 + .../Managing/Transporting/SplitReader.cs.meta | 11 + .../Transporting/TransportManager.QOL.cs | 65 + .../Transporting/TransportManager.QOL.cs.meta | 11 + .../Managing/Transporting/TransportManager.cs | 511 +++ .../Transporting/TransportManager.cs.meta | 11 + .../FishNet/Runtime/Managing/Utility.meta | 8 + .../Runtime/Managing/Utility/Utility.cs | 67 + .../Runtime/Managing/Utility/Utility.cs.meta | 11 + .../Assets/FishNet/Runtime/Object.meta | 8 + .../FishNet/Runtime/Object/Attributes.cs | 134 + .../FishNet/Runtime/Object/Attributes.cs.meta | 11 + .../Object/ChangedTransformProperties.cs | 35 + .../Object/ChangedTransformProperties.cs.meta | 11 + .../FishNet/Runtime/Object/Delegates.cs | 13 + .../FishNet/Runtime/Object/Delegates.cs.meta | 11 + .../Runtime/Object/EmptyNetworkBehaviour.cs | 13 + .../Object/EmptyNetworkBehaviour.cs.meta | 11 + .../FishNet/Runtime/Object/Helping.meta | 8 + .../FishNet/Runtime/Object/Helping/Hashing.cs | 153 + .../Runtime/Object/Helping/Hashing.cs.meta | 11 + .../FishNet/Runtime/Object/Helping/RpcLink.cs | 39 + .../Runtime/Object/Helping/RpcLink.cs.meta | 11 + .../FishNet/Runtime/Object/Helping/RpcType.cs | 13 + .../Runtime/Object/Helping/RpcType.cs.meta | 11 + .../Runtime/Object/Helping/StaticShortcuts.cs | 49 + .../Object/Helping/StaticShortcuts.cs.meta | 11 + .../Object/NetworkBehaviour.Callbacks.cs | 184 + .../Object/NetworkBehaviour.Callbacks.cs.meta | 11 + .../Object/NetworkBehaviour.Logging.cs | 22 + .../Object/NetworkBehaviour.Logging.cs.meta | 11 + .../Object/NetworkBehaviour.Prediction.cs | 277 ++ .../NetworkBehaviour.Prediction.cs.meta | 11 + .../Runtime/Object/NetworkBehaviour.QOL.cs | 183 + .../Object/NetworkBehaviour.QOL.cs.meta | 11 + .../Object/NetworkBehaviour.RPCLinks.cs | 128 + .../Object/NetworkBehaviour.RPCLinks.cs.meta | 11 + .../Runtime/Object/NetworkBehaviour.RPCs.cs | 426 ++ .../Object/NetworkBehaviour.RPCs.cs.meta | 11 + .../Object/NetworkBehaviour.SyncTypes.cs | 419 ++ .../Object/NetworkBehaviour.SyncTypes.cs.meta | 11 + .../Runtime/Object/NetworkBehaviour.cs | 146 + .../Runtime/Object/NetworkBehaviour.cs.meta | 11 + .../Runtime/Object/NetworkObject.Broadcast.cs | 32 + .../Object/NetworkObject.Broadcast.cs.meta | 11 + .../Runtime/Object/NetworkObject.Callbacks.cs | 132 + .../Object/NetworkObject.Callbacks.cs.meta | 11 + .../Runtime/Object/NetworkObject.Observers.cs | 179 + .../Object/NetworkObject.Observers.cs.meta | 11 + .../Runtime/Object/NetworkObject.QOL.cs | 254 ++ .../Runtime/Object/NetworkObject.QOL.cs.meta | 11 + .../Object/NetworkObject.ReferenceIds.cs | 208 + .../Object/NetworkObject.ReferenceIds.cs.meta | 11 + .../Runtime/Object/NetworkObject.RpcLinks.cs | 34 + .../Object/NetworkObject.RpcLinks.cs.meta | 11 + .../Runtime/Object/NetworkObject.SyncTypes.cs | 36 + .../Object/NetworkObject.SyncTypes.cs.meta | 11 + .../FishNet/Runtime/Object/NetworkObject.cs | 763 ++++ .../Runtime/Object/NetworkObject.cs.meta | 11 + .../Runtime/Object/NetworkObjectState.cs | 24 + .../Runtime/Object/NetworkObjectState.cs.meta | 11 + .../FishNet/Runtime/Object/Prediction.meta | 8 + .../Runtime/Object/Prediction/Attributes.cs | 29 + .../Object/Prediction/Attributes.cs.meta | 11 + .../Runtime/Object/Prediction/Delegates.cs | 15 + .../Object/Prediction/Delegates.cs.meta | 11 + .../FishNet/Runtime/Object/RpcLinkType.cs | 25 + .../Runtime/Object/RpcLinkType.cs.meta | 11 + .../FishNet/Runtime/Object/Synchronizing.meta | 8 + .../Object/Synchronizing/ICustomSync.cs | 19 + .../Object/Synchronizing/ICustomSync.cs.meta | 11 + .../Object/Synchronizing/ISyncObject.cs | 48 + .../Object/Synchronizing/ISyncObject.cs.meta | 11 + .../MissingObjectPacketLength.cs | 11 + .../MissingObjectPacketLength.cs.meta | 11 + .../Object/Synchronizing/ReadPermissions.cs | 21 + .../Synchronizing/ReadPermissions.cs.meta | 11 + .../Object/Synchronizing/SecretMenu.meta | 8 + .../SecretMenu/SyncVarExtensions.cs | 21 + .../SecretMenu/SyncVarExtensions.cs.meta | 11 + .../Runtime/Object/Synchronizing/Settings.cs | 53 + .../Object/Synchronizing/Settings.cs.meta | 11 + .../Runtime/Object/Synchronizing/SyncBase.cs | 211 + .../Object/Synchronizing/SyncBase.cs.meta | 11 + .../Object/Synchronizing/SyncDictionary.cs | 627 +++ .../Synchronizing/SyncDictionary.cs.meta | 11 + .../Synchronizing/SyncDictionaryOperation.cs | 31 + .../SyncDictionaryOperation.cs.meta | 11 + .../Synchronizing/SyncHashSetOperation.cs | 31 + .../SyncHashSetOperation.cs.meta | 11 + .../Object/Synchronizing/SyncHashset.cs | 626 +++ .../Object/Synchronizing/SyncHashset.cs.meta | 11 + .../Runtime/Object/Synchronizing/SyncList.cs | 731 ++++ .../Object/Synchronizing/SyncList.cs.meta | 11 + .../Object/Synchronizing/SyncListOperation.cs | 35 + .../Synchronizing/SyncListOperation.cs.meta | 11 + .../Runtime/Object/Synchronizing/SyncVar.cs | 286 ++ .../Object/Synchronizing/SyncVar.cs.meta | 11 + .../Object/Synchronizing/WritePermissions.cs | 10 + .../Synchronizing/WritePermissions.cs.meta | 11 + .../Runtime/Object/TransformProperties.cs | 20 + .../Object/TransformProperties.cs.meta | 11 + .../Assets/FishNet/Runtime/Observing.meta | 8 + .../FishNet/Runtime/Observing/Conditions.meta | 8 + .../Observing/Conditions/DistanceCondition.cs | 143 + .../Conditions/DistanceCondition.cs.meta | 11 + .../Runtime/Observing/Conditions/Editor.meta | 8 + .../Conditions/Editor/MatchConditionEditor.cs | 25 + .../Editor/MatchConditionEditor.cs.meta | 11 + .../Observing/Conditions/MatchCondition.cs | 585 +++ .../Conditions/MatchCondition.cs.meta | 11 + .../Conditions/OwnerOnlyCondition.cs | 47 + .../Conditions/OwnerOnlyCondition.cs.meta | 11 + .../Observing/Conditions/SceneCondition.cs | 88 + .../Conditions/SceneCondition.cs.meta | 11 + .../Conditions/ServerOnlyCondition.cs | 49 + .../Conditions/ServerOnlyCondition.cs.meta | 11 + .../Observing/HostVisibilityUpdateTypes.cs | 17 + .../HostVisibilityUpdateTypes.cs.meta | 11 + .../Runtime/Observing/NetworkObserver.cs | 355 ++ .../Runtime/Observing/NetworkObserver.cs.meta | 11 + .../Runtime/Observing/ObserverCondition.cs | 48 + .../Observing/ObserverCondition.cs.meta | 11 + .../Runtime/Observing/ObserverStateChange.cs | 12 + .../Observing/ObserverStateChange.cs.meta | 11 + .../Assets/FishNet/Runtime/Plugins.meta | 8 + .../Runtime/Plugins/ColliderRollback.meta | 8 + .../Plugins/ColliderRollback/Attributions.txt | 5 + .../ColliderRollback/Attributions.txt.meta | 7 + .../Plugins/ColliderRollback/LICENSE.txt | 1 + .../Plugins/ColliderRollback/LICENSE.txt.meta | 7 + .../Plugins/ColliderRollback/Scripts.meta | 8 + .../Scripts/ColliderRollback.cs | 23 + .../Scripts/ColliderRollback.cs.meta | 11 + .../Scripts/RollbackManager.cs | 47 + .../Scripts/RollbackManager.cs.meta | 11 + .../Assets/FishNet/Runtime/Plugins/Yak.meta | 8 + .../FishNet/Runtime/Plugins/Yak/CHANGELOG.txt | 2 + .../Runtime/Plugins/Yak/CHANGELOG.txt.meta | 7 + .../Runtime/Plugins/Yak}/Core.meta | 2 +- .../Runtime/Plugins/Yak/Core/ClientSocket.cs | 0 .../Plugins/Yak/Core/ClientSocket.cs.meta | 11 + .../Runtime/Plugins/Yak/Core/CommonSocket.cs | 0 .../Plugins/Yak/Core/CommonSocket.cs.meta | 11 + .../Runtime/Plugins/Yak/Core/LocalPacket.cs | 1 + .../Plugins/Yak/Core/LocalPacket.cs.meta | 11 + .../Runtime/Plugins/Yak/Core/ServerSocket.cs | 0 .../Plugins/Yak/Core/ServerSocket.cs.meta | 11 + .../FishNet/Runtime/Plugins/Yak/VERSION.txt | 1 + .../Runtime/Plugins/Yak/VERSION.txt.meta | 7 + .../Assets/FishNet/Runtime/Plugins/Yak/Yak.cs | 0 .../FishNet/Runtime/Plugins/Yak/Yak.cs.meta | 11 + .../Assets/FishNet/Runtime/Serializing.meta | 8 + .../Runtime/Serializing/AutoPackType.cs | 21 + .../Runtime/Serializing/AutoPackType.cs.meta | 11 + .../FishNet/Runtime/Serializing/Helping.meta | 8 + .../Runtime/Serializing/Helping/Attributes.cs | 12 + .../Serializing/Helping/Attributes.cs.meta | 11 + .../Runtime/Serializing/Helping/Broadcasts.cs | 34 + .../Serializing/Helping/Broadcasts.cs.meta | 11 + .../Runtime/Serializing/Helping/Comparers.cs | 48 + .../Serializing/Helping/Comparers.cs.meta | 11 + .../Serializing/Helping/Quaternion32.cs | 163 + .../Serializing/Helping/Quaternion32.cs.meta | 11 + .../Serializing/Helping/Quaternion64.cs | 192 + .../Serializing/Helping/Quaternion64.cs.meta | 11 + .../Helping/QuaternionConverter.cs | 126 + .../Helping/QuaternionConverter.cs.meta | 11 + .../Serializing/Helping/ValueConversions.cs | 41 + .../Helping/ValueConversions.cs.meta | 11 + .../FishNet/Runtime/Serializing/Reader.cs | 1209 +++++ .../Runtime/Serializing/Reader.cs.meta | 11 + .../Runtime/Serializing/ReaderExtensions.cs | 66 + .../Serializing/ReaderExtensions.cs.meta | 11 + .../FishNet/Runtime/Serializing/ReaderPool.cs | 68 + .../Runtime/Serializing/ReaderPool.cs.meta | 11 + .../Serializing/TransformPackingData.cs | 10 + .../Serializing/TransformPackingData.cs.meta | 11 + .../FishNet/Runtime/Serializing/Writer.cs | 1090 +++++ .../Runtime/Serializing/Writer.cs.meta | 11 + .../Runtime/Serializing/WriterExtensions.cs | 114 + .../Serializing/WriterExtensions.cs.meta | 11 + .../FishNet/Runtime/Serializing/WriterPool.cs | 56 + .../Runtime/Serializing/WriterPool.cs.meta | 11 + .../Assets/FishNet/Runtime/Transporting.meta | 8 + .../FishNet/Runtime/Transporting/Channels.cs | 19 + .../Runtime/Transporting/Channels.cs.meta | 11 + .../Runtime/Transporting/ConnectionStates.cs | 43 + .../Transporting/ConnectionStates.cs.meta | 11 + .../Runtime/Transporting/EventStructures.cs | 152 + .../Transporting/EventStructures.cs.meta | 11 + .../Runtime/Transporting/IPAddressType.cs | 19 + .../Transporting/IPAddressType.cs.meta | 11 + .../Runtime/Transporting/NetworkReaderLoop.cs | 33 + .../Transporting/NetworkReaderLoop.cs.meta | 11 + .../Runtime/Transporting/NetworkWriterLoop.cs | 38 + .../Transporting/NetworkWriterLoop.cs.meta | 11 + .../FishNet/Runtime/Transporting/PacketId.cs | 32 + .../Runtime/Transporting/PacketId.cs.meta | 11 + .../FishNet/Runtime/Transporting/Transport.cs | 248 ++ .../Runtime/Transporting/Transport.cs.meta | 11 + .../Runtime/Transporting/Transports.meta | 8 + .../Transporting/Transports/Multipass.meta | 8 + .../Transports/Multipass/CHANGELOG.txt | 2 + .../Transports/Multipass/CHANGELOG.txt.meta | 7 + .../Transports/Multipass/Multipass.cs | 963 ++++ .../Transports/Multipass/Multipass.cs.meta | 11 + .../Transports/Multipass/VERSION.txt | 1 + .../Transports/Multipass/VERSION.txt.meta | 7 + .../Transporting/Transports/Tugboat.meta | 8 + .../Transporting/Transports/Tugboat/Core.meta | 8 + .../Transports/Tugboat/Core/ClientSocket.cs | 308 ++ .../Tugboat/Core/ClientSocket.cs.meta | 11 + .../Transports/Tugboat/Core/CommonSocket.cs | 125 + .../Tugboat/Core/CommonSocket.cs.meta | 11 + .../Transports/Tugboat/Core/ServerSocket.cs | 500 +++ .../Tugboat/Core/ServerSocket.cs.meta | 11 + .../Transports/Tugboat/Core/Supporting.cs | 63 + .../Tugboat/Core/Supporting.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib.meta | 8 + .../Tugboat/LiteNetLib/BaseChannel.cs | 46 + .../Tugboat/LiteNetLib/BaseChannel.cs.meta | 11 + .../Tugboat/LiteNetLib/ConnectionRequest.cs | 134 + .../LiteNetLib/ConnectionRequest.cs.meta | 11 + .../Tugboat/LiteNetLib/INetEventListener.cs | 272 ++ .../LiteNetLib/INetEventListener.cs.meta | 11 + .../Tugboat/LiteNetLib/InternalPackets.cs | 133 + .../LiteNetLib/InternalPackets.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib/Layers.meta | 8 + .../Tugboat/LiteNetLib/Layers/Crc32cLayer.cs | 41 + .../LiteNetLib/Layers/Crc32cLayer.cs.meta | 11 + .../LiteNetLib/Layers/PacketLayerBase.cs | 17 + .../LiteNetLib/Layers/PacketLayerBase.cs.meta | 11 + .../LiteNetLib/Layers/XorEncryptLayer.cs | 60 + .../LiteNetLib/Layers/XorEncryptLayer.cs.meta | 11 + .../Tugboat/LiteNetLib/LiteNetLib.csproj.meta | 7 + .../Tugboat/LiteNetLib/NatPunchModule.cs | 259 ++ .../Tugboat/LiteNetLib/NatPunchModule.cs.meta | 11 + .../Tugboat/LiteNetLib/NativeSocket.cs | 301 ++ .../Tugboat/LiteNetLib/NativeSocket.cs.meta | 11 + .../Tugboat/LiteNetLib/NetConstants.cs | 75 + .../Tugboat/LiteNetLib/NetConstants.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib/NetDebug.cs | 92 + .../Tugboat/LiteNetLib/NetDebug.cs.meta | 11 + .../LiteNetLib/NetManager.PacketPool.cs | 80 + .../LiteNetLib/NetManager.PacketPool.cs.meta | 11 + .../Tugboat/LiteNetLib/NetManager.Socket.cs | 751 ++++ .../LiteNetLib/NetManager.Socket.cs.meta | 11 + .../Tugboat/LiteNetLib/NetManager.cs | 1786 ++++++++ .../Tugboat/LiteNetLib/NetManager.cs.meta | 11 + .../Tugboat/LiteNetLib/NetPacket.cs | 161 + .../Tugboat/LiteNetLib/NetPacket.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib/NetPeer.cs | 1405 ++++++ .../Tugboat/LiteNetLib/NetPeer.cs.meta | 11 + .../Tugboat/LiteNetLib/NetStatistics.cs | 81 + .../Tugboat/LiteNetLib/NetStatistics.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib/NetUtils.cs | 194 + .../Tugboat/LiteNetLib/NetUtils.cs.meta | 11 + .../Tugboat/LiteNetLib/PooledPacket.cs | 32 + .../Tugboat/LiteNetLib/PooledPacket.cs.meta | 11 + .../Tugboat/LiteNetLib/ReliableChannel.cs | 336 ++ .../LiteNetLib/ReliableChannel.cs.meta | 11 + .../Tugboat/LiteNetLib/SequencedChannel.cs | 110 + .../LiteNetLib/SequencedChannel.cs.meta | 11 + .../Transports/Tugboat/LiteNetLib/Utils.meta | 8 + .../Tugboat/LiteNetLib/Utils/CRC32C.cs | 150 + .../Tugboat/LiteNetLib/Utils/CRC32C.cs.meta | 11 + .../LiteNetLib/Utils/FastBitConverter.cs | 175 + .../LiteNetLib/Utils/FastBitConverter.cs.meta | 11 + .../LiteNetLib/Utils/INetSerializable.cs | 8 + .../LiteNetLib/Utils/INetSerializable.cs.meta | 11 + .../Tugboat/LiteNetLib/Utils/NetDataReader.cs | 680 +++ .../LiteNetLib/Utils/NetDataReader.cs.meta | 11 + .../Tugboat/LiteNetLib/Utils/NetDataWriter.cs | 379 ++ .../LiteNetLib/Utils/NetDataWriter.cs.meta | 11 + .../LiteNetLib/Utils/NetPacketProcessor.cs | 296 ++ .../Utils/NetPacketProcessor.cs.meta | 11 + .../Tugboat/LiteNetLib/Utils/NetSerializer.cs | 738 ++++ .../LiteNetLib/Utils/NetSerializer.cs.meta | 11 + .../Tugboat/LiteNetLib/Utils/NtpPacket.cs | 423 ++ .../LiteNetLib/Utils/NtpPacket.cs.meta | 11 + .../Tugboat/LiteNetLib/Utils/NtpRequest.cs | 42 + .../LiteNetLib/Utils/NtpRequest.cs.meta | 11 + .../Transports/Tugboat/Tugboat.cs | 509 +++ .../Transports/Tugboat/Tugboat.cs.meta | 11 + .../Assets/FishNet/Runtime/Utility.meta | 8 + .../Runtime/Utility/ApplicationState.cs | 64 + .../Runtime/Utility/ApplicationState.cs.meta | 11 + .../FishNet/Runtime/Utility/Constants.cs | 11 + .../FishNet/Runtime/Utility/Constants.cs.meta | 11 + .../FishNet/Runtime/Utility/DDOLFinder.cs | 60 + .../Runtime/Utility/DDOLFinder.cs.meta | 11 + .../FishNet/Runtime/Utility/Editor.meta | 8 + .../Runtime/Utility/Editor/MiscMenu.cs | 1 + .../Runtime/Utility/Editor/MiscMenu.cs.meta | 11 + .../Runtime/Utility/Editor/SceneDrawer.cs | 51 + .../Utility/Editor/SceneDrawer.cs.meta | 11 + .../FishNet/Runtime/Utility/Extension.meta | 8 + .../Runtime/Utility/Extension/Collection.cs | 33 + .../Utility/Extension/Collection.cs.meta | 11 + .../Runtime/Utility/Extension/Dictionary.cs | 35 + .../Utility/Extension/Dictionary.cs.meta | 11 + .../FishNet/Runtime/Utility/Extension/Enum.cs | 31 + .../Runtime/Utility/Extension/Enum.cs.meta | 11 + .../FishNet/Runtime/Utility/Extension/Math.cs | 34 + .../Runtime/Utility/Extension/Math.cs.meta | 11 + .../Runtime/Utility/Extension/Object.cs | 28 + .../Runtime/Utility/Extension/Object.cs.meta | 11 + .../Runtime/Utility/Extension/Quaternion.cs | 44 + .../Utility/Extension/Quaternion.cs.meta | 11 + .../Runtime/Utility/Extension/Scene.cs | 76 + .../Runtime/Utility/Extension/Scene.cs.meta | 11 + .../Runtime/Utility/Extension/Transform.cs | 2 + .../Utility/Extension/Transform.cs.meta | 11 + .../Runtime/Utility/Extension/Transforms.cs | 30 + .../Utility/Extension/Transforms.cs.meta | 11 + .../FishNet/Runtime/Utility/Performance.meta | 8 + .../Utility/Performance/ByteArrayPool.cs | 53 + .../Utility/Performance/ByteArrayPool.cs.meta | 11 + .../Runtime/Utility/Performance/ListCache.cs | 277 ++ .../Utility/Performance/ListCache.cs.meta | 11 + .../Runtime/Utility/Performance/Transform.cs | 2 + .../Utility/Performance/Transform.cs.meta | 11 + .../Runtime/Utility/Performance/Transforms.cs | 39 + .../Utility/Performance/Transforms.cs.meta | 11 + .../FishNet/Runtime/Utility/SceneAttribute.cs | 12 + .../Runtime/Utility/SceneAttribute.cs.meta | 11 + .../Assets/FishNet/THIRD PARTY NOTICE.md | 82 + .../Assets/FishNet/THIRD PARTY NOTICE.md.meta | 7 + UnityProject/Assets/FishNet/Upgrading.meta | 8 + .../Assets/FishNet/Upgrading/MirrorUpgrade.cs | 438 ++ .../FishNet/Upgrading/MirrorUpgrade.cs.meta | 11 + .../Upgrading/UpgradeFromMirrorMenu.cs | 75 + .../Upgrading/UpgradeFromMirrorMenu.cs.meta | 11 + UnityProject/Assets/FishNet/VERSION.txt | 1 + UnityProject/Assets/FishNet/VERSION.txt.meta | 7 + UnityProject/Assets/FishNetworkManager.prefab | 707 +++ .../Assets/FishNetworkManager.prefab.meta | 7 + .../Ignorance/Demo/PongChamp/AtariBall.prefab | 188 - .../Demo/PongChamp/AtariRacket.prefab | 188 - .../Ignorance/Demo/PongChamp/Demo.unity | 1166 ----- .../Demo/PongChamp/Scripts/AtariPongBall.cs | 67 - .../PongChamp/Scripts/AtariPongBall.cs.meta | 12 - .../Demo/PongChamp/Scripts/AtariPongRacket.cs | 25 - .../PongChamp/Scripts/AtariPongRacket.cs.meta | 12 - .../Demo/PongChamp/Scripts/OnlineTimer.cs | 49 - .../Demo/PongChamp/TenryuuBall.prefab | 178 - .../Demo/PongChamp/Textures/PoutRyuu.png | Bin 30056 -> 0 bytes .../Demo/PongChamp/Textures/Sprites.meta | 8 - .../Demo/PongChamp/Textures/Sprites/Ball.png | Bin 2791 -> 0 bytes .../PongChamp/Textures/Sprites/DottedLine.png | Bin 2799 -> 0 bytes .../PongChamp/Textures/Sprites/Racket.png | Bin 2800 -> 0 bytes .../Textures/Sprites/WallHorizontal.png | Bin 2796 -> 0 bytes .../Textures/Sprites/WallVertical.png | Bin 2800 -> 0 bytes .../Textures/Sprites/WallVertical.png.meta | 88 - .../Demo/PongChamp/Textures/pogchamp.png | Bin 129087 -> 0 bytes .../Assets/Ignorance/Demo/Super Basic.meta | 8 - .../{Mirror/Runtime/Transport => }/LRM.meta | 0 .../Transport => }/LRM/BiDictionary.cs | 0 .../Transport => }/LRM/BiDictionary.cs.meta | 0 .../Runtime/Transport => }/LRM/Editor.meta | 0 .../Transport => }/LRM/Editor/LRMInspector.cs | 28 +- .../LRM/Editor/LRMInspector.cs.meta | 0 .../Transport => }/LRM/HelpAttribute.cs | 0 .../Transport => }/LRM/HelpAttribute.cs.meta | 0 .../Runtime/Transport => }/LRM/LRM.asmdef | 0 .../Transport => }/LRM/LRM.asmdef.meta | 0 .../LRM/LRMDirectConnectModule.cs | 57 +- .../LRM/LRMDirectConnectModule.cs.meta | 0 .../Runtime/Transport => }/LRM/LRMTools.cs | 0 .../Transport => }/LRM/LRMTools.cs.meta | 0 .../Transport => }/LRM/LRMTransport.meta | 0 .../LRMTransport/LRMTransportDirectConnect.cs | 0 .../LRMTransportDirectConnect.cs.meta | 0 .../LRMTransport/LRMTransportNATPuncher.cs | 0 .../LRMTransportNATPuncher.cs.meta | 0 .../LRM/LRMTransport/LRMTransportOverrides.cs | 74 +- .../LRMTransportOverrides.cs.meta | 0 .../LRM/LRMTransport/LRMTransportRequests.cs | 4 + .../LRMTransport/LRMTransportRequests.cs.meta | 0 .../LRM/LRMTransport/LRMTransportVariables.cs | 0 .../LRMTransportVariables.cs.meta | 0 .../LightReflectiveMirrorTransport.cs | 28 +- .../LightReflectiveMirrorTransport.cs.meta | 0 .../Runtime/Transport => }/LRM/Resources.meta | 0 .../Transport => }/LRM/Resources/LRM.png | Bin .../Transport => }/LRM/Resources/LRM.png.meta | 0 .../Runtime/Transport => }/LRM/SocketProxy.cs | 0 .../Transport => }/LRM/SocketProxy.cs.meta | 0 .../Runtime/Transport => }/LRM/package.json | 0 .../Transport => }/LRM/package.json.meta | 0 UnityProject/Assets/LRMFunctionTester.unity | 836 +++- UnityProject/Assets/LRMTestScene.unity | 937 +++- .../BallMaterial.physicsMaterial2D.meta | 8 +- .../Examples/Pong/Sprites/Racket.png.meta | 10 +- .../Assets/Mirror/Runtime/NetworkIdentity.cs | 8 +- .../Mirror/Runtime/Transport/Ignorance.meta | 8 - .../Ignorance/Core/IgnoranceClient.cs | 296 -- .../Ignorance/Core/IgnoranceServer.cs | 328 -- .../Transport/Ignorance/Dependencies.meta | 8 - .../Transport/Ignorance/Dependencies/ENet.cs | 1411 ------ .../Ignorance/Editor/AddScriptingDefine.cs | 83 - .../Editor/AddScriptingDefine.cs.meta | 11 - .../Ignorance/Editor/IgnoranceToolbox.cs | 44 - .../Ignorance/Editor/IgnoranceToolbox.cs.meta | 11 - .../Runtime/Transport/Ignorance/Ignorance.cs | 746 ---- .../Transport/Ignorance/Ignorance.cs.meta | 11 - .../Ignorance/IgnoranceDefinitions.cs | 94 - .../Ignorance/IgnoranceDefinitions.cs.meta | 11 - .../Transport/Ignorance/Plugins/Android.meta | 8 - .../Ignorance/Plugins/Android/arm64-v8a.meta | 8 - .../Plugins/Android/arm64-v8a/libenet.so | Bin 47024 -> 0 bytes .../Plugins/Android/arm64-v8a/libenet.so.meta | 111 - .../Plugins/Android/armeabi-v7a.meta | 8 - .../Plugins/Android/armeabi-v7a/libenet.so | Bin 42636 -> 0 bytes .../Android/armeabi-v7a/libenet.so.meta | 106 - .../Ignorance/Plugins/Android/x86.meta | 8 - .../Ignorance/Plugins/Android/x86/libenet.so | Bin 50764 -> 0 bytes .../Transport/Ignorance/Plugins/Linux.meta | 8 - .../Ignorance/Plugins/Linux/libenet.so | Bin 60144 -> 0 bytes .../Ignorance/Plugins/Linux/libenet.so.meta | 97 - .../Transport/Ignorance/Plugins/Windows.meta | 8 - .../Ignorance/Plugins/Windows/README.txt | 3 - .../Ignorance/Plugins/Windows/enet.dll | Bin 124928 -> 0 bytes .../Ignorance/Plugins/Windows/enet.dll.meta | 111 - .../Transport/Ignorance/Plugins/iOS.meta | 8 - .../Plugins/iOS/libenet-release-arm64.a | Bin 164440 -> 0 bytes .../Plugins/iOS/libenet-release-arm64.a.meta | 80 - .../Plugins/iOS/libenet-release-armv7.a | Bin 145208 -> 0 bytes .../Plugins/iOS/libenet-release-armv7.a.meta | 80 - .../Plugins/iOS/libenet-release-simulator64.a | Bin 167208 -> 0 bytes .../iOS/libenet-release-simulator64.a.meta | 80 - .../Transport/Ignorance/Plugins/macOS.meta | 8 - .../Ignorance/Plugins/macOS/libenet.dylib | Bin 53596 -> 0 bytes .../Transport/Ignorance/Plugins/readme.txt | 35 - .../Runtime/Transport/Ignorance/version.txt | 1 - UnityProject/Assets/StreamingAssets.meta | 8 + UnityProject/Assets/Tanks.meta | 8 + UnityProject/Assets/Tanks/Models.meta | 8 + .../Models/(Public Domain) Recon_Tank.meta | 8 + .../(Public Domain) Recon_Tank/BaseColor.png | Bin 0 -> 939498 bytes .../BaseColor.png.meta} | 40 +- .../Controller.controller | 272 ++ .../Controller.controller.meta | 8 + .../(Public Domain) Recon_Tank/Emissive.png | Bin 0 -> 80294 bytes .../Emissive.png.meta} | 40 +- .../(Public Domain) Recon_Tank/Metallic.png | Bin 0 -> 62860 bytes .../Metallic.png.meta} | 40 +- .../(Public Domain) Recon_Tank/Normal.png | Bin 0 -> 666342 bytes .../Normal.png.meta | 88 + .../Recon_Tank - License.txt | 7 + .../Recon_Tank - License.txt.meta | 7 + .../TankMaterial.mat | 82 + .../TankMaterial.mat.meta | 8 + .../(Public Domain) Recon_Tank/reconTank.fbx | Bin 0 -> 224204 bytes .../reconTank.fbx.meta | 239 + UnityProject/Assets/Tanks/Prefabs.meta | 8 + .../Assets/Tanks/Prefabs/Projectile.prefab | 291 ++ .../Tanks/Prefabs/Projectile.prefab.meta | 7 + UnityProject/Assets/Tanks/Prefabs/Tank.prefab | 382 ++ .../Assets/Tanks/Prefabs/Tank.prefab.meta | 8 + UnityProject/Assets/Tanks/Scenes.meta | 8 + UnityProject/Assets/Tanks/Scenes/Scene.meta | 8 + .../Scenes/Scene.unity} | 736 ++-- .../Assets/Tanks/Scenes/Scene.unity.meta | 7 + .../Assets/Tanks/Scenes/Scene/NavMesh.asset | Bin 0 -> 5444 bytes .../Tanks/Scenes/Scene/NavMesh.asset.meta | 8 + UnityProject/Assets/Tanks/Scripts.meta | 8 + .../Assets/Tanks/Scripts/Projectile.cs | 34 + .../Assets/Tanks/Scripts/Projectile.cs.meta | 11 + UnityProject/Assets/Tanks/Scripts/Tank.cs | 62 + .../Assets/Tanks/Scripts/Tank.cs.meta | 11 + UnityProject/Assets/Tanks/Textures.meta | 8 + ...lic Domain) Dirt Hand Painted Texture.meta | 8 + .../Dirt Hand Painted Texture - License.txt | 5 + ...rt Hand Painted Texture - License.txt.meta | 7 + .../Dirt.mat | 82 + .../Dirt.mat.meta | 8 + .../dirt.png | Bin 0 -> 105829 bytes .../dirt.png.meta} | 40 +- .../Tanks/Textures/ProjectileMaterial.mat | 77 + .../Textures/ProjectileMaterial.mat.meta | 8 + UnityProject/Packages/manifest.json | 13 +- UnityProject/Packages/packages-lock.json | 68 +- .../ProjectSettings/MemorySettings.asset | 35 + .../PackageManagerSettings.asset | 23 +- .../ProjectSettings/ProjectSettings.asset | 121 +- .../ProjectSettings/ProjectVersion.txt | 4 +- .../SceneTemplateSettings.json | 167 + .../VersionControlSettings.asset | 8 + UnityProject/ProjectSettings/boot.config | 0 1384 files changed, 119035 insertions(+), 9373 deletions(-) delete mode 100644 Dockerfile create mode 100644 FishBait.png delete mode 100644 LRM.png create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/Dockerfile delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceClient.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceServer.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Dependencies/ENet.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Ignorance.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/IgnoranceDefinitions.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/Linux/libenet.so delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/Windows/README.txt delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/Windows/enet.dll delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/readme.txt rename UnityProject/Assets/{Ignorance.meta => FishBait.meta} (77%) create mode 100644 UnityProject/Assets/FishBait/BiDictionary.cs rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs.meta => FishBait/BiDictionary.cs.meta} (83%) rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance => FishBait}/Editor.meta (77%) create mode 100644 UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs.meta => FishBait/Editor/FishBaitInspector.cs.meta} (83%) create mode 100644 UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs.meta => FishBait/FishBaitDirectConnectModule.cs.meta} (83%) create mode 100644 UnityProject/Assets/FishBait/FishBaitTools.cs rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs.meta => FishBait/FishBaitTools.cs.meta} (83%) rename UnityProject/Assets/{Ignorance/Demo.meta => FishBait/FishBaitTransport.meta} (77%) create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs.meta create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs.meta create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs create mode 100644 UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs.meta rename UnityProject/Assets/{Ignorance/Demo/PongChamp.meta => FishBait/Resources.meta} (77%) create mode 100644 UnityProject/Assets/FishBait/Resources/FishBait.png create mode 100644 UnityProject/Assets/FishBait/Resources/FishBait.png.meta create mode 100644 UnityProject/Assets/FishBait/SocketProxy.cs create mode 100644 UnityProject/Assets/FishBait/SocketProxy.cs.meta create mode 100644 UnityProject/Assets/FishNet.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Extension.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/version.txt.meta => FishNet/CodeGenerating/FN_README.txt.meta} (75%) create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props rename UnityProject/Assets/{Ignorance/Demo/Super Basic/SuperBasic.unity.meta => FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props.meta} (74%) create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt.meta => FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt.meta} (75%) create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Demo.unity.meta => FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props.meta} (74%) create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs create mode 100644 UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs.meta create mode 100644 UnityProject/Assets/FishNet/DOCUMENTATION.txt create mode 100644 UnityProject/Assets/FishNet/DOCUMENTATION.txt.meta create mode 100644 UnityProject/Assets/FishNet/Example.meta create mode 100644 UnityProject/Assets/FishNet/Example/All.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity.meta rename UnityProject/Assets/{Ignorance/Demo/PongChamp => FishNet/Example/All/Authenticator}/Scripts.meta (77%) create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab rename UnityProject/Assets/{Ignorance/Demo/PongChamp/TenryuuBall.prefab.meta => FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta} (74%) create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat rename UnityProject/Assets/{Ignorance/Demo/PongChamp/AtariRacket.prefab.meta => FishNet/Example/All/Prediction/Materials/BlueMat.mat.meta} (63%) create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat rename UnityProject/Assets/{Ignorance/Demo/PongChamp/AtariBall.prefab.meta => FishNet/Example/All/Prediction/Materials/GroundMat.mat.meta} (63%) create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs create mode 100644 UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs.meta create mode 100644 UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef create mode 100644 UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef.meta create mode 100644 UnityProject/Assets/FishNet/Example/Prefabs.meta create mode 100644 UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab create mode 100644 UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab.meta create mode 100644 UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab create mode 100644 UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab.meta create mode 100644 UnityProject/Assets/FishNet/Example/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs create mode 100644 UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs.meta create mode 100644 UnityProject/Assets/FishNet/LICENSE.txt create mode 100644 UnityProject/Assets/FishNet/LICENSE.txt.meta rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance => FishNet}/Plugins.meta (77%) create mode 100644 UnityProject/Assets/FishNet/Plugins/Addressables.meta create mode 100644 UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs create mode 100644 UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Plugins/CodeAnalysis.meta create mode 100644 UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so.meta => FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll.meta} (78%) create mode 100644 UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.dll rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Plugins/macOS/libenet.dylib.meta => FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.dll.meta} (79%) rename LICENSE => UnityProject/Assets/FishNet/Plugins/CodeAnalysis/LICENSE.txt (95%) create mode 100644 UnityProject/Assets/FishNet/Plugins/CodeAnalysis/LICENSE.txt.meta create mode 100644 UnityProject/Assets/FishNet/Plugins/CodeAnalysis/README.txt rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance/Plugins/Windows => FishNet/Plugins/CodeAnalysis}/README.txt.meta (75%) create mode 100644 UnityProject/Assets/FishNet/Runtime.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Authenticating.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Authenticating/Authenticator.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Authenticating/Authenticator.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast/Helping.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Config.json create mode 100644 UnityProject/Assets/FishNet/Runtime/Config.json.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Documenting.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuration.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs.meta rename UnityProject/Assets/{Ignorance/Demo/PongChamp => FishNet/Runtime/Editor}/Textures.meta (77%) create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon/fishnet_light.png create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon/fishnet_light.png.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Client_Background.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/PoutRyuu.png.meta => FishNet/Runtime/Editor/Textures/UI/Button_Dark_Client_Background.png.meta} (83%) create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/pogchamp.png.meta => FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png.meta} (79%) create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png create mode 100644 UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef create mode 100644 UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Debugging.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Logging.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Utility.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Prediction.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta rename UnityProject/Assets/{Mirror/Runtime/Transport/Ignorance => FishNet/Runtime/Plugins/Yak}/Core.meta (77%) create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Editor.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs.meta create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs create mode 100644 UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs.meta create mode 100644 UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md create mode 100644 UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md.meta create mode 100644 UnityProject/Assets/FishNet/Upgrading.meta create mode 100644 UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs create mode 100644 UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs.meta create mode 100644 UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs create mode 100644 UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs.meta create mode 100644 UnityProject/Assets/FishNet/VERSION.txt create mode 100644 UnityProject/Assets/FishNet/VERSION.txt.meta create mode 100644 UnityProject/Assets/FishNetworkManager.prefab create mode 100644 UnityProject/Assets/FishNetworkManager.prefab.meta delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs.meta delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs.meta delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites.meta delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/DottedLine.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Racket.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallHorizontal.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallVertical.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallVertical.png.meta delete mode 100644 UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/pogchamp.png delete mode 100644 UnityProject/Assets/Ignorance/Demo/Super Basic.meta rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/BiDictionary.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/BiDictionary.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Editor.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Editor/LRMInspector.cs (93%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Editor/LRMInspector.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/HelpAttribute.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/HelpAttribute.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRM.asmdef (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRM.asmdef.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMDirectConnectModule.cs (78%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMDirectConnectModule.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTools.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTools.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportDirectConnect.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportDirectConnect.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportNATPuncher.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportNATPuncher.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportOverrides.cs (80%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportOverrides.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportRequests.cs (98%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportRequests.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportVariables.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LRMTransportVariables.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LightReflectiveMirrorTransport.cs (95%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/LRMTransport/LightReflectiveMirrorTransport.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Resources.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Resources/LRM.png (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/Resources/LRM.png.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/SocketProxy.cs (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/SocketProxy.cs.meta (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/package.json (100%) rename UnityProject/Assets/{Mirror/Runtime/Transport => }/LRM/package.json.meta (100%) delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux/libenet.so delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux/libenet.so.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Windows.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Windows/README.txt delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Windows/enet.dll delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Windows/enet.dll.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-arm64.a delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-arm64.a.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS.meta delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS/libenet.dylib delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt delete mode 100644 UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt create mode 100644 UnityProject/Assets/StreamingAssets.meta create mode 100644 UnityProject/Assets/Tanks.meta create mode 100644 UnityProject/Assets/Tanks/Models.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/Sprites/WallHorizontal.png.meta => Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png.meta} (79%) create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png.meta => Tanks/Models/(Public Domain) Recon_Tank/Emissive.png.meta} (79%) create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Metallic.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/Sprites/DottedLine.png.meta => Tanks/Models/(Public Domain) Recon_Tank/Metallic.png.meta} (79%) create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Normal.png create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Normal.png.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat.meta create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx create mode 100644 UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx.meta create mode 100644 UnityProject/Assets/Tanks/Prefabs.meta create mode 100644 UnityProject/Assets/Tanks/Prefabs/Projectile.prefab create mode 100644 UnityProject/Assets/Tanks/Prefabs/Projectile.prefab.meta create mode 100644 UnityProject/Assets/Tanks/Prefabs/Tank.prefab create mode 100644 UnityProject/Assets/Tanks/Prefabs/Tank.prefab.meta create mode 100644 UnityProject/Assets/Tanks/Scenes.meta create mode 100644 UnityProject/Assets/Tanks/Scenes/Scene.meta rename UnityProject/Assets/{Ignorance/Demo/Super Basic/SuperBasic.unity => Tanks/Scenes/Scene.unity} (62%) create mode 100644 UnityProject/Assets/Tanks/Scenes/Scene.unity.meta create mode 100644 UnityProject/Assets/Tanks/Scenes/Scene/NavMesh.asset create mode 100644 UnityProject/Assets/Tanks/Scenes/Scene/NavMesh.asset.meta create mode 100644 UnityProject/Assets/Tanks/Scripts.meta create mode 100644 UnityProject/Assets/Tanks/Scripts/Projectile.cs create mode 100644 UnityProject/Assets/Tanks/Scripts/Projectile.cs.meta create mode 100644 UnityProject/Assets/Tanks/Scripts/Tank.cs create mode 100644 UnityProject/Assets/Tanks/Scripts/Tank.cs.meta create mode 100644 UnityProject/Assets/Tanks/Textures.meta create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture.meta create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt.meta create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat.meta create mode 100644 UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png rename UnityProject/Assets/{Ignorance/Demo/PongChamp/Textures/Sprites/Racket.png.meta => Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta} (79%) create mode 100644 UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat create mode 100644 UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat.meta create mode 100644 UnityProject/ProjectSettings/MemorySettings.asset create mode 100644 UnityProject/ProjectSettings/SceneTemplateSettings.json create mode 100644 UnityProject/ProjectSettings/VersionControlSettings.asset create mode 100644 UnityProject/ProjectSettings/boot.config diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 5afc025..0000000 --- a/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env -WORKDIR /lrm -COPY ./ServerProject-DONT-IMPORT-INTO-UNITY ./ -RUN dotnet publish LRM.sln --runtime ubuntu.20.04-x64 -c Release -o /out/ - -FROM mcr.microsoft.com/dotnet/aspnet:5.0 -WORKDIR /lrm -COPY --from=build-env /out/ . - -ENV NO_CONFIG="true" -ENV TRANSPORT_CLASS="kcp2k.KcpTransport" -ENV AUTH_KEY="Secret Auth Key" -ENV TRANSPORT_PORT="7777" -ENV UPDATE_LOOP_TIME="10" -ENV UPDATE_HEARTBEAT_INTERVAL="100" -ENV RANDOMLY_GENERATED_ID_LENGTH="5" -ENV USE_ENDPOINT="true" -ENV ENDPOINT_PORT="8080" -ENV ENDPOINT_SERVERLIST="true" -ENV ENABLE_NATPUNCH_SERVER="true" -ENV NAT_PUNCH_PORT="7776" -ENV USE_LOAD_BALANCER="false" -ENV LOAD_BALANCER_AUTH_KEY="AuthKey" -ENV LOAD_BALANCER_ADDRESS="127.0.0.1" -ENV LOAD_BALANCER_PORT="7070" -ENV LOAD_BALANCER_REGION="1" -ENV KCP_NODELAY="true" -ENV KCP_INTERVAL="10" -ENV KCP_FAST_RESEND="2" -ENV KCP_CONGESTION_WINDOW="false" -ENV KCP_SEND_WINDOW_SIZE="4096" -ENV KCP_RECEIVE_WINDOW_SIZE="4096" -ENV KCP_CONNECTION_TIMEOUT="10000" - -EXPOSE 7777/udp -EXPOSE 7776/udp -EXPOSE 8080 - -ENTRYPOINT [ "./LRM" ] diff --git a/FishBait.png b/FishBait.png new file mode 100644 index 0000000000000000000000000000000000000000..99800b94f700a035c1af7076c4bb576a6f264b3d GIT binary patch literal 265164 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

x$MnWy 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

B3>3%=r0y2f3m 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

aP2r9?%f47bdOZy>2^6;mE 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 literal 0 HcmV?d00001 diff --git a/LRM.png b/LRM.png deleted file mode 100644 index f9c0e16fee0549cca4b4b223e8af5da9bad83843..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11146 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 s[random.Next(s.Length)]).ToArray()); } while (cachedRooms.ContainsKey(randomID)); diff --git a/README.md b/README.md index 986f831..e75f355 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -![Logo](LRM.png) +![Logo](FishBait.png) diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/Dockerfile b/ServerProject-DONT-IMPORT-INTO-UNITY/Dockerfile new file mode 100644 index 0000000..151629c --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/Dockerfile @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS builder +WORKDIR /lrm +COPY . . +ARG BUILD_MODE="Release" +RUN dotnet publish \ + --output /build/ \ + --configuration $BUILD_MODE \ + --no-self-contained . + +FROM mcr.microsoft.com/dotnet/runtime:5.0-alpine +WORKDIR /lrm +COPY --from=builder /build/ . +ENV LRM_CONFIG_PATH="/config/config.json" +CMD [ "./LRM" ] +ENTRYPOINT [ "./LRM" ] diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Config.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Config.cs index 689a334..38227e1 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Config.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Config.cs @@ -1,7 +1,5 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using System.Text; namespace LightReflectiveMirror @@ -11,15 +9,12 @@ namespace LightReflectiveMirror //======================== // Required Settings //======================== + public string TransportDLL = "MultiCompiled.dll"; public string TransportClass = "kcp2k.KcpTransport"; public string AuthenticationKey = "Secret Auth Key"; public ushort TransportPort = 7777; public int UpdateLoopTime = 10; public int UpdateHeartbeatInterval = 100; - - // this wont be used if you are using load balancer - // load balancer will generate instead. - public int RandomlyGeneratedIDLength = 5; //======================== // Endpoint REST API Settings @@ -42,10 +37,5 @@ namespace LightReflectiveMirror public string LoadBalancerAddress = "127.0.0.1"; public ushort LoadBalancerPort = 7070; public LRMRegions LoadBalancerRegion = LRMRegions.NorthAmerica; - - public static string GetTransportDLL() - { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "MultiCompiled.dll" : "MultiCompiled.dll"; - } } } diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs index 25b49ed..dc203ab 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs @@ -25,9 +25,7 @@ namespace LightReflectiveMirror GetPublicIP(); - bool noConfig = bool.Parse(Environment.GetEnvironmentVariable("NO_CONFIG") ?? "false"); - - if (!File.Exists(CONFIG_PATH) && !noConfig) + if (!File.Exists(CONFIG_PATH)) { File.WriteAllText(CONFIG_PATH, JsonConvert.SerializeObject(new Config(), Formatting.Indented)); WriteLogMessage("A config.json file was generated. Please configure it to the proper settings and re-run!", ConsoleColor.Yellow); @@ -36,36 +34,14 @@ namespace LightReflectiveMirror } else { - if (!noConfig) - { - conf = JsonConvert.DeserializeObject(File.ReadAllText(CONFIG_PATH)); - ConfigureDocker(); - } - else - { - conf = new Config(); - conf.TransportClass = Environment.GetEnvironmentVariable("TRANSPORT_CLASS") ?? "kcp2k.KcpTransport"; - conf.AuthenticationKey = Environment.GetEnvironmentVariable("AUTH_KEY") ?? "Secret Auth Key"; - conf.TransportPort = ushort.Parse(Environment.GetEnvironmentVariable("TRANSPORT_PORT") ?? "7777"); - conf.UpdateLoopTime = int.Parse(Environment.GetEnvironmentVariable("UPDATE_LOOP_TIME") ?? "10"); - conf.UpdateHeartbeatInterval = int.Parse(Environment.GetEnvironmentVariable("UPDATE_HEARTBEAT_INTERVAL") ?? "100"); - conf.RandomlyGeneratedIDLength = int.Parse(Environment.GetEnvironmentVariable("RANDOMLY_GENERATED_ID_LENGTH") ?? "5"); - conf.UseEndpoint = bool.Parse(Environment.GetEnvironmentVariable("USE_ENDPOINT") ?? "true"); - conf.EndpointPort = ushort.Parse(Environment.GetEnvironmentVariable("ENDPOINT_PORT") ?? "8080"); - conf.EndpointServerList = bool.Parse(Environment.GetEnvironmentVariable("ENDPOINT_SERVERLIST") ?? "true"); - conf.EnableNATPunchtroughServer = bool.Parse(Environment.GetEnvironmentVariable("ENABLE_NATPUNCH_SERVER") ?? "true"); - conf.NATPunchtroughPort = ushort.Parse(Environment.GetEnvironmentVariable("NAT_PUNCH_PORT") ?? "7776"); - conf.UseLoadBalancer = bool.Parse(Environment.GetEnvironmentVariable("USE_LOAD_BALANCER") ?? "false"); - conf.LoadBalancerAuthKey = Environment.GetEnvironmentVariable("LOAD_BALANCER_AUTH_KEY") ?? "AuthKey"; - conf.LoadBalancerAddress = Environment.GetEnvironmentVariable("LOAD_BALANCER_ADDRESS") ?? "127.0.0.1"; - conf.LoadBalancerPort = ushort.Parse(Environment.GetEnvironmentVariable("LOAD_BALANCER_PORT") ?? "7070"); - conf.LoadBalancerRegion = (LRMRegions)int.Parse(Environment.GetEnvironmentVariable("LOAD_BALANCER_REGION") ?? "1"); - } + conf = JsonConvert.DeserializeObject(File.ReadAllText(CONFIG_PATH)); + + ConfigureDocker(); WriteLogMessage("Loading Assembly... ", ConsoleColor.White, true); try { - var asm = Assembly.LoadFile(Path.GetFullPath(Config.GetTransportDLL())); + var asm = Assembly.LoadFile(Path.GetFullPath(conf.TransportDLL)); WriteLogMessage($"OK", ConsoleColor.Green); WriteLogMessage("\nLoading Transport Class... ", ConsoleColor.White, true); diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs index dd91658..5e800f2 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs @@ -9,7 +9,7 @@ namespace LightReflectiveMirror // constructor for new relay handler public RelayHandler(int maxPacketSize) { - _maxPacketSize = maxPacketSize; + this._maxPacketSize = maxPacketSize; _sendBuffers = ArrayPool.Create(maxPacketSize, 50); } @@ -22,13 +22,14 @@ namespace LightReflectiveMirror private string GenerateRoomID() { + const int LENGTH = 5; const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var randomID = ""; var random = _cachedRandom; do { - randomID = new string(Enumerable.Repeat(chars, Program.conf.RandomlyGeneratedIDLength) + randomID = new string(Enumerable.Repeat(chars, LENGTH) .Select(s => s[random.Next(s.Length)]).ToArray()); } while (DoesServerIdExist(randomID)); @@ -73,7 +74,7 @@ namespace LightReflectiveMirror { if (room.clients.Contains(sendTo)) { - SendData(clientData, channel, sendTo, clientId); + SendData(clientData, channel, sendTo); } } else @@ -83,18 +84,11 @@ namespace LightReflectiveMirror } } - private void SendData(byte[] clientData, int channel, int sendTo, int senderId) + private void SendData(byte[] clientData, int channel, int sendTo) { - if (clientData.Length > _maxPacketSize) - { - Program.transport.ServerDisconnect(senderId); - Program.WriteLogMessage($"Client {senderId} tried to send more than max packet size! Disconnecting..."); - return; - } - int pos = 0; byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); - + sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); sendBuffer.WriteBytes(ref pos, clientData); @@ -102,22 +96,15 @@ namespace LightReflectiveMirror _sendBuffers.Return(sendBuffer); } - private void SendDataToRoomHost(int senderId, byte[] clientData, int channel, Room room) + private void SendDataToRoomHost(int clientId, byte[] clientData, int channel, Room room) { - if(clientData.Length > _maxPacketSize) - { - Program.transport.ServerDisconnect(senderId); - Program.WriteLogMessage($"Client {senderId} tried to send more than max packet size! Disconnecting..."); - return; - } - // We are not the host, so send the data to the host. - int pos = 0; + int pos = 0; byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); sendBuffer.WriteBytes(ref pos, clientData); - sendBuffer.WriteInt(ref pos, senderId); + sendBuffer.WriteInt(ref pos, clientId); Program.transport.ServerSend(room.hostId, channel, new ArraySegment(sendBuffer, 0, pos)); _sendBuffers.Return(sendBuffer); diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs index 4169542..2bfe4a2 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs @@ -46,8 +46,6 @@ namespace LightReflectiveMirror var sendBuffer = _sendBuffers.Rent(1); sendBuffer.WriteByte(ref writePos, (byte)OpCodes.Authenticated); Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, writePos)); - - _sendBuffers.Return(sendBuffer); } else { @@ -60,15 +58,8 @@ namespace LightReflectiveMirror switch (opcode) { - case OpCodes.CreateRoom: // bruh - CreateRoom(clientId, data.ReadInt (ref pos), - data.ReadString(ref pos), - data.ReadBool (ref pos), - data.ReadString(ref pos), - data.ReadBool (ref pos), - data.ReadString(ref pos), - data.ReadBool (ref pos), - data.ReadInt (ref pos)); + case OpCodes.CreateRoom: + CreateRoom(clientId, data.ReadInt(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadInt(ref pos)); break; case OpCodes.RequestID: SendClientID(clientId); @@ -109,9 +100,7 @@ namespace LightReflectiveMirror } catch { - // sent invalid data, boot them hehe - Program.WriteLogMessage($"Client {clientId} sent bad data! Removing from LRM node."); - Program.transport.ServerDisconnect(clientId); + // Do Nothing. Client probably sent some invalid data. } } diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs index 6d28c0d..93f8b5d 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs @@ -13,11 +13,11 @@ namespace LightReflectiveMirror /// The client requesting to create a room /// The maximum amount of players for this room /// The name for the server - /// Whether or not the server should show up on the server list + /// Weather or not the server should show up on the server list /// Extra data the host can include - /// Whether or not, the host is capable of doing direct connections + /// Weather or not, the host is capable of doing direct connections /// The hosts local IP - /// Whether or not, the host is supporting NAT Punch + /// Weather or not, the host is supporting NAT Punch /// The port of the direct connect transport on the host private void CreateRoom(int clientId, int maxPlayers, string serverName, bool isPublic, string serverData, bool useDirectConnect, string hostLocalIP, bool useNatPunch, int port) { @@ -98,7 +98,7 @@ namespace LightReflectiveMirror { sendJoinPos = 0; sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); - + Console.WriteLine(Program.instance.NATConnections[clientId].Address.ToString()); sendJoinBuffer.WriteString(ref sendJoinPos, Program.instance.NATConnections[clientId].Address.ToString()); sendJoinBuffer.WriteInt(ref sendJoinPos, Program.instance.NATConnections[clientId].Port); sendJoinBuffer.WriteBool(ref sendJoinPos, true); @@ -145,7 +145,6 @@ namespace LightReflectiveMirror { for (int i = 0; i < rooms.Count; i++) { - // if host left if (rooms[i].hostId == clientId) { int pos = 0; @@ -168,7 +167,6 @@ namespace LightReflectiveMirror } else { - // if the person that tried to kick wasnt host and it wasnt the client leaving on their own if (requiredHostId != -1 && rooms[i].hostId != requiredHostId) continue; @@ -182,19 +180,6 @@ namespace LightReflectiveMirror Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendBuffer, 0, pos)); _sendBuffers.Return(sendBuffer); - - // temporary solution to kicking bug - // this tells the local player that got kicked that he, well, got kicked. - pos = 0; - sendBuffer = _sendBuffers.Rent(1); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.ServerLeft); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - - //end temporary solution - Endpoint.RoomsModified(); _cachedClientRooms.Remove(clientId); } @@ -202,4 +187,4 @@ namespace LightReflectiveMirror } } } -} +} \ No newline at end of file diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceClient.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceClient.cs deleted file mode 100644 index f5b902b..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceClient.cs +++ /dev/null @@ -1,288 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. - -using ENet; -// using NetStack.Buffers; -using System; -using System.Collections.Concurrent; -using System.Threading; -using Event = ENet.Event; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using EventType = ENet.EventType; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using Object = System.Object; // fixes CS0104 ambigous reference between the same thing in UnityEngine - -namespace IgnoranceTransport -{ - public class IgnoranceClient - { - // Client connection address and port - public string ConnectAddress = "127.0.0.1"; - public int ConnectPort = 7777; - // How many channels are expected - public int ExpectedChannels = 2; - // Native poll waiting time - public int PollTime = 1; - // Maximum Packet Size - public int MaximumPacketSize = 33554432; - // General Verbosity by default. - public int Verbosity = 1; - - // Queues - public ConcurrentQueue Incoming = new ConcurrentQueue(); - public ConcurrentQueue Outgoing = new ConcurrentQueue(); - public ConcurrentQueue Commands = new ConcurrentQueue(); - public ConcurrentQueue ConnectionEvents = new ConcurrentQueue(); - public ConcurrentQueue StatusUpdates = new ConcurrentQueue(); - - public bool IsAlive => WorkerThread != null && WorkerThread.IsAlive; - - private volatile bool CeaseOperation = false; - private Thread WorkerThread; - - public void Start() - { - // Debug.Log("IgnoranceClient.Start()"); - - if (WorkerThread != null && WorkerThread.IsAlive) - { - // Cannot do that. - // Debug.LogError("A worker thread is already running. Cannot start another."); - return; - } - - CeaseOperation = false; - ThreadParamInfo threadParams = new ThreadParamInfo() - { - Address = ConnectAddress, - Port = ConnectPort, - Channels = ExpectedChannels, - PollTime = PollTime, - PacketSizeLimit = MaximumPacketSize, - Verbosity = Verbosity - }; - - // Drain queues. - if (Incoming != null) while (Incoming.TryDequeue(out _)) ; - if (Outgoing != null) while (Outgoing.TryDequeue(out _)) ; - if (Commands != null) while (Commands.TryDequeue(out _)) ; - if (ConnectionEvents != null) while (ConnectionEvents.TryDequeue(out _)) ; - if (StatusUpdates != null) while (StatusUpdates.TryDequeue(out _)) ; - - WorkerThread = new Thread(ThreadWorker); - WorkerThread.Start(threadParams); - - // Debug.Log("Client has dispatched worker thread."); - } - - public void Stop() - { - // Debug.Log("Telling client thread to stop, this may take a while depending on network load"); - CeaseOperation = true; - } - - // This runs in a seperate thread, be careful accessing anything outside of it's thread - // or you may get an AccessViolation/crash. - private void ThreadWorker(Object parameters) - { - // if (Verbosity > 0) - // Debug.Log("Ignorance Client: Initializing. Please stand by..."); - - ThreadParamInfo setupInfo; - Address clientAddress = new Address(); - Peer clientPeer; - Host clientENetHost; - Event clientENetEvent; - IgnoranceClientStats icsu = default; - - // Grab the setup information. - if (parameters.GetType() == typeof(ThreadParamInfo)) - { - setupInfo = (ThreadParamInfo)parameters; - } - else - { - // Debug.LogError("Ignorance Client: Startup failure: Invalid thread parameters. Aborting."); - return; - } - - // Attempt to initialize ENet inside the thread. - if (Library.Initialize()) - { - Console.WriteLine("Ignorance Client: ENet initialized."); - } - else - { - // Debug.LogError("Ignorance Client: Failed to initialize ENet. This threads' fucked."); - return; - } - - // Attempt to connect to our target. - clientAddress.SetHost(setupInfo.Address); - clientAddress.Port = (ushort)setupInfo.Port; - - using (clientENetHost = new Host()) - { - // TODO: Maybe try catch this - clientENetHost.Create(); - clientPeer = clientENetHost.Connect(clientAddress, setupInfo.Channels); - - while (!CeaseOperation) - { - bool pollComplete = false; - - // Step 0: Handle commands. - while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) - { - switch (commandPacket.Type) - { - default: - break; - - case IgnoranceCommandType.ClientWantsToStop: - CeaseOperation = true; - break; - - case IgnoranceCommandType.ClientRequestsStatusUpdate: - // Respond with statistics so far. - if (!clientPeer.IsSet) - break; - - icsu.RTT = clientPeer.RoundTripTime; - - icsu.BytesReceived = clientPeer.BytesReceived; - icsu.BytesSent = clientPeer.BytesSent; - - icsu.PacketsReceived = clientENetHost.PacketsReceived; - icsu.PacketsSent = clientPeer.PacketsSent; - icsu.PacketsLost = clientPeer.PacketsLost; - - StatusUpdates.Enqueue(icsu); - break; - } - } - // Step 1: Send out data. - // ---> Sending to Server - while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) - { - // TODO: Revise this, could we tell the Peer to disconnect right here? - // Stop early if we get a client stop packet. - // if (outgoingPacket.Type == IgnorancePacketType.ClientWantsToStop) break; - - int ret = clientPeer.Send(outgoingPacket.Channel, ref outgoingPacket.Payload); - - } - - // Step 2: - // <----- Receive Data packets - // This loops until polling is completed. It may take a while, if it's - // a slow networking day. - while (!pollComplete) - { - Packet incomingPacket; - Peer incomingPeer; - int incomingPacketLength; - - // Any events worth checking out? - if (clientENetHost.CheckEvents(out clientENetEvent) <= 0) - { - // If service time is met, break out of it. - if (clientENetHost.Service(setupInfo.PollTime, out clientENetEvent) <= 0) break; - - // Poll is done. - pollComplete = true; - } - - // Setup the packet references. - incomingPeer = clientENetEvent.Peer; - - // Now, let's handle those events. - switch (clientENetEvent.Type) - { - case EventType.None: - default: - break; - - case EventType.Connect: - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - NativePeerId = incomingPeer.ID, - IP = incomingPeer.IP, - Port = incomingPeer.Port - }); - break; - - case EventType.Disconnect: - case EventType.Timeout: - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - WasDisconnect = true - }); - break; - - - case EventType.Receive: - // Receive event type usually includes a packet; so cache its reference. - incomingPacket = clientENetEvent.Packet; - - if (!incomingPacket.IsSet) - { - - break; - } - - incomingPacketLength = incomingPacket.Length; - - // Never consume more than we can have capacity for. - if (incomingPacketLength > setupInfo.PacketSizeLimit) - { - - incomingPacket.Dispose(); - break; - } - - IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket - { - Channel = clientENetEvent.ChannelID, - NativePeerId = incomingPeer.ID, - Payload = incomingPacket - }; - - Incoming.Enqueue(incomingQueuePacket); - break; - } - } - } - - Console.WriteLine("Ignorance Server: Shutdown commencing, disconnecting and flushing connection."); - - // Flush the client and disconnect. - clientPeer.Disconnect(0); - clientENetHost.Flush(); - - // Fix for client stuck in limbo, since the disconnection event may not be fired until next loop. - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - WasDisconnect = true - }); - } - - // Deinitialize - Library.Deinitialize(); - } - - - private struct ThreadParamInfo - { - public int Channels; - public int PollTime; - public int Port; - public int PacketSizeLimit; - public int Verbosity; - public string Address; - } - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceServer.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceServer.cs deleted file mode 100644 index 0e7bae9..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Core/IgnoranceServer.cs +++ /dev/null @@ -1,303 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. - -using ENet; -// using NetStack.Buffers; -using System.Collections.Concurrent; -using System.Threading; -using Event = ENet.Event; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using EventType = ENet.EventType; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using Object = System.Object; // fixes CS0104 ambigous reference between the same thing in UnityEngine - -namespace IgnoranceTransport -{ - public class IgnoranceServer - { - // Server Properties - // - Bind Settings - public string BindAddress = "127.0.0.1"; - public int BindPort = 7777; - // - Maximum allowed channels, peers, etc. - public int MaximumChannels = 2; - public int MaximumPeers = 100; - public int MaximumPacketSize = 33554432; // ENet.cs: uint maxPacketSize = 32 * 1024 * 1024 = 33554432 - // - Native poll waiting time - public int PollTime = 1; - public int Verbosity = 1; - - public bool IsAlive => WorkerThread != null && WorkerThread.IsAlive; - - private volatile bool CeaseOperation = false; - - // Queues - public ConcurrentQueue Incoming = new ConcurrentQueue(); - public ConcurrentQueue Outgoing = new ConcurrentQueue(); - public ConcurrentQueue Commands = new ConcurrentQueue(); - public ConcurrentQueue ConnectionEvents = new ConcurrentQueue(); - public ConcurrentQueue DisconnectionEvents = new ConcurrentQueue(); - - // Thread - private Thread WorkerThread; - - public void Start() - { - if (WorkerThread != null && WorkerThread.IsAlive) - { - // Cannot do that. - - return; - } - - CeaseOperation = false; - ThreadParamInfo threadParams = new ThreadParamInfo() - { - Address = BindAddress, - Port = BindPort, - Peers = MaximumPeers, - Channels = MaximumChannels, - PollTime = PollTime, - PacketSizeLimit = MaximumPacketSize, - Verbosity = Verbosity - }; - - // Drain queues. - if (Incoming != null) while (Incoming.TryDequeue(out _)) ; - if (Outgoing != null) while (Outgoing.TryDequeue(out _)) ; - if (Commands != null) while (Commands.TryDequeue(out _)) ; - if (ConnectionEvents != null) while (ConnectionEvents.TryDequeue(out _)) ; - if (DisconnectionEvents != null) while (DisconnectionEvents.TryDequeue(out _)) ; - - WorkerThread = new Thread(ThreadWorker); - WorkerThread.Start(threadParams); - - - } - - public void Stop() - { - - CeaseOperation = true; - } - - private void ThreadWorker(Object parameters) - { - - // Thread cache items - ThreadParamInfo setupInfo; - Address serverAddress = new Address(); - Host serverENetHost; - Event serverENetEvent; - - Peer[] serverPeerArray; - - // Grab the setup information. - if (parameters.GetType() == typeof(ThreadParamInfo)) - { - setupInfo = (ThreadParamInfo)parameters; - } - else - { - return; - } - - // Attempt to initialize ENet inside the thread. - if (Library.Initialize()) - { - - } - else - { - - return; - } - - // Configure the server address. - serverAddress.SetHost(setupInfo.Address); - serverAddress.Port = (ushort)setupInfo.Port; - serverPeerArray = new Peer[setupInfo.Peers]; - - using (serverENetHost = new Host()) - { - // Create the server object. - serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels); - - // Loop until we're told to cease operations. - while (!CeaseOperation) - { - // Intermission: Command Handling - while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) - { - switch (commandPacket.Type) - { - default: - break; - - // Boot a Peer off the Server. - case IgnoranceCommandType.ServerKickPeer: - uint targetPeer = commandPacket.PeerId; - - if (!serverPeerArray[targetPeer].IsSet) continue; - - IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() - { - WasDisconnect = true, - NativePeerId = targetPeer - }; - - DisconnectionEvents.Enqueue(iced); - - // Disconnect and reset the peer array's entry for that peer. - serverPeerArray[targetPeer].DisconnectNow(0); - serverPeerArray[targetPeer] = default; - break; - } - } - - // Step One: - // ---> Sending to peers - while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) - { - // Only create a packet if the server knows the peer. - if (serverPeerArray[outgoingPacket.NativePeerId].IsSet) - { - int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload); - - } - else - { - // A peer might have disconnected, this is OK - just log the packet if set to paranoid. - - } - - } - - // Step 2 - // <--- Receiving from peers - bool pollComplete = false; - - while (!pollComplete) - { - Packet incomingPacket; - Peer incomingPeer; - int incomingPacketLength; - - // Any events happening? - if (serverENetHost.CheckEvents(out serverENetEvent) <= 0) - { - // If service time is met, break out of it. - if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0) break; - - pollComplete = true; - } - - // Setup the packet references. - incomingPeer = serverENetEvent.Peer; - - switch (serverENetEvent.Type) - { - // Idle. - case EventType.None: - default: - break; - - // Connection Event. - case EventType.Connect: - IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent() - { - NativePeerId = incomingPeer.ID, - IP = incomingPeer.IP, - Port = incomingPeer.Port - }; - - ConnectionEvents.Enqueue(ice); - - // Assign a reference to the Peer. - serverPeerArray[incomingPeer.ID] = incomingPeer; - break; - - // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together. - case EventType.Disconnect: - case EventType.Timeout: - if (!serverPeerArray[incomingPeer.ID].IsSet) break; - - IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() - { - WasDisconnect = true, - NativePeerId = incomingPeer.ID - }; - - DisconnectionEvents.Enqueue(iced); - - // Reset the peer array's entry for that peer. - serverPeerArray[incomingPeer.ID] = default; - break; - - case EventType.Receive: - // Receive event type usually includes a packet; so cache its reference. - incomingPacket = serverENetEvent.Packet; - if (!incomingPacket.IsSet) - { - - break; - } - - incomingPacketLength = incomingPacket.Length; - - // Firstly check if the packet is too big. If it is, do not process it - drop it. - if (incomingPacketLength > setupInfo.PacketSizeLimit) - { - - incomingPacket.Dispose(); - break; - } - - IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket - { - Channel = serverENetEvent.ChannelID, - NativePeerId = incomingPeer.ID, - Payload = incomingPacket, - }; - - // Enqueue. - Incoming.Enqueue(incomingQueuePacket); - break; - } - } - } - - - // Cleanup and flush everything. - serverENetHost.Flush(); - - // Kick everyone. - for (int i = 0; i < serverPeerArray.Length; i++) - { - if (!serverPeerArray[i].IsSet) continue; - serverPeerArray[i].DisconnectNow(0); - } - } - - // Flush again to ensure ENet gets those Disconnection stuff out. - // May not be needed; better to err on side of caution - - - Library.Deinitialize(); - } - - private struct ThreadParamInfo - { - public int Channels; - public int Peers; - public int PollTime; - public int Port; - public int PacketSizeLimit; - public int Verbosity; - public string Address; - } - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Dependencies/ENet.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Dependencies/ENet.cs deleted file mode 100644 index 564c4b5..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Dependencies/ENet.cs +++ /dev/null @@ -1,1385 +0,0 @@ -/* - * Managed C# wrapper for an extended version of ENet - * This is a fork from upstream and is available at http://github.com/SoftwareGuy/ENet-CSharp - * - * Copyright (c) 2019 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns) - * Copyright (c) 2013 James Bellinger, 2016 Nate Shoffner, 2018 Stanislav Denisov - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -using System; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -namespace ENet -{ - [Flags] - public enum PacketFlags - { - None = 0, - Reliable = 1 << 0, - Unsequenced = 1 << 1, - NoAllocate = 1 << 2, - UnreliableFragmented = 1 << 3, - Instant = 1 << 4, - Unthrottled = 1 << 5, - Sent = 1 << 8 - } - - public enum EventType - { - None = 0, - Connect = 1, - Disconnect = 2, - Receive = 3, - Timeout = 4 - } - - public enum PeerState - { - Uninitialized = -1, - Disconnected = 0, - Connecting = 1, - AcknowledgingConnect = 2, - ConnectionPending = 3, - ConnectionSucceeded = 4, - Connected = 5, - DisconnectLater = 6, - Disconnecting = 7, - AcknowledgingDisconnect = 8, - Zombie = 9 - } - - [StructLayout(LayoutKind.Explicit, Size = 18)] - internal struct ENetAddress - { - [FieldOffset(16)] - public ushort port; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ENetEvent - { - public EventType type; - public IntPtr peer; - public byte channelID; - public uint data; - public IntPtr packet; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ENetCallbacks - { - public AllocCallback malloc; - public FreeCallback free; - public NoMemoryCallback noMemory; - } - - public delegate IntPtr AllocCallback(IntPtr size); - public delegate void FreeCallback(IntPtr memory); - public delegate void NoMemoryCallback(); - public delegate void PacketFreeCallback(Packet packet); - public delegate int InterceptCallback(ref Event @event, ref Address address, IntPtr receivedData, int receivedDataLength); - public delegate ulong ChecksumCallback(IntPtr buffers, int bufferCount); - - internal static class ArrayPool - { - [ThreadStatic] - private static byte[] byteBuffer; - [ThreadStatic] - private static IntPtr[] pointerBuffer; - - public static byte[] GetByteBuffer() - { - if (byteBuffer == null) - byteBuffer = new byte[64]; - - return byteBuffer; - } - - public static IntPtr[] GetPointerBuffer() - { - if (pointerBuffer == null) - pointerBuffer = new IntPtr[Library.maxPeers]; - - return pointerBuffer; - } - } - - public struct Address - { - private ENetAddress nativeAddress; - - internal ENetAddress NativeData - { - get - { - return nativeAddress; - } - - set - { - nativeAddress = value; - } - } - - internal Address(ENetAddress address) - { - nativeAddress = address; - } - - public ushort Port - { - get - { - return nativeAddress.port; - } - - set - { - nativeAddress.port = value; - } - } - - public string GetIP() - { - StringBuilder ip = new StringBuilder(1025); - - if (Native.enet_address_get_ip(ref nativeAddress, ip, (IntPtr)ip.Capacity) != 0) - return String.Empty; - - return ip.ToString(); - } - - public bool SetIP(string ip) - { - if (ip == null) - throw new ArgumentNullException("ip"); - - return Native.enet_address_set_ip(ref nativeAddress, ip) == 0; - } - - public string GetHost() - { - StringBuilder hostName = new StringBuilder(1025); - - if (Native.enet_address_get_hostname(ref nativeAddress, hostName, (IntPtr)hostName.Capacity) != 0) - return String.Empty; - - return hostName.ToString(); - } - - public bool SetHost(string hostName) - { - if (hostName == null) - throw new ArgumentNullException("hostName"); - - return Native.enet_address_set_hostname(ref nativeAddress, hostName) == 0; - } - } - - public struct Event - { - private ENetEvent nativeEvent; - - internal ENetEvent NativeData - { - get - { - return nativeEvent; - } - - set - { - nativeEvent = value; - } - } - - internal Event(ENetEvent @event) - { - nativeEvent = @event; - } - - public EventType Type - { - get - { - return nativeEvent.type; - } - } - - public Peer Peer - { - get - { - return new Peer(nativeEvent.peer); - } - } - - public byte ChannelID - { - get - { - return nativeEvent.channelID; - } - } - - public uint Data - { - get - { - return nativeEvent.data; - } - } - - public Packet Packet - { - get - { - return new Packet(nativeEvent.packet); - } - } - } - - public class Callbacks - { - private ENetCallbacks nativeCallbacks; - - internal ENetCallbacks NativeData - { - get - { - return nativeCallbacks; - } - - set - { - nativeCallbacks = value; - } - } - - public Callbacks(AllocCallback allocCallback, FreeCallback freeCallback, NoMemoryCallback noMemoryCallback) - { - nativeCallbacks.malloc = allocCallback; - nativeCallbacks.free = freeCallback; - nativeCallbacks.noMemory = noMemoryCallback; - } - } - - public struct Packet : IDisposable - { - private IntPtr nativePacket; - - internal IntPtr NativeData - { - get - { - return nativePacket; - } - - set - { - nativePacket = value; - } - } - - internal Packet(IntPtr packet) - { - nativePacket = packet; - } - - public void Dispose() - { - if (nativePacket != IntPtr.Zero) - { - Native.enet_packet_dispose(nativePacket); - nativePacket = IntPtr.Zero; - } - } - - public bool IsSet - { - get - { - return nativePacket != IntPtr.Zero; - } - } - - public IntPtr Data - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_data(nativePacket); - } - } - - public IntPtr UserData - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_user_data(nativePacket); - } - - set - { - ThrowIfNotCreated(); - - Native.enet_packet_set_user_data(nativePacket, value); - } - } - - public int Length - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_length(nativePacket); - } - } - - public bool HasReferences - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_check_references(nativePacket) != 0; - } - } - - internal void ThrowIfNotCreated() - { - if (nativePacket == IntPtr.Zero) - throw new InvalidOperationException("Packet not created"); - } - - public void SetFreeCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_packet_set_free_callback(nativePacket, callback); - } - - public void SetFreeCallback(PacketFreeCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_packet_set_free_callback(nativePacket, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void Create(byte[] data) - { - if (data == null) - throw new ArgumentNullException("data"); - - Create(data, data.Length); - } - - public void Create(byte[] data, int length) - { - Create(data, length, PacketFlags.None); - } - - public void Create(byte[] data, PacketFlags flags) - { - Create(data, data.Length, flags); - } - - public void Create(byte[] data, int length, PacketFlags flags) - { - if (data == null) - throw new ArgumentNullException("data"); - - if (length < 0 || length > data.Length) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); - } - - public void Create(IntPtr data, int length, PacketFlags flags) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - - if (length < 0) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); - } - - public void Create(byte[] data, int offset, int length, PacketFlags flags) - { - if (data == null) - throw new ArgumentNullException("data"); - - if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); - - if (length < 0 || length > data.Length) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); - } - - public void Create(IntPtr data, int offset, int length, PacketFlags flags) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - - if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); - - if (length < 0) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); - } - - public void CopyTo(byte[] destination, int startPos = 0) - { - if (destination == null) - throw new ArgumentNullException("destination"); - - // Fix by katori, prevents trying to copy a NULL - // from native world (ie. disconnect a client) - if (Data == null) - { - return; - } - - Marshal.Copy(Data, destination, startPos, Length); - } - } - - public class Host : IDisposable - { - private IntPtr nativeHost; - - internal IntPtr NativeData - { - get - { - return nativeHost; - } - - set - { - nativeHost = value; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (nativeHost != IntPtr.Zero) - { - Native.enet_host_destroy(nativeHost); - nativeHost = IntPtr.Zero; - } - } - - ~Host() - { - Dispose(false); - } - - public bool IsSet - { - get - { - return nativeHost != IntPtr.Zero; - } - } - - public uint PeersCount - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_peers_count(nativeHost); - } - } - - public uint PacketsSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_packets_sent(nativeHost); - } - } - - public uint PacketsReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_packets_received(nativeHost); - } - } - - public uint BytesSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_bytes_sent(nativeHost); - } - } - - public uint BytesReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_bytes_received(nativeHost); - } - } - - internal void ThrowIfNotCreated() - { - if (nativeHost == IntPtr.Zero) - throw new InvalidOperationException("Host not created"); - } - - private static void ThrowIfChannelsExceeded(int channelLimit) - { - if (channelLimit < 0 || channelLimit > Library.maxChannelCount) - throw new ArgumentOutOfRangeException("channelLimit"); - } - - public void Create() - { - Create(null, 1, 0); - } - - public void Create(int bufferSize) - { - Create(null, 1, 0, 0, 0, bufferSize); - } - - public void Create(Address? address, int peerLimit) - { - Create(address, peerLimit, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit) - { - Create(address, peerLimit, channelLimit, 0, 0, 0); - } - - public void Create(int peerLimit, int channelLimit) - { - Create(null, peerLimit, channelLimit, 0, 0, 0); - } - - public void Create(int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) - { - Create(null, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) - { - Create(address, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize) - { - if (nativeHost != IntPtr.Zero) - throw new InvalidOperationException("Host already created"); - - if (peerLimit < 0 || peerLimit > Library.maxPeers) - throw new ArgumentOutOfRangeException("peerLimit"); - - ThrowIfChannelsExceeded(channelLimit); - - if (address != null) - { - var nativeAddress = address.Value.NativeData; - - nativeHost = Native.enet_host_create(ref nativeAddress, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); - } - else - { - nativeHost = Native.enet_host_create(IntPtr.Zero, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); - } - - if (nativeHost == IntPtr.Zero) - throw new InvalidOperationException("Host creation call failed"); - } - - public void PreventConnections(bool state) - { - ThrowIfNotCreated(); - - Native.enet_host_prevent_connections(nativeHost, (byte)(state ? 1 : 0)); - } - - public void Broadcast(byte channelID, ref Packet packet) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - Native.enet_host_broadcast(nativeHost, channelID, packet.NativeData); - packet.NativeData = IntPtr.Zero; - } - - public void Broadcast(byte channelID, ref Packet packet, Peer excludedPeer) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - Native.enet_host_broadcast_exclude(nativeHost, channelID, packet.NativeData, excludedPeer.NativeData); - packet.NativeData = IntPtr.Zero; - } - - public void Broadcast(byte channelID, ref Packet packet, Peer[] peers) - { - if (peers == null) - throw new ArgumentNullException("peers"); - - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - - if (peers.Length > 0) - { - IntPtr[] nativePeers = ArrayPool.GetPointerBuffer(); - int nativeCount = 0; - - for (int i = 0; i < peers.Length; i++) - { - if (peers[i].NativeData != IntPtr.Zero) - { - nativePeers[nativeCount] = peers[i].NativeData; - nativeCount++; - } - } - - Native.enet_host_broadcast_selective(nativeHost, channelID, packet.NativeData, nativePeers, (IntPtr)nativeCount); - } - - packet.NativeData = IntPtr.Zero; - } - - public int CheckEvents(out Event @event) - { - ThrowIfNotCreated(); - - ENetEvent nativeEvent; - - var result = Native.enet_host_check_events(nativeHost, out nativeEvent); - - if (result <= 0) - { - @event = default(Event); - - return result; - } - - @event = new Event(nativeEvent); - - return result; - } - - public Peer Connect(Address address) - { - return Connect(address, 0, 0); - } - - public Peer Connect(Address address, int channelLimit) - { - return Connect(address, channelLimit, 0); - } - - public Peer Connect(Address address, int channelLimit, uint data) - { - ThrowIfNotCreated(); - ThrowIfChannelsExceeded(channelLimit); - - var nativeAddress = address.NativeData; - var peer = new Peer(Native.enet_host_connect(nativeHost, ref nativeAddress, (IntPtr)channelLimit, data)); - - if (peer.NativeData == IntPtr.Zero) - throw new InvalidOperationException("Host connect call failed"); - - return peer; - } - - public int Service(int timeout, out Event @event) - { - if (timeout < 0) - throw new ArgumentOutOfRangeException("timeout"); - - ThrowIfNotCreated(); - - ENetEvent nativeEvent; - - var result = Native.enet_host_service(nativeHost, out nativeEvent, (uint)timeout); - - if (result <= 0) - { - @event = default(Event); - - return result; - } - - @event = new Event(nativeEvent); - - return result; - } - - public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth) - { - ThrowIfNotCreated(); - - Native.enet_host_bandwidth_limit(nativeHost, incomingBandwidth, outgoingBandwidth); - } - - public void SetChannelLimit(int channelLimit) - { - ThrowIfNotCreated(); - ThrowIfChannelsExceeded(channelLimit); - - Native.enet_host_channel_limit(nativeHost, (IntPtr)channelLimit); - } - - public void SetMaxDuplicatePeers(ushort number) - { - ThrowIfNotCreated(); - - Native.enet_host_set_max_duplicate_peers(nativeHost, number); - } - - public void SetInterceptCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_intercept_callback(nativeHost, callback); - } - - public void SetInterceptCallback(InterceptCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_intercept_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void SetChecksumCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_checksum_callback(nativeHost, callback); - } - - public void SetChecksumCallback(ChecksumCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_checksum_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void Flush() - { - ThrowIfNotCreated(); - - Native.enet_host_flush(nativeHost); - } - } - - public struct Peer - { - private IntPtr nativePeer; - private uint nativeID; - - internal IntPtr NativeData - { - get - { - return nativePeer; - } - - set - { - nativePeer = value; - } - } - - internal Peer(IntPtr peer) - { - nativePeer = peer; - nativeID = nativePeer != IntPtr.Zero ? Native.enet_peer_get_id(nativePeer) : 0; - } - - public bool IsSet - { - get - { - return nativePeer != IntPtr.Zero; - } - } - - public uint ID - { - get - { - return nativeID; - } - } - - public string IP - { - get - { - ThrowIfNotCreated(); - - byte[] ip = ArrayPool.GetByteBuffer(); - - if (Native.enet_peer_get_ip(nativePeer, ip, (IntPtr)ip.Length) == 0) - return Encoding.ASCII.GetString(ip, 0, ip.StringLength()); - else - return String.Empty; - } - } - - public ushort Port - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_port(nativePeer); - } - } - - public uint MTU - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_mtu(nativePeer); - } - } - - public PeerState State - { - get - { - return nativePeer == IntPtr.Zero ? PeerState.Uninitialized : Native.enet_peer_get_state(nativePeer); - } - } - - public uint RoundTripTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_rtt(nativePeer); - } - } - - public uint LastRoundTripTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_last_rtt(nativePeer); - } - } - - public uint LastSendTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_lastsendtime(nativePeer); - } - } - - public uint LastReceiveTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_lastreceivetime(nativePeer); - } - } - - public ulong PacketsSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_sent(nativePeer); - } - } - - public ulong PacketsLost - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_lost(nativePeer); - } - } - - public float PacketsThrottle - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_throttle(nativePeer); - } - } - - public ulong BytesSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_bytes_sent(nativePeer); - } - } - - public ulong BytesReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_bytes_received(nativePeer); - } - } - - public IntPtr Data - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_data(nativePeer); - } - - set - { - ThrowIfNotCreated(); - - Native.enet_peer_set_data(nativePeer, value); - } - } - - internal void ThrowIfNotCreated() - { - if (nativePeer == IntPtr.Zero) - throw new InvalidOperationException("Peer not created"); - } - - public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold) - { - ThrowIfNotCreated(); - - Native.enet_peer_throttle_configure(nativePeer, interval, acceleration, deceleration, threshold); - } - - public int Send(byte channelID, ref Packet packet) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - - return Native.enet_peer_send(nativePeer, channelID, packet.NativeData); - } - - public bool Receive(out byte channelID, out Packet packet) - { - ThrowIfNotCreated(); - - IntPtr nativePacket = Native.enet_peer_receive(nativePeer, out channelID); - - if (nativePacket != IntPtr.Zero) - { - packet = new Packet(nativePacket); - - return true; - } - - packet = default(Packet); - - return false; - } - - public void Ping() - { - ThrowIfNotCreated(); - - Native.enet_peer_ping(nativePeer); - } - - public void PingInterval(uint interval) - { - ThrowIfNotCreated(); - - Native.enet_peer_ping_interval(nativePeer, interval); - } - - public void Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum) - { - ThrowIfNotCreated(); - - Native.enet_peer_timeout(nativePeer, timeoutLimit, timeoutMinimum, timeoutMaximum); - } - - public void Disconnect(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect(nativePeer, data); - } - - public void DisconnectNow(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect_now(nativePeer, data); - } - - public void DisconnectLater(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect_later(nativePeer, data); - } - - public void Reset() - { - ThrowIfNotCreated(); - - Native.enet_peer_reset(nativePeer); - } - } - - public static class Extensions - { - public static int StringLength(this byte[] data) - { - if (data == null) - throw new ArgumentNullException("data"); - - int i; - - for (i = 0; i < data.Length && data[i] != 0; i++) ; - - return i; - } - } - - public static class Library - { - public const uint maxChannelCount = 0xFF; - public const uint maxPeers = 0xFFF; - public const uint maxPacketSize = 32 * 1024 * 1024; - public const uint throttleThreshold = 40; - public const uint throttleScale = 32; - public const uint throttleAcceleration = 2; - public const uint throttleDeceleration = 2; - public const uint throttleInterval = 5000; - public const uint timeoutLimit = 32; - public const uint timeoutMinimum = 5000; - public const uint timeoutMaximum = 30000; - public const uint version = (2 << 16) | (4 << 8) | (7); - - public static uint Time - { - get - { - return Native.enet_time_get(); - } - } - - public static bool Initialize() - { - if (Native.enet_linked_version() != version) - throw new InvalidOperationException("ENet native is out of date. Download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); - - return Native.enet_initialize() == 0; - } - - public static bool Initialize(Callbacks callbacks) - { - if (callbacks == null) - throw new ArgumentNullException("callbacks"); - - if (Native.enet_linked_version() != version) - throw new InvalidOperationException("ENet native is out of date. Download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); - - ENetCallbacks nativeCallbacks = callbacks.NativeData; - - return Native.enet_initialize_with_callbacks(version, ref nativeCallbacks) == 0; - } - - public static void Deinitialize() - { - Native.enet_deinitialize(); - } - - public static ulong CRC64(IntPtr buffers, int bufferCount) - { - return Native.enet_crc64(buffers, bufferCount); - } - } - - [SuppressUnmanagedCodeSecurity] - internal static class Native - { - private const string nativeLibrary = enetWindows; - - private const string enetLinux = "lib/linux/libenet"; - private const string enetWindows = "lib/win/enet"; - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_initialize(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_initialize_with_callbacks(uint version, ref ENetCallbacks inits); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_deinitialize(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_linked_version(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_time_get(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_crc64(IntPtr buffers, int bufferCount); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_set_ip(ref ENetAddress address, string ip); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_set_hostname(ref ENetAddress address, string hostName); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_get_ip(ref ENetAddress address, StringBuilder ip, IntPtr ipLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_get_hostname(ref ENetAddress address, StringBuilder hostName, IntPtr nameLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_packet_check_references(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_get_data(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_get_user_data(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_set_user_data(IntPtr packet, IntPtr userData); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_packet_get_length(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_packet_dispose(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast_exclude(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_peers_count(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_packets_sent(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_packets_received(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_bytes_sent(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_bytes_received(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_max_duplicate_peers(IntPtr host, ushort number); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_intercept_callback(IntPtr host, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_checksum_callback(IntPtr host, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_flush(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_destroy(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_prevent_connections(IntPtr host, byte state); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_id(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ushort enet_peer_get_port(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_mtu(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern PeerState enet_peer_get_state(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_rtt(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_last_rtt(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_lastsendtime(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_packets_sent(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_packets_lost(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern float enet_peer_get_packets_throttle(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_bytes_received(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_peer_get_data(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_ping(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_reset(IntPtr peer); - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Ignorance.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Ignorance.cs deleted file mode 100644 index 9abff62..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Ignorance.cs +++ /dev/null @@ -1,510 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. -// ----------------- -// Ignorance Experimental (New) Version -// ----------------- -using ENet; -using Mirror; -using System; -using System.Collections.Generic; - -namespace IgnoranceTransport -{ - public class Ignorance : Transport - { - public int port = 7777; - - public IgnoranceLogType LogType = IgnoranceLogType.Standard; - public bool DebugDisplay = false; - - public bool serverBindsAll = true; - public string serverBindAddress = string.Empty; - public int serverMaxPeerCapacity = 50; - public int serverMaxNativeWaitTime = 1; - - public int clientMaxNativeWaitTime = 3; - - public IgnoranceChannelTypes[] Channels = new[] { IgnoranceChannelTypes.Reliable, IgnoranceChannelTypes.Unreliable }; - - public int PacketBufferCapacity = 4096; - - public int MaxAllowedPacketSize = 33554432; - - public IgnoranceClientStats ClientStatistics; - - public override bool Available() - { - return true; - } - - public override void Awake() - { - if (LogType != IgnoranceLogType.Nothing) - Console.WriteLine($"Thanks for using Ignorance {IgnoranceInternals.Version}. Keep up to date, report bugs and support the developer at https://github.com/SoftwareGuy/Ignorance!"); - } - - public override string ToString() - { - return $"Ignorance v{IgnoranceInternals.Version}"; - } - - public override void ClientConnect(string address) - { - ClientState = ConnectionState.Connecting; - cachedConnectionAddress = address; - - // Initialize. - InitializeClientBackend(); - - // Get going. - ignoreDataPackets = false; - - // Start! - Client.Start(); - } - - public override void ClientConnect(Uri uri) - { - if (uri.Scheme != IgnoranceInternals.Scheme) - throw new ArgumentException($"You used an invalid URI: {uri}. Please use {IgnoranceInternals.Scheme}://host:port instead", nameof(uri)); - - if (!uri.IsDefaultPort) - // Set the communication port to the one specified. - port = uri.Port; - - // Pass onwards to the proper handler. - ClientConnect(uri.Host); - } - - public override bool ClientConnected() => ClientState == ConnectionState.Connected; - - public override void ClientDisconnect() - { - if (Client != null) - Client.Stop(); - - // TODO: Figure this one out to see if it's related to a race condition. - // Maybe experiment with a while loop to pause main thread when disconnecting, - // since client might not stop on a dime. - // while(Client.IsAlive) ; - // v1.4.0b1: Probably fixed in IgnoranceClient.cs; need further testing. - - // ignoreDataPackets = true; - ClientState = ConnectionState.Disconnected; - } - - - // v1.4.0b6: Mirror rearranged the ClientSend params, so we need to apply a fix for that or - // we end up using the obsoleted version. The obsolete version isn't a fatal error, but - // it's best to stick with the new structures. - public override void ClientSend(int channelId, ArraySegment segment) - { - if (Client == null) - { - - return; - } - - if (channelId < 0 || channelId > Channels.Length) - { - - return; - } - - // Create our struct... - Packet clientOutgoingPacket = default; - int byteCount = segment.Count; - int byteOffset = segment.Offset; - // Set our desired flags... - PacketFlags desiredFlags = (PacketFlags)Channels[channelId]; - - // Create the packet. - clientOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, desiredFlags); - // byteCount - - // Enqueue the packet. - IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket - { - Channel = (byte)channelId, - Payload = clientOutgoingPacket - }; - - // Pass the packet onto the thread for dispatch. - Client.Outgoing.Enqueue(dispatchPacket); - } - - public override bool ServerActive() - { - // Very simple check. - return Server != null && Server.IsAlive; - } - - public override bool ServerDisconnect(int connectionId) => ServerDisconnectLegacy(connectionId); - - public override string ServerGetClientAddress(int connectionId) - { - if (ConnectionLookupDict.TryGetValue(connectionId, out PeerConnectionData details)) - return $"{details.IP}:{details.Port}"; - - return "(unavailable)"; - } - - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - // Debug.Log($"ServerSend({connectionId}, {channelId}, <{segment.Count} byte segment>)"); - - if (Server == null) - { - // Debug.LogError("Cannot enqueue data packet; our Server object is null. Something has gone wrong."); - return; - } - - if (channelId < 0 || channelId > Channels.Length) - { - // Debug.LogError("Channel ID is out of bounds."); - return; - } - - // Packet Struct - Packet serverOutgoingPacket = default; - int byteCount = segment.Count; - int byteOffset = segment.Offset; - PacketFlags desiredFlags = (PacketFlags)Channels[channelId]; - - // Create the packet. - serverOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, desiredFlags); - - // Enqueue the packet. - IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket - { - Channel = (byte)channelId, - NativePeerId = (uint)connectionId - 1, // ENet's native peer ID will be ConnID - 1 - Payload = serverOutgoingPacket - }; - - Server.Outgoing.Enqueue(dispatchPacket); - - } - - public override void ServerStart(ushort _port) - { - if (LogType != IgnoranceLogType.Nothing) - Console.WriteLine("Ignorance Server Instance starting up..."); - port = _port; - - InitializeServerBackend(); - - Server.Start(); - } - - public override void ServerStop() - { - if (Server != null) - { - if (LogType != IgnoranceLogType.Nothing) - Console.WriteLine("Ignorance Server Instance shutting down..."); - - Server.Stop(); - } - - ConnectionLookupDict.Clear(); - } - - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder - { - Scheme = IgnoranceInternals.Scheme, - Host = serverBindAddress, - Port = port - }; - - return builder.Uri; - } - - public override void Shutdown() - { - // TODO: Nothing needed here? - } - - private void InitializeServerBackend() - { - if (Server == null) - { - // Debug.LogWarning("IgnoranceServer reference for Server mode was null. This shouldn't happen, but to be safe we'll reinitialize it."); - Server = new IgnoranceServer(); - } - - // Set up the new IgnoranceServer reference. - if (serverBindsAll) - // MacOS is special. It's also a massive thorn in my backside. - Server.BindAddress = IgnoranceInternals.BindAllMacs; - else - // Use the supplied bind address. - Server.BindAddress = serverBindAddress; - - // Sets port, maximum peers, max channels, the server poll time, maximum packet size and verbosity. - Server.BindPort = port; - Server.MaximumPeers = serverMaxPeerCapacity; - Server.MaximumChannels = Channels.Length; - Server.PollTime = serverMaxNativeWaitTime; - Server.MaximumPacketSize = MaxAllowedPacketSize; - Server.Verbosity = (int)LogType; - - // Initializes the packet buffer. - // Allocates once, that's it. - if (InternalPacketBuffer == null) - InternalPacketBuffer = new byte[PacketBufferCapacity]; - } - - private void InitializeClientBackend() - { - if (Client == null) - { - // Debug.LogWarning("Ignorance: IgnoranceClient reference for Client mode was null. This shouldn't happen, but to be safe we'll reinitialize it."); - Client = new IgnoranceClient(); - } - - // Sets address, port, channels to expect, verbosity, the server poll time and maximum packet size. - Client.ConnectAddress = cachedConnectionAddress; - Client.ConnectPort = port; - Client.ExpectedChannels = Channels.Length; - Client.PollTime = clientMaxNativeWaitTime; - Client.MaximumPacketSize = MaxAllowedPacketSize; - Client.Verbosity = (int)LogType; - - // Initializes the packet buffer. - // Allocates once, that's it. - if (InternalPacketBuffer == null) - InternalPacketBuffer = new byte[PacketBufferCapacity]; - } - - private void ProcessServerPackets() - { - IgnoranceIncomingPacket incomingPacket; - IgnoranceConnectionEvent connectionEvent; - int adjustedConnectionId; - Packet payload; - - // Incoming connection events. - while (Server.ConnectionEvents.TryDequeue(out connectionEvent)) - { - adjustedConnectionId = (int)connectionEvent.NativePeerId + 1; - - // TODO: Investigate ArgumentException: An item with the same key has already been added. Key: - ConnectionLookupDict.Add(adjustedConnectionId, new PeerConnectionData - { - NativePeerId = connectionEvent.NativePeerId, - IP = connectionEvent.IP, - Port = connectionEvent.Port - }); - - OnServerConnected?.Invoke(adjustedConnectionId); - } - - // Handle incoming data packets. - // Console.WriteLine($"Server Incoming Queue is {Server.Incoming.Count}"); - while (Server.Incoming.TryDequeue(out incomingPacket)) - { - adjustedConnectionId = (int)incomingPacket.NativePeerId + 1; - payload = incomingPacket.Payload; - - int length = payload.Length; - ArraySegment dataSegment; - - // Copy to working buffer and dispose of it. - if (length > InternalPacketBuffer.Length) - { - byte[] oneFreshNTastyGcAlloc = new byte[length]; - - payload.CopyTo(oneFreshNTastyGcAlloc); - dataSegment = new ArraySegment(oneFreshNTastyGcAlloc, 0, length); - } - else - { - payload.CopyTo(InternalPacketBuffer); - dataSegment = new ArraySegment(InternalPacketBuffer, 0, length); - } - - payload.Dispose(); - - OnServerDataReceived?.Invoke(adjustedConnectionId, dataSegment, incomingPacket.Channel); - } - - // Disconnection events. - while (Server.DisconnectionEvents.TryDequeue(out IgnoranceConnectionEvent disconnectionEvent)) - { - adjustedConnectionId = (int)disconnectionEvent.NativePeerId + 1; - - ConnectionLookupDict.Remove(adjustedConnectionId); - - // Invoke Mirror handler. - OnServerDisconnected?.Invoke(adjustedConnectionId); - } - } - - private void ProcessClientPackets() - { - Packet payload; - - // Handle connection events. - while (Client.ConnectionEvents.TryDequeue(out IgnoranceConnectionEvent connectionEvent)) - { - - if (connectionEvent.WasDisconnect) - { - // Disconnected from server. - ClientState = ConnectionState.Disconnected; - - ignoreDataPackets = true; - OnClientDisconnected?.Invoke(); - } - else - { - // Connected to server. - ClientState = ConnectionState.Connected; - - ignoreDataPackets = false; - OnClientConnected?.Invoke(); - } - } - - // Now handle the incoming messages. - while (Client.Incoming.TryDequeue(out IgnoranceIncomingPacket incomingPacket)) - { - // Temporary fix: if ENet thread is too fast for Mirror, then ignore the packet. - // This is seen sometimes if you stop the client and there's still stuff in the queue. - if (ignoreDataPackets) - { - break; - } - - // Otherwise client recieved data, advise Mirror. - // print($"Byte array: {incomingPacket.RentedByteArray.Length}. Packet Length: {incomingPacket.Length}"); - payload = incomingPacket.Payload; - int length = payload.Length; - ArraySegment dataSegment; - - // Copy to working buffer and dispose of it. - if (length > InternalPacketBuffer.Length) - { - // Unity's favourite: A fresh 'n' tasty GC Allocation! - byte[] oneFreshNTastyGcAlloc = new byte[length]; - - payload.CopyTo(oneFreshNTastyGcAlloc); - dataSegment = new ArraySegment(oneFreshNTastyGcAlloc, 0, length); - } - else - { - payload.CopyTo(InternalPacketBuffer); - dataSegment = new ArraySegment(InternalPacketBuffer, 0, length); - } - - payload.Dispose(); - - OnClientDataReceived?.Invoke(dataSegment, incomingPacket.Channel); - } - - // Step 3: Handle other commands. - while (Client.Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) - { - switch (commandPacket.Type) - { - // ... - default: - break; - } - } - - // Step 4: Handle status updates. - if (Client.StatusUpdates.TryDequeue(out IgnoranceClientStats clientStats)) - { - ClientStatistics = clientStats; - } - } - - // Ignorance 1.4.0b5: To use Mirror's polling or not use Mirror's polling, that is up to the developer to decide - - // IMPORTANT: Set Ignorance' execution order before everything else. Yes, that's -32000 !! - // This ensures it has priority over other things. - - // FixedUpdate can be called many times per frame. - // Once we've handled stuff, we set a flag so that we don't poll again for this frame. - - private bool fixedUpdateCompletedWork; - public void FixedUpdate() - { - if (fixedUpdateCompletedWork) return; - - ProcessAndExecuteAllPackets(); - - // Flip the bool to signal we've done our work. - fixedUpdateCompletedWork = true; - } - - // Normally, Mirror blocks Update() due to poor design decisions... - // But thanks to Vincenzo, we've found a way to bypass that block. - // Update is called once per frame. We don't have to worry about this shit now. - public override void Update() - { - // Process what FixedUpdate missed, only if the boolean is not set. - if (!fixedUpdateCompletedWork) - ProcessAndExecuteAllPackets(); - - // Flip back the bool, so it can be reset. - fixedUpdateCompletedWork = false; - } - - // Processes and Executes All Packets. - private void ProcessAndExecuteAllPackets() - { - // Process Server Events... - if (Server.IsAlive) - ProcessServerPackets(); - - // Process Client Events... - if (Client.IsAlive) - { - ProcessClientPackets(); - } - } - - public override int GetMaxPacketSize(int channelId = 0) => MaxAllowedPacketSize; - - private bool ignoreDataPackets; - private string cachedConnectionAddress = string.Empty; - private IgnoranceServer Server = new IgnoranceServer(); - private IgnoranceClient Client = new IgnoranceClient(); - private Dictionary ConnectionLookupDict = new Dictionary(); - - private enum ConnectionState { Connecting, Connected, Disconnecting, Disconnected } - private ConnectionState ClientState = ConnectionState.Disconnected; - private byte[] InternalPacketBuffer; - - public bool ServerDisconnectLegacy(int connectionId) - { - if (Server == null) - { - // Debug.LogError("Cannot enqueue kick packet; our Server object is null. Something has gone wrong."); - // Return here because otherwise we will get a NRE when trying to enqueue the kick packet. - return false; - } - - IgnoranceCommandPacket kickPacket = new IgnoranceCommandPacket - { - Type = IgnoranceCommandType.ServerKickPeer, - PeerId = (uint)connectionId - 1 // ENet's native peer ID will be ConnID - 1 - }; - - // Pass the packet onto the thread for dispatch. - Server.Commands.Enqueue(kickPacket); - return true; - } - - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/IgnoranceDefinitions.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/IgnoranceDefinitions.cs deleted file mode 100644 index ca677ac..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/IgnoranceDefinitions.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using ENet; - -namespace IgnoranceTransport -{ - // Snipped from the transport files, as this will help - // me keep things up to date. - [Serializable] - public enum IgnoranceChannelTypes - { - Reliable = PacketFlags.Reliable, // TCP Emulation. - ReliableUnsequenced = PacketFlags.Reliable | PacketFlags.Unsequenced, // TCP Emulation, but no sequencing. - Unreliable = PacketFlags.Unsequenced, // Pure UDP. - UnreliableFragmented = PacketFlags.UnreliableFragmented, // Pure UDP, but fragmented. - UnreliableSequenced = PacketFlags.None, // Pure UDP, but sequenced. - Unthrottled = PacketFlags.Unthrottled, // Apparently ENet's version of Taco Bell. - } - - public class IgnoranceInternals - { - public const string Version = "1.4.0b6"; - public const string Scheme = "enet"; - public const string BindAllIPv4 = "0.0.0.0"; - public const string BindAllMacs = "::0"; - } - - public enum IgnoranceLogType - { - Nothing, - Standard, - Verbose - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceIncomingPacket - { - public byte Channel; - public uint NativePeerId; - public Packet Payload; - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceOutgoingPacket - { - public byte Channel; - public uint NativePeerId; - public Packet Payload; - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceConnectionEvent - { - public bool WasDisconnect; - public ushort Port; - public uint NativePeerId; - public string IP; - } - - public struct IgnoranceCommandPacket - { - public IgnoranceCommandType Type; - public uint PeerId; - } - - public struct IgnoranceClientStats - { - // Stats only - may not always be used! - public uint RTT; - public ulong BytesReceived; - public ulong BytesSent; - public ulong PacketsReceived; - public ulong PacketsSent; - public ulong PacketsLost; - } - - public enum IgnoranceCommandType - { - // Client - ClientWantsToStop, - ClientRequestsStatusUpdate, - // ENet internal - ResponseToClientStatusRequest, - // Server - ServerKickPeer - } - - // TODO: Optimize struct for Cache performance. - public struct PeerConnectionData - { - public ushort Port; - public uint NativePeerId; - public string IP; - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/Linux/libenet.so b/ServerProject-DONT-IMPORT-INTO-UNITY/MultiCompiled/Ignorance/Plugins/Linux/libenet.so deleted file mode 100644 index c64bfb75bee9db3d5c8c0c23fd880b209259ea50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60144 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.ReadAllText("KCPConfig.json")); + conf = JsonConvert.DeserializeObject(File.ReadAllText("KCPConfig.json")); } NoDelay = conf.NoDelay; diff --git a/UnityProject/Assets/Ignorance.meta b/UnityProject/Assets/FishBait.meta similarity index 77% rename from UnityProject/Assets/Ignorance.meta rename to UnityProject/Assets/FishBait.meta index a52c77f..290043d 100644 --- a/UnityProject/Assets/Ignorance.meta +++ b/UnityProject/Assets/FishBait.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8e62b1f8d9ebd624a9fc425eda441bcd +guid: 546899055272faa4bbcc3514890bb897 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishBait/BiDictionary.cs b/UnityProject/Assets/FishBait/BiDictionary.cs new file mode 100644 index 0000000..23608ef --- /dev/null +++ b/UnityProject/Assets/FishBait/BiDictionary.cs @@ -0,0 +1,56 @@ +// +// Source: https://stackoverflow.com/questions/255341/getting-multiple-keys-of-specified-value-of-a-generic-dictionary#255630 +// +using System; +using System.Collections.Generic; + +namespace FishBait +{ + class BiDictionary + { + IDictionary firstToSecond = new Dictionary(); + IDictionary secondToFirst = new Dictionary(); + + public void Add(TFirst first, TSecond second) + { + if (firstToSecond.ContainsKey(first) || + secondToFirst.ContainsKey(second)) + { + throw new ArgumentException("Duplicate first or second"); + } + firstToSecond.Add(first, second); + secondToFirst.Add(second, first); + } + + public bool TryGetByFirst(TFirst first, out TSecond second) + { + return firstToSecond.TryGetValue(first, out second); + } + + public void Remove(TFirst first) + { + secondToFirst.Remove(firstToSecond[first]); + firstToSecond.Remove(first); + } + + public ICollection GetAllKeys() + { + return secondToFirst.Values; + } + + public bool TryGetBySecond(TSecond second, out TFirst first) + { + return secondToFirst.TryGetValue(second, out first); + } + + public TSecond GetByFirst(TFirst first) + { + return firstToSecond[first]; + } + + public TFirst GetBySecond(TSecond second) + { + return secondToFirst[second]; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs.meta b/UnityProject/Assets/FishBait/BiDictionary.cs.meta similarity index 83% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs.meta rename to UnityProject/Assets/FishBait/BiDictionary.cs.meta index 8b3212b..f301688 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs.meta +++ b/UnityProject/Assets/FishBait/BiDictionary.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1069f42b88a4adb4ab1990cec4949343 +guid: e602ddfa0d8a4484ca59bdfba7833fb4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor.meta b/UnityProject/Assets/FishBait/Editor.meta similarity index 77% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor.meta rename to UnityProject/Assets/FishBait/Editor.meta index 40c6fd2..0a0cba5 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor.meta +++ b/UnityProject/Assets/FishBait/Editor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0995e08af14888348b42ecaa6eb21544 +guid: 40dd8a7d9b0c2a649a7989442ae66d1a folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs b/UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs new file mode 100644 index 0000000..552ed54 --- /dev/null +++ b/UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs @@ -0,0 +1,310 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System.Net; +using System.Reflection; +using System.Linq; +using System; +using FishNet.Transporting; + +namespace FishBait +{ +#if UNITY_EDITOR + [CustomEditor(typeof(FishBaitTransport))] + public class FishBaitInspector : Editor + { + int serverPort = 7777; + string serverIP; + float invalidServerIP = 0; + bool usingLLB = false; + FishBaitDirectConnectModule directModule; + string[] tabs = new string[] { "FishBait Settings", "NAT Punch", "Load Balancer", "Other" }; + int currentTab = 0; + [HideInInspector] + public Transport transportHolder; + + public override void OnInspectorGUI() + { + var fishBait = (FishBaitTransport)target; + directModule = fishBait.GetComponent(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label(Resources.Load("FishBait"), GUILayout.Height(50), GUILayout.Width(100)); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + if (string.IsNullOrEmpty(fishBait.loadBalancerAddress)) + { + // First setup screen, ask if they are using LLB or just a single FishBait node. + EditorGUILayout.HelpBox("Thank you for using FishBait!\nTo get started, please select which setup you are using.", MessageType.None); + + if (GUILayout.Button("Load Balancer Setup")) + { + usingLLB = true; + fishBait.loadBalancerAddress = "127.0.0.1"; + serverPort = 7070; + } + + if (GUILayout.Button("Single FishBait Node Setup")) + { + fishBait.loadBalancerAddress = "127.0.0.1"; + fishBait.useLoadBalancer = false; + usingLLB = false; + serverIP = "172.105.109.117"; + } + } + else if (usingLLB) + { + // They said they are using LLB, configure it! + EditorGUILayout.HelpBox("The Load Balancer is another server that is different than the FishBait node. Please enter the IP address or domain name of your Load Balancer server, along with the port.", MessageType.None); + EditorGUILayout.HelpBox("Acceptable Examples: 127.0.0.1, mydomain.com", MessageType.Info); + if (Time.realtimeSinceStartup - invalidServerIP < 5) + EditorGUILayout.HelpBox("Invalid Server Address!", MessageType.Error); + + serverIP = EditorGUILayout.TextField("Server Address", serverIP); + serverPort = Mathf.Clamp(EditorGUILayout.IntField("Server Port", serverPort), ushort.MinValue, ushort.MaxValue); + + if (GUILayout.Button("Continue")) + { + if (IPAddress.TryParse(serverIP, out IPAddress serverAddr)) + { + fishBait.loadBalancerAddress = serverAddr.ToString(); + fishBait.loadBalancerPort = (ushort)serverPort; + fishBait.serverIP = "127.0.0.1"; + fishBait.useLoadBalancer = true; + usingLLB = false; + serverIP = ""; + } + else + { + try + { + if (Dns.GetHostEntry(serverIP).AddressList.Length > 0) + { + fishBait.loadBalancerAddress = serverIP; + fishBait.loadBalancerPort = (ushort)serverPort; + fishBait.serverIP = "127.0.0.1"; + usingLLB = false; + serverIP = ""; + } + else + invalidServerIP = Time.realtimeSinceStartup; + } + catch + { + invalidServerIP = Time.realtimeSinceStartup; + } + } + } + } + else if (fishBait.transport == null) + { + // next up, the actual transport. We are going to loop over all the transport types here and let them select one. + EditorGUILayout.HelpBox("We need to use the same transport used on the server. Please select the same transport used on your FishBait Node(s)", MessageType.None); + + transportHolder = (Transport)EditorGUILayout.ObjectField(transportHolder, typeof(Transport), true); + + if (GUILayout.Button("Continue")) + { + Type transportType = transportHolder.GetType(); + + var fishBaitConnectorGO = new GameObject("FishBait - Connector"); + fishBaitConnectorGO.transform.SetParent(fishBait.transform); + var fishBaitConnectorAttachTransport = fishBaitConnectorGO.AddComponent(transportType); + Transport fishBaitConnectorTransport = fishBaitConnectorGO.GetComponent(); + fishBait.transport = fishBaitConnectorTransport; + DestroyImmediate(transportHolder); + transportHolder = null; + } + } + else if (string.IsNullOrEmpty(fishBait.serverIP)) + { + // Empty server IP, this is pretty important! Lets show the UI to require it. + EditorGUILayout.HelpBox("For a single FishBait node setup, we need the IP address or domain name of your FishBait server.", MessageType.None); + EditorGUILayout.HelpBox("Acceptable Examples: 172.105.109.117, mydomain.com", MessageType.Info); + + if (Time.realtimeSinceStartup - invalidServerIP < 5) + EditorGUILayout.HelpBox("Invalid Server Address!", MessageType.Error); + + serverIP = EditorGUILayout.TextField("Server Address", serverIP); + serverPort = Mathf.Clamp(EditorGUILayout.IntField("Server Port", serverPort), ushort.MinValue, ushort.MaxValue); + + if (GUILayout.Button("Continue")) + { + if (IPAddress.TryParse(serverIP, out IPAddress serverAddr)) + { + fishBait.serverIP = serverAddr.ToString(); + fishBait.SetTransportPort((ushort)serverPort); + } + else + { + try + { + if (Dns.GetHostEntry(serverIP).AddressList.Length > 0) + { + fishBait.serverIP = serverIP; + fishBait.SetTransportPort((ushort)serverPort); + } + else + invalidServerIP = Time.realtimeSinceStartup; + } + catch + { + invalidServerIP = Time.realtimeSinceStartup; + } + } + } + } + else if (fishBait.NATPunchtroughPort < 0) + { + // NAT Punchthrough configuration. + EditorGUILayout.HelpBox("Do you wish to use NAT Punchthrough? This can reduce load by up to 80% on your FishBait nodes, but exposes players IP's to other players.", MessageType.None); + + if (GUILayout.Button("Use NAT Punchthrough")) + { + fishBait.NATPunchtroughPort = 1; + fishBait.useNATPunch = true; + fishBait.gameObject.AddComponent(); + } + + if (GUILayout.Button("Do NOT use NAT Punchthrough")) + fishBait.NATPunchtroughPort = 1; + + } + else if (directModule != null && directModule.directConnectTransport == null) + { + // NAT Punchthrough setup. + EditorGUILayout.HelpBox("To use direct connecting, we need a transport to communicate with the other clients. Please select a transport to use.", MessageType.None); + + transportHolder = (Transport)EditorGUILayout.ObjectField(transportHolder, typeof(Transport), true); + + + if (GUILayout.Button("Continue")) + { + Type transportType = transportHolder.GetType(); + + var fishBaitDirectConnectGO = new GameObject("FishBait - Direct Connect"); + fishBaitDirectConnectGO.transform.SetParent(fishBait.transform); + var fishBaitDirectConnectTransport = fishBaitDirectConnectGO.AddComponent(transportType); + Transport transport = fishBaitDirectConnectGO.GetComponent(); + directModule.directConnectTransport = transport; + DestroyImmediate(transportHolder); + transportHolder = null; + } + } + else + { + // They have completed the "setup guide" Show them the main UI + + // Remove unused transports... + foreach (var transport in fishBait.GetComponentsInChildren()) + { + if (!(transport is FishBaitTransport)) + { + if (transport != fishBait.transport && (directModule == null ? true : directModule.directConnectTransport != transport)) + { + if (transport.gameObject == fishBait.gameObject) + DestroyImmediate(transport); + else + DestroyImmediate(transport.gameObject); + } + } + } + + currentTab = GUILayout.Toolbar(currentTab, tabs); + EditorGUILayout.Space(); + + EditorGUILayout.BeginVertical("Window"); + switch (currentTab) + { + case 0: + using (var change = new EditorGUI.ChangeCheckScope()) + { + + + // They are in the FishBait Settings tab. + if (fishBait.useLoadBalancer) + { + EditorGUILayout.HelpBox("While using a Load Balancer, you don't set the FishBait node IP or port.", MessageType.Info); + GUI.enabled = false; + } + fishBait.serverIP = EditorGUILayout.TextField("FishBait Node IP", fishBait.serverIP); + fishBait.serverPort = (ushort)Mathf.Clamp(EditorGUILayout.IntField("FishBait Node Port", fishBait.serverPort), ushort.MinValue, ushort.MaxValue); + fishBait.endpointServerPort = (ushort)Mathf.Clamp(EditorGUILayout.IntField("Endpoint Port", fishBait.endpointServerPort), ushort.MinValue, ushort.MaxValue); + + if (fishBait.useLoadBalancer) + { + GUI.enabled = true; + } + + fishBait.authenticationKey = EditorGUILayout.TextField("FishBait Auth Key", fishBait.authenticationKey); + fishBait.heartBeatInterval = EditorGUILayout.Slider("Heartbeat Time", fishBait.heartBeatInterval, 0.1f, 5f); + fishBait.connectOnAwake = EditorGUILayout.Toggle("Connect on Awake", fishBait.connectOnAwake); + fishBait.transport = (Transport)EditorGUILayout.ObjectField("FishBait Transport", fishBait.transport, typeof(Transport), true); + if (change.changed) + { + EditorUtility.SetDirty(fishBait); + } + } + serializedObject.ApplyModifiedProperties(); + break; + case 1: + // NAT punch tab. + if (directModule == null) + { + EditorGUILayout.HelpBox("NAT Punchthrough disabled, missing Direct Connect.", MessageType.Info); + if (GUILayout.Button("Add Direct Connect")) + fishBait.gameObject.AddComponent(); + } + else + { + fishBait.useNATPunch = EditorGUILayout.Toggle("Use NAT Punch", fishBait.useNATPunch); + GUI.enabled = true; + directModule.directConnectTransport = (Transport)EditorGUILayout.ObjectField("Direct Transport", directModule.directConnectTransport, typeof(Transport), true); + } + serializedObject.ApplyModifiedProperties(); + break; + case 2: + // Load balancer tab + fishBait.useLoadBalancer = EditorGUILayout.Toggle("Use Load Balancer", fishBait.useLoadBalancer); + if (!fishBait.useLoadBalancer) + GUI.enabled = false; + fishBait.loadBalancerAddress = EditorGUILayout.TextField("Load Balancer Address", fishBait.loadBalancerAddress); + fishBait.loadBalancerPort = (ushort)Mathf.Clamp(EditorGUILayout.IntField("Load Balancer Port", fishBait.loadBalancerPort), ushort.MinValue, ushort.MaxValue); + fishBait.region = (FishBaitRegions)EditorGUILayout.EnumPopup("Node Region", fishBait.region); + if (!fishBait.useLoadBalancer) + GUI.enabled = true; + serializedObject.ApplyModifiedProperties(); + break; + case 3: + // Other tab... + + GUI.enabled = false; + EditorGUILayout.TextField("Server Status", fishBait.serverStatus); + EditorGUILayout.TextField("Server ID", string.IsNullOrEmpty(fishBait.serverId) ? "Not Hosting." : fishBait.serverId); + GUI.enabled = true; + + EditorGUILayout.Space(); + + fishBait.serverName = EditorGUILayout.TextField("Server Name", fishBait.serverName); + fishBait.extraServerData = EditorGUILayout.TextField("Extra Server Data", fishBait.extraServerData); + fishBait.maxServerPlayers = EditorGUILayout.IntField("Max Server Players", fishBait.maxServerPlayers); + fishBait.isPublicServer = EditorGUILayout.Toggle("Is Public Server", fishBait.isPublicServer); + + EditorGUILayout.Space(); + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(serializedObject.FindProperty("connectedToRelay")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("disconnectedFromRelay")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("serverListUpdated")); + serializedObject.ApplyModifiedProperties(); + break; + } + EditorGUILayout.EndVertical(); + } + } + } +#endif +} + diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs.meta b/UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs.meta similarity index 83% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs.meta rename to UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs.meta index d58413a..a42ba58 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs.meta +++ b/UnityProject/Assets/FishBait/Editor/FishBaitInspector.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 12a7875e95f5ebb4a9b58390441dd933 +guid: 0a8926e6ba59d18419fbc44b9ec2408c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs b/UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs new file mode 100644 index 0000000..1ae04e8 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs @@ -0,0 +1,180 @@ +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using UnityEngine; +using FishBait; + +[RequireComponent(typeof(FishBaitTransport))] +public class FishBaitDirectConnectModule : MonoBehaviour +{ + [HideInInspector] + public Transport directConnectTransport; + public bool showDebugLogs; + private FishBaitTransport fishBaitTransport; + private int connectionId; + + void Awake() + { + fishBaitTransport = GetComponent(); + + if (directConnectTransport == null) + { + Debug.Log("Direct Connect Transport is null!"); + return; + } + + if (directConnectTransport is FishBaitTransport) + { + Debug.Log("Direct Connect Transport Cannot be the relay, silly. :P"); + return; + } + + directConnectTransport.OnServerConnectionState += ServerConnectionState; + directConnectTransport.OnServerReceivedData += ServerDataRecived; + + directConnectTransport.OnClientConnectionState += ClientConnectionState; + directConnectTransport.OnClientReceivedData += ClientDataRecived; + } + + void RemoteConnectionState(RemoteConnectionStateArgs args) + { + connectionId = args.ConnectionId; + } + + void ServerConnectionState(ServerConnectionStateArgs args) + { + + switch (args.ConnectionState) + { + case LocalConnectionState.Started: + OnServerConnected(connectionId); + break; + case LocalConnectionState.Stopped: + OnServerDisconnected(connectionId); + break; + } + } + + void ServerDataRecived(ServerReceivedDataArgs args) + { + OnServerDataReceived(args.ConnectionId, args.Data, ((int)args.Channel)); + } + + void ClientConnectionState(ClientConnectionStateArgs args) + { + + switch (args.ConnectionState) + { + case LocalConnectionState.Started: + OnClientConnected(); + break; + case LocalConnectionState.Stopped: + OnClientDisconnected(); + break; + } + } + + void ClientDataRecived(ClientReceivedDataArgs args) + { + OnClientDataReceived(args.Data, ((int)args.Channel)); + } + + public void StartServer(int port) + { + if (port > 0) + SetTransportPort(port); + + directConnectTransport.StartConnection(true); + if (showDebugLogs) + Debug.Log("Direct Connect Server Created!"); + } + + public void StopServer() + { + directConnectTransport.StopConnection(true); + } + + public void JoinServer(string ip, int port) + { + if (SupportsNATPunch()) + SetTransportPort(port); + directConnectTransport.SetClientAddress(ip); + directConnectTransport.StartConnection(false); + } + + public void SetTransportPort(int port) + { + directConnectTransport.SetPort((ushort)port); + } + + public int GetTransportPort() + { + return directConnectTransport.GetPort(); + } + + public bool SupportsNATPunch() + { + return directConnectTransport is kcp2k.KcpTransport; + } + + public bool KickClient(int clientID) + { + if (showDebugLogs) + Debug.Log("Kicked direct connect client."); + directConnectTransport.StopConnection(clientID, true); + return true; + } + + public void ClientDisconnect() + { + directConnectTransport.StopConnection(false); + } + + public void ServerSend(int clientID, ArraySegment data, int channel) + { + + directConnectTransport.SendToClient((byte)channel, data, clientID); + } + + public void ClientSend(ArraySegment data, int channel) + { + directConnectTransport.SendToServer((byte)channel, data); + } + + #region Transport Callbacks + void OnServerConnected(int clientID) + { + if (showDebugLogs) + Debug.Log("Direct Connect Client Connected"); + fishBaitTransport.DirectAddClient(clientID); + } + + void OnServerDataReceived(int clientID, ArraySegment data, int channel) + { + fishBaitTransport.DirectReceiveData(data, channel, clientID); + } + + void OnServerDisconnected(int clientID) + { + fishBaitTransport.DirectRemoveClient(clientID); + } + + void OnClientConnected() + { + if (showDebugLogs) + Debug.Log("Direct Connect Client Joined"); + + fishBaitTransport.DirectClientConnected(); + } + + void OnClientDisconnected() + { + fishBaitTransport.DirectDisconnected(); + } + + void OnClientDataReceived(ArraySegment data, int channel) + { + fishBaitTransport.DirectReceiveData(data, channel); + } + #endregion +} \ No newline at end of file diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs.meta b/UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs.meta similarity index 83% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs.meta rename to UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs.meta index 2f627ba..6332cba 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs.meta +++ b/UnityProject/Assets/FishBait/FishBaitDirectConnectModule.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d0996ec573094c24890a4d4233ee871e +guid: 21eba6e2b0a7e964eb29db14a4eae4d6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/UnityProject/Assets/FishBait/FishBaitTools.cs b/UnityProject/Assets/FishBait/FishBaitTools.cs new file mode 100644 index 0000000..7ee6266 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTools.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using UnityEngine; + +namespace FishBait +{ + public static class FishBaitTools + { + + public static void WriteByte(this byte[] data, ref int position, byte value) + { + data[position] = value; + position += 1; + } + + public static byte ReadByte(this byte[] data, ref int position) + { + byte value = data[position]; + position += 1; + return value; + } + + public static void WriteBool(this byte[] data, ref int position, bool value) + { + unsafe + { + fixed (byte* dataPtr = &data[position]) + { + bool* valuePtr = (bool*)dataPtr; + *valuePtr = value; + position += 1; + } + } + } + + public static bool ReadBool(this byte[] data, ref int position) + { + bool value = BitConverter.ToBoolean(data, position); + position += 1; + return value; + } + + public static void WriteString(this byte[] data, ref int position, string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + data.WriteInt(ref position, 0); + } + else + { + data.WriteInt(ref position, value.Length); + for (int i = 0; i < value.Length; i++) + data.WriteChar(ref position, value[i]); + } + } + + public static string ReadString(this byte[] data, ref int position) + { + string value = default; + + int stringSize = data.ReadInt(ref position); + + for (int i = 0; i < stringSize; i++) + value += data.ReadChar(ref position); + + return value; + } + + public static void WriteBytes(this byte[] data, ref int position, byte[] value) + { + data.WriteInt(ref position, value.Length); + for (int i = 0; i < value.Length; i++) + data.WriteByte(ref position, value[i]); + } + + public static byte[] ReadBytes(this byte[] data, ref int position) + { + int byteSize = data.ReadInt(ref position); + + byte[] value = new byte[byteSize]; + + for (int i = 0; i < byteSize; i++) + value[i] = data.ReadByte(ref position); + + return value; + } + + public static void WriteChar(this byte[] data, ref int position, char value) + { + unsafe + { + fixed (byte* dataPtr = &data[position]) + { + char* valuePtr = (char*)dataPtr; + *valuePtr = value; + position += 2; + } + } + } + + public static char ReadChar(this byte[] data, ref int position) + { + char value = BitConverter.ToChar(data, position); + position += 2; + return value; + } + + public static void WriteInt(this byte[] data, ref int position, int value) + { + unsafe + { + fixed (byte* dataPtr = &data[position]) + { + int* valuePtr = (int*)dataPtr; + *valuePtr = value; + position += 4; + } + } + } + + public static int ReadInt(this byte[] data, ref int position) + { + int value = BitConverter.ToInt32(data, position); + position += 4; + return value; + } + } + + internal static class CompressorExtensions + { + ///

+ /// Decompresses the string. + /// + /// The compressed text. + /// + public static string Decompress(this string compressedText) + { + byte[] gZipBuffer = Convert.FromBase64String(compressedText); + using (var memoryStream = new MemoryStream()) + { + int dataLength = BitConverter.ToInt32(gZipBuffer, 0); + memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); + + var buffer = new byte[dataLength]; + + memoryStream.Position = 0; + using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) + { + gZipStream.Read(buffer, 0, buffer.Length); + } + + return Encoding.UTF8.GetString(buffer); + } + } + } + + internal static class JsonUtilityHelper + { + public static bool IsJsonArray(string json) + { + return json.StartsWith("[") && json.EndsWith("]"); + } + + public static T[] FromJson(string json) + { + if (!IsJsonArray(json)) + { + throw new System.FormatException("The input json string is not a Json Array"); + } + json = "{\"Items\":" + json + "}"; + JsonWrapper wrapper = JsonUtility.FromJson>(json); + return wrapper.Items; + } + + public static string ToJson(T[] array) + { + JsonWrapper wrapper = new JsonWrapper(); + wrapper.Items = array; + return JsonUtility.ToJson(wrapper); + } + + public static string ToJson(T[] array, bool prettyPrint) + { + JsonWrapper wrapper = new JsonWrapper(); + wrapper.Items = array; + return JsonUtility.ToJson(wrapper, prettyPrint); + } + + [Serializable] + private class JsonWrapper + { + public T[] Items; + } + + } +} + diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs.meta b/UnityProject/Assets/FishBait/FishBaitTools.cs.meta similarity index 83% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs.meta rename to UnityProject/Assets/FishBait/FishBaitTools.cs.meta index fe965ca..9e57a9c 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs.meta +++ b/UnityProject/Assets/FishBait/FishBaitTools.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b7b9e2c091c3d42439840a02fe700252 +guid: 581bb3a7217af5e4bb8d4f514a4adc9b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/UnityProject/Assets/Ignorance/Demo.meta b/UnityProject/Assets/FishBait/FishBaitTransport.meta similarity index 77% rename from UnityProject/Assets/Ignorance/Demo.meta rename to UnityProject/Assets/FishBait/FishBaitTransport.meta index 74b45a7..18a94c7 100644 --- a/UnityProject/Assets/Ignorance/Demo.meta +++ b/UnityProject/Assets/FishBait/FishBaitTransport.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0f3dc386b0074be4caf7b858e3189529 +guid: 47e639efdf360c049b37e5c7e54cecbf folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs new file mode 100644 index 0000000..e7924c5 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs @@ -0,0 +1,200 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Net; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEngine; +using FishNet.Transporting.Tugboat; +using FishNet.Managing.Transporting; +using FishNet.Transporting.Multipass; + +namespace FishBait +{ + [DefaultExecutionOrder(1001)] + public partial class FishBaitTransport : Transport + { + #region Forward everything to Transport + public override event Action OnClientConnectionState + { + add + { + transport.OnClientConnectionState += value; + } + + remove + { + transport.OnClientConnectionState -= value; + } + } + + public override event Action OnServerConnectionState + { + add + { + transport.OnServerConnectionState += value; + } + + remove + { + transport.OnServerConnectionState -= value; + } + } + + public override event Action OnRemoteConnectionState + { + add + { + transport.OnRemoteConnectionState += value; + } + + remove + { + transport.OnRemoteConnectionState -= value; + } + } + + public override event Action OnClientReceivedData + { + add + { + transport.OnClientReceivedData += value; + } + + remove + { + transport.OnClientReceivedData -= value; + } + } + + public override event Action OnServerReceivedData + { + add + { + transport.OnServerReceivedData += value; + } + + remove + { + transport.OnServerReceivedData -= value; + } + } + + public override string GetConnectionAddress(int connectionId) + { + return transport.GetConnectionAddress(connectionId); + } + + public override LocalConnectionState GetConnectionState(bool server) + { + return transport.GetConnectionState(server); + } + + public override RemoteConnectionState GetConnectionState(int connectionId) + { + return transport.GetConnectionState(connectionId); + } + + public override int GetMTU(byte channel) + { + return transport.GetMTU(channel); + } + + public override void HandleClientConnectionState(ClientConnectionStateArgs connectionStateArgs) + { + transport.HandleClientConnectionState(connectionStateArgs); + } + + public override void HandleClientReceivedDataArgs(ClientReceivedDataArgs receivedDataArgs) + { + transport.HandleClientReceivedDataArgs(receivedDataArgs); + } + + public override void HandleRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs) + { + transport.HandleRemoteConnectionState(connectionStateArgs); + } + + public override void HandleServerConnectionState(ServerConnectionStateArgs connectionStateArgs) + { + transport.HandleServerConnectionState(connectionStateArgs); + } + + public override void HandleServerReceivedDataArgs(ServerReceivedDataArgs receivedDataArgs) + { + transport.HandleServerReceivedDataArgs(receivedDataArgs); + } + + public override void IterateIncoming(bool server) + { + transport.IterateIncoming(server); + } + + public override void IterateOutgoing(bool server) + { + transport.IterateOutgoing(server); + } + + public override void SendToClient(byte channelId, ArraySegment segment, int connectionId) + { + transport.SendToClient(channelId, segment, connectionId); + } + + public override void SendToServer(byte channelId, ArraySegment segment) + { + transport.SendToServer(channelId, segment); + } + + public override void Shutdown() + { + transport.Shutdown(); + } + + public override bool StartConnection(bool server) + { + return transport.StartConnection(server); + } + + public override bool StopConnection(bool server) + { + return transport.StopConnection(server); + } + + public override bool StopConnection(int connectionId, bool immediately) + { + return transport.StopConnection(connectionId, immediately); + } + #endregion + + + /// Called by Transport when a new client connected to the server. + public Action OnServerConnected = (connId) => Debug.LogWarning("OnServerConnected called with no handler"); + /// Called by Transport when a client disconnected from the server. + public Action OnServerDisconnected = (connId) => Debug.LogWarning("OnServerDisconnected called with no handler"); + /// Called by Transport when the server received a message from a client. + public Action, int> OnServerDataReceived = (connId, data, channel) => Debug.LogWarning("OnServerDataReceived called with no handler"); + /// Called by Transport when the client received a message from the server. + public Action, int> OnClientDataReceived = (data, channel) => Debug.LogWarning("OnClientDataReceived called with no handler"); + /// Called by Transport when the client connected to the server. + public Action OnClientConnected = () => Debug.LogWarning("OnClientConnected called with no handler"); + /// Called by Transport when the client disconnected from the server. + public Action OnClientDisconnected = () => Debug.LogWarning("OnClientDisconnected called with no handler"); + public void SetTransportPort(ushort port) + { + transport.SetPort(port); + } + + public enum OpCodes + { + Default = 0, RequestID = 1, JoinServer = 2, SendData = 3, GetID = 4, ServerJoined = 5, GetData = 6, CreateRoom = 7, ServerLeft = 8, PlayerDisconnected = 9, RoomCreated = 10, + LeaveRoom = 11, KickPlayer = 12, AuthenticationRequest = 13, AuthenticationResponse = 14, Authenticated = 17, UpdateRoomData = 18, ServerConnectionData = 19, RequestNATConnection = 20, + DirectConnectIP = 21 + } + + } +} + diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs.meta b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs.meta new file mode 100644 index 0000000..dd44abc --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37bf248b7e575fe4592c1ec247b10573 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 95b2cfa2667f26845b384fc393df6c6b, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs new file mode 100644 index 0000000..6069008 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs @@ -0,0 +1,71 @@ +using System; +using FishNet.Transporting; + +namespace FishBait +{ + public partial class FishBaitTransport : Transport + { + public void DirectAddClient(int clientID) + { + if (!_isServer) + return; + + _connectedDirectClients.Add(clientID, _currentMemberId); + OnServerConnected?.Invoke(_currentMemberId); + _currentMemberId++; + } + + public void DirectRemoveClient(int clientID) + { + if (!_isServer) + return; + + OnServerDisconnected?.Invoke(_connectedDirectClients.GetByFirst(clientID)); + _connectedDirectClients.Remove(clientID); + } + + public void DirectReceiveData(ArraySegment data, int channel, int clientID = -1) + { + if (_isServer) + OnServerDataReceived?.Invoke(_connectedDirectClients.GetByFirst(clientID), data, channel); + + if (_isClient) + OnClientDataReceived?.Invoke(data, channel); + } + + public void DirectClientConnected() + { + _directConnected = true; + OnClientConnected?.Invoke(); + } + + public void DirectDisconnected() + { + if (_directConnected) + { + _isClient = false; + _directConnected = false; + OnClientDisconnected?.Invoke(); + } + else + { + int pos = 0; + _directConnected = false; + _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.JoinServer); + _clientSendBuffer.WriteString(ref pos, _cachedHostID); + _clientSendBuffer.WriteBool(ref pos, false); // Direct failed, use relay + + _isClient = true; + + transport.SendToServer(0, new System.ArraySegment(_clientSendBuffer, 0, pos)); + + } + + if (_clientProxy != null) + { + _clientProxy.Dispose(); + _clientProxy = null; + } + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs.meta b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs.meta new file mode 100644 index 0000000..fbded28 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportDirectConnect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f914ef01ff1129d47a315fea4ece04fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs new file mode 100644 index 0000000..70b88cd --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using UnityEngine.Events; +using UnityEngine; +using FishNet.Transporting; + +namespace FishBait +{ + public partial class FishBaitTransport : Transport + { + // Connection/auth variables + [Tooltip("Transport to use.")] + [SerializeField] + public Transport transport; + public string serverIP = null; + public ushort serverPort = 7777; + public ushort endpointServerPort = 8080; + public float heartBeatInterval = 3; + public bool connectOnAwake = true; + public string authenticationKey = "Secret Auth Key"; + + public UnityEvent disconnectedFromRelay; + public UnityEvent connectedToRelay; + + // NAT Puncher variables + public bool useNATPunch = false; + public int NATPunchtroughPort = -1; + private const int NAT_PUNCH_ATTEMPTS = 3; + + // LLB variables (LRM Load Balancer) + public bool useLoadBalancer = false; + public ushort loadBalancerPort = 7070; + public string loadBalancerAddress = null; + + // Server hosting variables + public string serverName = "My awesome server!"; + public string extraServerData = "Map 1"; + public int maxServerPlayers = 10; + public bool isPublicServer = true; + + private const string LOCALHOST = "127.0.0.1"; + + // Server list variables + public UnityEvent serverListUpdated; + public List relayServerList { private set; get; } = new List(); + + // Current Server Information + public string serverStatus = "Not Started."; + public string serverId = string.Empty; + + private LRMDirectConnectModule _directConnectModule; + + public FishBaitRegions region = FishBaitRegions.NorthAmerica; + private byte[] _clientSendBuffer; + private bool _connectedToRelay = false; + private bool _isClient = false; + private bool _isServer = false; + private bool _directConnected = false; + private bool _isAuthenticated = false; + private int _currentMemberId; + private bool _callbacksInitialized = false; + private string _cachedHostID; + private UdpClient _NATPuncher; + private IPEndPoint _NATIP; + private IPEndPoint _relayPuncherIP; + private byte[] _punchData = new byte[1] { 1 }; + private IPEndPoint _directConnectEndpoint; + private SocketProxy _clientProxy; + private BiDictionary _serverProxies = new BiDictionary(); + private BiDictionary _connectedRelayClients = new BiDictionary(); + private BiDictionary _connectedDirectClients = new BiDictionary(); + private bool _serverListUpdated = false; + } + + public enum FishBaitRegions { Any, NorthAmerica, SouthAmerica, Europe, Asia, Africa, Oceania } +} diff --git a/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs.meta b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs.meta new file mode 100644 index 0000000..a0216d9 --- /dev/null +++ b/UnityProject/Assets/FishBait/FishBaitTransport/FishBaitTransportVariables.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3df9f15433ecfc549b36006c3a9627dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp.meta b/UnityProject/Assets/FishBait/Resources.meta similarity index 77% rename from UnityProject/Assets/Ignorance/Demo/PongChamp.meta rename to UnityProject/Assets/FishBait/Resources.meta index fbf9985..78e7431 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp.meta +++ b/UnityProject/Assets/FishBait/Resources.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 634f781b33ac69147bff9edd5829cfd6 +guid: 4d320dfa8847f3740bbb237370ab5895 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishBait/Resources/FishBait.png b/UnityProject/Assets/FishBait/Resources/FishBait.png new file mode 100644 index 0000000000000000000000000000000000000000..99800b94f700a035c1af7076c4bb576a6f264b3d GIT binary patch literal 265164 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

x$MnWy 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

B3>3%=r0y2f3m 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

aP2r9?%f47bdOZy>2^6;mE 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 literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/FishBait/Resources/FishBait.png.meta b/UnityProject/Assets/FishBait/Resources/FishBait.png.meta new file mode 100644 index 0000000..54ed06c --- /dev/null +++ b/UnityProject/Assets/FishBait/Resources/FishBait.png.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: 95b2cfa2667f26845b384fc393df6c6b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishBait/SocketProxy.cs b/UnityProject/Assets/FishBait/SocketProxy.cs new file mode 100644 index 0000000..1d91058 --- /dev/null +++ b/UnityProject/Assets/FishBait/SocketProxy.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using UnityEngine; + +namespace FishBait +{ + + // This class handles the proxying from punched socket to transport. + public class SocketProxy + { + public DateTime lastInteractionTime; + public Action dataReceived; + UdpClient _udpClient; + IPEndPoint _recvEndpoint = new IPEndPoint(IPAddress.Any, 0); + IPEndPoint _remoteEndpoint; + bool _clientInitialRecv = false; + + public SocketProxy(int port, IPEndPoint remoteEndpoint) + { + _udpClient = new UdpClient(); + _udpClient.Connect(new IPEndPoint(IPAddress.Loopback, port)); + _udpClient.BeginReceive(new AsyncCallback(RecvData), _udpClient); + lastInteractionTime = DateTime.Now; + // Clone it so when main socket recvies new data, it wont switcheroo on us. + _remoteEndpoint = new IPEndPoint(remoteEndpoint.Address, remoteEndpoint.Port); + } + + public SocketProxy(int port) + { + _udpClient = new UdpClient(port); + _udpClient.BeginReceive(new AsyncCallback(RecvData), _udpClient); + lastInteractionTime = DateTime.Now; + } + + public void RelayData(byte[] data, int length) + { + _udpClient.Send(data, length); + lastInteractionTime = DateTime.Now; + } + + public void ClientRelayData(byte[] data, int length) + { + if (_clientInitialRecv) + { + _udpClient.Send(data, length, _recvEndpoint); + lastInteractionTime = DateTime.Now; + } + } + + public void Dispose() + { + _udpClient.Dispose(); + } + + void RecvData(IAsyncResult result) + { + byte[] data = _udpClient.EndReceive(result, ref _recvEndpoint); + _udpClient.BeginReceive(new AsyncCallback(RecvData), _udpClient); + _clientInitialRecv = true; + lastInteractionTime = DateTime.Now; + dataReceived?.Invoke(_remoteEndpoint, data); + + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishBait/SocketProxy.cs.meta b/UnityProject/Assets/FishBait/SocketProxy.cs.meta new file mode 100644 index 0000000..06361c2 --- /dev/null +++ b/UnityProject/Assets/FishBait/SocketProxy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 968c346ce63c10442aa4bae404eee2f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet.meta b/UnityProject/Assets/FishNet.meta new file mode 100644 index 0000000..29be534 --- /dev/null +++ b/UnityProject/Assets/FishNet.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 546a3ff244764224486eff29cdfacabb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating.meta b/UnityProject/Assets/FishNet/CodeGenerating.meta new file mode 100644 index 0000000..0da94fd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbb4974b4302f435b9f4663c64d8f803 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Extension.meta b/UnityProject/Assets/FishNet/CodeGenerating/Extension.meta new file mode 100644 index 0000000..fd3a139 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Extension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 206db668838ebc34b90ae36be24ce3be +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs new file mode 100644 index 0000000..8b504b5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs @@ -0,0 +1,96 @@ + +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using MonoFN.Cecil; +using UnityEngine; + +namespace FishNet.CodeGenerating.Extension +{ + + + internal static class TypeDefinitionExtensions + { + ///

+ /// Returns a method in the next base class. + /// + public static MethodReference GetMethodReferenceInBase(this TypeDefinition td, string methodName) + { + if (td == null) + { + CodegenSession.LogError($"TypeDefinition is null."); + return null; + } + if (td.BaseType == null) + { + CodegenSession.LogError($"BaseType for {td.FullName} is null."); + return null; + } + + TypeDefinition baseTd = td.BaseType.CachedResolve(); + MethodDefinition baseMd = baseTd.GetMethod(methodName); + //Not found. + if (baseMd == null) + return null; + + //Is generic. + if (baseTd.HasGenericParameters) + { + TypeReference baseTr = td.BaseType; + GenericInstanceType baseGit = (GenericInstanceType)baseTr; + + CodegenSession.ImportReference(baseMd.ReturnType); + MethodReference mr = new MethodReference(methodName, baseMd.ReturnType) + { + DeclaringType = baseGit, + CallingConvention = baseMd.CallingConvention, + HasThis = baseMd.HasThis, + ExplicitThis = baseMd.ExplicitThis, + }; + return mr; + } + //Not generic. + else + { + return CodegenSession.ImportReference(baseMd); + } + } + + /// + /// Returns a method in any inherited classes. The first found method is returned. + /// + public static MethodDefinition GetMethodDefinitionInAnyBase(this TypeDefinition td, string methodName) + { + while (td != null) + { + foreach (MethodDefinition md in td.Methods) + { + if (md.Name == methodName) + return md; + } + + try + { + td = td.GetNextBaseTypeDefinition(); + } + catch + { + return null; + } + } + + return null; + } + + /// + /// Returns the next base type. + /// + internal static TypeDefinition GetNextBaseTypeDefinition(this TypeDefinition typeDef) + { + return (typeDef.BaseType == null) ? null : typeDef.BaseType.CachedResolve(); + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta new file mode 100644 index 0000000..dfb8256 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9f00cf3dc8b90b469c3c9cb8b87fc88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs new file mode 100644 index 0000000..a490504 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs @@ -0,0 +1,24 @@ + +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using MonoFN.Cecil; +using UnityEngine; + +namespace FishNet.CodeGenerating.Extension +{ + + + internal static class TypeReferenceExtensions + { + + /// + /// Returns a method in the next base class. + /// + public static MethodReference GetMethodInBase(this TypeReference tr, string methodName) + { + return GetMethodInBase(tr.CachedResolve(), methodName); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta new file mode 100644 index 0000000..19d7526 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 239b1b10db80c594d93b7ba4ee2c1ec5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt b/UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt new file mode 100644 index 0000000..3efe3cf --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt @@ -0,0 +1,9 @@ +After updating a custom Cecil to fix conflict with Unity.Burst in 2021 perform the following: + +- Open cecil in it's own project; eg: do not place directly in FN. +- Rename namespace.Mono to namespace.MonoFN. +- Current project rename strings, "Mono to "MonoFN +- Replace current project #if INSIDE_ROCKS to #if UNITY_EDITOR +- Comment out `[assembly: AssemblyTitle ("MonoFN.Cecil.Rocks")]` within rocks\Mono.Cecil.Rocks\AssemblyInfo.cs. +- Delete obj/bin/tests folders. +- Copy into FN project. diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt.meta b/UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt.meta similarity index 75% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt.meta rename to UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt.meta index bd4c745..04e8428 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt.meta +++ b/UnityProject/Assets/FishNet/CodeGenerating/FN_README.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ad80075449f17c548877161f32a9841a +guid: 9133eb285bd7f3c4f89f4d7a2a079c6b TextScriptImporter: externalObjects: {} userData: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers.meta new file mode 100644 index 0000000..0dc1ce9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: efeca2428bd9fe64d872a626b93ff0cf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs new file mode 100644 index 0000000..daa52ac --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs @@ -0,0 +1,94 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Object; +using FishNet.Object.Helping; +using FishNet.Object.Prediction; +using FishNet.Object.Synchronizing; +using MonoFN.Cecil; + + +namespace FishNet.CodeGenerating.Helping +{ + public class AttributeHelper + { + #region Reflection references. + internal string ReplicateAttribute_FullName; + internal string ReconcileAttribute_FullName; + private string ServerAttribute_FullName; + private string ClientAttribute_FullName; + private string ServerRpcAttribute_FullName; + private string ObserversRpcAttribute_FullName; + private string TargetRpcAttribute_FullName; + private string SyncVarAttribute_FullName; + private string SyncObjectAttribute_FullName; + #endregion + + internal bool ImportReferences() + { + ServerAttribute_FullName = typeof(ServerAttribute).FullName; + ClientAttribute_FullName = typeof(ClientAttribute).FullName; + ServerRpcAttribute_FullName = typeof(ServerRpcAttribute).FullName; + ObserversRpcAttribute_FullName = typeof(ObserversRpcAttribute).FullName; + TargetRpcAttribute_FullName = typeof(TargetRpcAttribute).FullName; + SyncVarAttribute_FullName = typeof(SyncVarAttribute).FullName; + SyncObjectAttribute_FullName = typeof(SyncObjectAttribute).FullName; + ReplicateAttribute_FullName = typeof(ReplicateAttribute).FullName; + ReconcileAttribute_FullName = typeof(ReconcileAttribute).FullName; + + return true; + } + + /// + /// Returns type of Rpc attributeFullName is for. + /// + /// + /// + public RpcType GetRpcAttributeType(CustomAttribute ca) + { + if (ca.Is(ServerRpcAttribute_FullName)) + return RpcType.Server; + else if (ca.Is(ObserversRpcAttribute_FullName)) + return RpcType.Observers; + else if (ca.Is(TargetRpcAttribute_FullName)) + return RpcType.Target; + else + return RpcType.None; + } + + + /// + /// Returns type of Rpc attributeFullName is for. + /// + /// + /// + internal QolAttributeType GetQolAttributeType(string attributeFullName) + { + if (attributeFullName == ServerAttribute_FullName) + return QolAttributeType.Server; + else if (attributeFullName == ClientAttribute_FullName) + return QolAttributeType.Client; + else + return QolAttributeType.None; + } + + + /// + /// Returns if attribute if a SyncVarAttribute. + /// + /// + /// + public bool IsSyncVarAttribute(string attributeFullName) + { + return (attributeFullName == SyncVarAttribute_FullName); + } + /// + /// Returns if attribute if a SyncObjectAttribute. + /// + /// + /// + public bool IsSyncObjectAttribute(string attributeFullName) + { + return (attributeFullName == SyncObjectAttribute_FullName); + } + } + +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta new file mode 100644 index 0000000..d84b8e4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d32f3dc23b55598429c5cfe6156e6243 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs new file mode 100644 index 0000000..546638f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs @@ -0,0 +1,221 @@ +using FishNet.CodeGenerating.Processing; +using FishNet.CodeGenerating.Processing.Rpc; +using MonoFN.Cecil; +using System.Collections.Generic; +using Unity.CompilationPipeline.Common.Diagnostics; +using UnityEngine; +using SR = System.Reflection; + +namespace FishNet.CodeGenerating.Helping +{ + + internal static class CodegenSession + { + [System.ThreadStatic] + internal static ModuleDefinition Module; + [System.ThreadStatic] + internal static List Diagnostics; + + [System.ThreadStatic] + internal static TimeManagerHelper TimeManagerHelper; + [System.ThreadStatic] + internal static AttributeHelper AttributeHelper; + [System.ThreadStatic] + internal static GeneralHelper GeneralHelper; + [System.ThreadStatic] + internal static GenericReaderHelper GenericReaderHelper; + [System.ThreadStatic] + internal static GenericWriterHelper GenericWriterHelper; + [System.ThreadStatic] + internal static ObjectHelper ObjectHelper; + [System.ThreadStatic] + internal static NetworkBehaviourHelper NetworkBehaviourHelper; + [System.ThreadStatic] + internal static ReaderGenerator ReaderGenerator; + [System.ThreadStatic] + internal static ReaderHelper ReaderHelper; + [System.ThreadStatic] + internal static CreatedSyncVarGenerator CreatedSyncVarGenerator; + [System.ThreadStatic] + internal static TransportHelper TransportHelper; + [System.ThreadStatic] + internal static WriterGenerator WriterGenerator; + [System.ThreadStatic] + internal static WriterHelper WriterHelper; + [System.ThreadStatic] + internal static CustomSerializerProcessor CustomSerializerProcessor; + [System.ThreadStatic] + internal static NetworkBehaviourProcessor NetworkBehaviourProcessor; + [System.ThreadStatic] + internal static QolAttributeProcessor QolAttributeProcessor; + [System.ThreadStatic] + internal static RpcProcessor RpcProcessor; + [System.ThreadStatic] + internal static NetworkBehaviourSyncProcessor NetworkBehaviourSyncProcessor; + [System.ThreadStatic] + internal static NetworkBehaviourPredictionProcessor NetworkBehaviourPredictionProcessor; + /// + /// SyncVars that are being accessed from an assembly other than the currently being processed one. + /// + [System.ThreadStatic] + internal static List DifferentAssemblySyncVars; + + /// + /// Logs a warning. + /// + /// + internal static void LogWarning(string msg) + { +#if UNITY_2020_1_OR_NEWER + Diagnostics.AddWarning(msg); +#else + Debug.LogWarning(msg); +#endif + } + /// + /// Logs an error. + /// + /// + internal static void LogError(string msg) + { +#if UNITY_2020_1_OR_NEWER + Diagnostics.AddError(msg); +#else + Debug.LogError(msg); +#endif + } + /// + /// Resets all helpers while importing any information needed by them. + /// + /// + /// + internal static bool Reset(ModuleDefinition module) + { + Module = module; + Diagnostics = new List(); + + TimeManagerHelper = new TimeManagerHelper(); + AttributeHelper = new AttributeHelper(); + GeneralHelper = new GeneralHelper(); + GenericReaderHelper = new GenericReaderHelper(); + GenericWriterHelper = new GenericWriterHelper(); + ObjectHelper = new ObjectHelper(); + NetworkBehaviourHelper = new NetworkBehaviourHelper(); + ReaderGenerator = new ReaderGenerator(); + ReaderHelper = new ReaderHelper(); + CreatedSyncVarGenerator = new CreatedSyncVarGenerator(); + TransportHelper = new TransportHelper(); + WriterGenerator = new WriterGenerator(); + WriterHelper = new WriterHelper(); + + CustomSerializerProcessor = new CustomSerializerProcessor(); + NetworkBehaviourProcessor = new NetworkBehaviourProcessor(); + QolAttributeProcessor = new QolAttributeProcessor(); + RpcProcessor = new RpcProcessor(); + NetworkBehaviourSyncProcessor = new NetworkBehaviourSyncProcessor(); + NetworkBehaviourPredictionProcessor = new NetworkBehaviourPredictionProcessor(); + DifferentAssemblySyncVars = new List(); + + if (!TimeManagerHelper.ImportReferences()) + return false; + if (!NetworkBehaviourPredictionProcessor.ImportReferences()) + return false; + if (!NetworkBehaviourSyncProcessor.ImportReferences()) + return false; + if (!GeneralHelper.ImportReferences()) + return false; + if (!AttributeHelper.ImportReferences()) + return false; + if (!GenericReaderHelper.ImportReferences()) + return false; + if (!GenericWriterHelper.ImportReferences()) + return false; + if (!ObjectHelper.ImportReferences()) + return false; + if (!NetworkBehaviourHelper.ImportReferences()) + return false; + if (!ReaderGenerator.ImportReferences()) + return false; + if (!ReaderHelper.ImportReferences()) + return false; + if (!CreatedSyncVarGenerator.ImportReferences()) + return false; + if (!TransportHelper.ImportReferences()) + return false; + if (!WriterGenerator.ImportReferences()) + return false; + if (!WriterHelper.ImportReferences()) + return false; + + return true; + } + + + + #region ImportReference. + + public static MethodReference ImportReference(SR.MethodBase method) + { + return Module.ImportReference(method); + } + + public static MethodReference ImportReference(SR.MethodBase method, IGenericParameterProvider context) + { + return Module.ImportReference(method, context); + } + + public static TypeReference ImportReference(TypeReference type) + { + return Module.ImportReference(type); + } + + public static TypeReference ImportReference(TypeReference type, IGenericParameterProvider context) + { + return Module.ImportReference(type, context); + } + + public static FieldReference ImportReference(FieldReference field) + { + return Module.ImportReference(field); + } + + public static FieldReference ImportReference(FieldReference field, IGenericParameterProvider context) + { + return Module.ImportReference(field, context); + } + public static MethodReference ImportReference(MethodReference method) + { + return Module.ImportReference(method); + } + + public static MethodReference ImportReference(MethodReference method, IGenericParameterProvider context) + { + return Module.ImportReference(method, context); + } + public static TypeReference ImportReference(System.Type type) + { + return ImportReference(type, null); + } + + + public static TypeReference ImportReference(System.Type type, IGenericParameterProvider context) + { + return Module.ImportReference(type, context); + } + + + public static FieldReference ImportReference(SR.FieldInfo field) + { + return Module.ImportReference(field); + } + + public static FieldReference ImportReference(SR.FieldInfo field, IGenericParameterProvider context) + { + return Module.ImportReference(field, context); + } + + #endregion + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta new file mode 100644 index 0000000..3373edc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e8416eee3308f54fa942003de975420 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs new file mode 100644 index 0000000..2fdb154 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs @@ -0,0 +1,121 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using MonoFN.Cecil; +using MonoFN.Cecil.Rocks; +using System; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + internal class CreatedSyncVarGenerator + { + private readonly Dictionary _createdSyncVars = new Dictionary(); + + #region Relfection references. + private TypeReference _syncBase_TypeRef; + internal TypeReference SyncVar_TypeRef; + private MethodReference _syncVar_Constructor_MethodRef; + #endregion + + #region Const. + private const string GETVALUE_NAME = "GetValue"; + private const string SETVALUE_NAME = "SetValue"; + #endregion + + /* //feature add and test the dirty boolean changes + * eg... instead of base.Dirty() + * do if (!base.Dirty()) return false; + * See synclist for more info. */ + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + SyncVar_TypeRef = CodegenSession.ImportReference(typeof(SyncVar<>)); + MethodDefinition svConstructor = SyncVar_TypeRef.GetFirstConstructor(true); + _syncVar_Constructor_MethodRef = CodegenSession.ImportReference(svConstructor); + + Type syncBaseType = typeof(SyncBase); + _syncBase_TypeRef = CodegenSession.ImportReference(syncBaseType); + + return true; + } + + /// + /// Gets and optionally creates data for SyncVar + /// + /// + /// + internal CreatedSyncVar GetCreatedSyncVar(FieldDefinition originalFd, bool createMissing) + { + TypeReference dataTr = originalFd.FieldType; + TypeDefinition dataTd = dataTr.CachedResolve(); + + string typeHash = dataTr.FullName + dataTr.IsArray.ToString(); + + if (_createdSyncVars.TryGetValue(typeHash, out CreatedSyncVar createdSyncVar)) + { + return createdSyncVar; + } + else + { + if (!createMissing) + return null; + + CodegenSession.ImportReference(dataTd); + + GenericInstanceType syncVarGit = SyncVar_TypeRef.MakeGenericInstanceType(new TypeReference[] { dataTr }); + TypeReference genericDataTr = syncVarGit.GenericArguments[0]; + + //Make sure can serialize. + bool canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(genericDataTr, true); + if (!canSerialize) + { + CodegenSession.LogError($"SyncVar {originalFd.Name} data type {genericDataTr.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return null; + } + + //Set needed methods from syncbase. + MethodReference setSyncIndexMr; + MethodReference genericSyncVarCtor = _syncVar_Constructor_MethodRef.MakeHostInstanceGeneric(syncVarGit); + + if (!CodegenSession.NetworkBehaviourSyncProcessor.SetSyncBaseMethods(_syncBase_TypeRef.CachedResolve(), out setSyncIndexMr, out _)) + return null; + + MethodReference setValueMr = null; + MethodReference getValueMr = null; + foreach (MethodDefinition md in SyncVar_TypeRef.CachedResolve().Methods) + { + //GetValue. + if (md.Name == GETVALUE_NAME) + { + MethodReference mr = CodegenSession.ImportReference(md); + getValueMr = mr.MakeHostInstanceGeneric(syncVarGit); + } + //SetValue. + else if (md.Name == SETVALUE_NAME) + { + MethodReference mr = CodegenSession.ImportReference(md); + setValueMr = mr.MakeHostInstanceGeneric(syncVarGit); + } + + } + + if (setValueMr == null || getValueMr == null) + return null; + + CreatedSyncVar csv = new CreatedSyncVar(syncVarGit, dataTd, getValueMr, setValueMr, setSyncIndexMr, null, genericSyncVarCtor); + _createdSyncVars.Add(typeHash, csv); + return csv; + } + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta new file mode 100644 index 0000000..086dc59 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 935ec97b96b35b94f8c6880c6908304c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension.meta new file mode 100644 index 0000000..a4c0b09 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df90983b61081f84b990ac494ac8bdb6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs new file mode 100644 index 0000000..b11e91c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs @@ -0,0 +1,54 @@ +using MonoFN.Cecil; +using System.Linq; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + internal static class CustomAttributeExtensions + { + /// + /// Finds a field within an attribute. + /// + /// + /// + /// + /// + /// + internal static T GetField(this CustomAttribute customAttr, string field, T defaultValue) + { + foreach (CustomAttributeNamedArgument customField in customAttr.Fields) + { + if (customField.Name == field) + { + return (T)customField.Argument.Value; + } + } + + return defaultValue; + } + + /// + /// Returns if any of the attributes match IAtrribute. + /// + /// + /// + /// + internal static bool HasCustomAttribute(this ICustomAttributeProvider attributeProvider) + { + return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is()); + } + + /// + /// Returns if ca is of type target. + /// + /// + /// + /// + internal static bool Is(this CustomAttribute ca, string targetFullName) + { + return ca.AttributeType.FullName == targetFullName; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta new file mode 100644 index 0000000..87b14e3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a66d771ab331fae408142a5c04abd74e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs new file mode 100644 index 0000000..5fda8fe --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs @@ -0,0 +1,41 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.CompilationPipeline.Common.Diagnostics; + +namespace FishNet.CodeGenerating.Helping +{ + internal static class Diagnostics + { + internal static void AddError(this List diagnostics, string message) + { + diagnostics.AddMessage(DiagnosticType.Error, (SequencePoint)null, message); + } + + internal static void AddWarning(this List diagnostics, string message) + { + diagnostics.AddMessage(DiagnosticType.Warning, (SequencePoint)null, message); + } + + internal static void AddError(this List diagnostics, MethodDefinition methodDef, string message) + { + diagnostics.AddMessage(DiagnosticType.Error, methodDef.DebugInformation.SequencePoints.FirstOrDefault(), message); + } + + internal static void AddMessage(this List diagnostics, DiagnosticType diagnosticType, SequencePoint sequencePoint, string message) + { + diagnostics.Add(new DiagnosticMessage + { + DiagnosticType = diagnosticType, + File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""), + Line = sequencePoint?.StartLine ?? 0, + Column = sequencePoint?.StartColumn ?? 0, + MessageData = $" - {message}" + }); + } + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta new file mode 100644 index 0000000..a70954f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb7b65b572b01444cbe3c9d830cd3587 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs new file mode 100644 index 0000000..695c9b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs @@ -0,0 +1,32 @@ +using MonoFN.Cecil; +using System; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + internal static class FieldReferenceExtensions + { + + /// + /// Gets a Resolve favoring cached results first. + /// + internal static FieldDefinition CachedResolve(this FieldReference fieldRef) + { + return CodegenSession.GeneralHelper.GetFieldReferenceResolve(fieldRef); + } + + + public static FieldReference MakeHostGenericIfNeeded(this FieldReference fd) + { + if (fd.DeclaringType.HasGenericParameters) + { + return new FieldReference(fd.Name, fd.FieldType, fd.DeclaringType.CachedResolve().ConvertToGenericIfNeeded()); + } + + return fd; + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta new file mode 100644 index 0000000..c868340 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d983ebd0c9e1b745902030c2f7a8e99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs new file mode 100644 index 0000000..b6948eb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs @@ -0,0 +1,191 @@ +using FishNet.CodeGenerating.Helping.Extension; +using MonoFN.Cecil; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + public static class Constructors + { + + /// + /// Gets the first constructor that optionally has, or doesn't have parameters. + /// + /// + /// + public static MethodDefinition GetFirstConstructor(this TypeReference typeRef, bool requireParameters) + { + return typeRef.CachedResolve().GetFirstConstructor(requireParameters); + } + /// + /// Gets the first constructor that optionally has, or doesn't have parameters. + /// + /// + /// + public static MethodDefinition GetFirstConstructor(this TypeDefinition typeDef, bool requireParameters) + { + + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor && methodDef.IsPublic) + { + if (requireParameters && methodDef.Parameters.Count > 0) + return methodDef; + else if (!requireParameters && methodDef.Parameters.Count == 0) + return methodDef; + } + + } + + return null; + } + + /// + /// Gets the first public constructor with no parameters. + /// + /// + public static MethodDefinition GetConstructor(this TypeReference typeRef) + { + return typeRef.CachedResolve().GetConstructor(); + } + /// + /// Gets the first public constructor with no parameters. + /// + /// + public static MethodDefinition GetConstructor(this TypeDefinition typeDef) + { + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == 0) + return methodDef; + } + + return null; + } + + /// + /// Gets all constructors on typeDef. + /// + /// + public static List GetConstructors(this TypeDefinition typeDef) + { + List lst = new List(); + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor) + lst.Add(methodDef); + } + + return lst; + } + + + /// + /// Gets constructor which has arguments. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeReference typeRef, Type[] arguments) + { + return typeRef.CachedResolve().GetConstructor(arguments); + } + + /// + /// Gets constructor which has arguments. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeDefinition typeDef, Type[] arguments) + { + Type[] argsCopy = (arguments == null) ? new Type[0] : arguments; + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length) + { + bool match = true; + for (int i = 0; i < argsCopy.Length; i++) + { + if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName) + { + match = false; + break; + } + } + + if (match) + return methodDef; + } + } + return null; + } + + + /// + /// Gets constructor which has arguments. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeReference typeRef, TypeReference[] arguments) + { + return typeRef.CachedResolve().GetConstructor(arguments); + } + + /// + /// Gets constructor which has arguments. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeDefinition typeDef, TypeReference[] arguments) + { + TypeReference[] argsCopy = (arguments == null) ? new TypeReference[0] : arguments; + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length) + { + bool match = true; + for (int i = 0; i < argsCopy.Length; i++) + { + if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName) + { + match = false; + break; + } + } + + if (match) + return methodDef; + } + } + return null; + } + + /// + /// Resolves the constructor with parameterCount for typeRef. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeReference typeRef, int parameterCount) + { + return typeRef.CachedResolve().GetConstructor(parameterCount); + } + + + /// + /// Resolves the constructor with parameterCount for typeRef. + /// + /// + /// + public static MethodDefinition GetConstructor(this TypeDefinition typeDef, int parameterCount) + { + foreach (MethodDefinition methodDef in typeDef.Methods) + { + if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == parameterCount) + return methodDef; + } + return null; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta new file mode 100644 index 0000000..c66fc8f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a7e03137ca78704e999f3a3dc68b953 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs new file mode 100644 index 0000000..7f467e8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs @@ -0,0 +1,169 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + public static class ILProcessorExtensions + { + + /// + /// Creates a debug log for text without any conditions. + /// + public static void DebugLog(this ILProcessor processor, string txt) + { + processor.Emit(OpCodes.Ldstr, txt); + processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Debug_LogCommon_MethodRef); + } + /// + /// Creates a debug log for vd without any conditions. + /// + public static void DebugLog(this ILProcessor processor, VariableDefinition vd) + { + processor.Emit(OpCodes.Ldloc, vd); + processor.Emit(OpCodes.Box, vd.VariableType); + processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Debug_LogCommon_MethodRef); + } + /// + /// Creates a debug log for vd without any conditions. + /// + public static void DebugLog(this ILProcessor processor, FieldDefinition fd, bool loadArg0) + { + if (loadArg0) + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, fd); + processor.Emit(OpCodes.Box, fd.FieldType); + processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Debug_LogCommon_MethodRef); + } + /// + /// Creates a debug log for pd without any conditions. + /// + public static void DebugLog(this ILProcessor processor, ParameterDefinition pd) + { + processor.Emit(OpCodes.Ldloc, pd); + processor.Emit(OpCodes.Box, pd.ParameterType); + processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Debug_LogCommon_MethodRef); + } + + ///// + ///// Creates a debug log for mr without any conditions. + ///// + //public static void DebugLog(this ILProcessor processor, MethodReference mr) + //{ + // processor.Emit(OpCodes.Call, mr); + // processor.Emit(OpCodes.Box, mr.ReturnType); + // processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Debug_LogCommon_MethodRef); + //} + + + /// + /// Inserts instructions at the beginning. + /// + /// + /// + public static void InsertAt(this ILProcessor processor, int target, List instructions) + { + for (int i = 0; i < instructions.Count; i++) + processor.Body.Instructions.Insert(i + target, instructions[i]); + } + + + /// + /// Inserts instructions at the beginning. + /// + /// + /// + public static void InsertFirst(this ILProcessor processor, List instructions) + { + for (int i = 0; i < instructions.Count; i++) + processor.Body.Instructions.Insert(i, instructions[i]); + } + + /// + /// Inserts instructions at the end while also moving Ret down. + /// + /// + /// + public static void InsertLast(this ILProcessor processor, List instructions) + { + bool retRemoved = false; + int startingCount = processor.Body.Instructions.Count; + //Remove ret if it exist and add it back in later. + if (startingCount > 0) + { + if (processor.Body.Instructions[startingCount - 1].OpCode == OpCodes.Ret) + { + processor.Body.Instructions.RemoveAt(startingCount - 1); + retRemoved = true; + } + } + + foreach (Instruction inst in instructions) + processor.Append(inst); + + //Add ret back if it was removed. + if (retRemoved) + processor.Emit(OpCodes.Ret); + } + + /// + /// Inserts instructions before target. + /// + /// + /// + public static void InsertBefore(this ILProcessor processor, Instruction target, List instructions) + { + int index = processor.Body.Instructions.IndexOf(target); + for (int i = 0; i < instructions.Count; i++) + processor.Body.Instructions.Insert(index + i, instructions[i]); + } + + /// + /// Adds instructions to the end of processor. + /// + /// + /// + public static void Add(this ILProcessor processor, List instructions) + { + for (int i = 0; i < instructions.Count; i++) + processor.Body.Instructions.Add(instructions[i]); + } + + /// + /// Inserts instructions before returns. Only works on void types. + /// + /// + /// + public static void InsertBeforeReturns(this ILProcessor processor, List instructions) + { + if (processor.Body.Method.ReturnType.FullName != CodegenSession.Module.TypeSystem.Void.FullName) + { + CodegenSession.LogError($"Cannot insert instructions before returns on {processor.Body.Method.FullName} because it does not return void."); + return; + } + + /* Insert at the end of the method + * and get the first instruction that was inserted. + * Any returns or breaks which would exit the method + * will jump to this instruction instead. */ + processor.InsertLast(instructions); + Instruction startInst = processor.Body.Instructions[processor.Body.Instructions.Count - instructions.Count]; + + //Look for anything that jumps to rets. + for (int i = 0; i < processor.Body.Instructions.Count; i++) + { + Instruction inst = processor.Body.Instructions[i]; + if (inst.Operand is Instruction operInst) + { + if (operInst.OpCode == OpCodes.Ret) + inst.Operand = startInst; + } + } + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta new file mode 100644 index 0000000..dfed3f0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 820cf8401d4d71c4196dda444559ef8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs new file mode 100644 index 0000000..aefd42c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs @@ -0,0 +1,12 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + public static class Instructions + { + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta new file mode 100644 index 0000000..ba87cbb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 360667149f16b6c4aba61fd05427cbfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs new file mode 100644 index 0000000..fa98b34 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs @@ -0,0 +1,55 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + internal static class MethodDefinitionExtensions + { + /// + /// Clears the method content and returns ret. + /// + internal static void ClearMethodWithRet(this MethodDefinition md, ModuleDefinition importReturnModule = null) + { + md.Body.Instructions.Clear(); + ILProcessor processor = md.Body.GetILProcessor(); + processor.Add(CodegenSession.GeneralHelper.CreateRetDefault(md, importReturnModule)); + } + + /// + /// Returns the ParameterDefinition index from end of parameters. + /// + /// + /// + /// + internal static ParameterDefinition GetEndParameter(this MethodDefinition md, int index) + { + //Not enough parameters. + if (md.Parameters.Count < (index + 1)) + return null; + + return md.Parameters[md.Parameters.Count - (index + 1)]; + } + + + /// + /// Creates a variable type within the body and returns it's VariableDef. + /// + internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, TypeReference variableTypeRef) + { + VariableDefinition variableDef = new VariableDefinition(variableTypeRef); + methodDef.Body.Variables.Add(variableDef); + return variableDef; + } + + /// + /// Creates a variable type within the body and returns it's VariableDef. + /// + internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, System.Type variableType) + { + return CreateVariable(methodDef, CodegenSession.GeneralHelper.GetTypeReference(variableType)); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta new file mode 100644 index 0000000..a64ef0a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 999d4ae4862274f4ba50569c221976dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs new file mode 100644 index 0000000..5187839 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs @@ -0,0 +1,123 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Rocks; +using System; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + public static class MethodReferenceExtensions + { + /// + /// Makes a generic method with specified arguments. + /// + /// + /// + /// + public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments) + { + GenericInstanceMethod result = new GenericInstanceMethod(method); + foreach (TypeReference argument in genericArguments) + result.GenericArguments.Add(argument); + return result; + } + + /// + /// Makes a generic method with the same arguments as the original. + /// + /// + /// + public static GenericInstanceMethod MakeGenericMethod(this MethodReference method) + { + GenericInstanceMethod result = new GenericInstanceMethod(method); + foreach (ParameterDefinition pd in method.Parameters) + result.GenericArguments.Add(pd.ParameterType); + + return result; + } + + /// + /// Gets a Resolve favoring cached results first. + /// + internal static MethodDefinition CachedResolve(this MethodReference methodRef) + { + return CodegenSession.GeneralHelper.GetMethodReferenceResolve(methodRef); + } + + /// + /// Given a method of a generic class such as ArraySegment`T.get_Count, + /// and a generic instance such as ArraySegment`int + /// Creates a reference to the specialized method ArraySegment`int`.get_Count + /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + /// + /// + /// + /// + public static MethodReference MakeHostInstanceGeneric(this MethodReference self, GenericInstanceType instanceType) + { + MethodReference reference = new MethodReference(self.Name, self.ReturnType, instanceType) + { + CallingConvention = self.CallingConvention, + HasThis = self.HasThis, + ExplicitThis = self.ExplicitThis + }; + + foreach (ParameterDefinition parameter in self.Parameters) + reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); + + foreach (GenericParameter generic_parameter in self.GenericParameters) + reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference)); + + return CodegenSession.ImportReference(reference); + } + /// + /// Given a method of a generic class such as ArraySegment`T.get_Count, + /// and a generic instance such as ArraySegment`int + /// Creates a reference to the specialized method ArraySegment`int`.get_Count + /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + /// + /// + /// + /// + public static MethodReference MakeHostInstanceGeneric(this MethodReference self, TypeReference typeRef, params TypeReference[] args) + { + + GenericInstanceType git = typeRef.MakeGenericInstanceType(args); + MethodReference reference = new MethodReference(self.Name, self.ReturnType, git) + { + CallingConvention = self.CallingConvention, + HasThis = self.HasThis, + ExplicitThis = self.ExplicitThis + }; + + foreach (ParameterDefinition parameter in self.Parameters) + reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); + + foreach (GenericParameter generic_parameter in self.GenericParameters) + reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference)); + + return reference; + } + public static bool Is(this MethodReference method, string name) + { + return method.DeclaringType.Is() && method.Name == name; + } + public static bool Is(this TypeReference td) + { + return Is(td, typeof(T)); + } + + public static bool Is(this TypeReference td, Type t) + { + if (t.IsGenericType) + { + return td.GetElementType().FullName == t.FullName; + } + return td.FullName == t.FullName; + } + + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta new file mode 100644 index 0000000..1a5c3a8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee1c15a06ab386e439ec5aa41e3496f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs new file mode 100644 index 0000000..cc22a7b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs @@ -0,0 +1,65 @@ +using FishNet.CodeGenerating.ILCore; +using MonoFN.Cecil; +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + public static class ModuleDefinitionExtensions + { + /// + /// Gets a class within CodegenSession.Module. + /// + /// + /// + public static TypeDefinition GetClass(this ModuleDefinition moduleDef, string className) + { + return CodegenSession.Module.GetType(FishNetILPP.RUNTIME_ASSEMBLY_NAME, className); + } + + public static TypeReference ImportReference(this ModuleDefinition moduleDef) + { + return CodegenSession.ImportReference(typeof(T)); + } + + public static MethodReference ImportReference(this ModuleDefinition moduleDef, Expression expression) + { + return ImportReference(moduleDef, (LambdaExpression)expression); + } + public static MethodReference ImportReference(this ModuleDefinition module, Expression> expression) + { + return ImportReference(module, (LambdaExpression)expression); + } + + public static MethodReference ImportReference(this ModuleDefinition module, LambdaExpression expression) + { + if (expression.Body is MethodCallExpression outermostExpression) + { + MethodInfo methodInfo = outermostExpression.Method; + return module.ImportReference(methodInfo); + } + + if (expression.Body is NewExpression newExpression) + { + ConstructorInfo methodInfo = newExpression.Constructor; + // constructor is null when creating an ArraySegment + methodInfo = methodInfo ?? newExpression.Type.GetConstructors()[0]; + return module.ImportReference(methodInfo); + } + + if (expression.Body is MemberExpression memberExpression) + { + var property = memberExpression.Member as PropertyInfo; + return module.ImportReference(property.GetMethod); + } + + throw new ArgumentException($"Invalid Expression {expression.Body.GetType()}"); + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs.meta new file mode 100644 index 0000000..a712e78 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42648785493390646898f5fa13e1dfd6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs new file mode 100644 index 0000000..542524a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs @@ -0,0 +1,24 @@ +using MonoFN.Cecil; +using System; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + internal static class ParameterDefinitionExtensions + { + /// + /// Returns if parameterDef is Type. + /// + /// + /// + /// + public static bool Is(this ParameterDefinition parameterDef, Type type) + { + return parameterDef.ParameterType.FullName == type.FullName; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs.meta new file mode 100644 index 0000000..bcb2358 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/ParameterDefinitionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31071055a2e388141b8f11e1ba4e147e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs new file mode 100644 index 0000000..49c7594 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs @@ -0,0 +1,468 @@ +using FishNet.CodeGenerating.Extension; +using MonoFN.Cecil; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + + internal static class TypeDefinitionExtensionsOld + { + + /// + /// Creates a GenericInstanceType and adds parameters. + /// + internal static GenericInstanceType CreateGenericInstanceType(this TypeDefinition type, Collection parameters) + { + GenericInstanceType git = new GenericInstanceType(type); + foreach (GenericParameter gp in parameters) + git.GenericArguments.Add(gp); + + return git; + } + + /// + /// Finds public fields in type and base type + /// + /// + /// + public static IEnumerable FindAllPublicFields(this TypeDefinition typeDef, bool ignoreStatic, bool ignoreNonSerialized, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null) + { + while (typeDef != null) + { + if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes)) + break; + + foreach (FieldDefinition fd in typeDef.Fields) + { + if (ignoreStatic && fd.IsStatic) + continue; + if (fd.IsPrivate) + continue; + if (ignoreNonSerialized && fd.IsNotSerialized) + continue; + if (CodegenSession.GeneralHelper.CodegenExclude(fd)) + continue; + + yield return fd; + } + + try { typeDef = typeDef.BaseType?.CachedResolve(); } + catch { break; } + } + } + + /// + /// Finds public properties on typeDef and all base types which have a public get/set accessor. + /// + /// + /// + public static IEnumerable FindAllPublicProperties(this TypeDefinition typeDef, bool excludeGenerics = true, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null) + { + while (typeDef != null) + { + if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes)) + break; + + foreach (PropertyDefinition pd in typeDef.Properties) + { + //Missing get or set method. + if (pd.GetMethod == null || pd.SetMethod == null) + continue; + //Get or set is private. + if (pd.GetMethod.IsPrivate || pd.SetMethod.IsPrivate) + continue; + if (excludeGenerics && pd.GetMethod.ReturnType.IsGenericParameter) + continue; + if (CodegenSession.GeneralHelper.CodegenExclude(pd)) + continue; + + yield return pd; + } + + try { typeDef = typeDef.BaseType?.CachedResolve(); } + catch { break; } + } + + + } + + /// + /// Returns if typeDef is excluded. + /// + private static bool IsExcluded(TypeDefinition typeDef, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null) + { + if (excludedBaseTypes != null) + { + foreach (System.Type t in excludedBaseTypes) + { + if (typeDef.FullName == t.FullName) + return true; + } + } + if (excludedAssemblyPrefixes != null) + { + foreach (string s in excludedAssemblyPrefixes) + { + int len = s.Length; + string tdAsmName = typeDef.Module.Assembly.FullName; + if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == s.ToLower()) + return true; + } + } + + //Fall through, not excluded. + return false; + } + + + /// + /// Returns if typeDef is excluded. + /// + public static bool IsExcluded(this TypeDefinition typeDef, string excludedAssemblyPrefix) + { + + int len = excludedAssemblyPrefix.Length; + string tdAsmName = typeDef.Module.Assembly.FullName; + if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == excludedAssemblyPrefix.ToLower()) + return true; + + //Fall through, not excluded. + return false; + } + + /// + /// Returns if typeDef or any of it's parents inherit from NetworkBehaviour. + /// + /// + /// + internal static bool InheritsNetworkBehaviour(this TypeDefinition typeDef) + { + string nbFullName = CodegenSession.NetworkBehaviourHelper.FullName; + + TypeDefinition copyTd = typeDef; + while (copyTd != null) + { + if (copyTd.FullName == nbFullName) + return true; + + copyTd = copyTd.GetNextBaseTypeDefinition(); + } + + //Fall through, network behaviour not found. + return false; + } + + /// + /// Returns a nested TypeDefinition of name. + /// + internal static TypeDefinition GetNestedType(this TypeDefinition typeDef, string name) + { + foreach (TypeDefinition nestedTd in typeDef.NestedTypes) + { + if (nestedTd.Name == name) + return nestedTd; + } + + return null; + } + + /// + /// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour, + /// + /// + /// + internal static bool CanProcessBaseType(this TypeDefinition typeDef) + { + return (typeDef != null && typeDef.BaseType != null && typeDef.BaseType.FullName != CodegenSession.NetworkBehaviourHelper.FullName); + } + /// + /// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour, + /// + /// + /// + internal static TypeDefinition GetNextBaseClassToProcess(this TypeDefinition typeDef) + { + if (typeDef.BaseType != null && typeDef.BaseType.FullName != CodegenSession.NetworkBehaviourHelper.FullName) + return typeDef.BaseType.CachedResolve(); + else + return null; + } + + internal static TypeDefinition GetLastBaseClass(this TypeDefinition typeDef) + { + TypeDefinition copyTd = typeDef; + while (copyTd.BaseType != null) + copyTd = copyTd.BaseType.CachedResolve(); + + return copyTd; + } + + /// + /// Searches for a type in current and inherited types. + /// + internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, string typeFullName) + { + TypeDefinition copyTd = typeDef; + do + { + if (copyTd.FullName == typeFullName) + return copyTd; + + if (copyTd.BaseType != null) + copyTd = copyTd.BaseType.CachedResolve(); + else + copyTd = null; + + } while (copyTd != null); + + //Not found. + return null; + } + + /// + /// Searches for a type in current and inherited types. + /// + internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, TypeDefinition targetTypeDef) + { + if (typeDef == null) + return null; + + TypeDefinition copyTd = typeDef; + do + { + if (copyTd == targetTypeDef) + return copyTd; + + if (copyTd.BaseType != null) + copyTd = copyTd.BaseType.CachedResolve(); + else + copyTd = null; + + } while (copyTd != null); + + //Not found. + return null; + } + + + + /// + /// Returns if typeDef is static (abstract, sealed). + /// + internal static bool IsStatic(this TypeDefinition typeDef) + { + //Combining flags in a single check some reason doesn't work right with HasFlag. + return (typeDef.Attributes.HasFlag(TypeAttributes.Abstract) && typeDef.Attributes.HasFlag(TypeAttributes.Sealed)); + } + + /// + /// Gets an enum underlying type for typeDef. + /// + /// + /// + internal static TypeReference GetEnumUnderlyingTypeReference(this TypeDefinition typeDef) + { + foreach (FieldDefinition field in typeDef.Fields) + { + if (!field.IsStatic) + return field.FieldType; + } + throw new ArgumentException($"Invalid enum {typeDef.FullName}"); + } + + /// + /// Returns if typeDef is derived from type. + /// + /// + /// + /// + internal static bool InheritsFrom(this TypeDefinition typeDef) + { + return InheritsFrom(typeDef, typeof(T)); + } + + /// + /// Returns if typeDef is derived from type. + /// + /// + /// + /// + internal static bool InheritsFrom(this TypeDefinition typeDef, Type type) + { + if (!typeDef.IsClass) + return false; + + TypeDefinition copyTd = typeDef; + while (copyTd.BaseType != null) + { + if (copyTd.BaseType.IsType(type)) + return true; + + copyTd = copyTd.GetNextBaseTypeDefinition(); + } + + //Fall through. + return false; + } + + /// + /// Adds a method to typeDef. + /// + /// + /// + /// + /// + internal static MethodDefinition AddMethod(this TypeDefinition typDef, string methodName, MethodAttributes attributes) + { + return AddMethod(typDef, methodName, attributes, typDef.Module.ImportReference(typeof(void))); + } + /// + /// Adds a method to typeDef. + /// + /// + /// + /// + /// + /// + internal static MethodDefinition AddMethod(this TypeDefinition typeDef, string methodName, MethodAttributes attributes, TypeReference typeReference) + { + var method = new MethodDefinition(methodName, attributes, typeReference); + typeDef.Methods.Add(method); + return method; + } + + + /// + /// Finds the first method by a given name. + /// + /// + /// + /// + internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName) + { + return typeDef.Methods.FirstOrDefault(method => method.Name == methodName); + } + + /// + /// Finds the first method by a given name. + /// + /// + /// + /// + internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName, Type[] types) + { + throw new NotImplementedException(); + } + + /// + /// Returns if a type is a subclass of another. + /// + /// + /// + /// + internal static bool IsSubclassOf(this TypeDefinition typeDef, string ClassTypeFullName) + { + if (!typeDef.IsClass) return false; + + TypeReference baseTypeRef = typeDef.BaseType; + while (baseTypeRef != null) + { + if (baseTypeRef.FullName == ClassTypeFullName) + { + return true; + } + + try + { + baseTypeRef = baseTypeRef.CachedResolve().BaseType; + } + catch + { + return false; + } + } + + return false; + } + + /// + /// Gets a field reference by name. + /// + /// + /// + /// + public static FieldReference GetField(this TypeDefinition typeDef, string fieldName) + { + if (typeDef.HasFields) + { + for (int i = 0; i < typeDef.Fields.Count; i++) + { + if (typeDef.Fields[i].Name == fieldName) + { + return typeDef.Fields[i]; + } + } + } + + return null; + } + + + /// + /// Returns if the TypeDefinition implements TInterface. + /// + /// + /// + /// + public static bool ImplementsInterface(this TypeDefinition typeDef) + { + for (int i = 0; i < typeDef.Interfaces.Count; i++) + { + if (typeDef.Interfaces[i].InterfaceType.Is()) + return true; + } + + return false; + } + + + /// + /// Returns if the TypeDefinition implements TInterface. + /// + /// + /// + /// + public static bool ImplementsInterfaceRecursive(this TypeDefinition typeDef) + { + TypeDefinition climbTypeDef = typeDef; + + while (climbTypeDef != null) + { + if (climbTypeDef.Interfaces.Any(i => i.InterfaceType.Is())) + return true; + + try + { + if (climbTypeDef.BaseType != null) + climbTypeDef = climbTypeDef.BaseType.CachedResolve(); + else + climbTypeDef = null; + } + //Could not resolve assembly; can happen for assemblies being checked outside FishNet/csharp. + catch (AssemblyResolutionException) + { + break; + } + } + + return false; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs.meta new file mode 100644 index 0000000..da8687a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeDefinitionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 645e49fe7eeff3a4e9eb65d77fc6e2ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs new file mode 100644 index 0000000..6bf55c2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs @@ -0,0 +1,137 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Rocks; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping.Extension +{ + + internal static class TypeReferenceExtensionsOld + { + + /// + /// Gets a Resolve favoring cached results first. + /// + internal static TypeDefinition CachedResolve(this TypeReference typeRef) + { + return CodegenSession.GeneralHelper.GetTypeReferenceResolve(typeRef); + } + + /// + /// Returns if typeRef is a class or struct. + /// + internal static bool IsClassOrStruct(this TypeReference typeRef) + { + TypeDefinition typeDef = typeRef.CachedResolve(); + return (!typeDef.IsPrimitive && (typeDef.IsClass || typeDef.IsValueType)); + } + + /// + /// Returns all properties on typeRef and all base types which have a public get/set accessor. + /// + /// + /// + public static IEnumerable FindAllPublicProperties(this TypeReference typeRef, bool excludeGenerics = true, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null) + { + return typeRef.CachedResolve().FindAllPublicProperties(excludeGenerics, excludedBaseTypes, excludedAssemblyPrefixes); + } + + + /// + /// Gets all public fields in typeRef and base type. + /// + /// + /// + public static IEnumerable FindAllPublicFields(this TypeReference typeRef, bool ignoreStatic, bool ignoreNonSerialized, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null) + { + return typeRef.Resolve().FindAllPublicFields(ignoreStatic, ignoreNonSerialized, excludedBaseTypes, excludedAssemblyPrefixes); + } + + + /// + /// Returns if a typeRef is type. + /// + /// + /// + /// + public static bool IsType(this TypeReference typeRef, Type type) + { + if (type.IsGenericType) + return typeRef.GetElementType().FullName == type.FullName; + else + return typeRef.FullName == type.FullName; + } + + + + /// + /// Returns if typeRef is a multidimensional array. + /// + /// + /// + public static bool IsMultidimensionalArray(this TypeReference typeRef) + { + return typeRef is ArrayType arrayType && arrayType.Rank > 1; + } + + + /// + /// Returns if typeRef can be resolved. + /// + /// + /// + public static bool CanBeResolved(this TypeReference typeRef) + { + while (typeRef != null) + { + if (typeRef.Scope.Name == "Windows") + { + return false; + } + + if (typeRef.Scope.Name == "mscorlib") + { + TypeDefinition resolved = typeRef.CachedResolve(); + return resolved != null; + } + + try + { + typeRef = typeRef.CachedResolve().BaseType; + } + catch + { + return false; + } + } + return true; + } + + /// + /// Creates a generic type out of another type, if needed. + /// + /// + /// + public static TypeReference ConvertToGenericIfNeeded(this TypeDefinition type) + { + if (type.HasGenericParameters) + { + // get all the generic parameters and make a generic instance out of it + var genericTypes = new TypeReference[type.GenericParameters.Count]; + for (int i = 0; i < type.GenericParameters.Count; i++) + { + genericTypes[i] = type.GenericParameters[i].GetElementType(); + } + + return type.MakeGenericInstanceType(genericTypes); + } + else + { + return type; + } + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs.meta new file mode 100644 index 0000000..5edaeb9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Extension/TypeReferenceExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2344f5ab0fda07b498c03fbe0e082c14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs new file mode 100644 index 0000000..2e51ac0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs @@ -0,0 +1,941 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.ILCore; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Object.Helping; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; +using UnityEngine; +using SR = System.Reflection; + +namespace FishNet.CodeGenerating.Helping +{ + internal class GeneralHelper + { + #region Reflection references. + internal string CodegenExcludeAttribute_FullName; + internal MethodReference Queue_Enqueue_MethodRef; + internal MethodReference Queue_get_Count_MethodRef; + internal MethodReference Queue_Dequeue_MethodRef; + internal MethodReference Queue_Clear_MethodRef; + internal TypeReference List_TypeRef; + internal MethodReference List_Clear_MethodRef; + internal MethodReference List_get_Item_MethodRef; + internal MethodReference List_get_Count_MethodRef; + internal MethodReference List_Add_MethodRef; + internal MethodReference List_RemoveRange_MethodRef; + private MethodReference InstanceFinder_NetworkManager_MethodRef; + private MethodReference NetworkBehaviour_CanLog_MethodRef; + private MethodReference NetworkManager_CanLog_MethodRef; + private MethodReference NetworkBehaviour_NetworkManager_MethodRef; + private MethodReference NetworkManager_LogCommon_MethodRef; + private MethodReference NetworkManager_LogWarning_MethodRef; + private MethodReference NetworkManager_LogError_MethodRef; + internal MethodReference Debug_LogCommon_MethodRef; + internal MethodReference Debug_LogWarning_MethodRef; + internal MethodReference Debug_LogError_MethodRef; + internal MethodReference Comparers_EqualityCompare_MethodRef; + internal MethodReference Comparers_IsDefault_MethodRef; + internal MethodReference IsServer_MethodRef; + internal MethodReference IsClient_MethodRef; + internal MethodReference NetworkObject_Deinitializing_MethodRef; + internal MethodReference Application_IsPlaying_MethodRef; + private Dictionary _importedTypeReferences = new Dictionary(); + private Dictionary _importedFieldReferences = new Dictionary(); + private Dictionary _methodReferenceResolves = new Dictionary(); + private Dictionary _typeReferenceResolves = new Dictionary(); + private Dictionary _fieldReferenceResolves = new Dictionary(); + private string NonSerialized_Attribute_FullName; + private string Single_FullName; + #endregion + + #region Const. + public const string UNITYENGINE_ASSEMBLY_PREFIX = "UnityEngine."; + #endregion + + internal bool ImportReferences() + { + Type tmpType; + SR.MethodInfo tmpMi; + SR.PropertyInfo tmpPi; + + NonSerialized_Attribute_FullName = typeof(NonSerializedAttribute).FullName; + Single_FullName = typeof(float).FullName; + + CodegenExcludeAttribute_FullName = typeof(CodegenExcludeAttribute).FullName; + + tmpType = typeof(Queue<>); + CodegenSession.ImportReference(tmpType); + tmpMi = tmpType.GetMethod("get_Count"); + Queue_get_Count_MethodRef = CodegenSession.ImportReference(tmpMi); + foreach (SR.MethodInfo mi in tmpType.GetMethods()) + { + + if (mi.Name == nameof(Queue.Enqueue)) + Queue_Enqueue_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(Queue.Dequeue)) + Queue_Dequeue_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(Queue.Clear)) + Queue_Clear_MethodRef = CodegenSession.ImportReference(mi); + } + + Type comparers = typeof(Comparers); + foreach (SR.MethodInfo mi in comparers.GetMethods()) + { + if (mi.Name == nameof(Comparers.EqualityCompare)) + Comparers_EqualityCompare_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(Comparers.IsDefault)) + Comparers_IsDefault_MethodRef = CodegenSession.ImportReference(mi); + } + + //Misc. + tmpType = typeof(UnityEngine.Application); + tmpPi = tmpType.GetProperty(nameof(UnityEngine.Application.isPlaying)); + if (tmpPi != null) + Application_IsPlaying_MethodRef = CodegenSession.ImportReference(tmpPi.GetMethod); + + //Networkbehaviour. + Type networkBehaviourType = typeof(NetworkBehaviour); + foreach (SR.MethodInfo methodInfo in networkBehaviourType.GetMethods()) + { + if (methodInfo.Name == nameof(NetworkBehaviour.CanLog)) + NetworkBehaviour_CanLog_MethodRef = CodegenSession.ImportReference(methodInfo); + } + foreach (SR.PropertyInfo propertyInfo in networkBehaviourType.GetProperties()) + { + if (propertyInfo.Name == nameof(NetworkBehaviour.NetworkManager)) + NetworkBehaviour_NetworkManager_MethodRef = CodegenSession.ImportReference(propertyInfo.GetMethod); + } + + //Instancefinder. + Type instanceFinderType = typeof(InstanceFinder); + SR.PropertyInfo getNetworkManagerPropertyInfo = instanceFinderType.GetProperty(nameof(InstanceFinder.NetworkManager)); + InstanceFinder_NetworkManager_MethodRef = CodegenSession.ImportReference(getNetworkManagerPropertyInfo.GetMethod); + + //NetworkManager debug logs. + Type networkManagerType = typeof(NetworkManager); + foreach (SR.MethodInfo methodInfo in networkManagerType.GetMethods()) + { + if (methodInfo.Name == nameof(NetworkManager.Log)) + NetworkManager_LogCommon_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(NetworkManager.LogWarning)) + NetworkManager_LogWarning_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(NetworkManager.LogError)) + NetworkManager_LogError_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(NetworkManager.CanLog)) + NetworkManager_CanLog_MethodRef = CodegenSession.ImportReference(methodInfo); + } + + //Lists. + tmpType = typeof(List<>); + List_TypeRef = CodegenSession.ImportReference(tmpType); + SR.MethodInfo lstMi; + lstMi = tmpType.GetMethod("Add"); + List_Add_MethodRef = CodegenSession.ImportReference(lstMi); + lstMi = tmpType.GetMethod("RemoveRange"); + List_RemoveRange_MethodRef = CodegenSession.ImportReference(lstMi); + lstMi = tmpType.GetMethod("get_Count"); + List_get_Count_MethodRef = CodegenSession.ImportReference(lstMi); + lstMi = tmpType.GetMethod("get_Item"); + List_get_Item_MethodRef = CodegenSession.ImportReference(lstMi); + lstMi = tmpType.GetMethod("Clear"); + List_Clear_MethodRef = CodegenSession.ImportReference(lstMi); + + //Unity debug logs. + Type debugType = typeof(UnityEngine.Debug); + foreach (SR.MethodInfo methodInfo in debugType.GetMethods()) + { + if (methodInfo.Name == nameof(Debug.LogWarning) && methodInfo.GetParameters().Length == 1) + Debug_LogWarning_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(Debug.LogError) && methodInfo.GetParameters().Length == 1) + Debug_LogError_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(Debug.Log) && methodInfo.GetParameters().Length == 1) + Debug_LogCommon_MethodRef = CodegenSession.ImportReference(methodInfo); + } + + Type codegenHelper = typeof(CodegenHelper); + foreach (SR.MethodInfo methodInfo in codegenHelper.GetMethods()) + { + if (methodInfo.Name == nameof(CodegenHelper.NetworkObject_Deinitializing)) + NetworkObject_Deinitializing_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(CodegenHelper.IsClient)) + IsClient_MethodRef = CodegenSession.ImportReference(methodInfo); + else if (methodInfo.Name == nameof(CodegenHelper.IsServer)) + IsServer_MethodRef = CodegenSession.ImportReference(methodInfo); + } + + return true; + } + + + + #region Resolves. + /// + /// Adds a typeRef to TypeReferenceResolves. + /// + internal void AddTypeReferenceResolve(TypeReference typeRef, TypeDefinition typeDef) + { + _typeReferenceResolves[typeRef] = typeDef; + } + + /// + /// Gets a TypeDefinition for typeRef. + /// + internal TypeDefinition GetTypeReferenceResolve(TypeReference typeRef) + { + TypeDefinition result; + if (_typeReferenceResolves.TryGetValue(typeRef, out result)) + { + return result; + } + else + { + result = typeRef.Resolve(); + AddTypeReferenceResolve(typeRef, result); + } + + return result; + } + + /// + /// Adds a methodRef to MethodReferenceResolves. + /// + internal void AddMethodReferenceResolve(MethodReference methodRef, MethodDefinition methodDef) + { + _methodReferenceResolves[methodRef] = methodDef; + } + + /// + /// Gets a TypeDefinition for typeRef. + /// + internal MethodDefinition GetMethodReferenceResolve(MethodReference methodRef) + { + MethodDefinition result; + if (_methodReferenceResolves.TryGetValue(methodRef, out result)) + { + return result; + } + else + { + result = methodRef.Resolve(); + AddMethodReferenceResolve(methodRef, result); + } + + return result; + } + + + /// + /// Adds a fieldRef to FieldReferenceResolves. + /// + internal void AddFieldReferenceResolve(FieldReference fieldRef, FieldDefinition fieldDef) + { + _fieldReferenceResolves[fieldRef] = fieldDef; + } + + /// + /// Gets a FieldDefinition for fieldRef. + /// + internal FieldDefinition GetFieldReferenceResolve(FieldReference fieldRef) + { + FieldDefinition result; + if (_fieldReferenceResolves.TryGetValue(fieldRef, out result)) + { + return result; + } + else + { + result = fieldRef.Resolve(); + AddFieldReferenceResolve(fieldRef, result); + } + + return result; + } + #endregion + + + /// + /// Returns if typeDef should be ignored. + /// + /// + /// + internal bool IgnoreTypeDefinition(TypeDefinition typeDef) + { + //If FishNet assembly. + if (typeDef.Module.Assembly.Name.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME) + { + foreach (CustomAttribute item in typeDef.CustomAttributes) + { + if (item.AttributeType.FullName == typeof(CodegenIncludeInternalAttribute).FullName) + { + if (FishNetILPP.CODEGEN_THIS_NAMESPACE.Length > 0) + return !typeDef.FullName.Contains(FishNetILPP.CODEGEN_THIS_NAMESPACE); + else + return false; + } + } + + return true; + } + //Not FishNet assembly. + else + { + if (FishNetILPP.CODEGEN_THIS_NAMESPACE.Length > 0) + return true; + + foreach (CustomAttribute item in typeDef.CustomAttributes) + { + if (item.AttributeType.FullName == typeof(CodegenExcludeAttribute).FullName) + return true; + } + + return false; + } + } + + /// + /// Returns if type uses CodegenExcludeAttribute. + /// + internal bool CodegenExclude(SR.MethodInfo methodInfo) + { + foreach (SR.CustomAttributeData item in methodInfo.CustomAttributes) + { + if (item.AttributeType == typeof(CodegenExcludeAttribute)) + return true; + } + + return false; + } + + /// + /// Returns if type uses CodegenExcludeAttribute. + /// + internal bool CodegenExclude(MethodDefinition methodDef) + { + foreach (CustomAttribute item in methodDef.CustomAttributes) + { + if (item.AttributeType.FullName == CodegenExcludeAttribute_FullName) + return true; + } + + return false; + } + + /// + /// Returns if type uses CodegenExcludeAttribute. + /// + internal bool CodegenExclude(FieldDefinition fieldDef) + { + foreach (CustomAttribute item in fieldDef.CustomAttributes) + { + if (item.AttributeType.FullName == CodegenExcludeAttribute_FullName) + return true; + } + + return false; + } + + /// + /// Returns if type uses CodegenExcludeAttribute. + /// + internal bool CodegenExclude(PropertyDefinition propDef) + { + foreach (CustomAttribute item in propDef.CustomAttributes) + { + if (item.AttributeType.FullName == CodegenExcludeAttribute_FullName) + return true; + } + + return false; + } + + + + + /// + /// Calls copiedMd with the assumption md shares the same parameters. + /// + internal void CallCopiedMethod(MethodDefinition md, MethodDefinition copiedMd) + { + ILProcessor processor = md.Body.GetILProcessor(); + processor.Emit(OpCodes.Ldarg_0); + foreach (var item in copiedMd.Parameters) + processor.Emit(OpCodes.Ldarg, item); + processor.Emit(OpCodes.Call, copiedMd); + + } + + /// + /// Copies one method to another while transferring diagnostic paths. + /// + internal MethodDefinition CopyMethod(MethodDefinition originalMd, string toName, out bool alreadyCreated) + { + TypeDefinition typeDef = originalMd.DeclaringType; + + MethodDefinition copyMd = typeDef.GetMethod(toName); + //Already made. + if (copyMd != null) + { + alreadyCreated = true; + return copyMd; + } + else + { + alreadyCreated = false; + } + + //Create the method body. + copyMd = new MethodDefinition( + toName, originalMd.Attributes, originalMd.ReturnType); + typeDef.Methods.Add(copyMd); + copyMd.Body.InitLocals = true; + + //Copy parameter expecations into new method. + foreach (ParameterDefinition pd in originalMd.Parameters) + copyMd.Parameters.Add(pd); + + //Swap bodies. + (copyMd.Body, originalMd.Body) = (originalMd.Body, copyMd.Body); + //Move over all the debugging information + foreach (SequencePoint sequencePoint in originalMd.DebugInformation.SequencePoints) + copyMd.DebugInformation.SequencePoints.Add(sequencePoint); + originalMd.DebugInformation.SequencePoints.Clear(); + + foreach (CustomDebugInformation customInfo in originalMd.CustomDebugInformations) + copyMd.CustomDebugInformations.Add(customInfo); + originalMd.CustomDebugInformations.Clear(); + //Swap debuginformation scope. + (originalMd.DebugInformation.Scope, copyMd.DebugInformation.Scope) = (copyMd.DebugInformation.Scope, originalMd.DebugInformation.Scope); + + return copyMd; + } + + /// + /// Creates the RuntimeInitializeOnLoadMethod attribute for a method. + /// + internal void CreateRuntimeInitializeOnLoadMethodAttribute(MethodDefinition methodDef, string loadType = "") + { + TypeReference attTypeRef = GetTypeReference(typeof(RuntimeInitializeOnLoadMethodAttribute)); + foreach (CustomAttribute item in methodDef.CustomAttributes) + { + //Already exist. + if (item.AttributeType.FullName == attTypeRef.FullName) + return; + } + + int parameterRequirement = (loadType.Length == 0) ? 0 : 1; + MethodDefinition constructorMethodDef = attTypeRef.GetConstructor(parameterRequirement); + MethodReference constructorMethodRef = CodegenSession.ImportReference(constructorMethodDef); + CustomAttribute ca = new CustomAttribute(constructorMethodRef); + /* If load type isn't null then it + * has to be passed in as the first argument. */ + if (loadType.Length > 0) + { + Type t = typeof(RuntimeInitializeLoadType); + foreach (UnityEngine.RuntimeInitializeLoadType value in t.GetEnumValues()) + { + if (loadType == value.ToString()) + { + TypeReference tr = CodegenSession.ImportReference(t); + CustomAttributeArgument arg = new CustomAttributeArgument(tr, value); + ca.ConstructorArguments.Add(arg); + } + } + } + + methodDef.CustomAttributes.Add(ca); + } + + /// + /// Gets the default AutoPackType to use for typeRef. + /// + /// + /// + internal AutoPackType GetDefaultAutoPackType(TypeReference typeRef) + { + //Singles are defauled to unpacked. + if (typeRef.FullName == Single_FullName) + return AutoPackType.Unpacked; + else + return AutoPackType.Packed; + } + + /// + /// Gets the InitializeOnce method in typeDef or creates the method should it not exist. + /// + /// + /// + internal MethodDefinition GetOrCreateMethod(TypeDefinition typeDef, out bool created, MethodAttributes methodAttr, string methodName, TypeReference returnType) + { + MethodDefinition result = typeDef.GetMethod(methodName); + if (result == null) + { + created = true; + result = new MethodDefinition(methodName, methodAttr, returnType); + typeDef.Methods.Add(result); + } + else + { + created = false; + } + + return result; + } + + + /// + /// Gets a class within moduleDef or creates and returns the class if it does not already exist. + /// + /// + /// + internal TypeDefinition GetOrCreateClass(out bool created, TypeAttributes typeAttr, string className, TypeReference baseTypeRef) + { + TypeDefinition type = CodegenSession.Module.GetClass(className); + if (type != null) + { + created = false; + return type; + } + else + { + created = true; + type = new TypeDefinition(FishNetILPP.RUNTIME_ASSEMBLY_NAME, className, + typeAttr, CodegenSession.ImportReference(typeof(object))); + //Add base class if specified. + if (baseTypeRef != null) + type.BaseType = CodegenSession.ImportReference(baseTypeRef); + + CodegenSession.Module.Types.Add(type); + return type; + } + } + + #region HasNonSerializableAttribute + /// + /// Returns if fieldDef has a NonSerialized attribute. + /// + /// + /// + internal bool HasNonSerializableAttribute(FieldDefinition fieldDef) + { + foreach (CustomAttribute customAttribute in fieldDef.CustomAttributes) + { + if (customAttribute.AttributeType.FullName == NonSerialized_Attribute_FullName) + return true; + } + + //Fall through, no matches. + return false; + } + /// + /// Returns if typeDef has a NonSerialized attribute. + /// + /// + /// + internal bool HasNonSerializableAttribute(TypeDefinition typeDef) + { + foreach (CustomAttribute customAttribute in typeDef.CustomAttributes) + { + if (customAttribute.AttributeType.FullName == NonSerialized_Attribute_FullName) + return true; + } + + //Fall through, no matches. + return false; + } + #endregion + + /// + /// Gets a TypeReference for a type. + /// + /// + internal TypeReference GetTypeReference(Type type) + { + TypeReference result; + if (!_importedTypeReferences.TryGetValue(type, out result)) + { + result = CodegenSession.ImportReference(type); + _importedTypeReferences.Add(type, result); + } + + return result; + } + + /// + /// Gets a FieldReference for a type. + /// + /// + internal FieldReference GetFieldReference(FieldDefinition fieldDef) + { + FieldReference result; + if (!_importedFieldReferences.TryGetValue(fieldDef, out result)) + { + result = CodegenSession.ImportReference(fieldDef); + _importedFieldReferences.Add(fieldDef, result); + } + + return result; + } + + /// + /// Gets the current constructor for typeDef, or makes a new one if constructor doesn't exist. + /// + /// + /// + internal MethodDefinition GetOrCreateConstructor(TypeDefinition typeDef, out bool created, bool makeStatic) + { + // find constructor + MethodDefinition constructorMethodDef = typeDef.GetMethod(".cctor"); + if (constructorMethodDef == null) + constructorMethodDef = typeDef.GetMethod(".ctor"); + + //Constructor already exist. + if (constructorMethodDef != null) + { + if (!makeStatic) + constructorMethodDef.Attributes &= ~MethodAttributes.Static; + + created = false; + } + //Static constructor does not exist yet. + else + { + created = true; + MethodAttributes methodAttr = (MonoFN.Cecil.MethodAttributes.HideBySig | + MonoFN.Cecil.MethodAttributes.SpecialName | + MonoFN.Cecil.MethodAttributes.RTSpecialName); + if (makeStatic) + methodAttr |= MonoFN.Cecil.MethodAttributes.Static; + + //Create a constructor. + constructorMethodDef = new MethodDefinition(".ctor", methodAttr, + typeDef.Module.TypeSystem.Void + ); + + typeDef.Methods.Add(constructorMethodDef); + + //Add ret. + ILProcessor processor = constructorMethodDef.Body.GetILProcessor(); + processor.Emit(OpCodes.Ret); + } + + return constructorMethodDef; + } + + /// + /// Creates a return of boolean type. + /// + /// + /// + internal void CreateRetBoolean(ILProcessor processor, bool result) + { + OpCode code = (result) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0; + processor.Emit(code); + processor.Emit(OpCodes.Ret); + } + + #region Debug logging. + /// + /// Creates a debug print if NetworkManager.CanLog is true. + /// + /// + /// + /// True to use InstanceFinder, false to use base. + /// + internal List CreateDebugWithCanLogInstructions(ILProcessor processor, string message, LoggingType loggingType, bool useStatic, bool useNetworkManagerLog) + { + List instructions = new List(); + if (loggingType == LoggingType.Off) + return instructions; + + List debugPrint = CreateDebugInstructions(processor, message, loggingType, useNetworkManagerLog); + //Couldn't make debug print. + if (debugPrint.Count == 0) + return instructions; + + + VariableDefinition networkManagerVd = CreateVariable(processor.Body.Method, typeof(NetworkManager)); + //Using InstanceFinder(static). + if (useStatic) + { + //Store instancefinder to nm variable. + instructions.Add(processor.Create(OpCodes.Call, InstanceFinder_NetworkManager_MethodRef)); + instructions.Add(processor.Create(OpCodes.Stloc, networkManagerVd)); + } + //Using networkBehaviour. + else + { + //Store nm reference. + instructions.Add(processor.Create(OpCodes.Ldarg_0)); + instructions.Add(processor.Create(OpCodes.Call, NetworkBehaviour_NetworkManager_MethodRef)); + instructions.Add(processor.Create(OpCodes.Stloc, networkManagerVd)); + //If was set to null then try to log with instancefinder. + Instruction skipStaticSetInst = processor.Create(OpCodes.Nop); + //if (nmVd == null) nmVd = InstanceFinder.NetworkManager. + instructions.Add(processor.Create(OpCodes.Ldloc, networkManagerVd)); + instructions.Add(processor.Create(OpCodes.Brtrue_S, skipStaticSetInst)); + //Store instancefinder to nm variable. + instructions.Add(processor.Create(OpCodes.Call, InstanceFinder_NetworkManager_MethodRef)); + instructions.Add(processor.Create(OpCodes.Stloc, networkManagerVd)); + instructions.Add(skipStaticSetInst); + } + + Instruction skipDebugInst = processor.Create(OpCodes.Nop); + //null check nm reference. If null then skip logging. + instructions.Add(processor.Create(OpCodes.Ldloc, networkManagerVd)); + instructions.Add(processor.Create(OpCodes.Brfalse_S, skipDebugInst)); + + //Only need to call CanLog if not using networkmanager logging. + if (!useNetworkManagerLog) + { + //Call canlog. + instructions.Add(processor.Create(OpCodes.Ldarg_0)); + instructions.Add(processor.Create(OpCodes.Ldc_I4, (int)loggingType)); + instructions.Add(processor.Create(OpCodes.Call, NetworkBehaviour_CanLog_MethodRef)); + instructions.Add(processor.Create(OpCodes.Brfalse_S, skipDebugInst)); + } + + instructions.Add(processor.Create(OpCodes.Ldloc, networkManagerVd)); + instructions.AddRange(debugPrint); + instructions.Add(skipDebugInst); + + return instructions; + } + + /// + /// Creates a debug print if NetworkManager.CanLog is true. + /// + /// + /// + /// True to use InstanceFinder, false to use base. + /// + internal void CreateDebugWithCanLog(ILProcessor processor, string message, LoggingType loggingType, bool useStatic, bool useNetworkManagerLog) + { + List instructions = CreateDebugWithCanLogInstructions(processor, message, loggingType, useStatic, useNetworkManagerLog); + if (instructions.Count == 0) + return; + + processor.Add(instructions); + } + /// + /// Creates a debug and returns instructions. + /// + /// + private List CreateDebugInstructions(ILProcessor processor, string message, LoggingType loggingType, bool useNetworkManagerLog) + { + List instructions = new List(); + if (loggingType == LoggingType.Off) + { + CodegenSession.LogError($"CreateDebug called with LoggingType.Off."); + return instructions; + } + + instructions.Add(processor.Create(OpCodes.Ldstr, message)); + + MethodReference methodRef; + if (loggingType == LoggingType.Common) + methodRef = (useNetworkManagerLog) ? NetworkManager_LogCommon_MethodRef : Debug_LogCommon_MethodRef; + else if (loggingType == LoggingType.Warning) + methodRef = (useNetworkManagerLog) ? NetworkManager_LogWarning_MethodRef : Debug_LogWarning_MethodRef; + else + methodRef = (useNetworkManagerLog) ? NetworkManager_LogError_MethodRef : Debug_LogError_MethodRef; + + instructions.Add(processor.Create(OpCodes.Call, methodRef)); + + return instructions; + } + #endregion + + #region CreateVariable / CreateParameter. + /// + /// Creates a parameter within methodDef and returns it's ParameterDefinition. + /// + /// + /// + /// + internal ParameterDefinition CreateParameter(MethodDefinition methodDef, TypeDefinition parameterTypeDef, string name = "", ParameterAttributes attributes = ParameterAttributes.None, int index = -1) + { + TypeReference typeRef = methodDef.Module.ImportReference(parameterTypeDef); + return CreateParameter(methodDef, typeRef, name, attributes, index); + } + /// + /// Creates a parameter within methodDef and returns it's ParameterDefinition. + /// + /// + /// + /// + internal ParameterDefinition CreateParameter(MethodDefinition methodDef, TypeReference parameterTypeRef, string name = "", ParameterAttributes attributes = ParameterAttributes.None, int index = -1) + { + ParameterDefinition parameterDef = new ParameterDefinition(name, attributes, parameterTypeRef); + if (index == -1) + methodDef.Parameters.Add(parameterDef); + else + methodDef.Parameters.Insert(index, parameterDef); + return parameterDef; + } + /// + /// Creates a parameter within methodDef and returns it's ParameterDefinition. + /// + /// + /// + /// + internal ParameterDefinition CreateParameter(MethodDefinition methodDef, Type parameterType, string name = "", ParameterAttributes attributes = ParameterAttributes.None, int index = -1) + { + return CreateParameter(methodDef, GetTypeReference(parameterType), name, attributes, index); + } + /// + /// Creates a variable type within the body and returns it's VariableDef. + /// + /// + /// + /// + internal VariableDefinition CreateVariable(MethodDefinition methodDef, TypeReference variableTypeRef) + { + VariableDefinition variableDef = new VariableDefinition(variableTypeRef); + methodDef.Body.Variables.Add(variableDef); + return variableDef; + } + /// Creates a variable type within the body and returns it's VariableDef. + /// + /// + /// + /// + /// + internal VariableDefinition CreateVariable(MethodDefinition methodDef, Type variableType) + { + return CreateVariable(methodDef, GetTypeReference(variableType)); + } + #endregion + + #region SetVariableDef. + /// + /// Initializes variableDef as a new object or collection of typeDef. + /// + /// + /// + /// + internal void SetVariableDefinitionFromObject(ILProcessor processor, VariableDefinition variableDef, TypeDefinition typeDef) + { + TypeReference type = variableDef.VariableType; + if (type.IsValueType) + { + // structs are created with Initobj + processor.Emit(OpCodes.Ldloca, variableDef); + processor.Emit(OpCodes.Initobj, type); + } + else if (typeDef.InheritsFrom()) + { + MethodReference soCreateInstanceMr = processor.Body.Method.Module.ImportReference(() => UnityEngine.ScriptableObject.CreateInstance()); + GenericInstanceMethod genericInstanceMethod = soCreateInstanceMr.GetElementMethod().MakeGenericMethod(new TypeReference[] { type }); + processor.Emit(OpCodes.Call, genericInstanceMethod); + processor.Emit(OpCodes.Stloc, variableDef); + } + else + { + MethodDefinition constructorMethodDef = type.GetConstructor(); + if (constructorMethodDef == null) + { + CodegenSession.LogError($"{type.Name} can't be deserialized because a default constructor could not be found. Create a default constructor or a custom serializer/deserializer."); + return; + } + + MethodReference constructorMethodRef = processor.Body.Method.Module.ImportReference(constructorMethodDef); + processor.Emit(OpCodes.Newobj, constructorMethodRef); + processor.Emit(OpCodes.Stloc, variableDef); + } + } + + /// + /// Assigns value to a VariableDef. + /// + /// + /// + /// + internal void SetVariableDefinitionFromInt(ILProcessor processor, VariableDefinition variableDef, int value) + { + processor.Emit(OpCodes.Ldc_I4, value); + processor.Emit(OpCodes.Stloc, variableDef); + } + /// + /// Assigns value to a VariableDef. + /// + /// + /// + /// + internal void SetVariableDefinitionFromParameter(ILProcessor processor, VariableDefinition variableDef, ParameterDefinition value) + { + processor.Emit(OpCodes.Ldarg, value); + processor.Emit(OpCodes.Stloc, variableDef); + } + #endregion. + + /// + /// Returns if an instruction is a call to a method. + /// + /// + /// + /// + internal bool IsCallToMethod(Instruction instruction, out MethodDefinition calledMethod) + { + if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodDefinition method) + { + calledMethod = method; + return true; + } + else + { + calledMethod = null; + return false; + } + } + + + /// + /// Returns if a serializer and deserializer exist for typeRef. + /// + /// + /// True to create if missing. + /// + internal bool HasSerializerAndDeserializer(TypeReference typeRef, bool create) + { + //Make sure it's imported into current module. + typeRef = CodegenSession.ImportReference(typeRef); + //Can be serialized/deserialized. + bool hasWriter = CodegenSession.WriterHelper.HasSerializer(typeRef, create); + bool hasReader = CodegenSession.ReaderHelper.HasDeserializer(typeRef, create); + + return (hasWriter && hasReader); + } + + /// + /// Creates a return of default value for methodDef. + /// + /// + public List CreateRetDefault(MethodDefinition methodDef, ModuleDefinition importReturnModule = null) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + List instructions = new List(); + //If requires a value return. + if (methodDef.ReturnType != methodDef.Module.TypeSystem.Void) + { + //Import type first. + methodDef.Module.ImportReference(methodDef.ReturnType); + if (importReturnModule != null) + importReturnModule.ImportReference(methodDef.ReturnType); + VariableDefinition vd = CodegenSession.GeneralHelper.CreateVariable(methodDef, methodDef.ReturnType); + instructions.Add(processor.Create(OpCodes.Ldloca_S, vd)); + instructions.Add(processor.Create(OpCodes.Initobj, vd.VariableType)); + instructions.Add(processor.Create(OpCodes.Ldloc, vd)); + } + instructions.Add(processor.Create(OpCodes.Ret)); + + return instructions; + } + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta new file mode 100644 index 0000000..804c6a0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6139ff104f3c24442b26dbc4e40d5ce5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs new file mode 100644 index 0000000..df9e418 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs @@ -0,0 +1,143 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Rocks; +using System; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + + internal class GenericReaderHelper + { + + #region Reflection references. + private TypeReference _genericReaderTypeRef; + private TypeReference _readerTypeRef; + private MethodReference _readGetSetMethodRef; + private MethodReference _readAutoPackGetSetMethodRef; + private TypeReference _functionT2TypeRef; + private TypeReference _functionT3TypeRef; + private MethodReference _functionT2ConstructorMethodRef; + private MethodReference _functionT3ConstructorMethodRef; + private TypeDefinition _generatedReaderWriterClassTypeDef; + private MethodDefinition _generatedReaderWriterOnLoadMethodDef; + private TypeReference _autoPackTypeRef; + #endregion + + #region Misc. + /// + /// TypeReferences which have already had delegates made for. + /// + private HashSet _delegatedTypes = new HashSet(); + #endregion + + #region Const. + internal const string INITIALIZEONCE_METHOD_NAME = GenericWriterHelper.INITIALIZEONCE_METHOD_NAME; + internal const MethodAttributes INITIALIZEONCE_METHOD_ATTRIBUTES = GenericWriterHelper.INITIALIZEONCE_METHOD_ATTRIBUTES; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + _genericReaderTypeRef = CodegenSession.ImportReference(typeof(GenericReader<>)); + _readerTypeRef = CodegenSession.ImportReference(typeof(Reader)); + _functionT2TypeRef = CodegenSession.ImportReference(typeof(Func<,>)); + _functionT3TypeRef = CodegenSession.ImportReference(typeof(Func<,,>)); + _functionT2ConstructorMethodRef = CodegenSession.ImportReference(typeof(Func<,>).GetConstructors()[0]); + _functionT3ConstructorMethodRef = CodegenSession.ImportReference(typeof(Func<,,>).GetConstructors()[0]); + + _autoPackTypeRef = CodegenSession.ImportReference(typeof(AutoPackType)); + + System.Reflection.PropertyInfo writePropertyInfo; + writePropertyInfo = typeof(GenericReader<>).GetProperty(nameof(GenericReader.Read)); + _readGetSetMethodRef = CodegenSession.ImportReference(writePropertyInfo.GetSetMethod()); + writePropertyInfo = typeof(GenericReader<>).GetProperty(nameof(GenericReader.ReadAutoPack)); + _readAutoPackGetSetMethodRef = CodegenSession.ImportReference(writePropertyInfo.GetSetMethod()); + + return true; + } + + /// + /// Creates a Read delegate for readMethodRef and places it within the generated reader/writer constructor. + /// + /// + /// + internal void CreateReadDelegate(MethodReference readMethodRef) + { + bool created; + /* If class for generated reader/writers isn't known yet. + * It's possible this is the case if the entry being added + * now is the first entry. That would mean the class was just + * generated. */ + if (_generatedReaderWriterClassTypeDef == null) + _generatedReaderWriterClassTypeDef = CodegenSession.GeneralHelper.GetOrCreateClass(out _, ReaderGenerator.GENERATED_TYPE_ATTRIBUTES, ReaderGenerator.GENERATED_READERS_CLASS_NAME, null); + /* If constructor isn't set then try to get or create it + * and also add it to methods if were created. */ + if (_generatedReaderWriterOnLoadMethodDef == null) + { + _generatedReaderWriterOnLoadMethodDef = CodegenSession.GeneralHelper.GetOrCreateMethod(_generatedReaderWriterClassTypeDef, out created, INITIALIZEONCE_METHOD_ATTRIBUTES, INITIALIZEONCE_METHOD_NAME, CodegenSession.Module.TypeSystem.Void); + if (created) + CodegenSession.GeneralHelper.CreateRuntimeInitializeOnLoadMethodAttribute(_generatedReaderWriterOnLoadMethodDef); + } + //Check if ret already exist, if so remove it; ret will be added on again in this method. + if (_generatedReaderWriterOnLoadMethodDef.Body.Instructions.Count != 0) + { + int lastIndex = (_generatedReaderWriterOnLoadMethodDef.Body.Instructions.Count - 1); + if (_generatedReaderWriterOnLoadMethodDef.Body.Instructions[lastIndex].OpCode == OpCodes.Ret) + _generatedReaderWriterOnLoadMethodDef.Body.Instructions.RemoveAt(lastIndex); + } + //Check if already exist. + ILProcessor processor = _generatedReaderWriterOnLoadMethodDef.Body.GetILProcessor(); + TypeReference dataTypeRef = readMethodRef.ReturnType; + if (_delegatedTypes.Contains(dataTypeRef)) + { + CodegenSession.LogError($"Generic read already created for {dataTypeRef.FullName}."); + return; + } + else + { + _delegatedTypes.Add(dataTypeRef); + } + + //Create a Func delegate + processor.Emit(OpCodes.Ldnull); + processor.Emit(OpCodes.Ldftn, readMethodRef); + + GenericInstanceType functionGenericInstance; + MethodReference functionConstructorInstanceMethodRef; + bool isAutoPacked = CodegenSession.ReaderHelper.IsAutoPackedType(dataTypeRef); + + //Generate for autopacktype. + if (isAutoPacked) + { + functionGenericInstance = _functionT3TypeRef.MakeGenericInstanceType(_readerTypeRef, _autoPackTypeRef, dataTypeRef); + functionConstructorInstanceMethodRef = _functionT3ConstructorMethodRef.MakeHostInstanceGeneric(functionGenericInstance); + } + //Not autopacked. + else + { + functionGenericInstance = _functionT2TypeRef.MakeGenericInstanceType(_readerTypeRef, dataTypeRef); + functionConstructorInstanceMethodRef = _functionT2ConstructorMethodRef.MakeHostInstanceGeneric(functionGenericInstance); + } + + processor.Emit(OpCodes.Newobj, functionConstructorInstanceMethodRef); + + //Call delegate to GeneratedReader.Read + GenericInstanceType genericInstance = _genericReaderTypeRef.MakeGenericInstanceType(dataTypeRef); + MethodReference genericReaderMethodRef = (isAutoPacked) ? + _readAutoPackGetSetMethodRef.MakeHostInstanceGeneric(genericInstance) : + _readGetSetMethodRef.MakeHostInstanceGeneric(genericInstance); + processor.Emit(OpCodes.Call, genericReaderMethodRef); + + processor.Emit(OpCodes.Ret); + } + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs.meta new file mode 100644 index 0000000..d041ead --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericReaderHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f9d3654f5816c4409b88fa0602c6df4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs new file mode 100644 index 0000000..ef65fc9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs @@ -0,0 +1,197 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Rocks; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + + internal class GenericWriterHelper + { + + #region Reflection references. + private TypeReference _genericWriterTypeRef; + private TypeReference _writerTypeRef; + private MethodReference _writeGetSetMethodRef; + private MethodReference _writeAutoPackGetSetMethodRef; + internal TypeReference ActionT2TypeRef; + internal TypeReference ActionT3TypeRef; + internal MethodReference ActionT2ConstructorMethodRef; + internal MethodReference ActionT3ConstructorMethodRef; + private TypeDefinition _generatedReaderWriterClassTypeDef; + private MethodDefinition _generatedReaderWriterOnLoadMethodDef; + private TypeReference _autoPackTypeRef; + #endregion + + #region Misc. + /// + /// TypeReferences which have already had delegates made for. + /// + private HashSet _delegatedTypes = new HashSet(); + #endregion + + #region Const. + internal const string INITIALIZEONCE_METHOD_NAME = "InitializeOnce"; + internal const MethodAttributes INITIALIZEONCE_METHOD_ATTRIBUTES = MethodAttributes.Static; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + _genericWriterTypeRef = CodegenSession.ImportReference(typeof(GenericWriter<>)); + _writerTypeRef = CodegenSession.ImportReference(typeof(Writer)); + ActionT2TypeRef = CodegenSession.ImportReference(typeof(Action<,>)); + ActionT3TypeRef = CodegenSession.ImportReference(typeof(Action<,,>)); + ActionT2ConstructorMethodRef = CodegenSession.ImportReference(typeof(Action<,>).GetConstructors()[0]); + ActionT3ConstructorMethodRef = CodegenSession.ImportReference(typeof(Action<,,>).GetConstructors()[0]); + + _autoPackTypeRef = CodegenSession.ImportReference(typeof(AutoPackType)); + + System.Reflection.PropertyInfo writePropertyInfo; + writePropertyInfo = typeof(GenericWriter<>).GetProperty(nameof(GenericWriter.Write)); + _writeGetSetMethodRef = CodegenSession.ImportReference(writePropertyInfo.GetSetMethod()); + writePropertyInfo = typeof(GenericWriter<>).GetProperty(nameof(GenericWriter.WriteAutoPack)); + _writeAutoPackGetSetMethodRef = CodegenSession.ImportReference(writePropertyInfo.GetSetMethod()); + + + return true; + } + + /// + /// Creates a variant of an instanced write method. + /// + /// + /// + internal void CreateInstancedStaticWrite(MethodReference writeMethodRef) + { + if (_generatedReaderWriterClassTypeDef == null) + _generatedReaderWriterClassTypeDef = CodegenSession.GeneralHelper.GetOrCreateClass(out _, WriterGenerator.GENERATED_TYPE_ATTRIBUTES, WriterGenerator.GENERATED_WRITERS_CLASS_NAME, null); + + MethodDefinition writeMethodDef = writeMethodRef.CachedResolve(); + MethodDefinition createdMethodDef = new MethodDefinition($"Static___{writeMethodRef.Name}", + (MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig), + _generatedReaderWriterClassTypeDef.Module.TypeSystem.Void); + _generatedReaderWriterClassTypeDef.Methods.Add(createdMethodDef); + + TypeReference extensionAttributeTypeRef = CodegenSession.ImportReference(typeof(System.Runtime.CompilerServices.ExtensionAttribute)); + MethodDefinition constructor = extensionAttributeTypeRef.GetConstructor(); + + MethodReference extensionAttributeConstructorMethodRef = CodegenSession.ImportReference(constructor); + CustomAttribute extensionCustomAttribute = new CustomAttribute(extensionAttributeConstructorMethodRef); + createdMethodDef.CustomAttributes.Add(extensionCustomAttribute); + + /* Add parameters to new method. */ + //First add extension. + ParameterDefinition extensionParameterDef = CodegenSession.GeneralHelper.CreateParameter(createdMethodDef, typeof(PooledWriter), "pooledWriter", ParameterAttributes.None); + //Then other types. + ParameterDefinition[] remainingParameterDefs = new ParameterDefinition[writeMethodDef.Parameters.Count]; + for (int i = 0; i < writeMethodDef.Parameters.Count; i++) + { + remainingParameterDefs[i] = CodegenSession.GeneralHelper.CreateParameter(createdMethodDef, writeMethodDef.Parameters[i].ParameterType); + _generatedReaderWriterClassTypeDef.Module.ImportReference(remainingParameterDefs[i].ParameterType.CachedResolve()); + } + + ILProcessor processor = createdMethodDef.Body.GetILProcessor(); + //Load all parameters. + foreach (ParameterDefinition pd in remainingParameterDefs) + processor.Emit(OpCodes.Ldarg, pd); + //Call instanced method. + processor.Emit(OpCodes.Ldarg, extensionParameterDef); + processor.Emit(OpCodes.Call, writeMethodRef); + processor.Emit(OpCodes.Ret); + } + + + /// + /// Creates a Write delegate for writeMethodRef and places it within the generated reader/writer constructor. + /// + /// + internal void CreateWriteDelegate(MethodReference writeMethodRef, bool isStatic) + { + /* If class for generated reader/writers isn't known yet. + * It's possible this is the case if the entry being added + * now is the first entry. That would mean the class was just + * generated. */ + bool created; + + if (_generatedReaderWriterClassTypeDef == null) + _generatedReaderWriterClassTypeDef = CodegenSession.GeneralHelper.GetOrCreateClass(out created, WriterGenerator.GENERATED_TYPE_ATTRIBUTES, WriterGenerator.GENERATED_WRITERS_CLASS_NAME, null); + /* If constructor isn't set then try to get or create it + * and also add it to methods if were created. */ + if (_generatedReaderWriterOnLoadMethodDef == null) + { + _generatedReaderWriterOnLoadMethodDef = CodegenSession.GeneralHelper.GetOrCreateMethod(_generatedReaderWriterClassTypeDef, out created, INITIALIZEONCE_METHOD_ATTRIBUTES, INITIALIZEONCE_METHOD_NAME, CodegenSession.Module.TypeSystem.Void); + if (created) + CodegenSession.GeneralHelper.CreateRuntimeInitializeOnLoadMethodAttribute(_generatedReaderWriterOnLoadMethodDef); + } + //Check if ret already exist, if so remove it; ret will be added on again in this method. + if (_generatedReaderWriterOnLoadMethodDef.Body.Instructions.Count != 0) + { + int lastIndex = (_generatedReaderWriterOnLoadMethodDef.Body.Instructions.Count - 1); + if (_generatedReaderWriterOnLoadMethodDef.Body.Instructions[lastIndex].OpCode == OpCodes.Ret) + _generatedReaderWriterOnLoadMethodDef.Body.Instructions.RemoveAt(lastIndex); + } + + ILProcessor processor = _generatedReaderWriterOnLoadMethodDef.Body.GetILProcessor(); + TypeReference dataTypeRef; + //Static methods will have the data type as the second parameter (1). + if (isStatic) + dataTypeRef = writeMethodRef.Parameters[1].ParameterType; + else + dataTypeRef = writeMethodRef.Parameters[0].ParameterType; + //Check if writer already exist. + if (_delegatedTypes.Contains(dataTypeRef)) + { + CodegenSession.LogError($"Generic write already created for {dataTypeRef.FullName}."); + return; + } + else + { + _delegatedTypes.Add(dataTypeRef); + } + + /* Create a Action delegate. + * May also be Action delegate + * for packed types. */ + processor.Emit(OpCodes.Ldnull); + processor.Emit(OpCodes.Ldftn, writeMethodRef); + + GenericInstanceType actionGenericInstance; + MethodReference actionConstructorInstanceMethodRef; + bool isAutoPacked = CodegenSession.WriterHelper.IsAutoPackedType(dataTypeRef); + + //Generate for auto pack type. + if (isAutoPacked) + { + actionGenericInstance = ActionT3TypeRef.MakeGenericInstanceType(_writerTypeRef, dataTypeRef, _autoPackTypeRef); + actionConstructorInstanceMethodRef = ActionT3ConstructorMethodRef.MakeHostInstanceGeneric(actionGenericInstance); + } + //Generate for normal type. + else + { + actionGenericInstance = ActionT2TypeRef.MakeGenericInstanceType(_writerTypeRef, dataTypeRef); + actionConstructorInstanceMethodRef = ActionT2ConstructorMethodRef.MakeHostInstanceGeneric(actionGenericInstance); + } + + processor.Emit(OpCodes.Newobj, actionConstructorInstanceMethodRef); + //Call delegate to GenericWriter.Write + GenericInstanceType genericInstance = _genericWriterTypeRef.MakeGenericInstanceType(dataTypeRef); + MethodReference genericrWriteMethodRef = (isAutoPacked) ? + _writeAutoPackGetSetMethodRef.MakeHostInstanceGeneric(genericInstance) : + _writeGetSetMethodRef.MakeHostInstanceGeneric(genericInstance); + processor.Emit(OpCodes.Call, genericrWriteMethodRef); + + processor.Emit(OpCodes.Ret); + } + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs.meta new file mode 100644 index 0000000..9ba1d8a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/GenericWriterHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a4021bd44dc40f47abb494e0a4326f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs new file mode 100644 index 0000000..f68ad32 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs @@ -0,0 +1,441 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.Processing; +using FishNet.Configuring; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Object.Delegating; +using FishNet.Object.Helping; +using FishNet.Object.Prediction.Delegating; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace FishNet.CodeGenerating.Helping +{ + internal class NetworkBehaviourHelper + { + #region Reflection references. + //Names. + internal string FullName; + //Prediction. + internal MethodReference ClearReplicateCache_MethodRef; + internal MethodReference SetLastReconcileTick_MethodRef; + internal MethodReference TransformMayChange_MethodRef; + internal MethodReference SendReplicateRpc_MethodRef; + internal MethodReference SendReconcileRpc_MethodRef; + internal MethodReference RegisterReplicateRpc_MethodRef; + internal MethodReference RegisterReconcileRpc_MethodRef; + internal MethodReference ReplicateRpcDelegateConstructor_MethodRef; + internal MethodReference ReconcileRpcDelegateConstructor_MethodRef; + //RPCs. + internal MethodReference SendServerRpc_MethodRef; + internal MethodReference SendObserversRpc_MethodRef; + internal MethodReference SendTargetRpc_MethodRef; + internal MethodReference DirtySyncType_MethodRef; + internal MethodReference RegisterServerRpc_MethodRef; + internal MethodReference RegisterObserversRpc_MethodRef; + internal MethodReference RegisterTargetRpc_MethodRef; + internal MethodReference ServerRpcDelegateConstructor_MethodRef; + internal MethodReference ClientRpcDelegateConstructor_MethodRef; + //Is checks. + internal MethodReference IsClient_MethodRef; + internal MethodReference IsOwner_MethodRef; + internal MethodReference IsServer_MethodRef; + internal MethodReference IsHost_MethodRef; + //Misc. + internal TypeReference TypeRef; + internal MethodReference CompareOwner_MethodRef; + internal MethodReference LocalConnection_MethodRef; + internal MethodReference Owner_MethodRef; + internal MethodReference ReadSyncVar_MethodRef; + internal MethodReference NetworkInitializeInternal_MethodRef; + //TimeManager. + internal MethodReference TimeManager_MethodRef; + #endregion + + #region Const. + internal const uint MAX_RPC_ALLOWANCE = ushort.MaxValue; + internal const string AWAKE_METHOD_NAME = "Awake"; + internal const string DISABLE_LOGGING_TEXT = "This message may be disabled by setting the Logging field in your attribute to LoggingType.Off"; + #endregion + + internal bool ImportReferences() + { + Type networkBehaviourType = typeof(NetworkBehaviour); + TypeRef = CodegenSession.ImportReference(networkBehaviourType); + FullName = networkBehaviourType.FullName; + CodegenSession.ImportReference(networkBehaviourType); + + //ServerRpcDelegate and ClientRpcDelegate constructors. + ServerRpcDelegateConstructor_MethodRef = CodegenSession.ImportReference(typeof(ServerRpcDelegate).GetConstructors().First()); + ClientRpcDelegateConstructor_MethodRef = CodegenSession.ImportReference(typeof(ClientRpcDelegate).GetConstructors().First()); + //Prediction Rpc delegate constructors. + ReplicateRpcDelegateConstructor_MethodRef = CodegenSession.ImportReference(typeof(ReplicateRpcDelegate).GetConstructors().First()); + ReconcileRpcDelegateConstructor_MethodRef = CodegenSession.ImportReference(typeof(ReconcileRpcDelegate).GetConstructors().First()); + + foreach (MethodInfo mi in networkBehaviourType.GetMethods((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))) + { + //CreateDelegates. + if (mi.Name == nameof(NetworkBehaviour.RegisterServerRpc)) + RegisterServerRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.RegisterObserversRpc)) + RegisterObserversRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.RegisterTargetRpc)) + RegisterTargetRpc_MethodRef = CodegenSession.ImportReference(mi); + //SendPredictions. + else if (mi.Name == nameof(NetworkBehaviour.SendReplicateRpc)) + SendReplicateRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.SendReconcileRpc)) + SendReconcileRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.RegisterReplicateRpc)) + RegisterReplicateRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.RegisterReconcileRpc)) + RegisterReconcileRpc_MethodRef = CodegenSession.ImportReference(mi); + //SendRpcs. + else if (mi.Name == nameof(NetworkBehaviour.SendServerRpc)) + SendServerRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.SendObserversRpc)) + SendObserversRpc_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.SendTargetRpc)) + SendTargetRpc_MethodRef = CodegenSession.ImportReference(mi); + //Prediction. + else if (mi.Name == nameof(NetworkBehaviour.SetLastReconcileTick)) + SetLastReconcileTick_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.ClearReplicateCache)) + ClearReplicateCache_MethodRef = CodegenSession.ImportReference(mi); + //Misc. + else if (mi.Name == nameof(NetworkBehaviour.TransformMayChange)) + TransformMayChange_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.CompareOwner)) + CompareOwner_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.ReadSyncVar)) + ReadSyncVar_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.DirtySyncType)) + DirtySyncType_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(NetworkBehaviour.NetworkInitializeIfDisabledInternal)) + NetworkInitializeInternal_MethodRef = CodegenSession.ImportReference(mi); + } + + foreach (PropertyInfo pi in networkBehaviourType.GetProperties((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))) + { + //Server/Client states. + if (pi.Name == nameof(NetworkBehaviour.IsClient)) + IsClient_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(NetworkBehaviour.IsServer)) + IsServer_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(NetworkBehaviour.IsHost)) + IsHost_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(NetworkBehaviour.IsOwner)) + IsOwner_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + //Owner. + else if (pi.Name == nameof(NetworkBehaviour.Owner)) + Owner_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(NetworkBehaviour.LocalConnection)) + LocalConnection_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + //Misc. + else if (pi.Name == nameof(NetworkBehaviour.TimeManager)) + TimeManager_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + } + + return true; + } + + /// + /// Returnsthe child most Awake by iterating up childMostTypeDef. + /// + /// + /// + /// + internal MethodDefinition GetAwakeMethodDefinition(TypeDefinition typeDef) + { + return typeDef.GetMethod(AWAKE_METHOD_NAME); + } + + + /// + /// Creates a replicate delegate. + /// + /// + /// + /// + /// + internal void CreateReplicateDelegate(MethodDefinition originalMethodDef, MethodDefinition readerMethodDef, uint methodHash) + { + MethodDefinition methodDef = originalMethodDef.DeclaringType.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + List insts = new List(); + insts.Add(processor.Create(OpCodes.Ldarg_0)); + + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)methodHash)); + + /* Create delegate and call NetworkBehaviour method. */ + insts.Add(processor.Create(OpCodes.Ldnull)); + insts.Add(processor.Create(OpCodes.Ldftn, readerMethodDef)); + + /* Has to be done last. This allows the NetworkBehaviour to + * initialize it's fields first. */ + processor.InsertLast(insts); + } + + + + /// + /// Creates a RPC delegate for rpcType. + /// + /// + /// + /// + /// + internal void CreateRpcDelegate(bool runLocally, TypeDefinition typeDef, MethodDefinition readerMethodDef, RpcType rpcType, uint methodHash, CustomAttribute rpcAttribute) + { + + + MethodDefinition methodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + List insts = new List(); + insts.Add(processor.Create(OpCodes.Ldarg_0)); + + //uint methodHash = originalMethodDef.FullName.GetStableHash32(); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)methodHash)); + + /* Create delegate and call NetworkBehaviour method. */ + insts.Add(processor.Create(OpCodes.Ldnull)); + insts.Add(processor.Create(OpCodes.Ldftn, readerMethodDef)); + //Server. + if (rpcType == RpcType.Server) + { + insts.Add(processor.Create(OpCodes.Newobj, ServerRpcDelegateConstructor_MethodRef)); + insts.Add(processor.Create(OpCodes.Call, RegisterServerRpc_MethodRef)); + } + //Observers. + else if (rpcType == RpcType.Observers) + { + insts.Add(processor.Create(OpCodes.Newobj, ClientRpcDelegateConstructor_MethodRef)); + insts.Add(processor.Create(OpCodes.Call, RegisterObserversRpc_MethodRef)); + } + //Target + else if (rpcType == RpcType.Target) + { + insts.Add(processor.Create(OpCodes.Newobj, ClientRpcDelegateConstructor_MethodRef)); + insts.Add(processor.Create(OpCodes.Call, RegisterTargetRpc_MethodRef)); + } + + /* Has to be done last. This allows the NetworkBehaviour to + * initialize it's fields first. */ + processor.InsertLast(insts); + } + + /// + /// Creates exit method condition if local client is not owner. + /// + /// True if to ret when owner, false to ret when not owner. + /// Returns Ret instruction. + internal Instruction CreateLocalClientIsOwnerCheck(MethodDefinition methodDef, LoggingType loggingType, bool canDisableLogging, bool retIfOwner, bool insertFirst) + { + List instructions = new List(); + /* This is placed after the if check. + * Should the if check pass then code + * jumps to this instruction. */ + ILProcessor processor = methodDef.Body.GetILProcessor(); + Instruction endIf = processor.Create(OpCodes.Nop); + + instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this + //If !base.IsOwner endIf. + instructions.Add(processor.Create(OpCodes.Call, IsOwner_MethodRef)); + if (retIfOwner) + instructions.Add(processor.Create(OpCodes.Brfalse, endIf)); + else + instructions.Add(processor.Create(OpCodes.Brtrue, endIf)); + //If logging is not disabled. + if (loggingType != LoggingType.Off) + { + string disableLoggingText = (canDisableLogging) ? DISABLE_LOGGING_TEXT : string.Empty; + string msg = (retIfOwner) ? + $"Cannot complete action because you are the owner of this object. {disableLoggingText}." : + $"Cannot complete action because you are not the owner of this object. {disableLoggingText}."; + + instructions.AddRange( + CodegenSession.GeneralHelper.CreateDebugWithCanLogInstructions(processor, msg, loggingType, false, true) + ); + } + //Return block. + Instruction retInst = processor.Create(OpCodes.Ret); + instructions.Add(retInst); + //After if statement, jumped to when successful check. + instructions.Add(endIf); + + if (insertFirst) + { + processor.InsertFirst(instructions); + } + else + { + foreach (Instruction inst in instructions) + processor.Append(inst); + } + + return retInst; + } + + /// + /// Creates exit method condition if remote client is not owner. + /// + /// + internal Instruction CreateRemoteClientIsOwnerCheck(ILProcessor processor, ParameterDefinition connectionParameterDef) + { + /* This is placed after the if check. + * Should the if check pass then code + * jumps to this instruction. */ + Instruction endIf = processor.Create(OpCodes.Nop); + + processor.Emit(OpCodes.Ldarg_0); //argument: this + //If !base.IsOwner endIf. + processor.Emit(OpCodes.Ldarg, connectionParameterDef); + processor.Emit(OpCodes.Call, CompareOwner_MethodRef); + processor.Emit(OpCodes.Brtrue, endIf); + //Return block. + Instruction retInst = processor.Create(OpCodes.Ret); + processor.Append(retInst); + + //After if statement, jumped to when successful check. + processor.Append(endIf); + + return retInst; + } + + /// + /// Creates exit method condition if not client. + /// + /// + /// + /// + internal void CreateIsClientCheck(MethodDefinition methodDef, LoggingType loggingType, bool useStatic, bool insertFirst) + { + /* This is placed after the if check. + * Should the if check pass then code + * jumps to this instruction. */ + ILProcessor processor = methodDef.Body.GetILProcessor(); + Instruction endIf = processor.Create(OpCodes.Nop); + + List instructions = new List(); + //Checking against the NetworkObject. + if (!useStatic) + { + instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this + //If (!base.IsClient) + instructions.Add(processor.Create(OpCodes.Call, IsClient_MethodRef)); + } + //Checking instanceFinder. + else + { + instructions.Add(processor.Create(OpCodes.Call, CodegenSession.ObjectHelper.InstanceFinder_IsClient_MethodRef)); + } + instructions.Add(processor.Create(OpCodes.Brtrue, endIf)); + //If warning then also append warning text. + if (loggingType != LoggingType.Off) + { + string msg = $"Cannot complete action because client is not active. This may also occur if the object is not yet initialized or if it does not contain a NetworkObject component. {DISABLE_LOGGING_TEXT}."; + instructions.AddRange( + CodegenSession.GeneralHelper.CreateDebugWithCanLogInstructions(processor, msg, loggingType, useStatic, true) + ); + } + //Add return. + instructions.AddRange(CreateRetDefault(methodDef)); + //After if statement, jumped to when successful check. + instructions.Add(endIf); + + if (insertFirst) + { + processor.InsertFirst(instructions); + } + else + { + foreach (Instruction inst in instructions) + processor.Append(inst); + } + } + + + /// + /// Creates exit method condition if not server. + /// + /// + /// + internal void CreateIsServerCheck(MethodDefinition methodDef, LoggingType loggingType, bool useStatic, bool insertFirst) + { + /* This is placed after the if check. + * Should the if check pass then code + * jumps to this instruction. */ + ILProcessor processor = methodDef.Body.GetILProcessor(); + Instruction endIf = processor.Create(OpCodes.Nop); + + List instructions = new List(); + if (!useStatic) + { + instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this + //If (!base.IsServer) + instructions.Add(processor.Create(OpCodes.Call, IsServer_MethodRef)); + } + //Checking instanceFinder. + else + { + instructions.Add(processor.Create(OpCodes.Call, CodegenSession.ObjectHelper.InstanceFinder_IsServer_MethodRef)); + } + instructions.Add(processor.Create(OpCodes.Brtrue, endIf)); + //If warning then also append warning text. + if (loggingType != LoggingType.Off) + { + string msg = $"Cannot complete action because server is not active. This may also occur if the object is not yet initialized or if it does not contain a NetworkObject component. {DISABLE_LOGGING_TEXT}"; + instructions.AddRange( + CodegenSession.GeneralHelper.CreateDebugWithCanLogInstructions(processor, msg, loggingType, useStatic, true) + ); + } + //Add return. + instructions.AddRange(CreateRetDefault(methodDef)); + //After if statement, jumped to when successful check. + instructions.Add(endIf); + + if (insertFirst) + { + processor.InsertFirst(instructions); + } + else + { + foreach (Instruction inst in instructions) + processor.Append(inst); + } + } + + /// + /// Creates a return using the ReturnType for methodDef. + /// + /// + /// + /// + public List CreateRetDefault(MethodDefinition methodDef, ModuleDefinition importReturnModule = null) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + List instructions = new List(); + //If requires a value return. + if (methodDef.ReturnType != methodDef.Module.TypeSystem.Void) + { + //Import type first. + methodDef.Module.ImportReference(methodDef.ReturnType); + if (importReturnModule != null) + importReturnModule.ImportReference(methodDef.ReturnType); + VariableDefinition vd = CodegenSession.GeneralHelper.CreateVariable(methodDef, methodDef.ReturnType); + instructions.Add(processor.Create(OpCodes.Ldloca_S, vd)); + instructions.Add(processor.Create(OpCodes.Initobj, vd.VariableType)); + instructions.Add(processor.Create(OpCodes.Ldloc, vd)); + } + instructions.Add(processor.Create(OpCodes.Ret)); + + return instructions; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs.meta new file mode 100644 index 0000000..55c1c3c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c42e06349d6890459a155a2afe17d41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs new file mode 100644 index 0000000..194a675 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs @@ -0,0 +1,90 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Connection; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using MonoFN.Cecil; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace FishNet.CodeGenerating.Helping +{ + internal class ObjectHelper + { + #region Reflection references. + //Fullnames. + internal string SyncList_Name; + internal string SyncDictionary_Name; + internal string SyncHashSet_Name; + //Is checks. + internal MethodReference InstanceFinder_IsServer_MethodRef; + internal MethodReference InstanceFinder_IsClient_MethodRef; + //Misc. + internal MethodReference NetworkConnection_IsValid_MethodRef; + internal MethodReference NetworkConnection_IsActive_MethodRef; + internal MethodReference Dictionary_Add_UShort_SyncBase_MethodRef; + internal MethodReference NetworkConnection_GetIsLocalClient_MethodRef; + #endregion + + internal bool ImportReferences() + { + Type tmpType; + /* SyncObject names. */ + //SyncList. + tmpType = typeof(SyncList<>); + CodegenSession.ImportReference(tmpType); + SyncList_Name = tmpType.Name; + //SyncDictionary. + tmpType = typeof(SyncDictionary<,>); + CodegenSession.ImportReference(tmpType); + SyncDictionary_Name = tmpType.Name; + //SyncHashSet. + tmpType = typeof(SyncHashSet<>); + CodegenSession.ImportReference(tmpType); + SyncHashSet_Name = tmpType.Name; + + tmpType = typeof(NetworkConnection); + TypeReference networkConnectionTr = CodegenSession.ImportReference(tmpType); + foreach (PropertyDefinition item in networkConnectionTr.CachedResolve().Properties) + { + if (item.Name == nameof(NetworkConnection.IsLocalClient)) + NetworkConnection_GetIsLocalClient_MethodRef = CodegenSession.ImportReference(item.GetMethod); + } + + //Dictionary.Add(ushort, SyncBase). + Type dictType = typeof(Dictionary); + TypeReference dictTypeRef = CodegenSession.ImportReference(dictType); + //Dictionary_Add_UShort_SyncBase_MethodRef = dictTypeRef.CachedResolve().GetMethod("add_Item", ) + foreach (MethodDefinition item in dictTypeRef.CachedResolve().Methods) + { + if (item.Name == nameof(Dictionary.Add)) + { + Dictionary_Add_UShort_SyncBase_MethodRef = CodegenSession.ImportReference(item); + break; + } + } + + //InstanceFinder infos. + Type instanceFinderType = typeof(InstanceFinder); + foreach (PropertyInfo pi in instanceFinderType.GetProperties()) + { + if (pi.Name == nameof(InstanceFinder.IsClient)) + InstanceFinder_IsClient_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(InstanceFinder.IsServer)) + InstanceFinder_IsServer_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + } + + //NetworkConnection. + foreach (PropertyInfo pi in typeof(NetworkConnection).GetProperties((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))) + { + if (pi.Name == nameof(NetworkConnection.IsValid)) + NetworkConnection_IsValid_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(NetworkConnection.IsActive)) + NetworkConnection_IsActive_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + } + + return true; + } + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta new file mode 100644 index 0000000..4e50b5f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 033da35314653aa4689b4582e7929295 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs new file mode 100644 index 0000000..b26ce28 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs @@ -0,0 +1,494 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Object; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + internal class ReaderGenerator + { + + #region Const. + internal const string GENERATED_READERS_CLASS_NAME = "GeneratedReaders___FN"; + public const TypeAttributes GENERATED_TYPE_ATTRIBUTES = WriterGenerator.GENERATED_TYPE_ATTRIBUTES; + private const string READ_PREFIX = "Read___"; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + return true; + } + + /// + /// Generates a reader for objectTypeReference if one does not already exist. + /// + /// + /// + internal MethodReference CreateReader(TypeReference objectTr) + { + MethodReference resultMr = null; + TypeDefinition objectTypeDef; + + SerializerType serializerType = GeneratorHelper.GetSerializerType(objectTr, false, out objectTypeDef); + if (serializerType != SerializerType.Invalid) + { + //Array. + if (serializerType == SerializerType.Array) + resultMr = CreateArrayReaderMethodReference(objectTr); + //Enum. + else if (serializerType == SerializerType.Enum) + resultMr = CreateEnumReaderMethodDefinition(objectTr); + else if (serializerType == SerializerType.Dictionary) + resultMr = CreateDictionaryReaderMethodReference(objectTr); + //List. + else if (serializerType == SerializerType.List) + resultMr = CreateListReaderMethodReference(objectTr); + //NetworkBehaviour. + else if (serializerType == SerializerType.NetworkBehaviour) + resultMr = GetNetworkBehaviourReaderMethodReference(objectTr); + //Nullable. + else if (serializerType == SerializerType.Nullable) + resultMr = CreateNullableReaderMethodReference(objectTr); + //Class or struct. + else if (serializerType == SerializerType.ClassOrStruct) + resultMr = CreateClassOrStructReaderMethodReference(objectTr); + } + + //If was not created. + if (resultMr == null) + RemoveFromStaticReaders(objectTr); + + return resultMr; + } + + + /// + /// Removes from static writers. + /// + private void RemoveFromStaticReaders(TypeReference tr) + { + CodegenSession.ReaderHelper.RemoveReaderMethod(tr, false); + } + /// + /// Adds to static writers. + /// + private void AddToStaticReaders(TypeReference tr, MethodReference mr) + { + CodegenSession.ReaderHelper.AddReaderMethod(tr, mr.CachedResolve(), false, true); + } + + /// + /// Generates a reader for objectTypeReference if one does not already exist. + /// + /// + /// + private MethodReference CreateEnumReaderMethodDefinition(TypeReference objectTr) + { + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + + //Get type reference for enum type. eg byte int + TypeReference underlyingTypeRef = objectTr.CachedResolve().GetEnumUnderlyingTypeReference(); + //Get read method for underlying type. + MethodReference readMethodRef = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(underlyingTypeRef, true); + if (readMethodRef == null) + return null; + + ParameterDefinition readerParameterDef = createdReaderMd.Parameters[0]; + //reader.ReadXXX(). + processor.Emit(OpCodes.Ldarg, readerParameterDef); + if (CodegenSession.WriterHelper.IsAutoPackedType(underlyingTypeRef)) + processor.Emit(OpCodes.Ldc_I4, (int)AutoPackType.Packed); + + processor.Emit(OpCodes.Call, readMethodRef); + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdReaderMd); + } + + + /// + /// Creates a read for a class type which inherits NetworkBehaviour. + /// + /// + /// + private MethodReference GetNetworkBehaviourReaderMethodReference(TypeReference objectTr) + { + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + TypeReference networkBehaviourTypeRef = CodegenSession.GeneralHelper.GetTypeReference(typeof(NetworkBehaviour)); + + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.ReaderHelper.GetFavoredReadMethodReference(networkBehaviourTypeRef, true)); + processor.Emit(OpCodes.Castclass, objectTr); + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdReaderMd); + } + + /// + /// Create a reader for an array or list. + /// + private MethodReference CreateArrayReaderMethodReference(TypeReference objectTr) + { + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + TypeReference elementTypeRef = objectTr.GetElementType(); + MethodReference readMethodRef = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(elementTypeRef, true); + if (readMethodRef == null) + return null; + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + + ParameterDefinition readerParameterDef = createdReaderMd.Parameters[0]; + VariableDefinition sizeVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, typeof(int)); + //Load packed whole value into sizeVariableDef, exit if null indicator. + CodegenSession.ReaderHelper.CreateRetOnNull(processor, readerParameterDef, sizeVariableDef, false); + + //Make local variable of array type. + VariableDefinition collectionVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, objectTr); + //Create new array/list of size. + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Newarr, elementTypeRef); + //Store new object of arr/list into collection variable. + processor.Emit(OpCodes.Stloc, collectionVariableDef); + + VariableDefinition loopIndex = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, typeof(int)); + Instruction loopComparer = processor.Create(OpCodes.Ldloc, loopIndex); + + //int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, loopIndex); + processor.Emit(OpCodes.Br_S, loopComparer); + + //Loop content. + //Collection[index] + Instruction contentStart = processor.Create(OpCodes.Ldloc, collectionVariableDef); + processor.Append(contentStart); + /* Only arrays load the index since we are setting to that index. + * List call lst.Add */ + processor.Emit(OpCodes.Ldloc, loopIndex); + //Collection[index] = reader. + processor.Emit(OpCodes.Ldarg, readerParameterDef); + //Pass in AutoPackType default. + if (CodegenSession.ReaderHelper.IsAutoPackedType(elementTypeRef)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(elementTypeRef); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //Collection[index] = reader.ReadType(). + processor.Emit(OpCodes.Call, readMethodRef); + //Set value to collection. + processor.Emit(OpCodes.Stelem_Any, elementTypeRef); + + //i++ + processor.Emit(OpCodes.Ldloc, loopIndex); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, loopIndex); + //if i < length jmp to content start. + processor.Append(loopComparer); //if i < size + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Blt_S, contentStart); + + processor.Emit(OpCodes.Ldloc, collectionVariableDef); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdReaderMd); + } + + /// + /// Creates a reader for a dictionary. + /// + private MethodReference CreateDictionaryReaderMethodReference(TypeReference objectTr) + { + GenericInstanceType genericInstance = (GenericInstanceType)objectTr; + CodegenSession.ImportReference(genericInstance); + TypeReference keyTr = genericInstance.GenericArguments[0]; + TypeReference valueTr = genericInstance.GenericArguments[1]; + + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + MethodReference keyWriteMr = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(keyTr, true); + MethodReference valueWriteMr = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(valueTr, true); + if (keyWriteMr == null || valueWriteMr == null) + return null; + + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + GenericInstanceMethod genericInstanceMethod = CodegenSession.ReaderHelper.Reader_ReadDictionary_MethodRef.MakeGenericMethod(new TypeReference[] { keyTr, valueTr }); + + ParameterDefinition readerPd = createdReaderMd.Parameters[0]; + processor.Emit(OpCodes.Ldarg, readerPd); + processor.Emit(OpCodes.Callvirt, genericInstanceMethod); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdReaderMd); + } + + + /// + /// Create a reader for a list. + /// + private MethodReference CreateListReaderMethodReference(TypeReference objectTr) + { + GenericInstanceType genericInstance = (GenericInstanceType)objectTr; + CodegenSession.ImportReference(genericInstance); + TypeReference elementTypeRef = genericInstance.GenericArguments[0]; + + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + MethodReference readMethodRef = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(elementTypeRef, true); + if (readMethodRef == null) + return null; + + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + + //Find constructor for new list. + MethodDefinition constructorMd = objectTr.CachedResolve().GetConstructor(new Type[] { typeof(int) }); + MethodReference constructorMr = constructorMd.MakeHostInstanceGeneric(genericInstance); + //Find add method for list. + MethodReference lstAddMd = objectTr.CachedResolve().GetMethod("Add"); + MethodReference lstAddMr = lstAddMd.MakeHostInstanceGeneric(genericInstance); + + ParameterDefinition readerParameterDef = createdReaderMd.Parameters[0]; + VariableDefinition sizeVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, typeof(int)); + //Load packed whole value into sizeVariableDef, exit if null indicator. + CodegenSession.ReaderHelper.CreateRetOnNull(processor, readerParameterDef, sizeVariableDef, false); + + //Make variable of new list type, and create list object. + VariableDefinition collectionVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, genericInstance); + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Newobj, constructorMr); + processor.Emit(OpCodes.Stloc, collectionVariableDef); + + VariableDefinition loopIndex = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, typeof(int)); + Instruction loopComparer = processor.Create(OpCodes.Ldloc, loopIndex); + + //int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, loopIndex); + processor.Emit(OpCodes.Br_S, loopComparer); + + //Loop content. + //Collection[index] + Instruction contentStart = processor.Create(OpCodes.Ldloc, collectionVariableDef); + processor.Append(contentStart); + //Collection[index] = reader. + processor.Emit(OpCodes.Ldarg, readerParameterDef); + //Pass in AutoPackType default. + if (CodegenSession.ReaderHelper.IsAutoPackedType(elementTypeRef)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(elementTypeRef); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //Collection[index] = reader.ReadType(). + processor.Emit(OpCodes.Call, readMethodRef); + //Set value to collection. + processor.Emit(OpCodes.Callvirt, lstAddMr); + + //i++ + processor.Emit(OpCodes.Ldloc, loopIndex); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, loopIndex); + //if i < length jmp to content start. + processor.Append(loopComparer); //if i < size + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Blt_S, contentStart); + + processor.Emit(OpCodes.Ldloc, collectionVariableDef); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdReaderMd); + } + + + /// + /// Creates a reader method for a struct or class objectTypeRef. + /// + /// + /// + private MethodReference CreateNullableReaderMethodReference(TypeReference objectTr) + { + GenericInstanceType objectGit = objectTr as GenericInstanceType; + TypeReference valueTr = objectGit.GenericArguments[0]; + + //Make sure object has a ctor. + MethodDefinition objectCtorMd = objectTr.GetConstructor(1); + if (objectCtorMd == null) + { + CodegenSession.LogError($"{objectTr.Name} can't be deserialized because the nullable type does not have a constructor."); + return null; + } + + //Get the reader for the value. + MethodReference valueReaderMr = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(valueTr, true); + if (valueReaderMr == null) + return null; + + TypeDefinition objectTd = objectTr.CachedResolve(); + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + + ParameterDefinition readerPd = createdReaderMd.Parameters[0]; + // create local for return value + VariableDefinition resultVd = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, objectTr); + + //Read if null into boolean. + VariableDefinition nullBoolVd = createdReaderMd.CreateVariable(typeof(bool)); + CodegenSession.ReaderHelper.CreateReadBool(processor, readerPd, nullBoolVd); + + Instruction afterReturnNullInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, nullBoolVd); + processor.Emit(OpCodes.Brfalse, afterReturnNullInst); + //Return a null result. + CodegenSession.GeneralHelper.SetVariableDefinitionFromObject(processor, resultVd, objectTd); + processor.Emit(OpCodes.Ldloc, resultVd); + processor.Emit(OpCodes.Ret); + processor.Append(afterReturnNullInst); + + MethodReference initMr = objectCtorMd.MakeHostInstanceGeneric(objectGit); + processor.Emit(OpCodes.Ldarg, readerPd); + //If an auto pack method then insert default value. + if (CodegenSession.ReaderHelper.IsAutoPackedType(valueTr)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(valueTr); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + processor.Emit(OpCodes.Call, valueReaderMr); + processor.Emit(OpCodes.Newobj, initMr); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdReaderMd); + } + + + /// + /// Creates a reader method for a struct or class objectTypeRef. + /// + /// + /// + private MethodReference CreateClassOrStructReaderMethodReference(TypeReference objectTr) + { + MethodDefinition createdReaderMd = CreateStaticReaderStubMethodDefinition(objectTr); + AddToStaticReaders(objectTr, createdReaderMd); + + TypeDefinition objectTypeDef = objectTr.CachedResolve(); + ILProcessor processor = createdReaderMd.Body.GetILProcessor(); + + ParameterDefinition readerParameterDef = createdReaderMd.Parameters[0]; + // create local for return value + VariableDefinition objectVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, objectTr); + + //If not a value type create a return null check. + if (!objectTypeDef.IsValueType) + { + VariableDefinition nullVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdReaderMd, typeof(bool)); + //Load packed whole value into sizeVariableDef, exit if null indicator. + CodegenSession.ReaderHelper.CreateRetOnNull(processor, readerParameterDef, nullVariableDef, true); + } + + /* If here then not null. */ + //Make a new instance of object type and set to objectVariableDef. + CodegenSession.GeneralHelper.SetVariableDefinitionFromObject(processor, objectVariableDef, objectTypeDef); + if (!ReadFieldsAndProperties(createdReaderMd, readerParameterDef, objectVariableDef, objectTr)) + return null; + /* //codegen scriptableobjects seem to climb too high up to UnityEngine.Object when + * creating serializers/deserialized. Make sure this is not possible. */ + + //Load result and return it. + processor.Emit(OpCodes.Ldloc, objectVariableDef); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdReaderMd); + } + + + /// + /// Reads all fields of objectTypeRef. + /// + private bool ReadFieldsAndProperties(MethodDefinition readerMd, ParameterDefinition readerPd, VariableDefinition objectVd, TypeReference objectTr) + { + //This probably isn't needed but I'm too afraid to remove it. + if (objectTr.Module != CodegenSession.Module) + objectTr = CodegenSession.ImportReference(objectTr.CachedResolve()); + + //Fields. + foreach (FieldDefinition fieldDef in objectTr.FindAllPublicFields(true, true, + ReaderHelper.EXCLUDED_AUTO_SERIALIZER_TYPES, ReaderHelper.EXCLUDED_ASSEMBLY_PREFIXES)) + { + FieldReference importedFr = CodegenSession.ImportReference(fieldDef); + if (GetReadMethod(fieldDef.FieldType, out MethodReference readMr)) + CodegenSession.ReaderHelper.CreateReadIntoClassOrStruct(readerMd, readerPd, readMr, objectVd, importedFr); + } + + //Properties. + foreach (PropertyDefinition propertyDef in objectTr.FindAllPublicProperties( + true, ReaderHelper.EXCLUDED_AUTO_SERIALIZER_TYPES, ReaderHelper.EXCLUDED_ASSEMBLY_PREFIXES)) + { + if (GetReadMethod(propertyDef.PropertyType, out MethodReference readMr)) + { + MethodReference setMr = CodegenSession.Module.ImportReference(propertyDef.SetMethod); + CodegenSession.ReaderHelper.CreateReadIntoClassOrStruct(readerMd, readerPd, readMr, objectVd, setMr, propertyDef.PropertyType); + } + } + + //Gets or creates writer method and outputs it. Returns true if method is found or created. + bool GetReadMethod(TypeReference tr, out MethodReference readMr) + { + tr = CodegenSession.ImportReference(tr); + readMr = CodegenSession.ReaderHelper.GetOrCreateFavoredReadMethodReference(tr, true); + return (readMr != null); + } + + return true; + } + + + /// + /// Creates the stub for a new reader method. + /// + /// + /// + private MethodDefinition CreateStaticReaderStubMethodDefinition(TypeReference objectTypeRef, string nameExtension = "") + { + string methodName = $"{READ_PREFIX}{objectTypeRef.FullName}{nameExtension}s"; + // create new reader for this type + TypeDefinition readerTypeDef = CodegenSession.GeneralHelper.GetOrCreateClass(out _, GENERATED_TYPE_ATTRIBUTES, GENERATED_READERS_CLASS_NAME, null); + MethodDefinition readerMethodDef = readerTypeDef.AddMethod(methodName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig, + objectTypeRef); + + CodegenSession.GeneralHelper.CreateParameter(readerMethodDef, CodegenSession.ReaderHelper.Reader_TypeRef, "reader"); + readerMethodDef.Body.InitLocals = true; + + return readerMethodDef; + } + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs.meta new file mode 100644 index 0000000..9ff807d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a8afc0f62ceeaee45aa496ba5650d010 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs new file mode 100644 index 0000000..159ffa9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs @@ -0,0 +1,478 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.ILCore; +using FishNet.Connection; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + internal class ReaderHelper + { + #region Reflection references. + internal TypeReference PooledReader_TypeRef; + internal TypeReference Reader_TypeRef; + internal TypeReference NetworkConnection_TypeRef; + internal MethodReference PooledReader_ReadNetworkBehaviour_MethodRef; + private readonly Dictionary _instancedReaderMethods = new Dictionary(new TypeReferenceComparer()); + private readonly Dictionary _staticReaderMethods = new Dictionary(new TypeReferenceComparer()); + private HashSet _autoPackedMethods = new HashSet(new TypeReferenceComparer()); + private MethodReference Reader_ReadPackedWhole_MethodRef; + internal MethodReference Reader_ReadDictionary_MethodRef; + internal MethodReference Reader_ReadToCollection_MethodRef; + #endregion + + #region Const. + internal const string READ_PREFIX = "Read"; + /// + /// Types to exclude from being scanned for auto serialization. + /// + public static System.Type[] EXCLUDED_AUTO_SERIALIZER_TYPES => WriterHelper.EXCLUDED_AUTO_SERIALIZER_TYPES; + /// + /// Types to exclude from being scanned for auto serialization. + /// + public static string[] EXCLUDED_ASSEMBLY_PREFIXES => WriterHelper.EXCLUDED_ASSEMBLY_PREFIXES; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + PooledReader_TypeRef = CodegenSession.ImportReference(typeof(PooledReader)); + Reader_TypeRef = CodegenSession.ImportReference(typeof(Reader)); + NetworkConnection_TypeRef = CodegenSession.ImportReference(typeof(NetworkConnection)); + + Type pooledReaderType = typeof(PooledReader); + + foreach (MethodInfo methodInfo in pooledReaderType.GetMethods()) + { + /* Special methods. */ + //ReadPackedWhole. + if (methodInfo.Name == nameof(PooledReader.ReadPackedWhole)) + { + Reader_ReadPackedWhole_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + //ReadToCollection. + else if (methodInfo.Name == nameof(PooledReader.ReadArray)) + { + Reader_ReadToCollection_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + //ReadDictionary. + else if (methodInfo.Name == nameof(PooledReader.ReadDictionary)) + { + Reader_ReadDictionary_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + + else if (CodegenSession.GeneralHelper.CodegenExclude(methodInfo)) + continue; + //Generic methods are not supported. + else if (methodInfo.IsGenericMethod) + continue; + //Not long enough to be a write method. + else if (methodInfo.Name.Length < READ_PREFIX.Length) + continue; + //Method name doesn't start with writePrefix. + else if (methodInfo.Name.Substring(0, READ_PREFIX.Length) != READ_PREFIX) + continue; + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + //Can have at most one parameter for packing. + if (parameterInfos.Length > 1) + continue; + //If has one parameter make sure it's a packing type. + bool autoPackMethod = false; + if (parameterInfos.Length == 1) + { + autoPackMethod = (parameterInfos[0].ParameterType == typeof(AutoPackType)); + if (!autoPackMethod) + continue; + } + + /* TypeReference for the return type + * of the read method. */ + TypeReference typeRef = CodegenSession.ImportReference(methodInfo.ReturnType); + MethodReference methodRef = CodegenSession.ImportReference(methodInfo); + + /* If here all checks pass. */ + AddReaderMethod(typeRef, methodRef, true, true); + if (autoPackMethod) + _autoPackedMethods.Add(typeRef); + } + + Type readerExtensionsType = typeof(ReaderExtensions); + + foreach (MethodInfo methodInfo in readerExtensionsType.GetMethods()) + { + if (CodegenSession.GeneralHelper.CodegenExclude(methodInfo)) + continue; + //Generic methods are not supported. + if (methodInfo.IsGenericMethod) + continue; + //Not static. + if (!methodInfo.IsStatic) + continue; + //Not long enough to be a write method. + if (methodInfo.Name.Length < READ_PREFIX.Length) + continue; + //Method name doesn't start with writePrefix. + if (methodInfo.Name.Substring(0, READ_PREFIX.Length) != READ_PREFIX) + continue; + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + //Can have at most one parameter for packing. + if (parameterInfos.Length > 2) + continue; + //If has 2 parameters make sure it's a packing type. + bool autoPackMethod = false; + if (parameterInfos.Length == 2) + { + autoPackMethod = (parameterInfos[1].ParameterType == typeof(AutoPackType)); + if (!autoPackMethod) + continue; + } + + /* TypeReference for the return type + * of the read method. */ + TypeReference typeRef = CodegenSession.ImportReference(methodInfo.ReturnType); + MethodReference methodRef = CodegenSession.ImportReference(methodInfo); + + /* If here all checks pass. */ + AddReaderMethod(typeRef, methodRef, false, true); + } + + + return true; + } + + + /// + /// Creates generic write delegates for all currently known write types. + /// + internal bool CreateGenericDelegates() + { + bool modified = false; + /* Only write statics. This will include extensions and generated. */ + foreach (KeyValuePair item in _staticReaderMethods) + { + if (FishNetILPP.CODEGEN_THIS_NAMESPACE.Length == 0 || item.Key.FullName.Contains(FishNetILPP.CODEGEN_THIS_NAMESPACE)) + { + CodegenSession.GenericReaderHelper.CreateReadDelegate(item.Value); + modified = true; + } + } + + return modified; + } + + + /// + /// Returns if typeRef has a deserializer. + /// + /// + /// + /// + internal bool HasDeserializer(TypeReference typeRef, bool createMissing) + { + bool result = (GetInstancedReadMethodReference(typeRef) != null) || + (GetStaticReadMethodReference(typeRef) != null); + + if (!result && createMissing) + { + if (!CodegenSession.GeneralHelper.HasNonSerializableAttribute(typeRef.CachedResolve())) + { + MethodReference methodRef = CodegenSession.ReaderGenerator.CreateReader(typeRef); + result = (methodRef != null); + } + } + + return result; + } + + + /// + /// Returns if typeRef supports auto packing. + /// + /// + /// + internal bool IsAutoPackedType(TypeReference typeRef) + { + return _autoPackedMethods.Contains(typeRef); + } + /// + /// Creates a null check on the first argument and returns a null object if result indicates to do so. + /// + internal void CreateRetOnNull(ILProcessor processor, ParameterDefinition readerParameterDef, VariableDefinition resultVariableDef, bool useBool) + { + Instruction endIf = processor.Create(OpCodes.Nop); + + if (useBool) + CreateReadBool(processor, readerParameterDef, resultVariableDef); + else + CreateReadPackedWhole(processor, readerParameterDef, resultVariableDef); + + //If (true or == -1) jmp to endIf. True is null. + processor.Emit(OpCodes.Ldloc, resultVariableDef); + if (useBool) + { + processor.Emit(OpCodes.Brfalse, endIf); + } + else + { + //-1 + processor.Emit(OpCodes.Ldc_I4_M1); + processor.Emit(OpCodes.Bne_Un_S, endIf); + } + //Insert null. + processor.Emit(OpCodes.Ldnull); + //Exit method. + processor.Emit(OpCodes.Ret); + //End of if check. + processor.Append(endIf); + } + + /// + /// Creates a call to WriteBoolean with value. + /// + /// + /// + /// + internal void CreateReadBool(ILProcessor processor, ParameterDefinition readerParameterDef, VariableDefinition localBoolVariableDef) + { + MethodReference readBoolMethodRef = GetFavoredReadMethodReference(CodegenSession.GeneralHelper.GetTypeReference(typeof(bool)), true); + processor.Emit(OpCodes.Ldarg, readerParameterDef); + processor.Emit(OpCodes.Callvirt, readBoolMethodRef); + processor.Emit(OpCodes.Stloc, localBoolVariableDef); + } + + /// + /// Creates a call to WritePackWhole with value. + /// + /// + /// + internal void CreateReadPackedWhole(ILProcessor processor, ParameterDefinition readerParameterDef, VariableDefinition resultVariableDef) + { + //Reader. + processor.Emit(OpCodes.Ldarg, readerParameterDef); + //Reader.ReadPackedWhole(). + processor.Emit(OpCodes.Callvirt, Reader_ReadPackedWhole_MethodRef); + processor.Emit(OpCodes.Conv_I4); + processor.Emit(OpCodes.Stloc, resultVariableDef); + } + + + #region GetReaderMethodReference. + /// + /// Returns the MethodReference for typeRef. + /// + /// + /// + internal MethodReference GetInstancedReadMethodReference(TypeReference typeRef) + { + _instancedReaderMethods.TryGetValue(typeRef, out MethodReference methodRef); + return methodRef; + } + /// + /// Returns the MethodReference for typeRef. + /// + /// + /// + internal MethodReference GetStaticReadMethodReference(TypeReference typeRef) + { + _staticReaderMethods.TryGetValue(typeRef, out MethodReference methodRef); + return methodRef; + } + /// + /// Returns the MethodReference for typeRef favoring instanced or static. Returns null if not found. + /// + /// + /// + /// + internal MethodReference GetFavoredReadMethodReference(TypeReference typeRef, bool favorInstanced) + { + MethodReference result; + if (favorInstanced) + { + result = GetInstancedReadMethodReference(typeRef); + if (result == null) + result = GetStaticReadMethodReference(typeRef); + } + else + { + result = GetStaticReadMethodReference(typeRef); + if (result == null) + result = GetInstancedReadMethodReference(typeRef); + } + + return result; + } + /// + /// Returns the MethodReference for typeRef favoring instanced or static. + /// + /// + /// + /// + internal MethodReference GetOrCreateFavoredReadMethodReference(TypeReference typeRef, bool favorInstanced) + { + //Try to get existing writer, if not present make one. + MethodReference readMethodRef = GetFavoredReadMethodReference(typeRef, favorInstanced); + if (readMethodRef == null) + readMethodRef = CodegenSession.ReaderGenerator.CreateReader(typeRef); + if (readMethodRef == null) + CodegenSession.LogError($"Could not create deserializer for {typeRef.FullName}."); + + return readMethodRef; + } + #endregion + + /// + /// Adds typeRef, methodDef to instanced or readerMethods. + /// + /// + /// + /// + internal void AddReaderMethod(TypeReference typeRef, MethodReference methodRef, bool instanced, bool useAdd) + { + Dictionary dict = (instanced) ? + _instancedReaderMethods : _staticReaderMethods; + + if (useAdd) + dict.Add(typeRef, methodRef); + else + dict[typeRef] = methodRef; + } + + /// + /// Removes typeRef from static/instanced reader methods. + /// + internal void RemoveReaderMethod(TypeReference typeRef, bool instanced) + { + Dictionary dict = (instanced) ? + _instancedReaderMethods : _staticReaderMethods; + + dict.Remove(typeRef); + } + + /// + /// Creates read instructions returning instructions and outputing variable of read result. + /// + /// + /// + /// + /// + /// + /// + internal List CreateRead(MethodDefinition methodDef, ParameterDefinition readerParameterDef, TypeReference readTypeRef, out VariableDefinition createdVariableDef) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + List insts = new List(); + MethodReference readerMethodRef = GetFavoredReadMethodReference(readTypeRef, true); + if (readerMethodRef != null) + { + //Make a local variable. + createdVariableDef = CodegenSession.GeneralHelper.CreateVariable(methodDef, readTypeRef); + //pooledReader.ReadBool(); + insts.Add(processor.Create(OpCodes.Ldarg, readerParameterDef)); + //If an auto pack method then insert default value. + if (_autoPackedMethods.Contains(readTypeRef)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(readTypeRef); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)packType)); + } + insts.Add(processor.Create(OpCodes.Call, readerMethodRef)); + //Store into local variable. + insts.Add(processor.Create(OpCodes.Stloc, createdVariableDef)); + return insts; + } + else + { + CodegenSession.LogError("Reader not found for " + readTypeRef.ToString()); + createdVariableDef = null; + return null; + } + } + + + + /// + /// Creates a read for fieldRef and populates it into a created variable of class or struct type. + /// + internal bool CreateReadIntoClassOrStruct(MethodDefinition readerMd, ParameterDefinition readerPd, MethodReference readMr, VariableDefinition objectVd, FieldReference valueFr) + { + if (readMr != null) + { + ILProcessor processor = readerMd.Body.GetILProcessor(); + /* How to load object instance. If it's a structure + * then it must be loaded by address. Otherwise if + * class Ldloc can be used. */ + OpCode loadOpCode = (objectVd.VariableType.IsValueType) ? + OpCodes.Ldloca : OpCodes.Ldloc; + + processor.Emit(loadOpCode, objectVd); + //reader. + processor.Emit(OpCodes.Ldarg, readerPd); + if (IsAutoPackedType(valueFr.FieldType)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(valueFr.FieldType); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //reader.ReadXXXX(). + processor.Emit(OpCodes.Call, readMr); + //obj.Field = result / reader.ReadXXXX(). + processor.Emit(OpCodes.Stfld, valueFr); + + return true; + } + else + { + CodegenSession.LogError($"Reader not found for {valueFr.FullName}."); + return false; + } + } + + + /// + /// Creates a read for fieldRef and populates it into a created variable of class or struct type. + /// + internal bool CreateReadIntoClassOrStruct(MethodDefinition methodDef, ParameterDefinition readerPd, MethodReference readMr, VariableDefinition objectVariableDef, MethodReference setMr, TypeReference readTr) + { + if (readMr != null) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + /* How to load object instance. If it's a structure + * then it must be loaded by address. Otherwise if + * class Ldloc can be used. */ + OpCode loadOpCode = (objectVariableDef.VariableType.IsValueType) ? + OpCodes.Ldloca : OpCodes.Ldloc; + + processor.Emit(loadOpCode, objectVariableDef); + //reader. + processor.Emit(OpCodes.Ldarg, readerPd); + if (IsAutoPackedType(readTr)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(readTr); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //reader.ReadXXXX(). + processor.Emit(OpCodes.Call, readMr); + //obj.Property = result / reader.ReadXXXX(). + processor.Emit(OpCodes.Call, setMr); + + return true; + } + else + { + CodegenSession.LogError($"Reader not found for {readTr.FullName}."); + return false; + } + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta new file mode 100644 index 0000000..e491410 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 350861dcbcbabc447acd37e4310b0697 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs new file mode 100644 index 0000000..2b5f18a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs @@ -0,0 +1,51 @@ +using FishNet.Managing.Timing; +using MonoFN.Cecil; +using System; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + + internal class TimeManagerHelper + { + + #region Reflection references. + internal MethodReference LocalTick_MethodRef; + internal MethodReference TickDelta_MethodRef; + internal MethodReference MaximumBufferedInputs_MethodRef; + internal MethodReference PhysicsMode_MethodRef; + internal MethodReference InvokeOnReconcile_MethodRef; + internal MethodReference InvokeOnReplicateReplay_MethodRef; + #endregion + + + internal bool ImportReferences() + { + //TimeManager infos. + Type timeManagerType = typeof(TimeManager); + foreach (System.Reflection.PropertyInfo pi in timeManagerType.GetProperties()) + { + if (pi.Name == nameof(TimeManager.LocalTick)) + LocalTick_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(TimeManager.MaximumBufferedInputs)) + MaximumBufferedInputs_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(TimeManager.PhysicsMode)) + PhysicsMode_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + else if (pi.Name == nameof(TimeManager.TickDelta)) + TickDelta_MethodRef = CodegenSession.ImportReference(pi.GetMethod); + } + + foreach (System.Reflection.MethodInfo mi in timeManagerType.GetMethods()) + { + if (mi.Name == nameof(TimeManager.InvokeOnReconcile)) + InvokeOnReconcile_MethodRef = CodegenSession.ImportReference(mi); + else if (mi.Name == nameof(TimeManager.InvokeOnReplicateReplay)) + InvokeOnReplicateReplay_MethodRef = CodegenSession.ImportReference(mi); + } + + return true; + } + + + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs.meta new file mode 100644 index 0000000..a247b73 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11dbcc0798e079e4a85fe98dfc9fe23a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs new file mode 100644 index 0000000..261611b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs @@ -0,0 +1,36 @@ +using FishNet.Transporting; +using MonoFN.Cecil; + +namespace FishNet.CodeGenerating.Helping +{ + internal class TransportHelper + { + #region Reflection references. + internal TypeReference Channel_TypeRef; + #endregion + + /// + /// Resets cached values. + /// + private void ResetValues() + { + Channel_TypeRef = null; + } + + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + ResetValues(); + + Channel_TypeRef = CodegenSession.ImportReference(typeof(Channel)); + + return true; + } + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs.meta new file mode 100644 index 0000000..9821f2c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ced44bfdb3068f4cb7513c9be85729a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed.meta new file mode 100644 index 0000000..f51ce71 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 192c16e1ad7eca84cbcc19073c945ca9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs new file mode 100644 index 0000000..429a0d4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs @@ -0,0 +1,34 @@ +using MonoFN.Cecil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + internal class TypeDefinitionComparer : IEqualityComparer + { + public bool Equals(TypeDefinition a, TypeDefinition b) + { + return a.FullName == b.FullName; + } + + public int GetHashCode(TypeDefinition obj) + { + return obj.FullName.GetHashCode(); + } + } + + + internal class TypeReferenceComparer : IEqualityComparer + { + public bool Equals(TypeReference a, TypeReference b) + { + return a.FullName == b.FullName; + } + + public int GetHashCode(TypeReference obj) + { + return obj.FullName.GetHashCode(); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs.meta new file mode 100644 index 0000000..dff182e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b30600f0fdb27c4fb86c310b08f43b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs new file mode 100644 index 0000000..c6cf9a0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs @@ -0,0 +1,49 @@ +using MonoFN.Cecil; + +namespace FishNet.CodeGenerating.Helping +{ + + + + internal class CreatedSyncVar + { + public readonly TypeDefinition VariableTd; + public readonly MethodReference GetValueMr; + public readonly MethodReference SetValueMr; + public readonly MethodReference SetSyncIndexMr; + public readonly MethodReference ConstructorMr; + public readonly GenericInstanceType SyncVarGit; + public MethodReference HookMr; + public CreatedSyncVar(GenericInstanceType syncVarGit, TypeDefinition variableTd, MethodReference getValueMr, MethodReference setValueMr, MethodReference setSyncIndexMr,MethodReference hookMr, MethodReference constructorMr) + { + SyncVarGit = syncVarGit; + VariableTd = variableTd; + GetValueMr = getValueMr; + SetValueMr = setValueMr; + SetSyncIndexMr = setSyncIndexMr; + HookMr = hookMr; + ConstructorMr = constructorMr; + } + } + + + internal class CreatedSyncType + { + public TypeDefinition StubClassTypeDefinition; + public MethodReference GetValueMethodReference; + public MethodReference SetValueMethodReference; + public MethodReference GetPreviousClientValueMethodReference; + public MethodReference ReadMethodReference; + public MethodReference ConstructorMethodReference; + public CreatedSyncType(TypeDefinition stubClassTypeDef, MethodReference getMethodRef, MethodReference setMethodRef, MethodReference getPreviousMethodRef, MethodReference readMethodRef, MethodReference constructorMethodRef) + { + StubClassTypeDefinition = stubClassTypeDef; + GetValueMethodReference = getMethodRef; + SetValueMethodReference = setMethodRef; + GetPreviousClientValueMethodReference = getPreviousMethodRef; + ReadMethodReference = readMethodRef; + ConstructorMethodReference = constructorMethodRef; + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs.meta new file mode 100644 index 0000000..2a0abc7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/CreatedSyncType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cae698c9bc732641892caabf04365dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs new file mode 100644 index 0000000..84709b8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs @@ -0,0 +1,180 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Object; +using MonoFN.Cecil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + + + internal static class GeneratorHelper + { + /// + /// Gets what objectTypeRef will be serialized as. + /// + /// + /// + /// + /// + /// + internal static SerializerType GetSerializerType(TypeReference objectTr, bool writer, out TypeDefinition objectTd) + { + string errorPrefix = (writer) ? "CreateWrite: " : "CreateRead: "; + objectTd = null; + + /* Check if already has a serializer. */ + if (writer) + { + if (CodegenSession.WriterHelper.GetFavoredWriteMethodReference(objectTr, true) != null) + { + CodegenSession.LogError($"Writer already exist for {objectTr.FullName}."); + return SerializerType.Invalid; + } + } + else + { + if (CodegenSession.ReaderHelper.GetFavoredReadMethodReference(objectTr, true) != null) + { + CodegenSession.LogError($"Reader already exist for {objectTr.FullName}."); + return SerializerType.Invalid; + } + } + + objectTd = objectTr.CachedResolve(); + //Invalid typeDef. + if (objectTd == null) + { + CodegenSession.LogError($"{errorPrefix}{objectTd.FullName} could not be resolved."); + return SerializerType.Invalid; + } + //By reference. + if (objectTr.IsByReference) + { + CodegenSession.LogError($"{errorPrefix}Cannot pass {objectTr.Name} by reference"); + return SerializerType.Invalid; + } + /* Arrays have to be processed first because it's possible for them to meet other conditions + * below and be processed wrong. */ + else if (objectTr.IsArray) + { + if (objectTr.IsMultidimensionalArray()) + { + CodegenSession.LogError($"{errorPrefix}{objectTr.Name} is an unsupported type. Multidimensional arrays are not supported"); + return SerializerType.Invalid; + } + else + { + return SerializerType.Array; + } + } + //Enum. + else if (objectTd.IsEnum) + { + return SerializerType.Enum; + } + else if (objectTd.Is(typeof(Dictionary<,>))) + { + return SerializerType.Dictionary; + } + else if (objectTd.Is(typeof(List<>))) + { + return SerializerType.List; + } + else if (objectTd.InheritsFrom()) + { + return SerializerType.NetworkBehaviour; + } + else if (objectTr.Name == typeof(System.Nullable<>).Name) + { + GenericInstanceType git = objectTr as GenericInstanceType; + if (git == null || git.GenericArguments.Count != 1) + return SerializerType.Invalid; + else + return SerializerType.Nullable; + } + //Invalid type. This must be called after trying to generate everything but class. + else if (!GeneratorHelper.IsValidSerializeType(objectTd)) + { + return SerializerType.Invalid; + } + //If here then the only type left is struct or class. + else if (objectTr.IsClassOrStruct()) + { + return SerializerType.ClassOrStruct; + } + //Unknown type. + else + { + CodegenSession.LogError($"{errorPrefix}{objectTr.Name} is an unsupported type. Mostly because we don't know what the heck it is. Please let us know so we can fix this."); + return SerializerType.Invalid; + } + } + + + /// + /// Returns if objectTypeRef is an invalid type, which cannot be serialized. + /// + /// + /// + private static bool IsValidSerializeType(TypeDefinition objectTd) //todo rename. applies only to types which do not have a user made or included serializer. + { + string errorText = $"{objectTd.Name} is not a supported type. Use a supported type or provide a custom serializer"; + + System.Type unityObjectType = typeof(UnityEngine.Object); + //Unable to determine type, cannot generate for. + if (objectTd == null) + { + CodegenSession.LogError(errorText); + return false; + } + //Component. + if (objectTd.InheritsFrom()) + { + CodegenSession.LogError(errorText); + return false; + } + //Unity Object. + if (objectTd.Is(unityObjectType)) + { + CodegenSession.LogError(errorText); + return false; + } + //ScriptableObject. + if (objectTd.Is(typeof(UnityEngine.ScriptableObject))) + { + CodegenSession.LogError(errorText); + return false; + } + //Has generic parameters. + if (objectTd.HasGenericParameters) + { + CodegenSession.LogError(errorText); + return false; + } + //Is an interface. + if (objectTd.IsInterface) + { + CodegenSession.LogError(errorText); + return false; + } + //Is abstract. + if (objectTd.IsAbstract) + { + CodegenSession.LogError(errorText); + return false; + } + if (objectTd.InheritsFrom(unityObjectType) && objectTd.IsExcluded(GeneralHelper.UNITYENGINE_ASSEMBLY_PREFIX)) + { + CodegenSession.LogError(errorText); + return false; + } + + //If here type is valid. + return true; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs.meta new file mode 100644 index 0000000..bf4c3fa --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b1882eac63e3d94aad8f41915bc1ab8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs new file mode 100644 index 0000000..314c3d2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs @@ -0,0 +1,12 @@ +namespace FishNet.CodeGenerating.Helping +{ + + internal enum QolAttributeType + { + None, + Server, + Client + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs.meta new file mode 100644 index 0000000..f6a473d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/QOLAttributeType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 357a22940018b8e49976e13272c5b2ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs new file mode 100644 index 0000000..787d647 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs @@ -0,0 +1,19 @@ +namespace FishNet.CodeGenerating.Helping +{ + + internal enum SerializerType + { + Invalid, + Enum, + Array, + List, + NetworkBehaviour, + ClassOrStruct, + Nullable, + Dictionary, + Null, + ByReference, + MultiDimensionalArray + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs.meta new file mode 100644 index 0000000..a993edc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SerializatierType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7f1bbf5c398c3e4e92e53ec3e49d5e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs new file mode 100644 index 0000000..ecede30 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs @@ -0,0 +1,17 @@ +using MonoFN.Cecil.Cil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Helping +{ + + /// + /// Data used to modify an RpcIndex should the class have to be rebuilt. + /// + internal class SyncIndexData + { + public uint SyncCount = 0; + public List DelegateInstructions = new List(); + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs.meta new file mode 100644 index 0000000..a2adbd2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55f2e751e4788464b8394f6b8bdb548a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs new file mode 100644 index 0000000..c5dd521 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs @@ -0,0 +1,14 @@ +namespace FishNet.CodeGenerating.Helping +{ + + public enum SyncType + { + Unset, + Variable, + List, + Dictionary, + HashSet, + Custom + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta new file mode 100644 index 0000000..b60f670 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44c753d6ac0c7864c9962d91703b2afe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs new file mode 100644 index 0000000..29b1bc3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs @@ -0,0 +1,504 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Object; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + internal class WriterGenerator + { + + #region Const. + internal const string GENERATED_WRITERS_CLASS_NAME = "GeneratedWriters___FN"; + public const TypeAttributes GENERATED_TYPE_ATTRIBUTES = (TypeAttributes.BeforeFieldInit | TypeAttributes.Class | TypeAttributes.AnsiClass | + TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Abstract | TypeAttributes.Sealed); + private const string WRITE_PREFIX = "Write___"; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + return true; + } + + /// + /// Generates a writer for objectTypeReference if one does not already exist. + /// + /// + /// + internal MethodReference CreateWriter(TypeReference objectTr) + { + MethodReference methodRefResult = null; + TypeDefinition objectTd; + SerializerType serializerType = GeneratorHelper.GetSerializerType(objectTr, true, out objectTd); + + if (serializerType != SerializerType.Invalid) + { + //Array. + if (serializerType == SerializerType.Array) + methodRefResult = CreateArrayWriterMethodDefinition(objectTr); + //Enum. + else if (serializerType == SerializerType.Enum) + methodRefResult = CreateEnumWriterMethodDefinition(objectTr); + //Dictionary. + else if (serializerType == SerializerType.Dictionary) + methodRefResult = CreateDictionaryWriterMethodReference(objectTr); + //List. + else if (serializerType == SerializerType.List) + methodRefResult = CreateListWriterMethodReference(objectTr); + //NetworkBehaviour. + else if (serializerType == SerializerType.NetworkBehaviour) + methodRefResult = CreateNetworkBehaviourWriterMethodReference(objectTd); + //Nullable type. + else if (serializerType == SerializerType.Nullable) + methodRefResult = CreateNullableWriterMethodReference(objectTr, objectTd); + //Class or struct. + else if (serializerType == SerializerType.ClassOrStruct) + methodRefResult = CreateClassOrStructWriterMethodDefinition(objectTr); + } + + //If was not created. + if (methodRefResult == null) + RemoveFromStaticWriters(objectTr); + + return methodRefResult; + } + + /// + /// Removes from static writers. + /// + private void RemoveFromStaticWriters(TypeReference tr) + { + CodegenSession.WriterHelper.RemoveWriterMethod(tr, false); + } + /// + /// Adds to static writers. + /// + private void AddToStaticWriters(TypeReference tr, MethodReference mr) + { + CodegenSession.WriterHelper.AddWriterMethod(tr, mr.CachedResolve(), false, true); + } + + /// + /// Adds a write for a NetworkBehaviour class type to WriterMethods. + /// + /// + private MethodReference CreateNetworkBehaviourWriterMethodReference(TypeReference objectTr) + { + objectTr = CodegenSession.ImportReference(objectTr.Resolve()); + //All NetworkBehaviour types will simply WriteNetworkBehaviour/ReadNetworkBehaviour. + //Create generated reader/writer class. This class holds all generated reader/writers. + CodegenSession.GeneralHelper.GetOrCreateClass(out _, GENERATED_TYPE_ATTRIBUTES, GENERATED_WRITERS_CLASS_NAME, null); + + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + AddToStaticWriters(objectTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + MethodReference writeMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(CodegenSession.WriterHelper.NetworkBehaviour_TypeRef, true); + //Get parameters for method. + ParameterDefinition writerParameterDef = createdWriterMd.Parameters[0]; + ParameterDefinition classParameterDef = createdWriterMd.Parameters[1]; + + //Load parameters as arguments. + processor.Emit(OpCodes.Ldarg, writerParameterDef); + processor.Emit(OpCodes.Ldarg, classParameterDef); + //writer.WriteNetworkBehaviour(arg1); + processor.Emit(OpCodes.Call, writeMethodRef); + + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdWriterMd); + } + + /// + /// Gets the length of a collection and writes the value to a variable. + /// + private void CreateCollectionLength(ILProcessor processor, ParameterDefinition collectionParameterDef, VariableDefinition storeVariableDef) + { + processor.Emit(OpCodes.Ldarg, collectionParameterDef); + processor.Emit(OpCodes.Ldlen); + processor.Emit(OpCodes.Conv_I4); + processor.Emit(OpCodes.Stloc, storeVariableDef); + } + + + /// + /// Creates a writer for a class or struct of objectTypeRef. + /// + /// + /// + private MethodReference CreateNullableWriterMethodReference(TypeReference objectTr, TypeDefinition objectTd) + { + GenericInstanceType objectGit = objectTr as GenericInstanceType; + TypeReference valueTr = objectGit.GenericArguments[0]; + + //Get the writer for the value. + MethodReference valueWriterMr = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(valueTr, true); + if (valueWriterMr == null) + return null; + + + MethodDefinition tmpMd; + tmpMd = objectTd.GetMethod("get_Value"); + MethodReference genericGetValueMr = tmpMd.MakeHostInstanceGeneric(objectGit); + tmpMd = objectTd.GetMethod("get_HasValue"); + MethodReference genericHasValueMr = tmpMd.MakeHostInstanceGeneric(objectGit); + + + /* Stubs generate Method(Writer writer, T value). */ + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + //Value parameter. + ParameterDefinition valuePd = createdWriterMd.Parameters[1]; + + ParameterDefinition writerPd = createdWriterMd.Parameters[0]; + + //Have to write a new ret on null because nullables use hasValue for null checks. + Instruction afterNullRetInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarga, valuePd); + processor.Emit(OpCodes.Call, genericHasValueMr); + processor.Emit(OpCodes.Brtrue_S, afterNullRetInst); + CodegenSession.WriterHelper.CreateWriteBool(processor, writerPd, true); + processor.Emit(OpCodes.Ret); + processor.Append(afterNullRetInst); + + + //Code will only execute here and below if not null. + CodegenSession.WriterHelper.CreateWriteBool(processor, writerPd, false); + + processor.Emit(OpCodes.Ldarg, writerPd); + processor.Emit(OpCodes.Ldarga, valuePd); + processor.Emit(OpCodes.Call, genericGetValueMr); + //If an auto pack method then insert default value. + if (CodegenSession.WriterHelper.IsAutoPackedType(valueTr)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(valueTr); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + processor.Emit(OpCodes.Call, valueWriterMr); + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdWriterMd); + } + + + + /// + /// Creates a writer for a class or struct of objectTypeRef. + /// + /// + /// + private MethodReference CreateClassOrStructWriterMethodDefinition(TypeReference objectTr) + { + /*Stubs generate Method(Writer writer, T value). */ + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + AddToStaticWriters(objectTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + //If not a value type then add a null check. + if (!objectTr.CachedResolve().IsValueType) + { + ParameterDefinition writerPd = createdWriterMd.Parameters[0]; + CodegenSession.WriterHelper.CreateRetOnNull(processor, writerPd, createdWriterMd.Parameters[1], true); + //Code will only execute here and below if not null. + CodegenSession.WriterHelper.CreateWriteBool(processor, writerPd, false); + } + + //Write all fields for the class or struct. + ParameterDefinition valueParameterDef = createdWriterMd.Parameters[1]; + if (!WriteFieldsAndProperties(createdWriterMd, valueParameterDef, objectTr)) + return null; + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdWriterMd); + } + + /// + /// Find all fields in type and write them + /// + /// + /// + /// false if fail + private bool WriteFieldsAndProperties(MethodDefinition writerMd, ParameterDefinition valuePd, TypeReference objectTr) + { + //This probably isn't needed but I'm too afraid to remove it. + if (objectTr.Module != CodegenSession.Module) + objectTr = CodegenSession.ImportReference(objectTr.CachedResolve()); + + //Fields + foreach (FieldDefinition fieldDef in objectTr.FindAllPublicFields(true, true))//, WriterHelper.EXCLUDED_AUTO_SERIALIZER_TYPES)) + { + if (GetWriteMethod(fieldDef.FieldType, out MethodReference writeMr)) + CodegenSession.WriterHelper.CreateWrite(writerMd, valuePd, fieldDef, writeMr); + } + + //Properties. + foreach (PropertyDefinition propertyDef in objectTr.FindAllPublicProperties( + true, WriterHelper.EXCLUDED_AUTO_SERIALIZER_TYPES, WriterHelper.EXCLUDED_ASSEMBLY_PREFIXES)) + { + if (GetWriteMethod(propertyDef.PropertyType, out MethodReference writerMr)) + { + MethodReference getMr = CodegenSession.Module.ImportReference(propertyDef.GetMethod); + CodegenSession.WriterHelper.CreateWrite(writerMd, valuePd, getMr, writerMr); + } + } + + //Gets or creates writer method and outputs it. Returns true if method is found or created. + bool GetWriteMethod(TypeReference tr, out MethodReference writeMr) + { + tr = CodegenSession.ImportReference(tr); + writeMr = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(tr, true); + return (writeMr != null); + } + + return true; + } + + + /// + /// Creates a writer for an enum. + /// + /// + /// + private MethodReference CreateEnumWriterMethodDefinition(TypeReference enumTr) + { + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(enumTr); + AddToStaticWriters(enumTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + //Element type for enum. EG: byte int ect + TypeReference underlyingTypeRef = enumTr.CachedResolve().GetEnumUnderlyingTypeReference(); + //Method to write that type. + MethodReference underlyingWriterMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(underlyingTypeRef, true); + if (underlyingWriterMethodRef == null) + return null; + + ParameterDefinition writerParameterDef = createdWriterMd.Parameters[0]; + ParameterDefinition valueParameterDef = createdWriterMd.Parameters[1]; + //Push writer and value into call. + processor.Emit(OpCodes.Ldarg, writerParameterDef); + processor.Emit(OpCodes.Ldarg, valueParameterDef); + if (CodegenSession.WriterHelper.IsAutoPackedType(underlyingTypeRef)) + processor.Emit(OpCodes.Ldc_I4, (int)AutoPackType.Packed); + + //writer.WriteXXX(value) + processor.Emit(OpCodes.Call, underlyingWriterMethodRef); + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdWriterMd); + } + + + /// + /// Creates a writer for an array. + /// + private MethodReference CreateArrayWriterMethodDefinition(TypeReference objectTr) + { + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + TypeReference elementTypeRef = objectTr.GetElementType(); + MethodReference writeMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(elementTypeRef, true); + if (writeMethodRef == null) + return null; + + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + AddToStaticWriters(objectTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + //Null instructions. + CodegenSession.WriterHelper.CreateRetOnNull(processor, createdWriterMd.Parameters[0], createdWriterMd.Parameters[1], false); + + //Write length. It only makes it this far if not null. + //int length = arr[].Length. + VariableDefinition sizeVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdWriterMd, typeof(int)); + CreateCollectionLength(processor, createdWriterMd.Parameters[1], sizeVariableDef); + //writer.WritePackedWhole(length). + CodegenSession.WriterHelper.CreateWritePackedWhole(processor, createdWriterMd.Parameters[0], sizeVariableDef); + + VariableDefinition loopIndex = CodegenSession.GeneralHelper.CreateVariable(createdWriterMd, typeof(int)); + Instruction loopComparer = processor.Create(OpCodes.Ldloc, loopIndex); + + //int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, loopIndex); + processor.Emit(OpCodes.Br_S, loopComparer); + + //Loop content. + Instruction contentStart = processor.Create(OpCodes.Ldarg_0); + processor.Append(contentStart); + processor.Emit(OpCodes.Ldarg_1); + processor.Emit(OpCodes.Ldloc, loopIndex); + + if (elementTypeRef.IsValueType) + processor.Emit(OpCodes.Ldelem_Any, elementTypeRef); + else + processor.Emit(OpCodes.Ldelem_Ref); + //If auto pack type then write default auto pack. + if (CodegenSession.WriterHelper.IsAutoPackedType(elementTypeRef)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(elementTypeRef); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //writer.Write + processor.Emit(OpCodes.Call, writeMethodRef); + + //i++ + processor.Emit(OpCodes.Ldloc, loopIndex); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, loopIndex); + //if i < length jmp to content start. + processor.Append(loopComparer); //if i < obj(size). + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Blt_S, contentStart); + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdWriterMd); + } + + + /// + /// Creates a writer for a dictionary collection. + /// + private MethodReference CreateDictionaryWriterMethodReference(TypeReference objectTr) + { + GenericInstanceType genericInstance = (GenericInstanceType)objectTr; + CodegenSession.ImportReference(genericInstance); + TypeReference keyTr = genericInstance.GenericArguments[0]; + TypeReference valueTr = genericInstance.GenericArguments[1]; + + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + MethodReference keyWriteMr = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(keyTr, true); + MethodReference valueWriteMr = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(valueTr, true); + if (keyWriteMr == null || valueWriteMr == null) + return null; + + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + AddToStaticWriters(objectTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + GenericInstanceMethod genericInstanceMethod = CodegenSession.WriterHelper.Writer_WriteDictionary_MethodRef.MakeGenericMethod(new TypeReference[] { keyTr, valueTr }); + + ParameterDefinition writerPd = createdWriterMd.Parameters[0]; + ParameterDefinition valuePd = createdWriterMd.Parameters[1]; + processor.Emit(OpCodes.Ldarg, writerPd); + processor.Emit(OpCodes.Ldarg, valuePd); + processor.Emit(OpCodes.Callvirt, genericInstanceMethod); + processor.Emit(OpCodes.Ret); + + return CodegenSession.ImportReference(createdWriterMd); + } + + + /// + /// Creates a writer for a list. + /// + private MethodReference CreateListWriterMethodReference(TypeReference objectTr) + { + GenericInstanceType genericInstance = (GenericInstanceType)objectTr; + CodegenSession.ImportReference(genericInstance); + TypeReference elementTypeRef = genericInstance.GenericArguments[0]; + + /* Try to get instanced first for collection element type, if it doesn't exist then try to + * get/or make a one. */ + MethodReference writeMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(elementTypeRef, true); + if (writeMethodRef == null) + return null; + + MethodDefinition createdWriterMd = CreateStaticWriterStubMethodDefinition(objectTr); + AddToStaticWriters(objectTr, createdWriterMd); + + ILProcessor processor = createdWriterMd.Body.GetILProcessor(); + + //Find add method for list. + MethodReference lstGetItemMd = objectTr.CachedResolve().GetMethod("get_Item"); + MethodReference lstGetItemMr = lstGetItemMd.MakeHostInstanceGeneric(genericInstance); + + //Null instructions. + CodegenSession.WriterHelper.CreateRetOnNull(processor, createdWriterMd.Parameters[0], createdWriterMd.Parameters[1], false); + + //Write length. It only makes it this far if not null. + //int length = List.Count. + VariableDefinition sizeVariableDef = CodegenSession.GeneralHelper.CreateVariable(createdWriterMd, typeof(int)); + CreateCollectionLength(processor, createdWriterMd.Parameters[1], sizeVariableDef); + //writer.WritePackedWhole(length). + CodegenSession.WriterHelper.CreateWritePackedWhole(processor, createdWriterMd.Parameters[0], sizeVariableDef); + + VariableDefinition loopIndex = CodegenSession.GeneralHelper.CreateVariable(createdWriterMd, typeof(int)); + Instruction loopComparer = processor.Create(OpCodes.Ldloc, loopIndex); + + //int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, loopIndex); + processor.Emit(OpCodes.Br_S, loopComparer); + + //Loop content. + Instruction contentStart = processor.Create(OpCodes.Ldarg_0); + processor.Append(contentStart); + processor.Emit(OpCodes.Ldarg_1); + processor.Emit(OpCodes.Ldloc, loopIndex); + + processor.Emit(OpCodes.Callvirt, lstGetItemMr); + //If auto pack type then write default auto pack. + if (CodegenSession.WriterHelper.IsAutoPackedType(elementTypeRef)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(elementTypeRef); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + //writer.Write + processor.Emit(OpCodes.Call, writeMethodRef); + + //i++ + processor.Emit(OpCodes.Ldloc, loopIndex); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, loopIndex); + //if i < length jmp to content start. + processor.Append(loopComparer); //if i < obj(size). + processor.Emit(OpCodes.Ldloc, sizeVariableDef); + processor.Emit(OpCodes.Blt_S, contentStart); + + processor.Emit(OpCodes.Ret); + return CodegenSession.ImportReference(createdWriterMd); + } + + + /// + /// Creates a method definition stub for objectTypeRef. + /// + /// + /// + private MethodDefinition CreateStaticWriterStubMethodDefinition(TypeReference objectTypeRef, string nameExtension = "") + { + string methodName = $"{WRITE_PREFIX}{objectTypeRef.FullName}{nameExtension}"; + // create new writer for this type + TypeDefinition writerTypeDef = CodegenSession.GeneralHelper.GetOrCreateClass(out _, GENERATED_TYPE_ATTRIBUTES, GENERATED_WRITERS_CLASS_NAME, null); + + MethodDefinition writerMethodDef = writerTypeDef.AddMethod(methodName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig); + + CodegenSession.GeneralHelper.CreateParameter(writerMethodDef, CodegenSession.WriterHelper.Writer_TypeRef, "writer"); + CodegenSession.GeneralHelper.CreateParameter(writerMethodDef, objectTypeRef, "value"); + writerMethodDef.Body.InitLocals = true; + + return writerMethodDef; + } + + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs.meta new file mode 100644 index 0000000..06dad80 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4ff3023050c3ee41b59523def204ac8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs new file mode 100644 index 0000000..e9417bb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs @@ -0,0 +1,557 @@ +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.ILCore; +using FishNet.Object; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace FishNet.CodeGenerating.Helping +{ + internal class WriterHelper + { + #region Reflection references. + private MethodReference WriterPool_GetWriter_MethodRef; + private MethodReference Writer_WritePackedWhole_MethodRef; + internal TypeReference PooledWriter_TypeRef; + internal TypeReference Writer_TypeRef; + internal readonly Dictionary _instancedWriterMethods = new Dictionary(new TypeReferenceComparer()); + private readonly Dictionary _staticWriterMethods = new Dictionary(new TypeReferenceComparer()); + private HashSet _autoPackedMethods = new HashSet(new TypeReferenceComparer()); + private MethodReference PooledWriter_Dispose_MethodRef; + internal MethodReference Writer_WriteDictionary_MethodRef; + internal TypeReference NetworkBehaviour_TypeRef; + #endregion + + #region Const. + internal const string WRITE_PREFIX = "Write"; + /// + /// Types to exclude from being scanned for auto serialization. + /// + public static readonly System.Type[] EXCLUDED_AUTO_SERIALIZER_TYPES = new System.Type[] + { + typeof(NetworkBehaviour) + }; + /// + /// Types within assemblies which begin with these prefixes will not have serializers created for them. + /// + public static readonly string[] EXCLUDED_ASSEMBLY_PREFIXES = new string[] + { + "UnityEngine." + }; + #endregion + + /// + /// Imports references needed by this helper. + /// + /// + /// + internal bool ImportReferences() + { + PooledWriter_TypeRef = CodegenSession.ImportReference(typeof(PooledWriter)); + Writer_TypeRef = CodegenSession.ImportReference(typeof(Writer)); + NetworkBehaviour_TypeRef = CodegenSession.ImportReference(typeof(NetworkBehaviour)); + + //WriterPool.GetWriter + Type writerPoolType = typeof(WriterPool); + foreach (var methodInfo in writerPoolType.GetMethods()) + { + if (methodInfo.Name == nameof(WriterPool.GetWriter)) + WriterPool_GetWriter_MethodRef = CodegenSession.ImportReference(methodInfo); + } + + Type pooledWriterType = typeof(PooledWriter); + foreach (MethodInfo methodInfo in pooledWriterType.GetMethods()) + { + /* Special methods. */ + //Write.Dispose. + if (methodInfo.Name == nameof(PooledWriter.Dispose)) + { + PooledWriter_Dispose_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + //WritePackedWhole. + else if (methodInfo.Name == nameof(PooledWriter.WritePackedWhole)) + { + Writer_WritePackedWhole_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + //WriteDictionary. + else if (methodInfo.Name == nameof(PooledWriter.WriteDictionary)) + { + Writer_WriteDictionary_MethodRef = CodegenSession.ImportReference(methodInfo); + continue; + } + + else if (CodegenSession.GeneralHelper.CodegenExclude(methodInfo)) + continue; + //Generic methods are not supported. + else if (methodInfo.IsGenericMethod) + continue; + //Not long enough to be a write method. + else if (methodInfo.Name.Length < WRITE_PREFIX.Length) + continue; + //Method name doesn't start with writePrefix. + else if (methodInfo.Name.Substring(0, WRITE_PREFIX.Length) != WRITE_PREFIX) + continue; + + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + /* No parameters or more than 2 parameters. Most Write methods + * will have only 1 parameter but some will have 2 if + * there is a pack option. */ + if (parameterInfos.Length < 1 || parameterInfos.Length > 2) + continue; + /* If two parameters make sure the second parameter + * is a pack parameter. */ + bool autoPackMethod = false; + if (parameterInfos.Length == 2) + { + autoPackMethod = (parameterInfos[1].ParameterType == typeof(AutoPackType)); + if (!autoPackMethod) + continue; + } + //First parameter is generic; these are not supported. + if (parameterInfos[0].ParameterType.IsGenericParameter) + continue; + + + /* TypeReference for the first parameter in the write method. + * The first parameter will always be the type written. */ + TypeReference typeRef = CodegenSession.ImportReference(parameterInfos[0].ParameterType); + /* If here all checks pass. */ + MethodReference methodRef = CodegenSession.ImportReference(methodInfo); + AddWriterMethod(typeRef, methodRef, true, true); + if (autoPackMethod) + _autoPackedMethods.Add(typeRef); + } + + Type writerExtensionsType = typeof(WriterExtensions); + foreach (MethodInfo methodInfo in writerExtensionsType.GetMethods()) + { + if (CodegenSession.GeneralHelper.CodegenExclude(methodInfo)) + continue; + //Generic methods are not supported. + if (methodInfo.IsGenericMethod) + continue; + //Not static. + if (!methodInfo.IsStatic) + continue; + //Not long enough to be a write method. + if (methodInfo.Name.Length < WRITE_PREFIX.Length) + continue; + //Method name doesn't start with writePrefix. + if (methodInfo.Name.Substring(0, WRITE_PREFIX.Length) != WRITE_PREFIX) + continue; + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + /* No parameters or more than 3 parameters. Most extension Write methods + * will have only 2 parameter but some will have 3 if + * there is a pack option. */ + if (parameterInfos.Length < 2 || parameterInfos.Length > 3) + continue; + /* If 3 parameters make sure the 3rd parameter + * is a pack parameter. */ + bool autoPackMethod = false; + if (parameterInfos.Length == 3) + { + autoPackMethod = (parameterInfos[2].ParameterType == typeof(AutoPackType)); + if (!autoPackMethod) + continue; + } + //First parameter is generic; these are not supported. + if (parameterInfos[1].ParameterType.IsGenericParameter) + continue; + + /* TypeReference for the second parameter in the write method. + * The first parameter will always be the type written. */ + TypeReference typeRef = CodegenSession.ImportReference(parameterInfos[1].ParameterType); + /* If here all checks pass. */ + MethodReference methodRef = CodegenSession.ImportReference(methodInfo); + AddWriterMethod(typeRef, methodRef, false, true); + } + + return true; + } + + /// + /// Creates generic write delegates for all currently known write types. + /// + internal bool CreateGenericDelegates() + { + bool modified = false; + /* Only write statics. This will include extensions and generated. */ + foreach (KeyValuePair item in _staticWriterMethods) + { + if (FishNetILPP.CODEGEN_THIS_NAMESPACE.Length == 0 || item.Key.FullName.Contains(FishNetILPP.CODEGEN_THIS_NAMESPACE)) + { + CodegenSession.GenericWriterHelper.CreateWriteDelegate(item.Value, true); + modified = true; + } + } + + return modified; + } + + /// + /// Returns if typeRef has a serializer. + /// + /// + /// + internal bool HasSerializer(TypeReference typeRef, bool createMissing) + { + bool result = (GetInstancedWriteMethodReference(typeRef) != null) || + (GetStaticWriteMethodReference(typeRef) != null); + + if (!result && createMissing) + { + if (!CodegenSession.GeneralHelper.HasNonSerializableAttribute(typeRef.CachedResolve())) + { + MethodReference methodRef = CodegenSession.WriterGenerator.CreateWriter(typeRef); + result = (methodRef != null); + } + } + + return result; + } + + + #region GetWriterMethodReference. + /// + /// Returns the MethodReference for typeRef. + /// + /// + /// + internal MethodReference GetInstancedWriteMethodReference(TypeReference typeRef) + { + _instancedWriterMethods.TryGetValue(typeRef, out MethodReference methodRef); + return methodRef; + } + /// + /// Returns the MethodReference for typeRef. + /// + /// + /// + internal MethodReference GetStaticWriteMethodReference(TypeReference typeRef) + { + _staticWriterMethods.TryGetValue(typeRef, out MethodReference methodRef); + return methodRef; + } + /// + /// Returns the MethodReference for typeRef favoring instanced or static. + /// + /// + /// + /// + internal MethodReference GetFavoredWriteMethodReference(TypeReference typeRef, bool favorInstanced) + { + MethodReference result; + if (favorInstanced) + { + result = GetInstancedWriteMethodReference(typeRef); + if (result == null) + result = GetStaticWriteMethodReference(typeRef); + } + else + { + result = GetStaticWriteMethodReference(typeRef); + if (result == null) + result = GetInstancedWriteMethodReference(typeRef); + } + + return result; + } + /// + /// Gets the write MethodRef for typeRef, or tries to create it if not present. + /// + /// + /// + internal MethodReference GetOrCreateFavoredWriteMethodReference(TypeReference typeRef, bool favorInstanced) + { + //Try to get existing writer, if not present make one. + MethodReference writeMethodRef = GetFavoredWriteMethodReference(typeRef, favorInstanced); + + if (writeMethodRef == null) + writeMethodRef = CodegenSession.WriterGenerator.CreateWriter(typeRef); + if (writeMethodRef == null) + CodegenSession.LogError($"Could not create serializer for {typeRef.FullName}."); + + return writeMethodRef; + } + #endregion + + /// + /// Adds typeRef, methodDef to InstancedWriterMethods. + /// + /// + /// + /// + internal void AddWriterMethod(TypeReference typeRef, MethodReference methodRef, bool instanced, bool useAdd) + { + Dictionary dict = (instanced) ? + _instancedWriterMethods : _staticWriterMethods; + + if (useAdd) + dict.Add(typeRef, methodRef); + else + dict[typeRef] = methodRef; + } + + /// + /// Removes typeRef from Static or InstancedWriterMethods. + /// + internal void RemoveWriterMethod(TypeReference typeRef, bool instanced) + { + Dictionary dict = (instanced) ? + _instancedWriterMethods : _staticWriterMethods; + + dict.Remove(typeRef); + } + + /// + /// Creates a PooledWriter within the body/ and returns its variable index. + /// EG: PooledWriter writer = WriterPool.GetWriter(); + /// + internal VariableDefinition CreatePooledWriter(MethodDefinition methodDef) + { + VariableDefinition resultVd; + List insts = CreatePooledWriter(methodDef, out resultVd); + + ILProcessor processor = methodDef.Body.GetILProcessor(); + processor.Add(insts); + return resultVd; + } + /// + /// Creates a PooledWriter within the body/ and returns its variable index. + /// EG: PooledWriter writer = WriterPool.GetWriter(); + /// + /// + /// + /// + internal List CreatePooledWriter(MethodDefinition methodDef, out VariableDefinition resultVd) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + resultVd = CodegenSession.GeneralHelper.CreateVariable(methodDef, PooledWriter_TypeRef); + //Get a pooled writer from WriterPool and assign it to added PooledWriter. + insts.Add(processor.Create(OpCodes.Call, WriterPool_GetWriter_MethodRef)); + insts.Add(processor.Create(OpCodes.Stloc, resultVd)); + return insts; + } + + + /// + /// Calls Dispose on a PooledWriter. + /// EG: writer.Dispose(); + /// + /// + /// + internal List DisposePooledWriter(MethodDefinition methodDef, VariableDefinition writerDefinition) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.Add(processor.Create(OpCodes.Ldloc, writerDefinition)); + insts.Add(processor.Create(OpCodes.Callvirt, PooledWriter_Dispose_MethodRef)); + + return insts; + } + + /// + /// Returns if typeRef supports auto packing. + /// + /// + /// + internal bool IsAutoPackedType(TypeReference typeRef) + { + return _autoPackedMethods.Contains(typeRef); + } + + /// + /// Creates a null check on the second argument using a boolean. + /// + internal void CreateRetOnNull(ILProcessor processor, ParameterDefinition writerParameterDef, ParameterDefinition checkedParameterDef, bool useBool) + { + Instruction endIf = processor.Create(OpCodes.Nop); + //If (value) jmp to endIf. + processor.Emit(OpCodes.Ldarg, checkedParameterDef); + processor.Emit(OpCodes.Brtrue, endIf); + //writer.WriteBool / writer.WritePackedWhole + if (useBool) + CreateWriteBool(processor, writerParameterDef, true); + else + CreateWritePackedWhole(processor, writerParameterDef, -1); + //Exit method. + processor.Emit(OpCodes.Ret); + //End of if check. + processor.Append(endIf); + } + + #region CreateWritePackWhole + /// + /// Creates a call to WritePackWhole with value. + /// + /// + /// + internal void CreateWritePackedWhole(ILProcessor processor, ParameterDefinition writerParameterDef, int value) + { + //Create local int and set it to value. + VariableDefinition intVariableDef = CodegenSession.GeneralHelper.CreateVariable(processor.Body.Method, typeof(int)); + CodegenSession.GeneralHelper.SetVariableDefinitionFromInt(processor, intVariableDef, value); + //Writer. + processor.Emit(OpCodes.Ldarg, writerParameterDef); + //Writer.WritePackedWhole(value). + processor.Emit(OpCodes.Ldloc, intVariableDef); + processor.Emit(OpCodes.Conv_U8); + processor.Emit(OpCodes.Callvirt, Writer_WritePackedWhole_MethodRef); + } + /// + /// Creates a call to WritePackWhole with value. + /// + /// + /// + internal void CreateWritePackedWhole(ILProcessor processor, ParameterDefinition writerParameterDef, VariableDefinition value) + { + //Writer. + processor.Emit(OpCodes.Ldarg, writerParameterDef); + //Writer.WritePackedWhole(value). + processor.Emit(OpCodes.Ldloc, value); + processor.Emit(OpCodes.Conv_U8); + processor.Emit(OpCodes.Callvirt, Writer_WritePackedWhole_MethodRef); + } + #endregion + + /// + /// Creates a call to WriteBoolean with value. + /// + /// + /// + /// + internal void CreateWriteBool(ILProcessor processor, ParameterDefinition writerParameterDef, bool value) + { + MethodReference writeBoolMethodRef = GetFavoredWriteMethodReference(CodegenSession.GeneralHelper.GetTypeReference(typeof(bool)), true); + processor.Emit(OpCodes.Ldarg, writerParameterDef); + int intValue = (value) ? 1 : 0; + processor.Emit(OpCodes.Ldc_I4, intValue); + processor.Emit(OpCodes.Callvirt, writeBoolMethodRef); + } + + /// + /// Creates a Write call on a PooledWriter variable for parameterDef. + /// EG: writer.WriteBool(xxxxx); + /// + internal List CreateWriteInstructions(MethodDefinition methodDef, object pooledWriterDef, ParameterDefinition valueParameterDef, MethodReference writeMethodRef) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + if (writeMethodRef != null) + { + if (pooledWriterDef is VariableDefinition) + { + insts.Add(processor.Create(OpCodes.Ldloc, (VariableDefinition)pooledWriterDef)); + } + else if (pooledWriterDef is ParameterDefinition) + { + insts.Add(processor.Create(OpCodes.Ldarg, (ParameterDefinition)pooledWriterDef)); + } + else + { + CodegenSession.LogError($"{pooledWriterDef.GetType().FullName} is not a valid writerDef. Type must be VariableDefinition or ParameterDefinition."); + return new List(); + } + insts.Add(processor.Create(OpCodes.Ldarg, valueParameterDef)); + //If an auto pack method then insert default value. + if (_autoPackedMethods.Contains(valueParameterDef.ParameterType)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(valueParameterDef.ParameterType); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)packType)); + } + insts.Add(processor.Create(OpCodes.Call, writeMethodRef)); + return insts; + } + else + { + CodegenSession.LogError($"Writer not found for {valueParameterDef.ParameterType.FullName}."); + return new List(); + } + } + /// + /// Creates a Write call on a PooledWriter variable for parameterDef. + /// EG: writer.WriteBool(xxxxx); + /// + internal void CreateWrite(MethodDefinition methodDef, object writerDef, ParameterDefinition valuePd, MethodReference writeMr) + { + List insts = CreateWriteInstructions(methodDef, writerDef, valuePd, writeMr); + ILProcessor processor = methodDef.Body.GetILProcessor(); + processor.Add(insts); + } + /// + /// Creates a Write call to a writer. + /// EG: StaticClass.WriteBool(xxxxx); + /// + /// + /// + internal void CreateWrite(MethodDefinition writerMd, ParameterDefinition valuePd, FieldDefinition fieldDef, MethodReference writeMr) + { + if (writeMr != null) + { + ILProcessor processor = writerMd.Body.GetILProcessor(); + ParameterDefinition writerPd = writerMd.Parameters[0]; + + FieldReference fieldRef = CodegenSession.GeneralHelper.GetFieldReference(fieldDef); + processor.Emit(OpCodes.Ldarg, writerPd); + processor.Emit(OpCodes.Ldarg, valuePd); + processor.Emit(OpCodes.Ldfld, fieldRef); + //If an auto pack method then insert default value. + if (_autoPackedMethods.Contains(fieldDef.FieldType)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(fieldDef.FieldType); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + processor.Emit(OpCodes.Call, writeMr); + } + else + { + CodegenSession.LogError($"Writer not found for {fieldDef.FieldType.FullName}."); + } + } + + /// + /// Creates a Write call to a writer. + /// EG: StaticClass.WriteBool(xxxxx); + /// + /// + /// + internal void CreateWrite(MethodDefinition writerMd, ParameterDefinition valuePd, MethodReference getMr, MethodReference writeMr) + { + TypeReference returnTr = getMr.ReturnType; + + if (writeMr != null) + { + ILProcessor processor = writerMd.Body.GetILProcessor(); + ParameterDefinition writerPd = writerMd.Parameters[0]; + + processor.Emit(OpCodes.Ldarg, writerPd); + processor.Emit(OpCodes.Ldarg, valuePd); + processor.Emit(OpCodes.Call, getMr); + //If an auto pack method then insert default value. + if (_autoPackedMethods.Contains(returnTr)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(returnTr); + processor.Emit(OpCodes.Ldc_I4, (int)packType); + } + processor.Emit(OpCodes.Call, writeMr); + } + else + { + CodegenSession.LogError($"Writer not found for {returnTr.FullName}."); + } + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta new file mode 100644 index 0000000..334aa0d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27baf9dffdd8c9f40abb65a47dba4cca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore.meta new file mode 100644 index 0000000..8040bd1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abe522a1ad3df3a43a5c3389e3b8ee89 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs new file mode 100644 index 0000000..a870e0b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs @@ -0,0 +1,498 @@ +using FishNet.Broadcast; +using FishNet.CodeGenerating.Extension; +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.Processing; +using FishNet.Configuring; +using FishNet.Serializing.Helping; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace FishNet.CodeGenerating.ILCore +{ + public class FishNetILPP : ILPostProcessor + { + #region Const. + internal const string RUNTIME_ASSEMBLY_NAME = "FishNet.Runtime"; + /// + /// If not empty codegen will only include types within this Namespace while iterating RUNTIME_ASSEMBLY_NAME> + /// + //internal const string CODEGEN_THIS_NAMESPACE = "FishNet.Managing.Scened"; + internal const string CODEGEN_THIS_NAMESPACE = ""; + #endregion + + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + if (compiledAssembly.Name.StartsWith("Unity.")) + return false; + if (compiledAssembly.Name.StartsWith("UnityEngine.")) + return false; + if (compiledAssembly.Name.StartsWith("UnityEditor.")) + return false; + if (compiledAssembly.Name.Contains("Editor")) + return false; + + /* This line contradicts the one below where referencesFishNet + * becomes true if the assembly is FishNetAssembly. This is here + * intentionally to stop codegen from running on the runtime + * fishnet assembly, but the option below is for debugging. I would + * comment out this check if I wanted to compile fishnet runtime. */ + if (CODEGEN_THIS_NAMESPACE.Length == 0) + { + if (compiledAssembly.Name == RUNTIME_ASSEMBLY_NAME) + return false; + } + bool referencesFishNet = FishNetILPP.IsFishNetAssembly(compiledAssembly) || compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == RUNTIME_ASSEMBLY_NAME); + return referencesFishNet; + } + public override ILPostProcessor GetInstance() => this; + + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + AssemblyDefinition assemblyDef = ILCoreHelper.GetAssemblyDefinition(compiledAssembly); + if (assemblyDef == null) + return null; + //Check WillProcess again; somehow certain editor scripts skip the WillProcess check. + if (!WillProcess(compiledAssembly)) + return null; + //Resets instances of helpers and populates data needed by all helpers. + if (!CodegenSession.Reset(assemblyDef.MainModule)) + return null; + + bool modified = false; + + if (IsFishNetAssembly(compiledAssembly)) + { + //Not used... + modified |= ModifyMakePublicMethods(); + } + else + { + /* If one or more scripts use RPCs but don't inherit NetworkBehaviours + * then don't bother processing the rest. */ + if (CodegenSession.NetworkBehaviourProcessor.NonNetworkBehaviourHasInvalidAttributes(CodegenSession.Module.Types)) + return new ILPostProcessResult(null, CodegenSession.Diagnostics); + //before 226ms, after 17ms + modified |= CreateDeclaredDelegates(); + //before 5ms, after 5ms + modified |= CreateDeclaredSerializers(); + //before 30ms, after 26ms + modified |= CreateIBroadcast(); + //before 140ms, after 10ms + modified |= CreateQOLAttributes(); + //before 75ms, after 6ms + modified |= CreateNetworkBehaviours(); + //before 260ms, after 215ms + modified |= CreateGenericReadWriteDelegates(); + //before 52ms, after 27ms + + //Total at once + //before 761, after 236ms + + /* If there are warnings about SyncVars being in different assemblies. + * This is awful ... codegen would need to be reworked to save + * syncvars across all assemblies so that scripts referencing them from + * another assembly can have it's instructions changed. This however is an immense + * amount of work so it will have to be put on hold, for... a long.. long while. */ + if (CodegenSession.DifferentAssemblySyncVars.Count > 0) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Assembly {CodegenSession.Module.Name} has inherited access to SyncVars in different assemblies. When accessing SyncVars across assemblies be sure to use Get/Set methods withinin the inherited assembly script to change SyncVars. Accessible fields are:"); + + foreach (FieldDefinition item in CodegenSession.DifferentAssemblySyncVars) + sb.AppendLine($"Field {item.Name} within {item.DeclaringType.FullName} in assembly {item.Module.Name}."); + + CodegenSession.LogWarning("v------- IMPORTANT -------v"); + CodegenSession.LogWarning(sb.ToString()); + CodegenSession.DifferentAssemblySyncVars.Clear(); + } + } + + //CodegenSession.LogWarning($"Assembly {compiledAssembly.Name} took {stopwatch.ElapsedMilliseconds}."); + + if (!modified) + { + return null; + } + else + { + MemoryStream pe = new MemoryStream(); + MemoryStream pdb = new MemoryStream(); + WriterParameters writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), + SymbolStream = pdb, + WriteSymbols = true + }; + assemblyDef.Write(pe, writerParameters); + return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), CodegenSession.Diagnostics); + } + } + + /// + /// Makees methods public scope which use CodegenMakePublic attribute. + /// + /// + private bool ModifyMakePublicMethods() + { + string makePublicTypeFullName = typeof(CodegenMakePublicAttribute).FullName; + foreach (TypeDefinition td in CodegenSession.Module.Types) + { + foreach (MethodDefinition md in td.Methods) + { + foreach (CustomAttribute ca in md.CustomAttributes) + { + if (ca.AttributeType.FullName == makePublicTypeFullName) + { + md.Attributes &= ~MethodAttributes.Assembly; + md.Attributes |= MethodAttributes.Public; + } + } + } + } + + //There is always at least one modified. + return true; + } + /// + /// Creates delegates for user declared serializers. + /// + public bool CreateDeclaredDelegates() + { + bool modified = false; + + TypeAttributes readWriteExtensionTypeAttr = (TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract); + List allTypeDefs = CodegenSession.Module.Types.ToList(); + foreach (TypeDefinition td in allTypeDefs) + { + if (CodegenSession.GeneralHelper.IgnoreTypeDefinition(td)) + continue; + + if (td.Attributes.HasFlag(readWriteExtensionTypeAttr)) + modified |= CodegenSession.CustomSerializerProcessor.CreateDelegates(td); + } + + return modified; + } + + /// + /// Creates serializers for custom types within user declared serializers. + /// + /// + /// + private bool CreateDeclaredSerializers() + { + bool modified = false; + + TypeAttributes readWriteExtensionTypeAttr = (TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract); + List allTypeDefs = CodegenSession.Module.Types.ToList(); + foreach (TypeDefinition td in allTypeDefs) + { + if (CodegenSession.GeneralHelper.IgnoreTypeDefinition(td)) + continue; + + if (td.Attributes.HasFlag(readWriteExtensionTypeAttr)) + modified |= CodegenSession.CustomSerializerProcessor.CreateSerializers(td); + } + + return modified; + } + + /// + /// Creaters serializers and calls for IBroadcast. + /// + /// + /// + private bool CreateIBroadcast() + { + bool modified = false; + + string networkBehaviourFullName = CodegenSession.NetworkBehaviourHelper.FullName; + + HashSet typeDefs = new HashSet(); + foreach (TypeDefinition td in CodegenSession.Module.Types) + { + TypeDefinition climbTd = td; + do + { + //Reached NetworkBehaviour class. + if (climbTd.FullName == networkBehaviourFullName) + break; + + ///* Check initial class as well all types within + // * the class. Then check all of it's base classes. */ + if (climbTd.ImplementsInterface()) + typeDefs.Add(climbTd); + //7ms + + //Add nested. Only going to go a single layer deep. + foreach (TypeDefinition nestedTypeDef in td.NestedTypes) + { + if (nestedTypeDef.ImplementsInterface()) + typeDefs.Add(nestedTypeDef); + } + //0ms + + climbTd = climbTd.GetNextBaseTypeDefinition(); + //this + name check 40ms + } while (climbTd != null); + + } + + + //Create reader/writers for found typeDefs. + foreach (TypeDefinition td in typeDefs) + { + TypeReference typeRef = CodegenSession.ImportReference(td); + + bool canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(typeRef, true); + if (!canSerialize) + CodegenSession.LogError($"Broadcast {td.Name} does not support serialization. Use a supported type or create a custom serializer."); + else + modified = true; + } + + return modified; + } + + /// + /// Handles QOLAttributes such as [Server]. + /// + /// + private bool CreateQOLAttributes() + { + bool modified = false; + + bool codeStripping = false; + + List allTypeDefs = CodegenSession.Module.Types.ToList(); + + /* First pass, potentially only pass. + * If code stripping them this will be run again. The first iteration + * is to ensure things are removed in the proper order. */ + foreach (TypeDefinition td in allTypeDefs) + { + if (CodegenSession.GeneralHelper.IgnoreTypeDefinition(td)) + continue; + + modified |= CodegenSession.QolAttributeProcessor.Process(td, codeStripping); + } + + + + return modified; + } + + /// + /// Creates NetworkBehaviour changes. + /// + /// + /// + private bool CreateNetworkBehaviours() + { + bool modified = false; + //Get all network behaviours to process. + List networkBehaviourTypeDefs = CodegenSession.Module.Types + .Where(td => td.IsSubclassOf(CodegenSession.NetworkBehaviourHelper.FullName)) + .ToList(); + + //Moment a NetworkBehaviour exist the assembly is considered modified. + if (networkBehaviourTypeDefs.Count > 0) + modified = true; + + /* Remove types which are inherited. This gets the child most networkbehaviours. + * Since processing iterates all parent classes there's no reason to include them */ + RemoveInheritedTypeDefinitions(networkBehaviourTypeDefs); + //Set how many rpcs are in children classes for each typedef. + Dictionary inheritedRpcCounts = new Dictionary(); + SetChildRpcCounts(inheritedRpcCounts, networkBehaviourTypeDefs); + //Set how many synctypes are in children classes for each typedef. + Dictionary inheritedSyncTypeCounts = new Dictionary(); + SetChildSyncTypeCounts(inheritedSyncTypeCounts, networkBehaviourTypeDefs); + + /* This holds all sync types created, synclist, dictionary, var + * and so on. This data is used after all syncvars are made so + * other methods can look for references to created synctypes and + * replace accessors accordingly. */ + List<(SyncType, ProcessedSync)> allProcessedSyncs = new List<(SyncType, ProcessedSync)>(); + HashSet allProcessedCallbacks = new HashSet(); + List processedClasses = new List(); + + foreach (TypeDefinition typeDef in networkBehaviourTypeDefs) + { + CodegenSession.ImportReference(typeDef); + //Synctypes processed for this nb and it's inherited classes. + List<(SyncType, ProcessedSync)> processedSyncs = new List<(SyncType, ProcessedSync)>(); + CodegenSession.NetworkBehaviourProcessor.Process(typeDef, processedSyncs, + inheritedSyncTypeCounts, inheritedRpcCounts); + //Add to all processed. + allProcessedSyncs.AddRange(processedSyncs); + } + + /* Must run through all scripts should user change syncvar + * from outside the networkbehaviour. */ + if (allProcessedSyncs.Count > 0) + { + foreach (TypeDefinition td in CodegenSession.Module.Types) + { + CodegenSession.NetworkBehaviourSyncProcessor.ReplaceGetSets(td, allProcessedSyncs); + CodegenSession.RpcProcessor.RedirectBaseCalls(); + } + } + + /* Removes typedefinitions which are inherited by + * another within tds. For example, if the collection + * td contains A, B, C and our structure is + * A : B : C then B and C will be removed from the collection + * Since they are both inherited by A. */ + void RemoveInheritedTypeDefinitions(List tds) + { + HashSet inheritedTds = new HashSet(); + /* Remove any networkbehaviour typedefs which are inherited by + * another networkbehaviour typedef. When a networkbehaviour typedef + * is processed so are all of the inherited types. */ + for (int i = 0; i < tds.Count; i++) + { + /* Iterates all base types and + * adds them to inheritedTds so long + * as the base type is not a NetworkBehaviour. */ + TypeDefinition copyTd = tds[i].GetNextBaseTypeDefinition(); + while (copyTd != null) + { + //Class is NB. + if (copyTd.FullName == CodegenSession.NetworkBehaviourHelper.FullName) + break; + + inheritedTds.Add(copyTd); + copyTd = copyTd.GetNextBaseTypeDefinition(); + } + } + + //Remove all inherited types. + foreach (TypeDefinition item in inheritedTds) + tds.Remove(item); + } + + /* Sets how many Rpcs are within the children + * of each typedefinition. EG: if our structure is + * A : B : C, with the following RPC counts... + * A 3 + * B 1 + * C 2 + * then B child rpc counts will be 3, and C will be 4. */ + void SetChildRpcCounts(Dictionary typeDefCounts, List tds) + { + foreach (TypeDefinition typeDef in tds) + { + //Number of RPCs found while climbing typeDef. + uint childCount = 0; + + TypeDefinition copyTd = typeDef; + do + { + //How many RPCs are in copyTd. + uint copyCount = CodegenSession.RpcProcessor.GetRpcCount(copyTd); + + /* If not found it this is the first time being + * processed. When this occurs set the value + * to 0. It will be overwritten below if baseCount + * is higher. */ + uint previousCopyChildCount = 0; + if (!typeDefCounts.TryGetValue(copyTd, out previousCopyChildCount)) + typeDefCounts[copyTd] = 0; + /* If baseCount is higher then replace count for copyTd. + * This can occur when a class is inherited by several types + * and the first processed type might only have 1 rpc, while + * the next has 2. This could be better optimized but to keep + * the code easier to read, it will stay like this. */ + if (childCount > previousCopyChildCount) + typeDefCounts[copyTd] = childCount; + + //Increase baseCount with RPCs found here. + childCount += copyCount; + + copyTd = copyTd.GetNextBaseClassToProcess(); + } while (copyTd != null); + } + + } + + + /* This performs the same functionality as SetChildRpcCounts + * but for SyncTypes. */ + void SetChildSyncTypeCounts(Dictionary typeDefCounts, List tds) + { + foreach (TypeDefinition typeDef in tds) + { + //Number of RPCs found while climbing typeDef. + uint childCount = 0; + + TypeDefinition copyTd = typeDef; + /* Iterate up to the parent script and then reverse + * the order. This is so that the topmost is 0 + * and each inerhiting script adds onto that. + * Setting child types this way makes it so parent + * types don't need to have their synctype/rpc counts + * rebuilt when scripts are later to be found + * inheriting from them. */ + List reversedTypeDefs = new List(); + do + { + reversedTypeDefs.Add(copyTd); + copyTd = copyTd.GetNextBaseClassToProcess(); + } while (copyTd != null); + reversedTypeDefs.Reverse(); + + foreach (TypeDefinition td in reversedTypeDefs) + { + //How many RPCs are in copyTd. + uint copyCount = CodegenSession.NetworkBehaviourSyncProcessor.GetSyncTypeCount(td); + /* If not found it this is the first time being + * processed. When this occurs set the value + * to 0. It will be overwritten below if baseCount + * is higher. */ + uint previousCopyChildCount = 0; + if (!typeDefCounts.TryGetValue(td, out previousCopyChildCount)) + typeDefCounts[td] = 0; + /* If baseCount is higher then replace count for copyTd. + * This can occur when a class is inherited by several types + * and the first processed type might only have 1 rpc, while + * the next has 2. This could be better optimized but to keep + * the code easier to read, it will stay like this. */ + if (childCount > previousCopyChildCount) + typeDefCounts[td] = childCount; + //Increase baseCount with RPCs found here. + childCount += copyCount; + } + } + } + + + return modified; + } + + /// + /// Creates generic delegates for all read and write methods. + /// + /// + /// + private bool CreateGenericReadWriteDelegates() + { + bool modified = false; + modified |= CodegenSession.WriterHelper.CreateGenericDelegates(); + modified |= CodegenSession.ReaderHelper.CreateGenericDelegates(); + + return modified; + } + + internal static bool IsFishNetAssembly(ICompiledAssembly assembly) => (assembly.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME); + internal static bool IsFishNetAssembly() => (CodegenSession.Module.Assembly.Name.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME); + internal static bool IsFishNetAssembly(ModuleDefinition moduleDef) => (moduleDef.Assembly.Name.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME); + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta new file mode 100644 index 0000000..38eb26f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f03d76b376c1d5b4591039af6fd4c9e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs new file mode 100644 index 0000000..054dc56 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs @@ -0,0 +1,38 @@ +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.IO; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace FishNet.CodeGenerating.ILCore +{ + internal static class ILCoreHelper + { + + /// + /// Returns AssembleDefinition for compiledAssembly. + /// + /// + /// + internal static AssemblyDefinition GetAssemblyDefinition(ICompiledAssembly compiledAssembly) + { + PostProcessorAssemblyResolver assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly); + ReaderParameters readerParameters = new ReaderParameters + { + SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData), + SymbolReaderProvider = new PortablePdbReaderProvider(), + AssemblyResolver = assemblyResolver, + ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(), + ReadingMode = ReadingMode.Immediate + }; + + AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(new MemoryStream(compiledAssembly.InMemoryAssembly.PeData), readerParameters); + //Allows us to resolve inside FishNet assembly, such as for components. + assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition); + + return assemblyDefinition; + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs.meta new file mode 100644 index 0000000..63a163d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfcfb917dd9268744962ae61aa0115b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs new file mode 100644 index 0000000..6a9ca63 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs @@ -0,0 +1,139 @@ +using MonoFN.Cecil; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace FishNet.CodeGenerating +{ + internal class PostProcessorAssemblyResolver : IAssemblyResolver + { + private readonly string[] m_AssemblyReferences; + private readonly Dictionary m_AssemblyCache = new Dictionary(); + private readonly ICompiledAssembly m_CompiledAssembly; + private AssemblyDefinition m_SelfAssembly; + + public PostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly) + { + m_CompiledAssembly = compiledAssembly; + m_AssemblyReferences = compiledAssembly.References; + } + + public void Dispose() { } + + public AssemblyDefinition Resolve(AssemblyNameReference name) => Resolve(name, new ReaderParameters(ReadingMode.Deferred)); + + public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + { + lock (m_AssemblyCache) + { + if (name.Name == m_CompiledAssembly.Name) + { + return m_SelfAssembly; + } + + var fileName = FindFile(name); + if (fileName == null) + { + return null; + } + + var lastWriteTime = File.GetLastWriteTime(fileName); + var cacheKey = $"{fileName}{lastWriteTime}"; + if (m_AssemblyCache.TryGetValue(cacheKey, out var result)) + { + return result; + } + + parameters.AssemblyResolver = this; + + var ms = MemoryStreamFor(fileName); + var pdb = $"{fileName}.pdb"; + if (File.Exists(pdb)) + { + parameters.SymbolStream = MemoryStreamFor(pdb); + } + + var assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters); + m_AssemblyCache.Add(cacheKey, assemblyDefinition); + + return assemblyDefinition; + } + } + + private string FindFile(AssemblyNameReference name) + { + var fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.dll"); + if (fileName != null) + { + return fileName; + } + + // perhaps the type comes from an exe instead + fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.exe"); + if (fileName != null) + { + return fileName; + } + + //Unfortunately the current ICompiledAssembly API only provides direct references. + //It is very much possible that a postprocessor ends up investigating a type in a directly + //referenced assembly, that contains a field that is not in a directly referenced assembly. + //if we don't do anything special for that situation, it will fail to resolve. We should fix this + //in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references + //are always located next to direct references, so we search in all directories of direct references we + //got passed, and if we find the file in there, we resolve to it. + return m_AssemblyReferences + .Select(Path.GetDirectoryName) + .Distinct() + .Select(parentDir => Path.Combine(parentDir, $"{name.Name}.dll")) + .FirstOrDefault(File.Exists); + } + + private static MemoryStream MemoryStreamFor(string fileName) + { + return Retry(10, TimeSpan.FromSeconds(1), () => + { + byte[] byteArray; + using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + byteArray = new byte[fs.Length]; + var readLength = fs.Read(byteArray, 0, (int)fs.Length); + if (readLength != fs.Length) + { + throw new InvalidOperationException("File read length is not full length of file."); + } + } + + return new MemoryStream(byteArray); + }); + } + + private static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func func) + { + try + { + return func(); + } + catch (IOException) + { + if (retryCount == 0) + { + throw; + } + + Console.WriteLine($"Caught IO Exception, trying {retryCount} more times"); + Thread.Sleep(waitTime); + + return Retry(retryCount - 1, waitTime, func); + } + } + + public void AddAssemblyDefinitionBeingOperatedOn(AssemblyDefinition assemblyDefinition) + { + m_SelfAssembly = assemblyDefinition; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs.meta new file mode 100644 index 0000000..1a05af5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c247f4266b2864eb96e6a9ae6557d31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs new file mode 100644 index 0000000..32b9e8c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs @@ -0,0 +1,22 @@ +using MonoFN.Cecil; +using System.Linq; +using System.Reflection; + +namespace FishNet.CodeGenerating.ILCore +{ + internal class PostProcessorReflectionImporter : DefaultReflectionImporter + { + private const string k_SystemPrivateCoreLib = "System.Private.CoreLib"; + private readonly AssemblyNameReference m_CorrectCorlib; + + public PostProcessorReflectionImporter(ModuleDefinition module) : base(module) + { + m_CorrectCorlib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == k_SystemPrivateCoreLib); + } + + public override AssemblyNameReference ImportReference(AssemblyName reference) + { + return m_CorrectCorlib != null && reference.Name == k_SystemPrivateCoreLib ? m_CorrectCorlib : base.ImportReference(reference); + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs.meta new file mode 100644 index 0000000..8dca5f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 484e8ad8c4dde382ea67036b32935ef1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs new file mode 100644 index 0000000..7d38602 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs @@ -0,0 +1,12 @@ +using MonoFN.Cecil; + +namespace FishNet.CodeGenerating.ILCore +{ + internal class PostProcessorReflectionImporterProvider : IReflectionImporterProvider + { + public IReflectionImporter GetReflectionImporter(ModuleDefinition moduleDef) + { + return new PostProcessorReflectionImporter(moduleDef); + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs.meta new file mode 100644 index 0000000..12a58b8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/ILCore/PostProcessorReflectionImporterProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9273a5dad109ab0783891e36c983080 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing.meta new file mode 100644 index 0000000..21c7e9a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0d1eb51001374741a4c4de01c3bc05d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs new file mode 100644 index 0000000..887380e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs @@ -0,0 +1,296 @@ + +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Serializing; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.CodeGenerating.Processing +{ + internal class CustomSerializerProcessor + { + + #region Types. + internal enum ExtensionType + { + None, + Write, + Read + } + + #endregion + + internal bool CreateDelegates(TypeDefinition typeDef) + { + bool modified = false; + + /* Find all declared methods and register delegates to them. + * After they are all registered create any custom writers + * needed to complete the declared methods. It's important to + * make generated writers after so that a generated method + * isn't made for a type when the user has already made a declared one. */ + foreach (MethodDefinition methodDef in typeDef.Methods) + { + ExtensionType extensionType = GetExtensionType(methodDef); + if (extensionType == ExtensionType.None) + continue; + if (CodegenSession.GeneralHelper.CodegenExclude(methodDef)) + continue; + + MethodReference methodRef = CodegenSession.ImportReference(methodDef); + if (extensionType == ExtensionType.Write) + { + CodegenSession.WriterHelper.AddWriterMethod(methodRef.Parameters[1].ParameterType, methodRef, false, true); + modified = true; + } + else if (extensionType == ExtensionType.Read) + { + CodegenSession.ReaderHelper.AddReaderMethod(methodRef.ReturnType, methodRef, false, true); + modified = true; + } + } + + return modified; + } + + /// + /// Creates serializers for any custom types for declared methods. + /// + /// + /// + internal bool CreateSerializers(TypeDefinition typeDef) + { + bool modified = false; + + List<(MethodDefinition, ExtensionType)> declaredMethods = new List<(MethodDefinition, ExtensionType)>(); + /* Go through all custom serializers again and see if + * they use any types that the user didn't make a serializer for + * and that there isn't a built-in type for. Create serializers + * for these types. */ + foreach (MethodDefinition methodDef in typeDef.Methods) + { + ExtensionType extensionType = GetExtensionType(methodDef); + if (extensionType == ExtensionType.None) + continue; + if (CodegenSession.GeneralHelper.CodegenExclude(methodDef)) + continue; + + declaredMethods.Add((methodDef, extensionType)); + modified = true; + } + //Now that all declared are loaded see if any of them need generated serializers. + foreach ((MethodDefinition methodDef, ExtensionType extensionType) in declaredMethods) + CreateSerializers(extensionType, methodDef); + + return modified; + } + + + /// + /// Creates a custom serializer for any types not handled within users declared. + /// + /// + /// + /// + /// + private void CreateSerializers(ExtensionType extensionType, MethodDefinition methodDef) + { + for (int i = 0; i < methodDef.Body.Instructions.Count; i++) + CheckToModifyInstructions(extensionType, methodDef, ref i); + } + + /// + /// Checks if instructions need to be modified and does so. + /// + /// + /// + private void CheckToModifyInstructions(ExtensionType extensionType, MethodDefinition methodDef, ref int instructionIndex) + { + Instruction instruction = methodDef.Body.Instructions[instructionIndex]; + //Fields. + if (instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld) + CheckFieldReferenceInstruction(extensionType, methodDef, ref instructionIndex); + //Method calls. + else if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt) + CheckCallInstruction(extensionType, methodDef, ref instructionIndex, (MethodReference)instruction.Operand); + } + + + /// + /// Checks if a reader or writer must be generated for a field type. + /// + /// + /// + private void CheckFieldReferenceInstruction(ExtensionType extensionType, MethodDefinition methodDef, ref int instructionIndex) + { + Instruction instruction = methodDef.Body.Instructions[instructionIndex]; + FieldReference field = (FieldReference)instruction.Operand; + TypeReference type = field.DeclaringType; + + if (type.IsType(typeof(GenericWriter<>)) || type.IsType(typeof(GenericReader<>)) && type.IsGenericInstance) + { + GenericInstanceType typeGenericInst = (GenericInstanceType)type; + TypeReference parameterType = typeGenericInst.GenericArguments[0]; + CreateReaderOrWriter(extensionType, methodDef, ref instructionIndex, parameterType); + } + } + + + /// + /// Checks if a reader or writer must be generated for a call type. + /// + /// + /// + /// + /// + /// + private void CheckCallInstruction(ExtensionType extensionType, MethodDefinition methodDef, ref int instructionIndex, MethodReference method) + { + if (!method.IsGenericInstance) + return; + + //True if call is to read/write. + bool canCreate = ( + method.Is(nameof(Writer.Write)) || + method.Is(nameof(Reader.Read)) + ); + + if (canCreate) + { + GenericInstanceMethod instanceMethod = (GenericInstanceMethod)method; + TypeReference parameterType = instanceMethod.GenericArguments[0]; + if (parameterType.IsGenericParameter) + return; + + CreateReaderOrWriter(extensionType, methodDef, ref instructionIndex, parameterType); + } + } + + + /// + /// Creates a reader or writer for parameterType. + /// + /// + /// + /// + /// + private void CreateReaderOrWriter(ExtensionType extensionType, MethodDefinition methodDef, ref int instructionIndex, TypeReference parameterType) + { + if (!parameterType.IsGenericParameter && parameterType.CanBeResolved()) + { + TypeDefinition typeDefinition = parameterType.CachedResolve(); + //If class and not value type check for accessible constructor. + if (typeDefinition.IsClass && !typeDefinition.IsValueType) + { + MethodDefinition constructor = typeDefinition.GetMethod(".ctor"); + //Constructor is inaccessible, cannot create serializer for type. + if (!constructor.IsPublic) + { + CodegenSession.LogError($"Unable to generator serializers for {typeDefinition.FullName} because it's constructor is not public."); + return; + } + } + + ILProcessor processor = methodDef.Body.GetILProcessor(); + + //Find already existing read or write method. + MethodReference createdMethodRef = (extensionType == ExtensionType.Write) ? + CodegenSession.WriterHelper.GetFavoredWriteMethodReference(parameterType, true) : + CodegenSession.ReaderHelper.GetFavoredReadMethodReference(parameterType, true); + //If a created method already exist nothing further is required. + if (createdMethodRef != null) + { + //Replace call to generic with already made serializer. + Instruction newInstruction = processor.Create(OpCodes.Call, createdMethodRef); + methodDef.Body.Instructions[instructionIndex] = newInstruction; + return; + } + else + { + createdMethodRef = (extensionType == ExtensionType.Write) ? + CodegenSession.WriterGenerator.CreateWriter(parameterType) : + CodegenSession.ReaderGenerator.CreateReader(parameterType); + } + + //If method was created. + if (createdMethodRef != null) + { + /* If an autopack type then we have to inject the + * autopack above the new instruction. */ + if (CodegenSession.WriterHelper.IsAutoPackedType(parameterType)) + { + AutoPackType packType = CodegenSession.GeneralHelper.GetDefaultAutoPackType(parameterType); + Instruction autoPack = processor.Create(OpCodes.Ldc_I4, (int)packType); + methodDef.Body.Instructions.Insert(instructionIndex, autoPack); + instructionIndex++; + } + Instruction newInstruction = processor.Create(OpCodes.Call, createdMethodRef); + methodDef.Body.Instructions[instructionIndex] = newInstruction; + } + } + } + + + /// + /// Returns the RPC attribute on a method, if one exist. Otherwise returns null. + /// + /// + /// + private ExtensionType GetExtensionType(MethodDefinition methodDef) + { + bool hasExtensionAttribute = methodDef.HasCustomAttribute(); + if (!hasExtensionAttribute) + return ExtensionType.None; + + bool write = (methodDef.ReturnType == methodDef.Module.TypeSystem.Void); + + //Return None for Mirror types. +#if MIRROR + if (write) + { + if (methodDef.Parameters.Count > 0 && methodDef.Parameters[0].ParameterType.FullName == "Mirror.NetworkWriter") + return ExtensionType.None; + } + else + { + if (methodDef.Parameters.Count > 0 && methodDef.Parameters[0].ParameterType.FullName == "Mirror.NetworkReader") + return ExtensionType.None; + } +#endif + + + string prefix = (write) ? + WriterHelper.WRITE_PREFIX : ReaderHelper.READ_PREFIX; + + //Does not contain prefix. + if (methodDef.Name.Length < prefix.Length || methodDef.Name.Substring(0, prefix.Length) != prefix) + return ExtensionType.None; + + //Make sure first parameter is right. + if (methodDef.Parameters.Count >= 1) + { + TypeReference tr = methodDef.Parameters[0].ParameterType; + if (tr.FullName != CodegenSession.WriterHelper.Writer_TypeRef.FullName && + tr.FullName != CodegenSession.ReaderHelper.Reader_TypeRef.FullName) + return ExtensionType.None; + } + + if (write && methodDef.Parameters.Count < 2) + { + CodegenSession.LogError($"{methodDef.FullName} must have at least two parameters, the first being PooledWriter, and second value to write."); + return ExtensionType.None; + } + else if (!write && methodDef.Parameters.Count < 1) + { + CodegenSession.LogError($"{methodDef.FullName} must have at least one parameters, the first being PooledReader."); + return ExtensionType.None; + } + + return (write) ? ExtensionType.Write : ExtensionType.Read; + } + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs.meta new file mode 100644 index 0000000..8235bda --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/CustomSerializerProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9269fd8a62199e24c965b4c99b641244 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs new file mode 100644 index 0000000..7b9291e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs @@ -0,0 +1,1878 @@ +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Timing; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Rocks; +using System.Collections.Generic; +using UnityEngine; +using SR = System.Reflection; + +namespace FishNet.CodeGenerating.Processing +{ + internal class NetworkBehaviourPredictionProcessor + { + + #region Types. + private enum InsertType + { + First, + Last, + Current + } + + private class CreatedPredictionFields + { + /// + /// Replicate data buffered on the server. + /// + public readonly FieldReference ServerReplicateDatas; + /// + /// Replicate data buffered on the client. + /// + public readonly FieldReference ClientReplicateDatas; + /// + /// Last reconcile data received from the server. + /// + public readonly FieldReference ReconcileData; + /// + /// Last tick on data server replicated. + /// + public readonly FieldReference ServerReplicateTick; + /// + /// How many remaining ticks server can resend reconcile. + /// + public readonly FieldReference ServerReconcileResends; + /// + /// How many remaining ticks client can resend input. + /// + public readonly FieldReference ClientReplicateResends; + /// + /// True if client has data to reconcile with. + /// + public readonly FieldReference ClientHasReconcileData; + /// + /// True if client is replaying data. + /// + public readonly FieldReference ClientReplayingData; + /// + /// Last tick on a reconcile client received. + /// + public readonly FieldReference ClientReconcileTick; + /// + /// Last tick client sent new data. + /// + public readonly FieldReference ClientReplicateTick; + /// + /// Last tick on data received from client. + /// + public readonly FieldReference ServerReceivedTick; + /// + /// A buffer to read replicates into. + /// + public readonly FieldReference ServerReplicateReaderBuffer; + + public CreatedPredictionFields(FieldReference serverReplicateDatas, FieldReference clientReplicateDatas, FieldReference reconcileData, FieldReference serverReplicateTick, + FieldReference serverReconcileResends, FieldReference clientReplicateResends, FieldReference clientHasReconcileData, FieldReference clientReplayingData, + FieldReference clientReconcileTick, FieldReference clientReplicateTick, FieldReference serverReceivedTick, FieldReference serverReplicateReaderBuffer) + { + ServerReplicateDatas = serverReplicateDatas; + ClientReplicateDatas = clientReplicateDatas; + ReconcileData = reconcileData; + ServerReplicateTick = serverReplicateTick; + ServerReconcileResends = serverReconcileResends; + ClientReplicateResends = clientReplicateResends; + ClientHasReconcileData = clientHasReconcileData; + ClientReplayingData = clientReplayingData; + ClientReconcileTick = clientReconcileTick; + ClientReplicateTick = clientReplicateTick; + ServerReceivedTick = serverReceivedTick; + ServerReplicateReaderBuffer = serverReplicateReaderBuffer; + } + } + + private class PredictionReaders + { + public MethodReference ReplicateReader; + public MethodReference ReconcileReader; + + public PredictionReaders(MethodReference replicateReader, MethodReference reconcileReader) + { + ReplicateReader = replicateReader; + ReconcileReader = reconcileReader; + } + } + + #endregion + + #region Private + private MethodReference Unity_GetGameObject_MethodRef; + private MethodReference Unity_GetScene_MethodRef; + private MethodReference Unity_GetPhysicsScene2D_MethodRef; + private MethodReference Unity_GetPhysicsScene3D_MethodRef; + private MethodReference Physics3D_Simulate_MethodRef; + private MethodReference Physics2D_Simulate_MethodRef; + private MethodReference Physics3D_SyncTransforms_MethodRef; + private MethodReference Physics2D_SyncTransforms_MethodRef; + + private FieldReference ReplicateData_Tick_FieldRef; + private FieldReference ReconcileData_Tick_FieldRef; + + private string ClearReplicateCache_Method_Name; + #endregion + + #region Const. + private const string REPLICATE_LOGIC_PREFIX = "ReplicateLogic___"; + private const string REPLICATE_READER_PREFIX = "ReplicateReader___"; + private const string RECONCILE_LOGIC_PREFIX = "ReconcileLogic___"; + private const string RECONCILE_READER_PREFIX = "ReconcileReader___"; + private const string DATA_TICK_FIELD_NAME = "Generated___Tick"; + #endregion + + internal bool ImportReferences() + { + SR.MethodInfo locMi; + + ClearReplicateCache_Method_Name = nameof(NetworkBehaviour.InternalClearReplicateCache); + + //GetGameObject. + locMi = typeof(UnityEngine.Component).GetMethod("get_gameObject"); + Unity_GetGameObject_MethodRef = CodegenSession.ImportReference(locMi); + //GetScene. + locMi = typeof(UnityEngine.GameObject).GetMethod("get_scene"); + Unity_GetScene_MethodRef = CodegenSession.ImportReference(locMi); + + //Physics.SyncTransform. + foreach (SR.MethodInfo mi in typeof(Physics).GetMethods()) + { + if (mi.Name == nameof(Physics.SyncTransforms)) + { + Physics3D_SyncTransforms_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + foreach (SR.MethodInfo mi in typeof(Physics2D).GetMethods()) + { + if (mi.Name == nameof(Physics2D.SyncTransforms)) + { + Physics2D_SyncTransforms_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + + //PhysicsScene.Simulate. + foreach (SR.MethodInfo mi in typeof(PhysicsScene).GetMethods()) + { + if (mi.Name == nameof(PhysicsScene.Simulate)) + { + Physics3D_Simulate_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + foreach (SR.MethodInfo mi in typeof(PhysicsScene2D).GetMethods()) + { + if (mi.Name == nameof(PhysicsScene2D.Simulate)) + { + Physics2D_Simulate_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + + //GetPhysicsScene. + foreach (SR.MethodInfo mi in typeof(PhysicsSceneExtensions).GetMethods()) + { + if (mi.Name == nameof(PhysicsSceneExtensions.GetPhysicsScene)) + { + Unity_GetPhysicsScene3D_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + foreach (SR.MethodInfo mi in typeof(PhysicsSceneExtensions2D).GetMethods()) + { + if (mi.Name == nameof(PhysicsSceneExtensions2D.GetPhysicsScene2D)) + { + Unity_GetPhysicsScene2D_MethodRef = CodegenSession.ImportReference(mi); + break; + } + } + + + return true; + } + + internal bool Process(TypeDefinition typeDef, ref uint rpcCount) + { + bool modified = false; + modified |= ProcessLocal(typeDef, ref rpcCount); + + return modified; + } + + #region Setup and checks. + /// + /// Gets number of predictions by checking for prediction attributes. This does not perform error checking. + /// + /// + /// + internal uint GetPredictionCount(TypeDefinition typeDef) + { + /* Currently only one prediction method is allowed per typeDef. + * Return 1 soon as a method is found. */ + foreach (MethodDefinition methodDef in typeDef.Methods) + { + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + if (customAttribute.Is(CodegenSession.AttributeHelper.ReplicateAttribute_FullName)) + return 1; + } + } + + return 0; + } + + + /// + /// Ensures only one prediction and reconile method exist per typeDef, and outputs finding. + /// + /// True if there is only one set of prediction methods. False if none, or more than one set. + internal bool GetPredictionMethods(TypeDefinition typeDef, out MethodDefinition replicateMd, out MethodDefinition reconcileMd) + { + replicateMd = null; + reconcileMd = null; + + bool error = false; + foreach (MethodDefinition methodDef in typeDef.Methods) + { + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + if (customAttribute.Is(CodegenSession.AttributeHelper.ReplicateAttribute_FullName)) + { + if (!MethodIsPrivate(methodDef) || AlreadyFound(replicateMd)) + error = true; + else + replicateMd = methodDef; + } + else if (customAttribute.Is(CodegenSession.AttributeHelper.ReconcileAttribute_FullName)) + { + if (!MethodIsPrivate(methodDef) || AlreadyFound(reconcileMd)) + error = true; + else + reconcileMd = methodDef; + } + if (error) + break; + } + if (error) + break; + } + + bool MethodIsPrivate(MethodDefinition md) + { + bool isPrivate = md.Attributes.HasFlag(MethodAttributes.Private); + if (!isPrivate) + CodegenSession.LogError($"Method {md.Name} within {typeDef.Name} is a prediction method and must be private."); + return isPrivate; + } + + bool AlreadyFound(MethodDefinition md) + { + bool alreadyFound = (md != null); + if (alreadyFound) + CodegenSession.LogError($"{typeDef.Name} contains multiple prediction sets; currently only one set is allowed."); + + return alreadyFound; + } + + if (!error && ((replicateMd == null) != (reconcileMd == null))) + { + CodegenSession.LogError($"{typeDef.Name} must contain both a [Replicate] and [Reconcile] method when using prediction."); + error = true; + } + + if (error || (replicateMd == null) || (reconcileMd == null)) + return false; + else + return true; + } + #endregion + + private bool ProcessLocal(TypeDefinition typeDef, ref uint rpcCount) + { + MethodDefinition replicateMd; + MethodDefinition reconcileMd; + + //Not using prediction methods. + if (!GetPredictionMethods(typeDef, out replicateMd, out reconcileMd)) + return false; + + //If replication methods found but this hierarchy already has max. + if (rpcCount >= NetworkBehaviourHelper.MAX_RPC_ALLOWANCE) + { + CodegenSession.LogError($"{typeDef.FullName} and inherited types exceed {NetworkBehaviourHelper.MAX_RPC_ALLOWANCE} replicated methods. Only {NetworkBehaviourHelper.MAX_RPC_ALLOWANCE} replicated methods are supported per inheritance hierarchy."); + return false; + } + + bool parameterError = false; + parameterError |= HasParameterError(replicateMd, typeDef, true); + parameterError |= HasParameterError(reconcileMd, typeDef, false); + if (parameterError) + return false; + + //Add field to replicate/reconcile datas, which stores tick of data. + TypeDefinition replicateDataTd = replicateMd.Parameters[0].ParameterType.CachedResolve(); + TypeDefinition reconcileDataTd = reconcileMd.Parameters[0].ParameterType.CachedResolve(); + AddTickFieldToDatas(replicateMd.Parameters[0].ParameterType.CachedResolve(), reconcileMd.Parameters[0].ParameterType.CachedResolve()); + /* Make sure data can serialize. Use array type, this will + * generate a serializer for element type as well. */ + bool canSerialize; + //Make sure replicate data can serialize. + canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(replicateDataTd.MakeArrayType(), true); + if (!canSerialize) + { + CodegenSession.LogError($"Replicate data type {replicateDataTd.Name} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + //Make sure reconcile data can serialize. + canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(reconcileDataTd, true); + if (!canSerialize) + { + CodegenSession.LogError($"Reconcile data type {reconcileDataTd.Name} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + //Creates fields for buffers. + CreatedPredictionFields predictionFields; + CreateFields(typeDef, replicateMd, reconcileMd, out predictionFields); + + PredictionReaders predictionReaders; + CreatePredictionMethods(typeDef, replicateMd, reconcileMd, predictionFields, rpcCount, out predictionReaders); + + InitializeCollections(typeDef, replicateMd, predictionFields); + RegisterRpcs(typeDef, rpcCount, predictionReaders); + + rpcCount++; + return true; + } + + /// + /// Registers RPCs that prediction uses. + /// + private void RegisterRpcs(TypeDefinition typeDef, uint hash, PredictionReaders readers) + { + MethodDefinition injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = injectionMethodDef.Body.GetILProcessor(); + List insts = new List(); + + Register(readers.ReplicateReader.CachedResolve(), true); + Register(readers.ReconcileReader.CachedResolve(), false); + + void Register(MethodDefinition readerMd, bool replicate) + { + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)hash)); + /* Create delegate and call NetworkBehaviour method. */ + insts.Add(processor.Create(OpCodes.Ldnull)); + insts.Add(processor.Create(OpCodes.Ldftn, readerMd)); + + MethodReference ctorMr; + MethodReference callMr; + if (replicate) + { + ctorMr = CodegenSession.NetworkBehaviourHelper.ReplicateRpcDelegateConstructor_MethodRef; + callMr = CodegenSession.NetworkBehaviourHelper.RegisterReplicateRpc_MethodRef; + } + else + { + ctorMr = CodegenSession.NetworkBehaviourHelper.ReconcileRpcDelegateConstructor_MethodRef; + callMr = CodegenSession.NetworkBehaviourHelper.RegisterReconcileRpc_MethodRef; + } + + insts.Add(processor.Create(OpCodes.Newobj, ctorMr)); + insts.Add(processor.Create(OpCodes.Call, callMr)); + } + + processor.InsertLast(insts); + + } + + /// + /// Initializes collection fields made during this process. + /// + /// + private void InitializeCollections(TypeDefinition typeDef, MethodDefinition replicateMd, CreatedPredictionFields predictionFields) + { + TypeReference replicateDataTr = replicateMd.Parameters[0].ParameterType; + MethodDefinition injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = injectionMethodDef.Body.GetILProcessor(); + + Generate(predictionFields.ClientReplicateDatas, true); + Generate(predictionFields.ServerReplicateDatas, false); + + void Generate(FieldReference fr, bool isList) + { + MethodDefinition ctorMd = CodegenSession.GeneralHelper.List_TypeRef.CachedResolve().GetConstructor(); + GenericInstanceType collectionGit; + if (isList) + GetGenericLists(replicateDataTr, out collectionGit); + else + GetGenericQueues(replicateDataTr, out collectionGit); + MethodReference ctorMr = ctorMd.MakeHostInstanceGeneric(collectionGit); + + List insts = new List(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Newobj, ctorMr)); + insts.Add(processor.Create(OpCodes.Stfld, fr)); + processor.InsertFirst(insts); + } + + } + + /// + /// Creates field buffers for replicate datas. + /// + /// + /// + /// + /// + private void CreateFields(TypeDefinition typeDef, MethodDefinition replicateMd, MethodDefinition reconcileMd, out CreatedPredictionFields predictionFields) + { + TypeReference replicateDataTr = replicateMd.Parameters[0].ParameterType; + TypeReference replicateDataArrTr = replicateDataTr.MakeArrayType(); + TypeReference reconcileDataTr = reconcileMd.Parameters[0].ParameterType; + TypeReference uintTr = CodegenSession.GeneralHelper.GetTypeReference(typeof(uint)); + TypeReference boolTr = CodegenSession.GeneralHelper.GetTypeReference(typeof(bool)); + + GenericInstanceType lstDataGit; + GenericInstanceType queueDataGit; + GetGenericLists(replicateDataTr, out lstDataGit); + GetGenericQueues(replicateDataTr, out queueDataGit); + + /* Data buffer. */ + FieldDefinition serverReplicatesFd = new FieldDefinition($"{replicateMd.Name}___serverReplicates", FieldAttributes.Private, queueDataGit); + FieldDefinition clientReplicatesFd = new FieldDefinition($"{replicateMd.Name}___clientReplicates", FieldAttributes.Private, lstDataGit); + FieldDefinition clientReconcileFd = new FieldDefinition($"{replicateMd.Name}___clientReconcile", FieldAttributes.Private, reconcileDataTr); + FieldDefinition serverReplicateTickFd = new FieldDefinition($"{replicateMd.Name}___serverReplicateTick", FieldAttributes.Private, uintTr); + FieldDefinition serverReconcileResendsFd = new FieldDefinition($"{replicateMd.Name}___serverReconcileResends", FieldAttributes.Private, uintTr); + FieldDefinition clientReplicateResendsFd = new FieldDefinition($"{replicateMd.Name}___clientReplicateResends", FieldAttributes.Private, uintTr); + FieldDefinition clientHasReconcileDataFd = new FieldDefinition($"{replicateMd.Name}___clientHasReconcileData", FieldAttributes.Private, boolTr); + FieldDefinition clientReplayingDataaFd = new FieldDefinition($"{replicateMd.Name}___clientReplayingData", FieldAttributes.Private, boolTr); + FieldDefinition clientReconcileTickFd = new FieldDefinition($"{replicateMd.Name}___clientReconcileTick", FieldAttributes.Private, uintTr); + FieldDefinition clientReplicateTickFd = new FieldDefinition($"{replicateMd.Name}___clientReplicateTick", FieldAttributes.Private, uintTr); + FieldDefinition serverReceivedTickFd = new FieldDefinition($"{replicateMd.Name}___serverReceivedTick", FieldAttributes.Private, uintTr); + FieldDefinition serverReplicatesReadBufferFd = new FieldDefinition($"{replicateMd.Name}___serverReplicateReadBuffer", FieldAttributes.Private, replicateDataArrTr); + + typeDef.Fields.Add(serverReplicatesFd); + typeDef.Fields.Add(clientReplicatesFd); + typeDef.Fields.Add(clientReconcileFd); + typeDef.Fields.Add(serverReplicateTickFd); + typeDef.Fields.Add(serverReconcileResendsFd); + typeDef.Fields.Add(clientReplicateResendsFd); + typeDef.Fields.Add(clientHasReconcileDataFd); + typeDef.Fields.Add(clientReplayingDataaFd); + typeDef.Fields.Add(clientReconcileTickFd); + typeDef.Fields.Add(clientReplicateTickFd); + typeDef.Fields.Add(serverReceivedTickFd); + typeDef.Fields.Add(serverReplicatesReadBufferFd); + + predictionFields = new CreatedPredictionFields(serverReplicatesFd, clientReplicatesFd, clientReconcileFd, serverReplicateTickFd, serverReconcileResendsFd, + clientReplicateResendsFd, clientHasReconcileDataFd, clientReplayingDataaFd, clientReconcileTickFd, clientReplicateTickFd, + serverReceivedTickFd, serverReplicatesReadBufferFd); + } + + /// + /// Returns if there are any errors with the prediction methods parameters and will print if so. + /// + private bool HasParameterError(MethodDefinition methodDef, TypeDefinition typeDef, bool replicateMethod) + { + int count = (replicateMethod) ? 3 : 2; + + //Check parameter count. + if (methodDef.Parameters.Count != count) + { + PrintParameterExpectations(); + return true; + } + + //Make sure first parameter is class or struct. + if (!methodDef.Parameters[0].ParameterType.IsClassOrStruct()) + { + CodegenSession.LogError($"Prediction methods must use a class or structure as the first parameter type. Structures are recommended to avoid allocations."); + return true; + } + + //Make sure remaining parameters are booleans. + for (int i = 1; i < count; i++) + { + ParameterDefinition pd = methodDef.Parameters[i]; + if (pd.ParameterType.Name != typeof(bool).Name) + { + PrintParameterExpectations(); + return true; + } + + } + + void PrintParameterExpectations() + { + if (replicateMethod) + CodegenSession.LogError($"Replicate method {methodDef.Name} within {typeDef.Name} requires exactly 3 parameters. The first parameter must be the data to replicate, second a boolean indicating if being run asServer, and third a boolean indicating if data is being replayed."); + else + CodegenSession.LogError($"Reconcile method {methodDef.Name} within {typeDef.Name} requires exactly 2 parameters. The first parameter must be the data to reconcile with, and the second a boolean indicating if being run asServer."); + } + + //No errors with parameters. + return false; + } + + /// + /// Creates all methods needed for a RPC. + /// + /// + /// + /// + private bool CreatePredictionMethods(TypeDefinition typeDef, MethodDefinition replicateMd, MethodDefinition reconcileMd, CreatedPredictionFields predictionFields, uint rpcCount, out PredictionReaders predictionReaders) + { + predictionReaders = null; + + string copySuffix = "___UserLogic"; + MethodDefinition replicateUserMd = CodegenSession.GeneralHelper.CopyMethod(replicateMd, $"{replicateMd.Name}{copySuffix}", out _); + MethodDefinition reconcileUserMd = CodegenSession.GeneralHelper.CopyMethod(reconcileMd, $"{reconcileMd.Name}{copySuffix}", out _); + replicateMd.Body.Instructions.Clear(); + reconcileMd.Body.Instructions.Clear(); + + MethodDefinition replicateReader; + MethodDefinition reconcileReader; + + if (!CreateReplicate()) + return false; + if (!CreateReconcile()) + return false; + + CreateClearReplicateCacheMethod(typeDef, replicateMd.Parameters[0].ParameterType, predictionFields); + ServerCreateReplicateReader(typeDef, replicateMd, predictionFields, out replicateReader); + ClientCreateReconcileReader(typeDef, reconcileMd, predictionFields, out reconcileReader); + predictionReaders = new PredictionReaders(replicateReader, reconcileReader); + + bool CreateReplicate() + { + ILProcessor processor = replicateMd.Body.GetILProcessor(); + ParameterDefinition asServerPd = replicateMd.Parameters[1]; + + //Universal conditions. + CreateReplicateConditions(replicateMd, predictionFields); + + //Wrap server content in an asServer if statement. + Instruction afterAsServerInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brfalse, afterAsServerInst); + /***************************/ + ServerCreateReplicate(replicateMd, predictionFields); + /***************************/ + processor.Append(afterAsServerInst); + + //Wrap client content in an !asServer if statement. + Instruction afterNotAsServerInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brtrue, afterNotAsServerInst); + /***************************/ + ClientCreateReplicate(replicateMd, predictionFields, rpcCount); + /***************************/ + processor.Append(afterNotAsServerInst); + + //Call user instr method. + CodegenSession.GeneralHelper.CallCopiedMethod(replicateMd, replicateUserMd); + processor.Emit(OpCodes.Ret); + + return true; + } + + + bool CreateReconcile() + { + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + ParameterDefinition asServerPd = reconcileMd.Parameters[1]; + + //Wrap server content in an asServer if statement. + Instruction afterAsServerInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brfalse, afterAsServerInst); + /***************************/ + ServerCreateReconcile(reconcileMd, predictionFields, ref rpcCount); + /***************************/ + processor.Emit(OpCodes.Ret); + processor.Append(afterAsServerInst); + + + ClientRetIfNoReconcile(reconcileMd, predictionFields); + // _clientHasReconcileData = false; + processor.Add(ClientSetHasReconcileData(reconcileMd, false, predictionFields)); + + // if (base.IsServer) invoke reconciles, but do not reconcile. + /* ClientHost does not reconcile but script may be dependent on the + * pre/post reconcile events so invoke those anyway. */ + Instruction afterClearReconcileInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.IsServer_MethodRef); + processor.Emit(OpCodes.Brfalse, afterClearReconcileInst); + //Invoke OnPre/PostReconcile. + processor.Add(InvokeOnReconcile(reconcileMd, true)); + processor.Add(InvokeOnReconcile(reconcileMd, false)); + //Exit method. + processor.Emit(OpCodes.Ret); + processor.Append(afterClearReconcileInst); + + //Set data received to the reconcile parameter so that clients access the right data. + SetReconcileData(reconcileMd, predictionFields); + // uint reconcileTick = r.Generated___Tick. + VariableDefinition reconcileTickVd = reconcileMd.CreateVariable(typeof(uint)); + processor.Emit(OpCodes.Ldarg, reconcileMd.Parameters[0]); //the data. + processor.Emit(OpCodes.Ldfld, ReconcileData_Tick_FieldRef); //Generated___Tick field. + processor.Emit(OpCodes.Stloc, reconcileTickVd); + // base.SetLastReconcileTick(reconcileTick). + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldloc, reconcileTickVd); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.SetLastReconcileTick_MethodRef); + //Invoke reconciling start. + processor.Add(InvokeOnReconcile(reconcileMd, true)); + + //Call user instr method. + CodegenSession.GeneralHelper.CallCopiedMethod(reconcileMd, reconcileUserMd); + + ClientCreateReconcile(reconcileMd, replicateMd, predictionFields, reconcileTickVd); + + processor.Emit(OpCodes.Ret); + return true; + } + + return true; + } + + #region Universal prediction. + /// + /// Creates an override for the method responsible for resetting replicates. + /// + /// + /// + private void CreateClearReplicateCacheMethod(TypeDefinition typeDef, TypeReference dataTr, CreatedPredictionFields predictionFields) + { + MethodDefinition md = typeDef.GetMethod(ClearReplicateCache_Method_Name); + //Already exist when it shouldn't. + if (md != null) + { + CodegenSession.LogWarning($"{typeDef.Name} overrides method {md.Name} when it should not. Logic within {md.Name} will be replaced by code generation."); + md.Body.Instructions.Clear(); + } + else + { + md = new MethodDefinition(ClearReplicateCache_Method_Name, (MethodAttributes.Public | MethodAttributes.Virtual), CodegenSession.Module.TypeSystem.Void); + CodegenSession.GeneralHelper.CreateParameter(md, typeof(bool), "asServer"); + typeDef.Methods.Add(md); + CodegenSession.ImportReference(md); + } + + ILProcessor processor = md.Body.GetILProcessor(); + + GenericInstanceType genericDataLst; + GetGenericLists(dataTr, out genericDataLst); + GenericInstanceType genericDataQueue; + GetGenericQueues(dataTr, out genericDataQueue); + //Get clear method. + MethodReference lstClearMr = CodegenSession.GeneralHelper.List_Clear_MethodRef.MakeHostInstanceGeneric(genericDataLst); + MethodReference queueClearMr = CodegenSession.GeneralHelper.Queue_Clear_MethodRef.MakeHostInstanceGeneric(genericDataQueue); + + ParameterDefinition asServerPd = md.Parameters[0]; + + Instruction afterAsServerInst = processor.Create(OpCodes.Nop); + Instruction resetTicksInst = processor.Create(OpCodes.Nop); + + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brfalse_S, afterAsServerInst); + //Clear on server replicates. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueClearMr); + processor.Emit(OpCodes.Br_S, resetTicksInst); + processor.Append(afterAsServerInst); + //Clear on client replicates. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Callvirt, lstClearMr); + + processor.Append(resetTicksInst); + /* Reset last ticks. */ + // + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReconcileTick); + // + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReplicateTick); + // + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stfld, predictionFields.ServerReceivedTick); + // + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stfld, predictionFields.ServerReplicateTick); + processor.Emit(OpCodes.Ret); + } + /// + /// Adds DATA_TICK_FIELD_NAME to dataTd. + /// + /// + private void AddTickFieldToDatas(TypeDefinition replicateDataTd, TypeDefinition reconcileDataTd) + { + Add(replicateDataTd, true); + Add(reconcileDataTd, false); + + void Add(TypeDefinition td, bool replicate) + { + FieldReference fr = td.GetField(DATA_TICK_FIELD_NAME); + if (fr == null) + { + FieldDefinition fd = new FieldDefinition(DATA_TICK_FIELD_NAME, FieldAttributes.Public, + CodegenSession.GeneralHelper.GetTypeReference(typeof(uint))); + td.Fields.Add(fd); + fr = CodegenSession.ImportReference(fd); + } + + if (replicate) + ReplicateData_Tick_FieldRef = fr; + else + ReconcileData_Tick_FieldRef = fr; + } + } + + /// + /// Creates general conditions for replicate to run for server or client. + /// + private void CreateReplicateConditions(MethodDefinition replicateMd, CreatedPredictionFields predictionFields) + { + ILProcessor processor = replicateMd.Body.GetILProcessor(); + + ParameterDefinition asServerPd = replicateMd.Parameters[1]; + + // if (asServer && !base.Owner.IsActive) return; + Instruction afterNoOwnerCheckInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brfalse_S, afterNoOwnerCheckInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.Owner_MethodRef); + processor.Emit(OpCodes.Callvirt, CodegenSession.ObjectHelper.NetworkConnection_IsActive_MethodRef); + processor.Emit(OpCodes.Brtrue_S, afterNoOwnerCheckInst); + ClearReplicateCache(true, false); + processor.Emit(OpCodes.Ret); + processor.Append(afterNoOwnerCheckInst); + + // if (!asServer && !base.IsOwner) return; + Instruction afterClientCheckInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brtrue_S, afterClientCheckInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.IsOwner_MethodRef); + processor.Emit(OpCodes.Brtrue_S, afterClientCheckInst); + ClearReplicateCache(false, true); + processor.Emit(OpCodes.Ret); + processor.Append(afterClientCheckInst); + + // if (asServer && base.IsOwner) + //clientHost does not replicate. + Instruction afterAsServerIsClientInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, asServerPd); + processor.Emit(OpCodes.Brfalse_S, afterAsServerIsClientInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.IsOwner_MethodRef); + processor.Emit(OpCodes.Brfalse_S, afterAsServerIsClientInst); + ClearReplicateCache(true, true); + processor.Emit(OpCodes.Ret); + processor.Append(afterAsServerIsClientInst); + + void ClearReplicateCache(bool server, bool client) + { + if (server) + { + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.ClearReplicateCache_MethodRef); + } + if (client) + { + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.ClearReplicateCache_MethodRef); + } + } + } + + /// + /// Outputs generic lists for dataTr and uint. + /// + private void GetGenericLists(TypeReference dataTr, out GenericInstanceType lstData) + { + TypeReference listDataTr = CodegenSession.ImportReference(typeof(List<>)); + lstData = listDataTr.MakeGenericInstanceType(new TypeReference[] { dataTr }); + } + /// + /// Outputs generic lists for dataTr and uint. + /// + private void GetGenericQueues(TypeReference dataTr, out GenericInstanceType queueData) + { + TypeReference queueDataTr = CodegenSession.ImportReference(typeof(Queue<>)); + queueData = queueDataTr.MakeGenericInstanceType(new TypeReference[] { dataTr }); + } + /// + /// Adds to buffer at the front of methodDef. + /// + /// + /// + /// + /// + private void AddToReplicateBuffer(MethodDefinition methodDef, object dataDef, FieldDefinition dataFd) + { + TypeReference dataTr = null; + if (dataDef is ParameterDefinition pd) + dataTr = pd.ParameterType; + else if (dataDef is VariableDefinition vd) + dataTr = vd.VariableType; + + GenericInstanceType lstDataGit; + GetGenericLists(dataTr, out lstDataGit); + MethodReference dataAddMr = CodegenSession.GeneralHelper.List_Add_MethodRef.MakeHostInstanceGeneric(lstDataGit); + + ILProcessor processor = methodDef.Body.GetILProcessor(); + + //_dataLst.Add(dataPd); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, dataFd); + + if (dataDef is ParameterDefinition pd2) + processor.Emit(OpCodes.Ldarg, pd2); + else if (dataDef is VariableDefinition vd2) + processor.Emit(OpCodes.Ldloc, vd2); + processor.Emit(OpCodes.Callvirt, dataAddMr); + } + /// + /// Removes countVd from list of dataFd starting at index 0. + /// + private List ListRemoveRange(MethodDefinition methodDef, FieldDefinition dataFd, TypeReference dataTr, VariableDefinition countVd) + { + /* Remove entries which exceed maximum buffer. */ + //Method references for uint/data list: + //get_count, RemoveRange. */ + GenericInstanceType lstDataGit; + GetGenericLists(dataTr, out lstDataGit); + MethodReference lstDataRemoveRangeMr = CodegenSession.GeneralHelper.List_RemoveRange_MethodRef.MakeHostInstanceGeneric(lstDataGit); + + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + //Index 1 is the uint, 0 is the data. + insts.Add(processor.Create(OpCodes.Ldarg_0));//this. + insts.Add(processor.Create(OpCodes.Ldfld, dataFd)); + insts.Add(processor.Create(OpCodes.Ldc_I4_0)); + insts.Add(processor.Create(OpCodes.Ldloc, countVd)); + insts.Add(processor.Create(OpCodes.Callvirt, lstDataRemoveRangeMr)); + + return insts; + } + /// + /// Subtracts 1 from a field. + /// + private List SubtractFromField(MethodDefinition methodDef, FieldDefinition fieldDef) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + // _field--; + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldfld, fieldDef)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); + insts.Add(processor.Create(OpCodes.Sub)); + insts.Add(processor.Create(OpCodes.Stfld, fieldDef)); + + return insts; + } + /// + /// Subtracts 1 from a variable. + /// + private List SubtractFromVariable(MethodDefinition methodDef, VariableDefinition variableDef) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + // variable--; + insts.Add(processor.Create(OpCodes.Ldloc, variableDef)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); + insts.Add(processor.Create(OpCodes.Sub)); + insts.Add(processor.Create(OpCodes.Stloc, variableDef)); + + return insts; + } + + /// + /// Subtracts 1 from a variable. + /// + private List SubtractOneVariableFromAnother(MethodDefinition methodDef, VariableDefinition srcVd, VariableDefinition modifierVd) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + // variable -= v2; + insts.Add(processor.Create(OpCodes.Ldloc, srcVd)); + insts.Add(processor.Create(OpCodes.Ldloc, modifierVd)); + insts.Add(processor.Create(OpCodes.Sub)); + insts.Add(processor.Create(OpCodes.Stloc, srcVd)); + + return insts; + } + #endregion + + #region Server side. + /// + /// Creates replicate code for client. + /// + private void ServerCreateReplicate(MethodDefinition replicateMd, CreatedPredictionFields predictionFields) + { + //data.DATA_TICK_FIELD_NAME. + ParameterDefinition replicateDataPd = replicateMd.Parameters[0]; + TypeReference replicateDataTr = replicateDataPd.ParameterType; + + ILProcessor processor = replicateMd.Body.GetILProcessor(); + + /* If there is nothing buffered exit. */ + //Get count in buffered. + GenericInstanceType queueDataGit; + GetGenericQueues(replicateDataTr, out queueDataGit); + MethodReference queueDataGetCountMr = CodegenSession.GeneralHelper.Queue_get_Count_MethodRef.MakeHostInstanceGeneric(queueDataGit); + MethodReference queueDataGetItemMr = CodegenSession.GeneralHelper.Queue_Dequeue_MethodRef.MakeHostInstanceGeneric(queueDataGit); + + // int queueCount = _buffered.Count. + VariableDefinition queueCountVd = CodegenSession.GeneralHelper.CreateVariable(replicateMd, typeof(int)); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueDataGetCountMr); + processor.Emit(OpCodes.Stloc, queueCountVd); + /* If the queue count is 2 more than maximum + * buffered then dequeue an extra one. Currently + * the input will be lost, in a later release users + * will have the option to run multiple inputs + * per tick which this occurs. */ + //If (queueCount > 3) + Instruction afterDequeueInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, queueCountVd); + processor.Emit(OpCodes.Ldc_I4_3); + processor.Emit(OpCodes.Ble_S, afterDequeueInst); + //_buffer.Dequeue(); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueDataGetItemMr); + processor.Emit(OpCodes.Pop); + processor.Append(afterDequeueInst); + + //Replace with data from buffer. + // if (queueCount > 0) + Instruction afterReplaceDataInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, queueCountVd); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Ble, afterReplaceDataInst); + + /* Set the data parameter to a dequeued entry. */ + // dataPd = _buffered.Dequeue(); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueDataGetItemMr); + processor.Emit(OpCodes.Starg, replicateDataPd); + + /* Set last replicate tick. */ + // _serverReplicateTick = dataPd.DATA_TICK_FIELD_NAME. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldarg, replicateDataPd); + processor.Emit(OpCodes.Ldfld, ReplicateData_Tick_FieldRef); + processor.Emit(OpCodes.Stfld, predictionFields.ServerReplicateTick.CachedResolve()); + //Reset reconcile ticks. + // _serverReconcileTicks = 3; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_3); + processor.Emit(OpCodes.Stfld, predictionFields.ServerReconcileResends.CachedResolve()); + + processor.Append(afterReplaceDataInst); + } + + /// + /// Creates a reader for replicate data received from clients. + /// + private bool ServerCreateReplicateReader(TypeDefinition typeDef, MethodDefinition replicateMd, CreatedPredictionFields predictionFields, out MethodDefinition result) + { + string methodName = $"{REPLICATE_READER_PREFIX}{replicateMd.Name}"; + MethodDefinition createdMd = new MethodDefinition(methodName, + MethodAttributes.Private, + replicateMd.Module.TypeSystem.Void); + typeDef.Methods.Add(createdMd); + createdMd.Body.InitLocals = true; + + TypeReference replicateDataTr = replicateMd.Parameters[0].ParameterType; + ILProcessor processor = createdMd.Body.GetILProcessor(); + + //Create pooledreader parameter. + ParameterDefinition readerPd = CodegenSession.GeneralHelper.CreateParameter(createdMd, typeof(PooledReader)); + + //Read into cache. + // int readCount = pooledReader.ReadToCollection(_serverReplicateReadBuffer); + MethodReference genericReadMr = CodegenSession.ReaderHelper.Reader_ReadToCollection_MethodRef.MakeGenericMethod(replicateDataTr); + VariableDefinition readCountVd = createdMd.CreateVariable(typeof(int)); + processor.Emit(OpCodes.Ldarg, readerPd); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldflda, predictionFields.ServerReplicateReaderBuffer); + //processor.Emit(OpCodes.Ldloca, replicateDataArrVd); + processor.Emit(OpCodes.Callvirt, genericReadMr); + processor.Emit(OpCodes.Stloc, readCountVd); + + //Create NetworkConnection parameter to compare owner. + ParameterDefinition networkConnectionPd = CodegenSession.GeneralHelper.CreateParameter(createdMd, typeof(NetworkConnection)); + // if (base.ComparerOwner(networkConnectionPd) return; + CodegenSession.NetworkBehaviourHelper.CreateRemoteClientIsOwnerCheck(processor, networkConnectionPd); + + //Make a local array of same type for easier handling and set it's reference to field. + VariableDefinition replicateDataArrVd = createdMd.CreateVariable(predictionFields.ServerReplicateReaderBuffer.FieldType); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateReaderBuffer); + processor.Emit(OpCodes.Stloc, replicateDataArrVd); + + /* Store queue count into queueCount. */ + //START //Method references for uint get_Count. + GenericInstanceType queueDataGit; + GetGenericQueues(replicateDataTr, out queueDataGit); + MethodReference queueDataGetCountMr = CodegenSession.GeneralHelper.Queue_get_Count_MethodRef.MakeHostInstanceGeneric(queueDataGit); + MethodReference queueDataEnqueueMr = CodegenSession.GeneralHelper.Queue_Enqueue_MethodRef.MakeHostInstanceGeneric(queueDataGit); + MethodReference queueDataDequeueMr = CodegenSession.GeneralHelper.Queue_Dequeue_MethodRef.MakeHostInstanceGeneric(queueDataGit); + //END //Method references for uint get_Count. + + /* Add array entries to buffered. */ + // for (int i = 0; i < dataArr.Length; i++) + // { + // Data d = dataArr[i]; + // if (d.Tick > this.lastTick) + // _serverReplicateDatas.Add(d); + // this.lastTick = d.Tick; + // } + + VariableDefinition iteratorVd = CodegenSession.GeneralHelper.CreateVariable(createdMd, typeof(int)); + Instruction iteratorComparerInst = processor.Create(OpCodes.Ldloc, iteratorVd); + Instruction iteratorLogicInst = processor.Create(OpCodes.Nop); + Instruction iteratorIncreaseComparerInst = processor.Create(OpCodes.Ldloc, iteratorVd); + // for (int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, iteratorVd); + processor.Emit(OpCodes.Br_S, iteratorComparerInst); + //Logic. + processor.Append(iteratorLogicInst); + + //Store the data tick. + VariableDefinition dataTickVd = CodegenSession.GeneralHelper.CreateVariable(createdMd, typeof(int)); + processor.Emit(OpCodes.Ldloc, replicateDataArrVd); + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldelema, replicateDataTr); + processor.Emit(OpCodes.Ldfld, ReplicateData_Tick_FieldRef); + processor.Emit(OpCodes.Stloc, dataTickVd); + + processor.Emit(OpCodes.Ldloc, dataTickVd); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReceivedTick); + processor.Emit(OpCodes.Ble_S, iteratorIncreaseComparerInst); + //Add to buffer. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Ldloc, replicateDataArrVd); + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldelem_Any, replicateDataTr); + processor.Emit(OpCodes.Callvirt, queueDataEnqueueMr); + + //Set serverReceivedTick. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldloc, dataTickVd); + processor.Emit(OpCodes.Stfld, predictionFields.ServerReceivedTick); + // ; i++) + processor.Append(iteratorIncreaseComparerInst); //(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc_S, iteratorVd); + // ;i < arr.Length + processor.Append(iteratorComparerInst); //(OpCodes.Ldloc, iterator); + processor.Emit(OpCodes.Ldloc, readCountVd); + processor.Emit(OpCodes.Conv_I4); + processor.Emit(OpCodes.Blt_S, iteratorLogicInst); + + /* Remove entries which exceed maximum buffer. */ + VariableDefinition queueCountVd = CodegenSession.GeneralHelper.CreateVariable(createdMd, typeof(int)); + //Get maximum buffered. + // byte maximumBufferdInputs = base.TimeManager.MaximumBufferedInputs. + VariableDefinition maximumBufferedVd = CodegenSession.GeneralHelper.CreateVariable(createdMd, typeof(byte)); + processor.Emit(OpCodes.Ldarg_0); //base. + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef); + processor.Emit(OpCodes.Callvirt, CodegenSession.TimeManagerHelper.MaximumBufferedInputs_MethodRef); + processor.Emit(OpCodes.Stloc, maximumBufferedVd); + //Set queueCountVd to new count. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueDataGetCountMr); + processor.Emit(OpCodes.Stloc, queueCountVd); + + //Get number of inputs to remove. Will be positive if there are too many buffered inputs. + // int queueCount -= maximumBuffered. + processor.Emit(OpCodes.Ldloc, queueCountVd); + processor.Emit(OpCodes.Ldloc, maximumBufferedVd); + processor.Emit(OpCodes.Sub); + processor.Emit(OpCodes.Stloc, queueCountVd); + //If remove count is positive. + // if (queueCount > 0) + Instruction afterRemoveRangeInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, queueCountVd); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Ble_S, afterRemoveRangeInst); + + Instruction dequeueComparerInst = processor.Create(OpCodes.Nop); + Instruction dequeueLogicInst = processor.Create(OpCodes.Nop); + //Reuse iteratorVd + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, iteratorVd); + processor.Emit(OpCodes.Br_S, dequeueComparerInst); + + //Logic. + processor.Append(dequeueLogicInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateDatas); + processor.Emit(OpCodes.Callvirt, queueDataDequeueMr); + processor.Emit(OpCodes.Pop); + + //Increase iterator. + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, iteratorVd); + + //ComparerJmp. + processor.Append(dequeueComparerInst); + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldloc, queueCountVd); + processor.Emit(OpCodes.Blt_S, dequeueLogicInst); + + processor.Append(afterRemoveRangeInst); + + + //Add end of method. + processor.Emit(OpCodes.Ret); + + result = createdMd; + return true; + } + + /// + /// Creates server side code for reconcileMd. + /// + /// + /// + private void ServerCreateReconcile(MethodDefinition reconcileMd, CreatedPredictionFields predictionFields, ref uint rpcHash) + { + ParameterDefinition reconcileDataPd = reconcileMd.Parameters[0]; + List insts = new List(); + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + + GenericInstanceMethod sendReconcileRpcdMr = CodegenSession.NetworkBehaviourHelper.SendReconcileRpc_MethodRef.MakeGenericMethod(new TypeReference[] { reconcileDataPd.ParameterType }); + + Instruction afterRetInst = processor.Create(OpCodes.Nop); + // if (serverReconcileResends == 0) + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReconcileResends); + processor.Emit(OpCodes.Brtrue_S, afterRetInst); + processor.Emit(OpCodes.Ret); + processor.Append(afterRetInst); + + // _serverReconcileResends--; + processor.Add(SubtractFromField(reconcileMd, predictionFields.ServerReconcileResends.CachedResolve())); + + //Set channel based on if last resend. + VariableDefinition channelVd = reconcileMd.CreateVariable(typeof(Channel)); + //Default channel to unreliable. + processor.Emit(OpCodes.Ldc_I4, (int)Channel.Unreliable); + processor.Emit(OpCodes.Stloc, channelVd); + //Update channel to reliable if last reconcile. + Instruction afterChannelReliableInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReconcileResends); + processor.Emit(OpCodes.Brtrue_S, afterChannelReliableInst); + processor.Emit(OpCodes.Ldc_I4, (int)Channel.Reliable); + processor.Emit(OpCodes.Stloc, channelVd); + processor.Append(afterChannelReliableInst); + + //Replace data.DATA_TICK_FIELD_NAME with last tick replicated. + OpCode ldArgOC0 = (reconcileDataPd.ParameterType.IsValueType) ? OpCodes.Ldarga : OpCodes.Ldarg; + processor.Emit(ldArgOC0, reconcileDataPd); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ServerReplicateTick); + processor.Emit(OpCodes.Stfld, ReconcileData_Tick_FieldRef); + + // base.SendReconcileRpc(hash, data, channel); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4, (int)rpcHash); + processor.Emit(OpCodes.Ldarg, reconcileDataPd); + processor.Emit(OpCodes.Ldloc, channelVd); + processor.Emit(OpCodes.Call, sendReconcileRpcdMr); + + processor.Add(insts); + } + #endregion + + #region Client side. + /// + /// Creates replicate code for client. + /// + private void ClientCreateReplicate(MethodDefinition replicateMd, CreatedPredictionFields predictionFields, uint rpcCount) + { + ParameterDefinition replicateDataPd = replicateMd.Parameters[0]; + + ILProcessor processor = replicateMd.Body.GetILProcessor(); + + Instruction afterNetworkLogicInst = processor.Create(OpCodes.Nop); + // if (_replaying) skip sending logic. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplayingData); + processor.Emit(OpCodes.Brtrue, afterNetworkLogicInst); + // if (base.IsServer) skip sending, host doesn't need to send. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.IsServer_MethodRef); + processor.Emit(OpCodes.Brtrue, afterNetworkLogicInst); + + //Sets isDefault to if dataPd is default value. + VariableDefinition isDefaultVd; + ClientIsDefault(replicateMd, replicateDataPd, out isDefaultVd); + //Resets clientReplicateResends if dataPd is not default. + ClientResetResends(replicateMd, predictionFields, isDefaultVd); + ///Exits method if client has no resends remaining. + ClientSkipIfNoResends(replicateMd, predictionFields, afterNetworkLogicInst); + //Decreases clientReplicateResends. + processor.Add(SubtractFromField(replicateMd, predictionFields.ClientReplicateResends.CachedResolve())); + //Sets TimeManager.LocalTick to data. + ClientSetReplicateDataTick(replicateMd, replicateDataPd, predictionFields, isDefaultVd); + //Adds data to client buffer. + + // if (!isDefaultData) _replicateDatas.Add.... + Instruction afterAddToBufferInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, isDefaultVd); + processor.Emit(OpCodes.Brtrue_S, afterAddToBufferInst); + AddToReplicateBuffer(replicateMd, replicateDataPd, predictionFields.ClientReplicateDatas.CachedResolve()); + processor.Append(afterAddToBufferInst); + //Calls to send buffer to server. + ClientSendInput(replicateMd, rpcCount, predictionFields); + //Add instructions to beginning of method. + processor.Append(afterNetworkLogicInst); + } + + + /// + /// Exits method if no more client replicate resends are available. + /// + private void ClientSkipIfNoResends(MethodDefinition methodDef, CreatedPredictionFields predictionFields, Instruction skipInst) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateResends); + processor.Emit(OpCodes.Brfalse_S, skipInst); + } + + /// + /// Resets clientReplicateResends if isDefaultVd is false. + /// + private void ClientResetResends(MethodDefinition methodDef, CreatedPredictionFields predictionFields, VariableDefinition isDefaultVd) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + Instruction afterResetInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, isDefaultVd); + processor.Emit(OpCodes.Brtrue_S, afterResetInst); + // _clientReplicateResends = 3. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_3); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReplicateResends); + processor.Append(afterResetInst); + } + + /// + /// Creates an IsDefault check on dataPd and returns instructions, also outputting boolean variable. + /// + /// + /// + /// + private void ClientIsDefault(MethodDefinition methodDef, ParameterDefinition dataPd, out VariableDefinition boolVd) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + boolVd = CodegenSession.GeneralHelper.CreateVariable(methodDef, typeof(bool)); + //If client has no more resends and passedin default for data. + // if (!asServer && _clientReplicateResends == 0 && dataPd == default) return; + MethodReference genericIsDefaultMr = CodegenSession.GeneralHelper.Comparers_IsDefault_MethodRef.MakeGenericMethod( + new TypeReference[] { dataPd.ParameterType }); + + //Set to not default by ....default. + // default = false; + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, boolVd); + + // if (!base.TransformMayChange() && Comparers.IsDefault()) + // default = true; + Instruction afterSetDefaultInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TransformMayChange_MethodRef); + processor.Emit(OpCodes.Brtrue_S, afterSetDefaultInst); + processor.Emit(OpCodes.Ldarg, dataPd); + processor.Emit(OpCodes.Call, genericIsDefaultMr); + processor.Emit(OpCodes.Brfalse_S, afterSetDefaultInst); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Stloc, boolVd); + processor.Append(afterSetDefaultInst); + } + /// + /// Sets data.DATA_TICK_FIELD_NAME to TimeManager.LocalTick. + /// + private void ClientSetReplicateDataTick(MethodDefinition methodDef, ParameterDefinition dataPd, CreatedPredictionFields predictionFields, VariableDefinition isDefaultVd) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + VariableDefinition tickVd = CodegenSession.GeneralHelper.CreateVariable(methodDef, typeof(uint)); + Instruction afterCallLocalTickInst = processor.Create(OpCodes.Nop); + Instruction afterUseClientReplicateTickInst = processor.Create(OpCodes.Nop); + /* uint localTIck; + /* if (!isDefaultData) + * localTick = base.TimeManager.LocalTick; + * _clientReplicateTick = localTick; + * else + * localTick = _clientReplicateTick; */ + // if (!isDefault) localTick = base.TimeManager.LocalTick; + processor.Emit(OpCodes.Ldloc, isDefaultVd); + processor.Emit(OpCodes.Brtrue_S, afterCallLocalTickInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef); + processor.Emit(OpCodes.Callvirt, CodegenSession.TimeManagerHelper.LocalTick_MethodRef); + processor.Emit(OpCodes.Stloc, tickVd); + // _clientReplicateTick = localTick; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldloc, tickVd); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReplicateTick); + processor.Emit(OpCodes.Br_S, afterUseClientReplicateTickInst); + //ELSE + // localTick = _clientReplicateTick; + processor.Append(afterCallLocalTickInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateTick); + processor.Emit(OpCodes.Stloc, tickVd); + processor.Append(afterUseClientReplicateTickInst); + + //data.DATA_TICK_FIELD_NAME = tick. + OpCode ldArgOC = (dataPd.ParameterType.IsValueType) ? OpCodes.Ldarga : OpCodes.Ldarg; + processor.Emit(ldArgOC, dataPd); + processor.Emit(OpCodes.Ldloc, tickVd); + processor.Emit(OpCodes.Stfld, ReplicateData_Tick_FieldRef.CachedResolve()); + } + /// + /// Sends clients inputs to server. + /// + private void ClientSendInput(MethodDefinition replicateMd, uint hash, CreatedPredictionFields predictionFields) + { + ParameterDefinition dataPd = replicateMd.Parameters[0]; + TypeReference dataTr = dataPd.ParameterType; + + ILProcessor processor = replicateMd.Body.GetILProcessor(); + + //Make method reference NB.SendReplicateRpc + GenericInstanceMethod sendReplicateRpcdMr = CodegenSession.NetworkBehaviourHelper.SendReplicateRpc_MethodRef.MakeGenericMethod(new TypeReference[] { dataTr }); + + //Call WriteBufferedInput. + // base.WriteBufferedInput(hash, _clientBuffered, count); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4, (int)hash); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Ldc_I4_5); //past inputs, hardcoded for now. + processor.Emit(OpCodes.Call, sendReplicateRpcdMr); + } + + + /// + /// Creates a return if client does not have reconcile data. + /// + private bool ClientRetIfNoReconcile(MethodDefinition reconcileMd, CreatedPredictionFields predictionFields) + { + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + + Instruction afterHasDataCheckInst = processor.Create(OpCodes.Nop); + // if (!hasReconcileData) return; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientHasReconcileData); + processor.Emit(OpCodes.Brtrue_S, afterHasDataCheckInst); + processor.Emit(OpCodes.Ret); + processor.Append(afterHasDataCheckInst); + + return true; + } + + + /// + /// Sets stored reconcile data to the parameter of reconcileMd if !asServer. + /// + private void SetReconcileData(MethodDefinition reconcileMd, CreatedPredictionFields predictionFields) + { + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + + ParameterDefinition reconcileDataPd = reconcileMd.Parameters[0]; + + // reconcileDataPd = _clientReconcileData. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ReconcileData); + processor.Emit(OpCodes.Starg, reconcileDataPd); + } + + /// + /// Syncs transforms if simulateVd is true. + /// + private void ClientSyncTransforms(MethodDefinition methodDef) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + processor.Emit(OpCodes.Call, Physics2D_SyncTransforms_MethodRef); + processor.Emit(OpCodes.Call, Physics3D_SyncTransforms_MethodRef); + } + + + /// + /// Simulates physics if simulateVd is true. Use null on simulateVd to skip check. + /// + private List ClientTrySimulatePhysics(MethodDefinition methodDef, VariableDefinition simulateVd, VariableDefinition tickDeltaVd, VariableDefinition physicsScene3DVd, VariableDefinition physicsScene2DVd) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + Instruction afterSimulateInst = null; + if (simulateVd != null) + { + // if (simulate) { + afterSimulateInst = processor.Create(OpCodes.Nop); + insts.Add(processor.Create(OpCodes.Ldloc, simulateVd)); + insts.Add(processor.Create(OpCodes.Brfalse_S, afterSimulateInst)); + } + + AddSimulate(physicsScene3DVd, Physics3D_Simulate_MethodRef); + AddSimulate(physicsScene2DVd, Physics2D_Simulate_MethodRef); + + void AddSimulate(VariableDefinition physicsSceneVd, MethodReference simulateMr) + { + insts.Add(processor.Create(OpCodes.Ldloca_S, physicsSceneVd)); + insts.Add(processor.Create(OpCodes.Ldloc, tickDeltaVd)); + insts.Add(processor.Create(OpCodes.Conv_R4)); + insts.Add(processor.Create(OpCodes.Call, simulateMr)); + //If is 2d simulate then pop result. 2D uses a bool return while 3D uses a void. + if (simulateMr == Physics2D_Simulate_MethodRef) + insts.Add(processor.Create(OpCodes.Pop)); + } + + if (simulateVd != null) + insts.Add(afterSimulateInst); + + return insts; + } + + /// + /// Creates and outputs a bool to indicate if physics must be simulated manually. + /// + private void ClientCreateSimulatePhysicsBool(MethodDefinition methodDef, out VariableDefinition simulateVd) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + simulateVd = CodegenSession.GeneralHelper.CreateVariable(methodDef, typeof(bool)); + + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef); + processor.Emit(OpCodes.Call, CodegenSession.TimeManagerHelper.PhysicsMode_MethodRef); + processor.Emit(OpCodes.Ldc_I4, (int)PhysicsMode.TimeManager); + processor.Emit(OpCodes.Ceq); + processor.Emit(OpCodes.Stloc, simulateVd); + + } + + /// + /// Sets ClientHasReconcileData. + /// + private List ClientSetHasReconcileData(MethodDefinition methodDef, bool hasData, CreatedPredictionFields predictionFields) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + int boolValue = (hasData) ? 1 : 0; + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldc_I4, boolValue)); + insts.Add(processor.Create(OpCodes.Stfld, predictionFields.ClientHasReconcileData)); + + return insts; + } + + /// + /// Removes replicates prior and at index. + /// + private void ClientRemoveFromCache(MethodDefinition reconcileMd, MethodDefinition replicateMd, + CreatedPredictionFields predictionFields, VariableDefinition reconcileTickVd) + { + ParameterDefinition reconcileDataPd = reconcileMd.Parameters[0]; + TypeReference replicateDataTr = replicateMd.Parameters[0].ParameterType; + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + + VariableDefinition foundIndexVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(int)); + // index = -1; + processor.Emit(OpCodes.Ldc_I4_M1); + processor.Emit(OpCodes.Stloc, foundIndexVd); + + VariableDefinition iteratorVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(int)); + + GenericInstanceType lstDataGit; + GetGenericLists(replicateDataTr, out lstDataGit); + MethodReference replicateGetCountMr = CodegenSession.GeneralHelper.List_get_Count_MethodRef.MakeHostInstanceGeneric(lstDataGit); + MethodReference replicateGetItemMr = CodegenSession.GeneralHelper.List_get_Item_MethodRef.MakeHostInstanceGeneric(lstDataGit); + MethodReference replicateClearMr = CodegenSession.GeneralHelper.List_Clear_MethodRef.MakeHostInstanceGeneric(lstDataGit); + + Instruction iteratorIncreaseInst = processor.Create(OpCodes.Ldloc, iteratorVd); + Instruction iteratorComparerInst = processor.Create(OpCodes.Ldloc, iteratorVd); + Instruction iteratorLogicInst = processor.Create(OpCodes.Ldarg_0); + Instruction afterLoopInst = processor.Create(OpCodes.Nop); + // for (int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, iteratorVd); + processor.Emit(OpCodes.Br, iteratorComparerInst); + //Logic. + // if (replicateTick(replaying).Tick == reconcileTick(fromServer)) + processor.Append(iteratorLogicInst); //Ldarg_0. + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Callvirt, replicateGetItemMr); + processor.Emit(OpCodes.Ldfld, ReplicateData_Tick_FieldRef); + processor.Emit(OpCodes.Ldloc, reconcileTickVd); + processor.Emit(OpCodes.Bne_Un, iteratorIncreaseInst); + + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Stloc, foundIndexVd); + processor.Emit(OpCodes.Br, afterLoopInst); + // i++; + processor.Append(iteratorIncreaseInst); //Ldloc iteratorVd. + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, iteratorVd); + //Conditional. + processor.Append(iteratorComparerInst); //Ldloc iteratorVd. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Callvirt, replicateGetCountMr); + processor.Emit(OpCodes.Blt, iteratorLogicInst); + + processor.Append(afterLoopInst); + + /* Remove entries that server processed. */ + // if (index == -1) //Entry not found, shouldn't happen. + Instruction afterClearInst = processor.Create(OpCodes.Nop); + Instruction afterRemoveRangeInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, foundIndexVd); + processor.Emit(OpCodes.Ldc_I4_M1); + processor.Emit(OpCodes.Bne_Un, afterClearInst); + // replicates.Clear(); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Callvirt, replicateClearMr); + processor.Emit(OpCodes.Br, afterRemoveRangeInst); + + // index++; This is for RemoveRange. If index is 0 then remove count needs to be 1. + processor.Append(afterClearInst); + processor.Emit(OpCodes.Ldloc, foundIndexVd); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, foundIndexVd); + + processor.Add(ListRemoveRange(reconcileMd, predictionFields.ClientReplicateDatas.CachedResolve(), replicateDataTr, foundIndexVd)); + processor.Append(afterRemoveRangeInst); + } + + private void ClientGetPhysicsScenes(MethodDefinition reconcileMd, out VariableDefinition objectSceneVd, out VariableDefinition physicsScene3DVd, out VariableDefinition physicsScene2DVd) + { + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + objectSceneVd = reconcileMd.CreateVariable(typeof(UnityEngine.SceneManagement.Scene)); + physicsScene3DVd = reconcileMd.CreateVariable(typeof(PhysicsScene)); + physicsScene2DVd = reconcileMd.CreateVariable(typeof(PhysicsScene2D)); + + //Scene objectScene = gameObject.scene; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, Unity_GetGameObject_MethodRef); + processor.Emit(OpCodes.Callvirt, Unity_GetScene_MethodRef); + processor.Emit(OpCodes.Stloc, objectSceneVd); + + // PhysicsScene ps3d = objectScene.GetPhysicsScene(); + processor.Emit(OpCodes.Ldloc, objectSceneVd); + processor.Emit(OpCodes.Call, Unity_GetPhysicsScene3D_MethodRef); + processor.Emit(OpCodes.Stloc, physicsScene3DVd); + + // PhysicsScene2D ps2d = objectScene.GetPhysicsScene(); + processor.Emit(OpCodes.Ldloc, objectSceneVd); + processor.Emit(OpCodes.Call, Unity_GetPhysicsScene2D_MethodRef); + processor.Emit(OpCodes.Stloc, physicsScene2DVd); + } + /// + /// Replays all cached client datas. + /// + private void ClientReplayBuffered(MethodDefinition reconcileMd, MethodDefinition replicateMd, CreatedPredictionFields predictionFields, + VariableDefinition simulateVd, VariableDefinition sceneVd, VariableDefinition physicsSceneVd, VariableDefinition physicsScene2DVd) + { + MethodReference replicateMr = CodegenSession.ImportReference(replicateMd); + TypeReference replicateDataTr = replicateMd.Parameters[0].ParameterType; + + ILProcessor processor = reconcileMd.Body.GetILProcessor(); + + VariableDefinition iteratorVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(int)); + + GenericInstanceType lstDataGit; + GetGenericLists(replicateDataTr, out lstDataGit); + MethodReference dataCollectionGetCountMr = CodegenSession.GeneralHelper.List_get_Count_MethodRef.MakeHostInstanceGeneric(lstDataGit); + MethodReference dataCollectionGetItemMr = CodegenSession.GeneralHelper.List_get_Item_MethodRef.MakeHostInstanceGeneric(lstDataGit); + + Instruction iteratorComparerInst = processor.Create(OpCodes.Ldloc, iteratorVd); + Instruction iteratorLogicInst = processor.Create(OpCodes.Nop); + + //Set as replaying before iterating. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReplayingData); + + // double tickDelta = base.TimeManager.TickDelta; + VariableDefinition tickDeltaVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(double)); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef); + processor.Emit(OpCodes.Callvirt, CodegenSession.TimeManagerHelper.TickDelta_MethodRef); + processor.Emit(OpCodes.Stloc, tickDeltaVd); + + // int count = _replicateBuffer.Count. + VariableDefinition lstCountVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(int)); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Callvirt, dataCollectionGetCountMr); + processor.Emit(OpCodes.Stloc, lstCountVd); + + // for (int i = 0 + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stloc, iteratorVd); + processor.Emit(OpCodes.Br, iteratorComparerInst); + //Logic. + processor.Append(iteratorLogicInst); + processor.Add(InvokeOnReplicateReplay(replicateMd, sceneVd, physicsSceneVd, physicsScene2DVd, true)); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Callvirt, dataCollectionGetItemMr); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Ldc_I4_1); //true for replaying. + processor.Emit(OpCodes.Call, replicateMr); + processor.Add(ClientTrySimulatePhysics(reconcileMd, simulateVd, tickDeltaVd, physicsSceneVd, physicsScene2DVd)); + processor.Add(InvokeOnReplicateReplay(replicateMd, sceneVd, physicsSceneVd, physicsScene2DVd, false)); + // i++; + processor.Emit(OpCodes.Ldloc, iteratorVd); + processor.Emit(OpCodes.Ldc_I4_1); + processor.Emit(OpCodes.Add); + processor.Emit(OpCodes.Stloc, iteratorVd); + //Conditional. + processor.Append(iteratorComparerInst); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReplicateDatas); + processor.Emit(OpCodes.Callvirt, dataCollectionGetCountMr); + processor.Emit(OpCodes.Blt, iteratorLogicInst); + + //Invokes reconcile end. + processor.Add(InvokeOnReconcile(reconcileMd, false)); + + //Unset replaying. + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReplayingData); + + } + + + /// + /// Invokes OnReplicateReplay. + /// + private List InvokeOnReplicateReplay(MethodDefinition methodDef, VariableDefinition sceneVd, VariableDefinition physicsSceneVd, VariableDefinition physicsScene2DVd, bool start) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef)); + insts.Add(processor.Create(OpCodes.Ldloc, sceneVd)); + insts.Add(processor.Create(OpCodes.Ldloc, physicsSceneVd)); + insts.Add(processor.Create(OpCodes.Ldloc, physicsScene2DVd)); + if (start) + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); + else + insts.Add(processor.Create(OpCodes.Ldc_I4_0)); + insts.Add(processor.Create(OpCodes.Callvirt, CodegenSession.TimeManagerHelper.InvokeOnReplicateReplay_MethodRef)); + + return insts; + } + + /// + /// Invokes OnReconcile. Uses lstCountVd > 0 as a requirement if not null. + /// + private List InvokeOnReconcile(MethodDefinition methodDef, bool start) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.TimeManager_MethodRef)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this for NB. + if (start) + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); + else + insts.Add(processor.Create(OpCodes.Ldc_I4_0)); + insts.Add(processor.Create(OpCodes.Callvirt, CodegenSession.TimeManagerHelper.InvokeOnReconcile_MethodRef)); + + return insts; + } + + /// + /// Creates a reader for replicate data received from clients. + /// + private void ClientCreateReconcileReader(TypeDefinition typeDef, MethodDefinition reconcileMd, CreatedPredictionFields predictionFields, out MethodDefinition result) + { + string methodName = $"{RECONCILE_READER_PREFIX}{reconcileMd.Name}"; + /* If method already exist then clear it. This + * can occur when a method needs to be rebuilt due to + * inheritence, and renumbering the start counts. */ + MethodDefinition createdMd = createdMd = new MethodDefinition(methodName, + MethodAttributes.Private, + reconcileMd.Module.TypeSystem.Void); + typeDef.Methods.Add(createdMd); + createdMd.Body.InitLocals = true; + + //Create pooledreader parameter. + ParameterDefinition readerPd = CodegenSession.GeneralHelper.CreateParameter(createdMd, typeof(PooledReader)); + TypeReference reconcileDataTr = reconcileMd.Parameters[0].ParameterType; + //data.DATA_TICK_FIELD_NAME. + ILProcessor processor = createdMd.Body.GetILProcessor(); + + + VariableDefinition reconcileVr; + processor.Add(CodegenSession.ReaderHelper.CreateRead(createdMd, readerPd, reconcileDataTr, out reconcileVr)); + + /* Make sure is owner. This is always sent to owner, but + * unreliably. It's possible they will arrive after + * an owner change. */ + // if (!base.IsOwner) return; + CodegenSession.NetworkBehaviourHelper.CreateLocalClientIsOwnerCheck(createdMd, LoggingType.Off, true, false, false); + + //uint receivedTick = data.DATA_TICK_FIELD_NAME. + VariableDefinition receivedTickVd = CodegenSession.GeneralHelper.CreateVariable(createdMd, typeof(uint)); + processor.Emit(OpCodes.Ldloc, reconcileVr); + processor.Emit(OpCodes.Ldfld, ReconcileData_Tick_FieldRef); + processor.Emit(OpCodes.Stloc, receivedTickVd); + + /* If tick is less than last received tick then exit method. + * Already reconciled to a more recent tick. */ + // if (receivedTick <= _clientReconcileTick) return; + Instruction afterOldTickCheckInst = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldloc, receivedTickVd); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldfld, predictionFields.ClientReconcileTick); + processor.Emit(OpCodes.Bgt_Un_S, afterOldTickCheckInst); + processor.Emit(OpCodes.Ret); + processor.Append(afterOldTickCheckInst); + + // _clientReconcileTick = receivedTick; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldloc, receivedTickVd); + processor.Emit(OpCodes.Stfld, predictionFields.ClientReconcileTick); + // _clientHasReconcileData = true; + processor.Add(ClientSetHasReconcileData(createdMd, true, predictionFields)); + // _clientReconcileData = reconcileData; + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldloc, reconcileVr); + processor.Emit(OpCodes.Stfld, predictionFields.ReconcileData); + + //Add end of method. + processor.Emit(OpCodes.Ret); + + result = createdMd; + } + + /// + /// Creates client side code for reconcileMd. + /// + /// + /// + private void ClientCreateReconcile(MethodDefinition reconcileMd, MethodDefinition replicateMd + , CreatedPredictionFields predictionFields, VariableDefinition reconcileTickVd) + { + ILProcessor reconcileProcessor = reconcileMd.Body.GetILProcessor(); + + // bool simulate = (base.TimeManager.PhysicsMode == PhysicsMode.TimeManager); + VariableDefinition simulateVd; + /* Simulations to run after replaying inputs. Needed because + * even though there may not be inputs the ticks ran after + * the last input should re-simulate. EG: if inputs are performed + * on ticks 0, 1, 2, 3, 4 but ticks 5, 6, 7, 8 are run before the + * the client can reconcile then only 0-4 simulations will run, and the + * remaining will not causing a desync. */ + VariableDefinition extraSimulationsVd = CodegenSession.GeneralHelper.CreateVariable(reconcileMd, typeof(uint)); + // extraSimulations = 0; //default. + reconcileProcessor.Emit(OpCodes.Ldc_I4_0); + reconcileProcessor.Emit(OpCodes.Stloc, extraSimulationsVd); + + ClientCreateSimulatePhysicsBool(reconcileMd, out simulateVd); + // Physics/2D.SyncTransforms. + ClientSyncTransforms(reconcileMd); + //Remove data server processed. + ClientRemoveFromCache(reconcileMd, replicateMd, predictionFields, reconcileTickVd); + //Gets physics scenes. + VariableDefinition objectSceneVd; + VariableDefinition physicsScenDVd; + VariableDefinition physicsScene2DVd; + ClientGetPhysicsScenes(reconcileMd, out objectSceneVd, out physicsScenDVd, out physicsScene2DVd); + //Replays buffered inputs. + ClientReplayBuffered(reconcileMd, replicateMd, predictionFields, simulateVd, objectSceneVd, physicsScenDVd, physicsScene2DVd); + } + #endregion + + #region CreateSend... + /// + /// Emits common values into Send call that all prediction methods use. + /// + private void CreateSendPredictionCommon(ILProcessor processor, uint hash, VariableDefinition writerVd) + { + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Ldc_I4, (int)hash); + processor.Emit(OpCodes.Ldloc, writerVd); + } + /// + /// Calls SendReplicate. + /// + /// + /// + /// + private void CreateSendReplicate(ILProcessor processor, uint hash, VariableDefinition writerVd) + { + CreateSendPredictionCommon(processor, hash, writerVd); + //Call NetworkBehaviour.SendReplicate. + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.SendReplicateRpc_MethodRef); + } + #endregion + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs.meta new file mode 100644 index 0000000..c8266bc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourPredictionProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0663606e86b0b34bae85df164747e72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs new file mode 100644 index 0000000..68d338c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs @@ -0,0 +1,681 @@ +using FishNet.CodeGenerating.Extension; +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Configuring; +using FishNet.Object; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using MonoFN.Collections.Generic; +using System.Collections.Generic; +using System.Linq; +using DebugX = UnityEngine.Debug; + +namespace FishNet.CodeGenerating.Processing +{ + internal class NetworkBehaviourProcessor + { + #region Types. + private class NetworkInitializeMethodData + { + public MethodDefinition MethodDefinition; + public FieldDefinition CalledFieldDef; + public bool CalledFromAwake; + + public NetworkInitializeMethodData(MethodDefinition methodDefinition, FieldDefinition calledFieldDef) + { + MethodDefinition = methodDefinition; + CalledFieldDef = calledFieldDef; + CalledFromAwake = false; + } + } + private class AwakeMethodData + { + public MethodDefinition AwakeMethodDef; + public MethodDefinition UserLogicMethodDef; + public bool Created; + + public AwakeMethodData(MethodDefinition awakeMd, MethodDefinition userLogicMd, bool created) + { + AwakeMethodDef = awakeMd; + UserLogicMethodDef = userLogicMd; + Created = created; + } + } + #endregion + + #region Misc. + private Dictionary _earlyNetworkInitializeDatas = new Dictionary(); + private Dictionary _lateNetworkInitializeDatas = new Dictionary(); + /// + /// Methods modified or iterated during weaving. + /// + internal List ModifiedMethodDefinitions = new List(); + /// + /// Classes which have been processed for all NetworkBehaviour features. + /// + private HashSet _processedClasses = new HashSet(); + #endregion + + #region Const. + internal const string EARLY_INITIALIZED_NAME = "NetworkInitializeEarly_"; + internal const string LATE_INITIALIZED_NAME = "NetworkInitializeLate_"; + internal const string NETWORKINITIALIZE_EARLY_INTERNAL_NAME = "NetworkInitialize___Early"; + internal const string NETWORKINITIALIZE_LATE_INTERNAL_NAME = "NetworkInitialize__Late"; + private MethodAttributes PUBLIC_VIRTUAL_ATTRIBUTES = (MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig); +#pragma warning disable CS0414 + private MethodAttributes PROTECTED_VIRTUAL_ATTRIBUTES = (MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig); +#pragma warning restore CS0414 + #endregion + + internal bool Process(TypeDefinition typeDef, List<(SyncType, ProcessedSync)> allProcessedSyncs, Dictionary childSyncTypeCounts, Dictionary childRpcCounts) + { + bool modified = false; + TypeDefinition copyTypeDef = typeDef; + TypeDefinition firstTypeDef = typeDef; + + //Make collection of NBs to processor. + List typeDefs = new List(); + do + { + typeDefs.Add(copyTypeDef); + copyTypeDef = TypeDefinitionExtensionsOld.GetNextBaseClassToProcess(copyTypeDef); + } while (copyTypeDef != null); + + + /* Iterate from child-most to parent first + * while creating network initialize methods. + * This is because the child-most must call the parents + * base awake methods. */ + foreach (TypeDefinition td in typeDefs) + { + /* Class was already processed. Since child most is processed first + * this can occur if a class is inherited by multiple types. If a class + * has already been processed then there is no reason to scale up the hierarchy + * because it would have already been done. */ + if (HasClassBeenProcessed(td)) + continue; + + //Disallow nested network behaviours. + ICollection nestedTds = td.NestedTypes; + foreach (TypeDefinition item in nestedTds) + { + if (item.InheritsNetworkBehaviour()) + { + CodegenSession.LogError($"{td.FullName} contains nested NetworkBehaviours. These are not supported."); + return modified; + } + } + + /* Create NetworkInitialize before-hand so the other procesors + * can use it. */ + MethodDefinition networkInitializeInternalMd; + CreateNetworkInitializeMethods(td, out networkInitializeInternalMd); + CallNetworkInitializeMethods(networkInitializeInternalMd); + } + + /* Reverse and do RPCs/SyncTypes. + * This counts up on children instead of the + * parent, so we do not have to rewrite + * parent numbers. */ + typeDefs.Reverse(); + + foreach (TypeDefinition td in typeDefs) + { + /* Class was already processed. Since child most is processed first + * this can occur if a class is inherited by multiple types. If a class + * has already been processed then there is no reason to scale up the hierarchy + * because it would have already been done. */ + if (HasClassBeenProcessed(td)) + continue; + + //No longer used...remove in rework. + uint rpcCount = 0; + childRpcCounts.TryGetValue(td, out rpcCount); + /* Prediction. */ + /* Run prediction first since prediction will modify + * user data passed into prediction methods. Because of this + * other RPCs should use the modified version and reader/writers + * made for prediction. */ + modified |= CodegenSession.NetworkBehaviourPredictionProcessor.Process(td, ref rpcCount); + //25ms + + /* RPCs. */ + modified |= CodegenSession.RpcProcessor.Process(td, ref rpcCount); + //30ms + /* //perf rpcCounts can be optimized by having different counts + * for target, observers, server, replicate, and reoncile rpcs. Since + * each registers to their own delegates this is possible. */ + + + + /* SyncTypes. */ + uint syncTypeStartCount; + childSyncTypeCounts.TryGetValue(td, out syncTypeStartCount); + modified |= CodegenSession.NetworkBehaviourSyncProcessor.Process(td, allProcessedSyncs, ref syncTypeStartCount); + //70ms + _processedClasses.Add(td); + } + + int maxAllowSyncTypes = 256; + if (allProcessedSyncs.Count > maxAllowSyncTypes) + { + CodegenSession.LogError($"Found {allProcessedSyncs.Count} SyncTypes within {firstTypeDef.FullName}. The maximum number of allowed SyncTypes within type and inherited types is {maxAllowSyncTypes}. Remove SyncTypes or condense them using data containers, or a custom SyncObject."); + return false; + } + + /* If here then all inerited classes for firstTypeDef have + * been processed. */ + PrepareNetworkInitializeMethods(firstTypeDef); + + /* Make awake methods for all inherited classes + * public and virtual. This is so I can add logic + * to the firstTypeDef awake and still execute + * user awake methods. */ + List awakeDatas = new List(); + if (!CreateOrModifyAwakeMethods(firstTypeDef, ref awakeDatas)) + { + CodegenSession.LogError($"Was unable to make Awake methods public virtual starting on type {firstTypeDef.FullName}."); + return modified; + } + + //NetworkInitializeEarly. + CallNetworkInitializeFromAwake(awakeDatas, true); + //Call base awake, then call user logic methods. + CallBaseAwakeOnCreatedMethods(awakeDatas); + CallAwakeUserLogic(awakeDatas); + //NetworkInitializeLate + CallNetworkInitializeFromAwake(awakeDatas, false); + //Since awake methods are erased ret has to be added at the end. + AddReturnsToAwake(awakeDatas); + + CodegenSession.NetworkBehaviourSyncProcessor.CallBaseReadSyncVar(firstTypeDef); + + return modified; + } + + + /// + /// Returns if a class has been processed. + /// + /// + /// + private bool HasClassBeenProcessed(TypeDefinition typeDef) + { + return _processedClasses.Contains(typeDef); + } + + /// + /// Returns if any typeDefs have attributes which are not allowed to be used outside NetworkBehaviour. + /// + /// + /// + internal bool NonNetworkBehaviourHasInvalidAttributes(Collection typeDefs) + { + bool error = false; + foreach (TypeDefinition typeDef in typeDefs) + { + //Inherits, don't need to check. + if (typeDef.InheritsNetworkBehaviour()) + continue; + + //Check each method for attribute. + foreach (MethodDefinition md in typeDef.Methods) + { + //Has RPC attribute but doesn't inherit from NB. + if (CodegenSession.RpcProcessor.Attributes.HasRpcAttributes(md)) + { + CodegenSession.LogError($"{typeDef.FullName} has one or more RPC attributes but does not inherit from NetworkBehaviour."); + error = true; + } + } + //Check fields for attribute. + foreach (FieldDefinition fd in typeDef.Fields) + { + if (CodegenSession.NetworkBehaviourSyncProcessor.GetSyncType(fd, false, out _) != SyncType.Unset) + { + CodegenSession.LogError($"{typeDef.FullName} has one or more SyncType attributes but does not inherit from NetworkBehaviour."); + error = true; + } + } + } + + return error; + } + + + + /// + /// Calls the next awake method if the nested awake was created by codegen. + /// + /// + private void CallBaseAwakeOnCreatedMethods(List datas) + { + /* Method definitions are added from child most + * so they will always be going up the hierarchy. */ + for (int i = 0; i < datas.Count; i++) + { + AwakeMethodData amd = datas[i]; + /* If the awake already existed + * then let the user code be the final say + * if base is called. */ + if (!amd.Created) + continue; + + TypeDefinition copyTypeDef = amd.AwakeMethodDef.DeclaringType; + + /* Get next base awake first. + * If it doesn't exist then nothing can be called. */ + MethodReference baseAwakeMethodRef = copyTypeDef.GetMethodReferenceInBase(NetworkBehaviourHelper.AWAKE_METHOD_NAME);// GetNextAwake(i); + if (baseAwakeMethodRef == null) + return; + //MethodReference baseAwakeMethodRef = CodegenSession.ImportReference(baseAwakeMd); + /* Awake will always exist because it was added previously. + * Get awake for the current declaring type. */ + MethodDefinition copyAwakeMd = copyTypeDef.GetMethod(NetworkBehaviourHelper.AWAKE_METHOD_NAME); + + //Check if they already call base. + ILProcessor processor = copyAwakeMd.Body.GetILProcessor(); + bool alreadyHasBaseCall = false; + //Check if already calls baseAwake. + foreach (var item in copyAwakeMd.Body.Instructions) + { + + //If a call or call virt. Although, callvirt should never occur. + if (item.OpCode == OpCodes.Call || item.OpCode == OpCodes.Callvirt) + { + if (item.Operand != null && item.Operand.GetType().Name == nameof(MethodDefinition)) + { + MethodDefinition md = (MethodDefinition)item.Operand; + if (md == baseAwakeMethodRef.Resolve()) + { + alreadyHasBaseCall = true; + break; + } + } + } + } + + if (!alreadyHasBaseCall) + { + //Create instructions for base call. + processor.Emit(OpCodes.Ldarg_0); //base. + processor.Emit(OpCodes.Call, baseAwakeMethodRef); + } + } + } + + + /// + /// Calls the next awake method if the nested awake was created by codegen. + /// + /// + private void CallAwakeUserLogic(List datas) + { + /* Method definitions are added from child most + * so they will always be going up the hierarchy. */ + for (int i = 0; i < datas.Count; i++) + { + AwakeMethodData amd = datas[i]; + //If was created then there is no user logic. + if (amd.Created) + continue; + //If logic method is null. Should never be the case. + if (amd.UserLogicMethodDef == null) + continue; + + MethodDefinition awakeMd = amd.AwakeMethodDef; + CodegenSession.GeneralHelper.CallCopiedMethod(awakeMd, amd.UserLogicMethodDef); + } + + } + + + /// + /// Adds a check to NetworkInitialize to see if it has already run. + /// + /// + private void AddNetworkInitializeExecutedCheck(TypeDefinition firstTypeDef, bool initializeEarly, bool checkForExisting) + { + + TypeDefinition copyTypeDef = firstTypeDef; + AddCheck(copyTypeDef, initializeEarly); + + void AddCheck(TypeDefinition td, bool early) + { + string methodName; + string fieldName; + if (early) + { + methodName = NETWORKINITIALIZE_EARLY_INTERNAL_NAME; + fieldName = $"{EARLY_INITIALIZED_NAME}{td.FullName}_{td.Module.Name}"; + } + else + { + methodName = NETWORKINITIALIZE_LATE_INTERNAL_NAME; + fieldName = $"{LATE_INITIALIZED_NAME}{td.FullName}_{td.Module.Name}"; + } + + MethodDefinition md = td.GetMethod(methodName); + if (md == null) + return; + + FieldDefinition fd = copyTypeDef.GetField(fieldName)?.Resolve(); + if (fd == null) + { + TypeReference boolTr = CodegenSession.GeneralHelper.GetTypeReference(typeof(bool)); + //Add fields to see if it already ran. + fd = new FieldDefinition(fieldName, FieldAttributes.Private, boolTr); + td.Fields.Add(fd); + } + + if (checkForExisting) + { + bool alreadyChecked = false; + //Check if already calls baseAwake. + foreach (Instruction item in md.Body.Instructions) + { + //If a call or call virt. Although, callvirt should never occur. + if (item.OpCode == OpCodes.Ldfld && item.Operand != null && item.Operand is FieldDefinition opFd) + { + if (opFd == fd) + { + alreadyChecked = true; + break; + } + } + } + + if (alreadyChecked) + return; + } + + List insts = new List(); + ILProcessor processor = md.Body.GetILProcessor(); + //Add check if already called. + //if (alreadyInitialized) return; + Instruction skipFirstRetInst = processor.Create(OpCodes.Nop); + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldfld, fd)); + insts.Add(processor.Create(OpCodes.Brfalse_S, skipFirstRetInst)); + insts.Add(processor.Create(OpCodes.Ret)); + insts.Add(skipFirstRetInst); + //Set field to true. + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); + insts.Add(processor.Create(OpCodes.Stfld, fd)); + processor.InsertFirst(insts); + } + + } + /// + /// Gets the top-most parent away method. + /// + /// + /// + private void PrepareNetworkInitializeMethods(TypeDefinition firstTypeDef) + { + TypeDefinition thisTypeDef = firstTypeDef; + + string[] initializeMethodNames = new string[] { NETWORKINITIALIZE_EARLY_INTERNAL_NAME, NETWORKINITIALIZE_LATE_INTERNAL_NAME }; + + do + { + bool canCallBase = thisTypeDef.CanProcessBaseType(); + + foreach (string mdName in initializeMethodNames) + { + /* There are no more base calls to make but we still + * need to check if the initialize methods have already ran, so do that + * here. */ + if (!canCallBase) + { + AddNetworkInitializeExecutedCheck(thisTypeDef, (mdName == NETWORKINITIALIZE_EARLY_INTERNAL_NAME), true); + continue; + } + + /* Awake will always exist because it was added previously. + * Get awake for copy and base of copy. */ + MethodDefinition thisMd = thisTypeDef.GetMethod(mdName); + MethodDefinition baseMd = thisTypeDef.BaseType.CachedResolve().GetMethod(mdName); + MethodReference baseMr = thisTypeDef.GetMethodReferenceInBase(mdName); + ILProcessor processor = thisMd.Body.GetILProcessor(); + + bool alreadyHasBaseCall = false; + //Check if already calls baseAwake. + foreach (Instruction item in thisMd.Body.Instructions) + { + + //If a call or call virt. Although, callvirt should never occur. + if (item.OpCode == OpCodes.Call || item.OpCode == OpCodes.Callvirt) + { + if (item.Operand != null && item.Operand.GetType().Name == nameof(MethodDefinition)) + { + MethodDefinition md = (MethodDefinition)item.Operand; + if (md == baseMd) + { + alreadyHasBaseCall = true; + break; + } + } + } + } + + if (!alreadyHasBaseCall) + { + //Create instructions for base call. + List instructions = new List(); + instructions.Add(processor.Create(OpCodes.Ldarg_0)); //this. + instructions.Add(processor.Create(OpCodes.Call, baseMr)); + processor.InsertFirst(instructions); + + AddNetworkInitializeExecutedCheck(thisTypeDef, (mdName == NETWORKINITIALIZE_EARLY_INTERNAL_NAME), false); + } + } + + thisTypeDef = TypeDefinitionExtensionsOld.GetNextBaseClassToProcess(thisTypeDef); + } while (thisTypeDef != null); + + } + + /// + /// Adds returns awake method definitions within awakeDatas. + /// + private void AddReturnsToAwake(List awakeDatas) + { + foreach (AwakeMethodData amd in awakeDatas) + { + ILProcessor processor = amd.AwakeMethodDef.Body.GetILProcessor(); + //If no instructions or the last instruction isnt ret. + if (processor.Body.Instructions.Count == 0 + || processor.Body.Instructions[processor.Body.Instructions.Count - 1].OpCode != OpCodes.Ret) + { + processor.Emit(OpCodes.Ret); + } + } + } + + /// + /// Calls NetworKInitializeLate method on the typeDef. + /// + /// + private void CallNetworkInitializeFromAwake(List awakeDatas, bool callEarly) + { + /* InitializeLate should be called after the user runs + * all their Awake logic. This is so the user can configure + * sync types on Awake and it won't trigger those values + * as needing to be sent over the network, since both + * server and client will be assigning them on Awake. */ + foreach (AwakeMethodData amd in awakeDatas) + { + string methodName = (callEarly) ? NETWORKINITIALIZE_EARLY_INTERNAL_NAME : + NETWORKINITIALIZE_LATE_INTERNAL_NAME; + + TypeDefinition td = amd.AwakeMethodDef.DeclaringType; + MethodDefinition initializeMd = td.GetMethod(methodName); + MethodReference initializeMr = CodegenSession.ImportReference(initializeMd); + + ILProcessor processor = amd.AwakeMethodDef.Body.GetILProcessor(); + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Call, initializeMr); + } + } + + /// + /// Creates an 'NetworkInitialize' method which is called by the childmost class to initialize scripts on Awake. + /// + private void CreateNetworkInitializeMethods(TypeDefinition typeDef, out MethodDefinition networkInitializeInternalMd) + { + CreateMethod(NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + CreateMethod(NETWORKINITIALIZE_LATE_INTERNAL_NAME); + networkInitializeInternalMd = CreateMethod(CodegenSession.NetworkBehaviourHelper.NetworkInitializeInternal_MethodRef.Name); + + MethodDefinition CreateMethod(string name) + { + MethodDefinition md = typeDef.GetMethod(name); + //Already made. + if (md != null) + return md; + + //Create new public virtual method and add it to typedef. + md = new MethodDefinition(name, + PUBLIC_VIRTUAL_ATTRIBUTES, + typeDef.Module.TypeSystem.Void); + typeDef.Methods.Add(md); + + //Emit ret into new method. + ILProcessor processor = md.Body.GetILProcessor(); + //End of method return. + processor.Emit(OpCodes.Ret); + return md; + } + } + + + /// + /// Creates an 'NetworkInitialize' method which is called by the childmost class to initialize scripts on Awake. + /// + private void CallNetworkInitializeMethods(MethodDefinition networkInitializeInternalMd) + { + ILProcessor processor = networkInitializeInternalMd.Body.GetILProcessor(); + + networkInitializeInternalMd.Body.Instructions.Clear(); + CallMethod(NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + CallMethod(NETWORKINITIALIZE_LATE_INTERNAL_NAME); + processor.Emit(OpCodes.Ret); + + void CallMethod(string name) + { + MethodDefinition md = networkInitializeInternalMd.DeclaringType.GetMethod(name); + MethodReference mr = CodegenSession.ImportReference(md); + + processor.Emit(OpCodes.Ldarg_0); + processor.Emit(OpCodes.Callvirt, mr); + } + } + + + /// + /// Creates Awake method for and all parents of typeDef using the parentMostAwakeMethodDef as a template. + /// + /// True if successful. + private bool CreateOrModifyAwakeMethods(TypeDefinition typeDef, ref List datas) + { + //Now update all scopes/create methods. + TypeDefinition copyTypeDef = typeDef; + do + { + MethodDefinition tmpMd = copyTypeDef.GetMethod(NetworkBehaviourHelper.AWAKE_METHOD_NAME); + string logicMethodName = $"{NetworkBehaviourHelper.AWAKE_METHOD_NAME}___UserLogic"; + bool create = (tmpMd == null); + + //Awake is found. + if (!create) + { + if (tmpMd.ReturnType != copyTypeDef.Module.TypeSystem.Void) + { + CodegenSession.LogError($"IEnumerator Awake methods are not supported within NetworkBehaviours."); + return false; + } + tmpMd.Attributes = PUBLIC_VIRTUAL_ATTRIBUTES; + } + //No awake yet. + else + { + //Make awake. + tmpMd = new MethodDefinition(NetworkBehaviourHelper.AWAKE_METHOD_NAME, PUBLIC_VIRTUAL_ATTRIBUTES, copyTypeDef.Module.TypeSystem.Void); + copyTypeDef.Methods.Add(tmpMd); + ILProcessor processor = tmpMd.Body.GetILProcessor(); + processor.Emit(OpCodes.Ret); + } + + //If logic already exist then awake has been processed already. + MethodDefinition logicMd = copyTypeDef.GetMethod(logicMethodName); + if (logicMd == null) + { + logicMd = CodegenSession.GeneralHelper.CopyMethod(tmpMd, logicMethodName, out _); + //Clear awakeMethod. + tmpMd.Body.Instructions.Clear(); + } + datas.Add(new AwakeMethodData(tmpMd, logicMd, create)); + + copyTypeDef = TypeDefinitionExtensionsOld.GetNextBaseClassToProcess(copyTypeDef); + + } while (copyTypeDef != null); + + + return true; + } + + + + /// + /// Makes all Awake methods within typeDef and base classes public and virtual. + /// + /// + internal void CreateFirstNetworkInitializeCall(TypeDefinition typeDef, MethodDefinition firstUserAwakeMethodDef, MethodDefinition firstNetworkInitializeMethodDef) + { + ILProcessor processor; + //Get awake for current method. + MethodDefinition thisAwakeMethodDef = typeDef.GetMethod(NetworkBehaviourHelper.AWAKE_METHOD_NAME); + bool created = false; + + //If no awake then make one. + if (thisAwakeMethodDef == null) + { + created = true; + + thisAwakeMethodDef = new MethodDefinition(NetworkBehaviourHelper.AWAKE_METHOD_NAME, PUBLIC_VIRTUAL_ATTRIBUTES, + typeDef.Module.TypeSystem.Void); + thisAwakeMethodDef.Body.InitLocals = true; + typeDef.Methods.Add(thisAwakeMethodDef); + + processor = thisAwakeMethodDef.Body.GetILProcessor(); + processor.Emit(OpCodes.Ret); + } + + //MethodRefs for networkinitialize and awake. + MethodReference networkInitializeMethodRef = typeDef.Module.ImportReference(firstNetworkInitializeMethodDef); + + processor = thisAwakeMethodDef.Body.GetILProcessor(); + //Create instructions for base call. + List instructions = new List(); + instructions.Add(processor.Create(OpCodes.Ldarg_0)); //this. + instructions.Add(processor.Create(OpCodes.Call, networkInitializeMethodRef)); + + /* If awake was created then make a call to the users + * first awake. There's no reason to do this if awake + * already existed because the user would have control + * over making that call. */ + if (created && firstUserAwakeMethodDef != null) + { + MethodReference baseAwakeMethodRef = typeDef.Module.ImportReference(firstUserAwakeMethodDef); + instructions.Add(processor.Create(OpCodes.Ldarg_0));//this. + instructions.Add(processor.Create(OpCodes.Call, baseAwakeMethodRef)); + } + + processor.InsertFirst(instructions); + } + + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs.meta new file mode 100644 index 0000000..1efbb02 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23866e4d620216745a837fa99e801164 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs new file mode 100644 index 0000000..f5f6cb0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs @@ -0,0 +1,1408 @@ +using FishNet.CodeGenerating.Extension; +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Configuring; +using FishNet.Object; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using FishNet.Transporting; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Rocks; +using MonoFN.Collections.Generic; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.CodeGenerating.Processing +{ + internal class NetworkBehaviourSyncProcessor + { + #region Reflection references. + private TypeDefinition SyncBase_TypeDef; + #endregion + + #region Private. + /// + /// Last instruction to read a sync type. + /// + private Instruction _lastReadInstruction; + /// + /// Sync objects, such as get and set, created during this process. Used to skip modifying created methods. + /// + private List _createdSyncTypeMethodDefinitions = new List(); + /// + /// ReadSyncVar methods which have had their base call already made. + /// + private HashSet _baseCalledReadSyncVars = new HashSet(); + #endregion + + #region Const. + private const string SYNCVAR_PREFIX = "syncVar___"; + private const string ACCESSOR_PREFIX = "sync___"; + private const string SETREGISTERED_METHOD_NAME = "SetRegistered"; + private const string INITIALIZEINSTANCE_METHOD_NAME = "InitializeInstance"; + private const string GETSERIALIZEDTYPE_METHOD_NAME = "GetSerializedType"; + #endregion + + internal bool ImportReferences() + { + System.Type syncBaseType = typeof(SyncBase); + SyncBase_TypeDef = CodegenSession.ImportReference(syncBaseType).Resolve(); + + return true; + } + + /// + /// Processes SyncVars and Objects. + /// + /// + /// + internal bool Process(TypeDefinition typeDef, List<(SyncType, ProcessedSync)> allProcessedSyncs, ref uint syncTypeStartCount) + { + bool modified = false; + _createdSyncTypeMethodDefinitions.Clear(); + _lastReadInstruction = null; + + FieldDefinition[] fieldDefs = typeDef.Fields.ToArray(); + foreach (FieldDefinition fd in fieldDefs) + { + CustomAttribute syncAttribute; + SyncType st = GetSyncType(fd, true, out syncAttribute); + //Not a sync type field. + if (st == SyncType.Unset) + continue; + + if (st == SyncType.Variable) + { + if (TryCreateSyncVar(syncTypeStartCount, allProcessedSyncs, typeDef, fd, syncAttribute)) + syncTypeStartCount++; + } + else if (st == SyncType.List || st == SyncType.HashSet) + { + if (TryCreateSyncList_SyncHashSet(syncTypeStartCount, allProcessedSyncs, typeDef, fd, syncAttribute, st)) + syncTypeStartCount++; + } + else if (st == SyncType.Dictionary) + { + if (TryCreateSyncDictionary(syncTypeStartCount, allProcessedSyncs, typeDef, fd, syncAttribute)) + syncTypeStartCount++; + } + else if (st == SyncType.Custom) + { + if (TryCreateCustom(syncTypeStartCount, allProcessedSyncs, typeDef, fd, syncAttribute)) + syncTypeStartCount++; + } + + modified = true; + } + + return modified; + } + + + /// + /// Gets number of SyncTypes by checking for SyncVar/Object attributes. This does not perform error checking. + /// + /// + /// + internal uint GetSyncTypeCount(TypeDefinition typeDef) + { + uint count = 0; + foreach (FieldDefinition fd in typeDef.Fields) + { + if (HasSyncTypeAttributeUnchecked(fd)) + count++; + } + + return count; + } + + /// + /// Replaces GetSets for methods which may use a SyncType. + /// + internal bool ReplaceGetSets(TypeDefinition typeDef, List<(SyncType, ProcessedSync)> allProcessedSyncs) + { + bool modified = false; + + List modifiableMethods = GetModifiableMethods(typeDef); + modified |= ReplaceGetSetDirties(modifiableMethods, allProcessedSyncs); + + return modified; + } + + /// + /// Gets SyncType fieldDef is. + /// + /// + /// + /// + internal SyncType GetSyncType(FieldDefinition fieldDef, bool validate, out CustomAttribute syncAttribute) + { + syncAttribute = null; + //If the generated field for syncvars ignore it. + if (fieldDef.Name.StartsWith(SYNCVAR_PREFIX)) + return SyncType.Unset; + + bool syncObject; + bool error; + syncAttribute = GetSyncTypeAttribute(fieldDef, out syncObject, out error); + //Do not perform further checks if an error occurred. + if (error) + return SyncType.Unset; + /* If if attribute is null the code must progress + * to throw errors when user creates a sync type + * without using the attribute. */ + if (!validate) + { + return (syncAttribute == null) ? SyncType.Unset : SyncType.Custom; + } + else + { + /* If no attribute make sure the field does not implement + * ISyncType. If it does then a SyncObject or SyncVar attribute + * should exist. */ + if (syncAttribute == null) + { + TypeDefinition foundSyncBaseTd = fieldDef.FieldType.CachedResolve().GetClassInInheritance(SyncBase_TypeDef); + if (foundSyncBaseTd != null && foundSyncBaseTd.ImplementsInterface()) + CodegenSession.LogError($"{fieldDef.Name} within {fieldDef.DeclaringType.Name} is a SyncType but is missing the [SyncVar] or [SyncObject] attribute."); + + return SyncType.Unset; + } + + /* If the attribute is not [SyncObject] then the attribute + * is [SyncVar]. Only checks that need to be made is to make sure + * the user is not using a SyncVar attribute when they should be using a SyncObject attribute. */ + if (syncAttribute != null && !syncObject) + { + //Make sure syncvar attribute isnt on a sync object. + if (GetSyncObjectSyncType(syncAttribute) != SyncType.Unset) + { + CodegenSession.LogError($"{fieldDef.Name} within {fieldDef.DeclaringType.Name} uses a [SyncVar] attribute but should be using [SyncObject]."); + return SyncType.Unset; + } + else + return SyncType.Variable; + } + + /* If here could be syncObject + * or attribute might be null. */ + if (fieldDef.FieldType.CachedResolve().ImplementsInterfaceRecursive()) + return GetSyncObjectSyncType(syncAttribute); + + SyncType GetSyncObjectSyncType(CustomAttribute sa) + { + //If attribute is null then throw error. + if (sa == null) + { + CodegenSession.LogError($"{fieldDef.Name} within {fieldDef.DeclaringType.Name} is a SyncType but [SyncObject] attribute was not found."); + return SyncType.Unset; + } + + if (fieldDef.FieldType.Name == CodegenSession.ObjectHelper.SyncList_Name) + { + return SyncType.List; + } + else if (fieldDef.FieldType.Name == CodegenSession.ObjectHelper.SyncDictionary_Name) + { + return SyncType.Dictionary; + } + else if (fieldDef.FieldType.Name == CodegenSession.ObjectHelper.SyncHashSet_Name) + { + return SyncType.HashSet; + } + //Custom types must also implement ICustomSync. + else if (fieldDef.FieldType.CachedResolve().ImplementsInterfaceRecursive()) + { + return SyncType.Custom; + } + else + { + return SyncType.Unset; + } + } + + //Fall through. + if (syncAttribute != null) + CodegenSession.LogError($"SyncObject attribute found on {fieldDef.Name} within {fieldDef.DeclaringType.Name} but type {fieldDef.FieldType.Name} does not inherit from SyncBase, or if a custom type does not implement ICustomSync."); + + return SyncType.Unset; + } + + } + + + /// + /// Tries to create a SyncList. + /// + private bool TryCreateCustom(uint syncTypeCount, List<(SyncType, ProcessedSync)> allProcessedSyncs, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute syncAttribute) + { + //Get the serialized type. + MethodDefinition getSerialziedTypeMd = originalFieldDef.FieldType.CachedResolve().GetMethod(GETSERIALIZEDTYPE_METHOD_NAME); + MethodReference getSerialziedTypeMr = CodegenSession.ImportReference(getSerialziedTypeMd); + Collection instructions = getSerialziedTypeMr.CachedResolve().Body.Instructions; + + bool canSerialize = false; + TypeReference serializedDataTypeRef = null; + /* If the user is returning null then + * they are indicating a custom serializer does not + * have to be implemented. */ + if (instructions.Count == 2 && instructions[0].OpCode == OpCodes.Ldnull && instructions[1].OpCode == OpCodes.Ret) + { + canSerialize = true; + } + //If not returning null then make a serializer for return type. + else + { + foreach (Instruction item in instructions) + { + //This token references the type. + if (item.OpCode == OpCodes.Ldtoken) + { + TypeReference importedTr = null; + if (item.Operand is TypeDefinition td) + importedTr = CodegenSession.ImportReference(td); + else if (item.Operand is TypeReference tr) + importedTr = CodegenSession.ImportReference(tr); + + if (importedTr != null) + { + serializedDataTypeRef = importedTr; + canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(serializedDataTypeRef, true); + } + } + } + } + + //Wasn't able to determine serialized type, or create it. + if (!canSerialize) + { + CodegenSession.LogError($"Custom SyncObject {originalFieldDef.Name} data type {serializedDataTypeRef.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + + bool result = InitializeCustom(syncTypeCount, typeDef, originalFieldDef, syncAttribute); + if (result) + allProcessedSyncs.Add((SyncType.Custom, null)); + return result; + } + + + /// + /// Tries to create a SyncList. + /// + private bool TryCreateSyncList_SyncHashSet(uint syncTypeCount, List<(SyncType, ProcessedSync)> allProcessedSyncs, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute syncAttribute, SyncType syncType) + { + //Import fieldType to module. + TypeReference fieldTypeTr = CodegenSession.ImportReference(originalFieldDef.FieldType); + //Make sure type can be serialized. + GenericInstanceType tmpGenerinstanceType = fieldTypeTr as GenericInstanceType; + //this returns the correct data type, eg SyncList would return int. + TypeReference dataTypeRef = CodegenSession.ImportReference(tmpGenerinstanceType.GenericArguments[0]); + + bool canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(dataTypeRef, true); + if (!canSerialize) + { + CodegenSession.LogError($"SyncObject {originalFieldDef.Name} data type {dataTypeRef.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + + bool result = InitializeSyncList_SyncHashSet(syncTypeCount, typeDef, originalFieldDef, syncAttribute); + if (result) + allProcessedSyncs.Add((syncType, null)); + return result; + } + + /// + /// Tries to create a SyncDictionary. + /// + private bool TryCreateSyncDictionary(uint syncTypeCount, List<(SyncType, ProcessedSync)> allProcessedSyncs, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute syncAttribute) + { + //Make sure type can be serialized. + GenericInstanceType tmpGenerinstanceType = originalFieldDef.FieldType as GenericInstanceType; + //this returns the correct data type, eg SyncList would return int. + TypeReference keyTypeRef = tmpGenerinstanceType.GenericArguments[0]; + TypeReference valueTypeRef = tmpGenerinstanceType.GenericArguments[1]; + + bool canSerialize; + //Check key serializer. + canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(keyTypeRef, true); + if (!canSerialize) + { + CodegenSession.LogError($"SyncObject {originalFieldDef.Name} key type {keyTypeRef.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + //Check value serializer. + canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(valueTypeRef, true); + if (!canSerialize) + { + CodegenSession.LogError($"SyncObject {originalFieldDef.Name} value type {valueTypeRef.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + + bool result = InitializeSyncDictionary(syncTypeCount, typeDef, originalFieldDef, syncAttribute); + if (result) + allProcessedSyncs.Add((SyncType.Dictionary, null)); + return result; + } + + + /// + /// Tries to create a SyncVar. + /// + private bool TryCreateSyncVar(uint syncCount, List<(SyncType, ProcessedSync)> allProcessedSyncs, TypeDefinition typeDef, FieldDefinition fieldDef, CustomAttribute syncAttribute) + { + bool canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(fieldDef.FieldType, true); + if (!canSerialize) + { + CodegenSession.LogError($"SyncVar {fieldDef.FullName} field type {fieldDef.FieldType.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + + if (CodegenSession.Module != typeDef.Module) + { + //Only display warning if field is exposed. + if (!fieldDef.Attributes.HasFlag(FieldAttributes.Private)) + CodegenSession.DifferentAssemblySyncVars.Add(fieldDef); + return false; + } + + FieldDefinition syncVarFd; + MethodReference accessorSetValueMr; + MethodReference accessorGetValueMr; + bool created = CreateSyncVar(syncCount, typeDef, fieldDef, syncAttribute, out syncVarFd, out accessorSetValueMr, out accessorGetValueMr); + if (created) + { + FieldReference originalFr = CodegenSession.ImportReference(fieldDef); + allProcessedSyncs.Add((SyncType.Variable, new ProcessedSync(originalFr, syncVarFd, accessorSetValueMr, accessorGetValueMr))); + } + + return created; + } + + + + /// + /// Returns if fieldDef has a SyncType attribute. No error checking is performed. + /// + /// + /// + private bool HasSyncTypeAttributeUnchecked(FieldDefinition fieldDef) + { + foreach (CustomAttribute customAttribute in fieldDef.CustomAttributes) + { + if (CodegenSession.AttributeHelper.IsSyncVarAttribute(customAttribute.AttributeType.FullName)) + return true; + else if (CodegenSession.AttributeHelper.IsSyncObjectAttribute(customAttribute.AttributeType.FullName)) + return true; + } + + return false; + } + + + /// + /// Returns the syncvar attribute on a method, if one exist. Otherwise returns null. + /// + /// + /// + private CustomAttribute GetSyncTypeAttribute(FieldDefinition fieldDef, out bool syncObject, out bool error) + { + CustomAttribute foundAttribute = null; + //Becomes true if an error occurred during this process. + error = false; + syncObject = false; + + foreach (CustomAttribute customAttribute in fieldDef.CustomAttributes) + { + if (CodegenSession.AttributeHelper.IsSyncVarAttribute(customAttribute.AttributeType.FullName)) + syncObject = false; + else if (CodegenSession.AttributeHelper.IsSyncObjectAttribute(customAttribute.AttributeType.FullName)) + syncObject = true; + else + continue; + + //A syncvar attribute already exist. + if (foundAttribute != null) + { + CodegenSession.LogError($"{fieldDef.Name} cannot have multiple SyncType attributes."); + error = true; + } + //Static. + if (fieldDef.IsStatic) + { + CodegenSession.LogError($"{fieldDef.Name} SyncType cannot be static."); + error = true; + } + //Generic. + if (fieldDef.FieldType.IsGenericParameter) + { + CodegenSession.LogError($"{fieldDef.Name} SyncType cannot be be generic."); + error = true; + } + //SyncObject readonly check. + if (syncObject && !fieldDef.Attributes.HasFlag(FieldAttributes.InitOnly)) + { + CodegenSession.LogError($"{fieldDef.Name} SyncObject must be readonly."); + error = true; + } + + + //If all checks passed. + if (!error) + foundAttribute = customAttribute; + } + + //If an error occurred then reset results. + if (error) + foundAttribute = null; + + return foundAttribute; + } + + /// + /// Creates a syncVar class for the user's syncvar. + /// + /// + /// + /// + private bool CreateSyncVar(uint syncCount, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute syncTypeAttribute, out FieldDefinition createdSyncVarFd, out MethodReference accessorSetValueMethodRef, out MethodReference accessorGetValueMethodRef) + { + accessorGetValueMethodRef = null; + accessorSetValueMethodRef = null; + CreatedSyncVar createdSyncVar; + createdSyncVarFd = CreateSyncVarFieldDefinition(typeDef, originalFieldDef, out createdSyncVar); + + if (createdSyncVarFd != null) + { + MethodReference hookMr = GetSyncVarHookMethodReference(typeDef, originalFieldDef, syncTypeAttribute); + createdSyncVar.HookMr = hookMr; + + //If accessor was made add it's methods to createdSyncTypeObjects. + if (CreateSyncVarAccessor(originalFieldDef, createdSyncVarFd, createdSyncVar, out accessorGetValueMethodRef, + out accessorSetValueMethodRef, hookMr) != null) + { + _createdSyncTypeMethodDefinitions.Add(accessorGetValueMethodRef.CachedResolve()); + _createdSyncTypeMethodDefinitions.Add(accessorSetValueMethodRef.CachedResolve()); + } + + InitializeSyncVar(syncCount, createdSyncVarFd, typeDef, originalFieldDef, syncTypeAttribute, createdSyncVar); + + MethodDefinition syncVarReadMd = CreateSyncVarRead(typeDef, syncCount, originalFieldDef, accessorSetValueMethodRef); + if (syncVarReadMd != null) + _createdSyncTypeMethodDefinitions.Add(syncVarReadMd); + + return true; + } + else + { + return false; + } + + } + + /// + /// Creates or gets a SyncType class for originalFieldDef. + /// + /// + private FieldDefinition CreateSyncVarFieldDefinition(TypeDefinition typeDef, FieldDefinition originalFieldDef, out CreatedSyncVar createdSyncVar) + { + createdSyncVar = CodegenSession.CreatedSyncVarGenerator.GetCreatedSyncVar(originalFieldDef, true); + if (createdSyncVar == null) + return null; + + FieldDefinition createdFieldDef = new FieldDefinition($"{SYNCVAR_PREFIX}{originalFieldDef.Name}", originalFieldDef.Attributes, createdSyncVar.SyncVarGit); + if (createdFieldDef == null) + { + CodegenSession.LogError($"Could not create field for Sync type {originalFieldDef.FieldType.FullName}, name of {originalFieldDef.Name}."); + return null; + } + + typeDef.Fields.Add(createdFieldDef); + return createdFieldDef; + } + + /// + /// Validates and gets the hook MethodReference for a SyncVar if available. + /// + /// + /// + /// + /// + private MethodReference GetSyncVarHookMethodReference(TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute attribute) + { + string hook = attribute.GetField("OnChange", string.Empty); + //No hook is specified. + if (string.IsNullOrEmpty(hook)) + return null; + + MethodDefinition md = typeDef.GetMethod(hook); + + if (md != null) + { + string incorrectParametersMsg = $"OnChange method for {originalFieldDef.FullName} must contain 3 parameters in order of {originalFieldDef.FieldType.Name} oldValue, {originalFieldDef.FieldType.Name} newValue, {CodegenSession.Module.TypeSystem.Boolean} asServer."; + //Not correct number of parameters. + if (md.Parameters.Count != 3) + { + CodegenSession.LogError(incorrectParametersMsg); + return null; + } + /* Check if any parameters are not + * the expected type. */ + if (md.Parameters[0].ParameterType.CachedResolve() != originalFieldDef.FieldType.CachedResolve() || + md.Parameters[1].ParameterType.CachedResolve() != originalFieldDef.FieldType.CachedResolve() || + md.Parameters[2].ParameterType.CachedResolve() != CodegenSession.Module.TypeSystem.Boolean.CachedResolve()) + { + CodegenSession.LogError(incorrectParametersMsg); + return null; + } + + //If here everything checks out, return a method reference to hook method. + return CodegenSession.ImportReference(md); + } + //Hook specified but no method found. + else + { + CodegenSession.LogError($"Could not find method name {hook} for SyncType {originalFieldDef.FullName}."); + return null; + } + } + + /// + /// Creates accessor for a SyncVar. + /// + /// + private FieldDefinition CreateSyncVarAccessor(FieldDefinition originalFd, FieldDefinition createdSyncVarFd, CreatedSyncVar createdSyncVar, out MethodReference accessorGetValueMr, out MethodReference accessorSetValueMr, MethodReference hookMr) + { + /* Create and add property definition. */ + PropertyDefinition createdPropertyDef = new PropertyDefinition($"SyncAccessor_{originalFd.Name}", PropertyAttributes.None, originalFd.FieldType); + createdPropertyDef.DeclaringType = originalFd.DeclaringType; + //add the methods and property to the type. + originalFd.DeclaringType.Properties.Add(createdPropertyDef); + + ILProcessor processor; + + /* Get method for property definition. */ + MethodDefinition createdGetMethodDef = originalFd.DeclaringType.AddMethod($"{ACCESSOR_PREFIX}get_value_{originalFd.Name}", MethodAttributes.Public | + MethodAttributes.SpecialName | MethodAttributes.HideBySig, + originalFd.FieldType); + createdGetMethodDef.SemanticsAttributes = MethodSemanticsAttributes.Getter; + + processor = createdGetMethodDef.Body.GetILProcessor(); + processor.Emit(OpCodes.Ldarg_0); //this. + processor.Emit(OpCodes.Ldfld, originalFd); + processor.Emit(OpCodes.Ret); + accessorGetValueMr = CodegenSession.ImportReference(createdGetMethodDef); + //Add getter to properties. + createdPropertyDef.GetMethod = createdGetMethodDef; + + /* Set method. */ + //Create the set method + MethodDefinition createdSetMethodDef = originalFd.DeclaringType.AddMethod($"{ACCESSOR_PREFIX}set_value_{originalFd.Name}", MethodAttributes.Public | + MethodAttributes.SpecialName | + MethodAttributes.HideBySig); + createdSetMethodDef.SemanticsAttributes = MethodSemanticsAttributes.Setter; + + ParameterDefinition valueParameterDef = CodegenSession.GeneralHelper.CreateParameter(createdSetMethodDef, originalFd.FieldType, "value"); + ParameterDefinition calledByUserParameterDef = CodegenSession.GeneralHelper.CreateParameter(createdSetMethodDef, typeof(bool), "asServer"); + processor = createdSetMethodDef.Body.GetILProcessor(); + + /* Assign to new value. Do this first because SyncVar calls hook + * and value needs to be updated before hook. */ + // _originalField = value; + processor.Emit(OpCodes.Ldarg_0); //this. + processor.Emit(OpCodes.Ldarg, valueParameterDef); + processor.Emit(OpCodes.Stfld, originalFd); + + Instruction retInst = processor.Create(OpCodes.Ret); + + if (!Configuration.ConfigurationData.IsBuilding) + { + processor.Emit(OpCodes.Call, CodegenSession.GeneralHelper.Application_IsPlaying_MethodRef); + processor.Emit(OpCodes.Brfalse_S, retInst); + } + // SyncVar<>.SetValue(....); + processor.Emit(OpCodes.Ldarg_0); //this. + processor.Emit(OpCodes.Ldfld, createdSyncVarFd); + processor.Emit(OpCodes.Ldarg, valueParameterDef); + processor.Emit(OpCodes.Ldarg, calledByUserParameterDef); + processor.Emit(OpCodes.Callvirt, createdSyncVar.SetValueMr); + + processor.Append(retInst); + accessorSetValueMr = CodegenSession.ImportReference(createdSetMethodDef); + //Add setter to properties. + createdPropertyDef.SetMethod = createdSetMethodDef; + + return originalFd; + } + + /// + /// Sets methods used from SyncBase for typeDef. + /// + /// + internal bool SetSyncBaseMethods(TypeDefinition typeDef, out MethodReference setRegisteredMr, out MethodReference initializeInstanceMr) + { + setRegisteredMr = null; + initializeInstanceMr = null; + //Find the SyncBase class. + TypeDefinition syncBaseTd = null; + TypeDefinition copyTd = typeDef; + do + { + if (copyTd.Name == nameof(SyncBase)) + { + syncBaseTd = copyTd; + break; + } + copyTd = copyTd.GetNextBaseTypeDefinition(); + } while (copyTd != null); + + //If SyncBase isn't found. + if (syncBaseTd == null) + { + CodegenSession.LogError($"Could not find SyncBase within type {typeDef.FullName}."); + return false; + } + else + { + MethodDefinition tmpMd; + //InitializeInstance. + tmpMd = syncBaseTd.GetMethod(INITIALIZEINSTANCE_METHOD_NAME); + initializeInstanceMr = CodegenSession.ImportReference(tmpMd); + //SetSyncIndex. + tmpMd = syncBaseTd.GetMethod(SETREGISTERED_METHOD_NAME); + setRegisteredMr = CodegenSession.ImportReference(tmpMd); + return true; + } + + } + + /// + /// Initializes a custom SyncObject. + /// + internal bool InitializeCustom(uint syncCount, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute attribute) + { + float sendRate = 0.1f; + WritePermission writePermissions = WritePermission.ServerOnly; + ReadPermission readPermissions = ReadPermission.Observers; + Channel channel = Channel.Reliable; + //If attribute isn't null then override values. + if (attribute != null) + { + sendRate = attribute.GetField("SendRate", 0.1f); + writePermissions = WritePermission.ServerOnly; + readPermissions = attribute.GetField("ReadPermissions", ReadPermission.Observers); + channel = Channel.Reliable; //attribute.GetField("Channel", Channel.Reliable); + } + + //Set needed methods from syncbase. + MethodReference setSyncIndexMr; + MethodReference initializeInstanceMr; + if (!SetSyncBaseMethods(originalFieldDef.FieldType.CachedResolve(), out setSyncIndexMr, out initializeInstanceMr)) + return false; + + MethodDefinition injectionMethodDef; + ILProcessor processor; + + uint hash = (uint)syncCount; + List insts = new List(); + + /* Initialize with attribute settings. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + // + + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this again for NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)hash)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)writePermissions)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)readPermissions)); + insts.Add(processor.Create(OpCodes.Ldc_R4, sendRate)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)channel)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); //true for syncObject. + insts.Add(processor.Create(OpCodes.Call, initializeInstanceMr)); + processor.InsertFirst(insts); + + insts.Clear(); + /* Set NetworkBehaviour and SyncIndex to use. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_LATE_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + // + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Callvirt, setSyncIndexMr)); + + processor.InsertLast(insts); + + return true; + } + + + + /// + /// Initializes a SyncList. + /// + internal bool InitializeSyncList_SyncHashSet(uint syncCount, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute attribute) + { + float sendRate = 0.1f; + WritePermission writePermissions = WritePermission.ServerOnly; + ReadPermission readPermissions = ReadPermission.Observers; + Channel channel = Channel.Reliable; + //If attribute isn't null then override values. + if (attribute != null) + { + sendRate = attribute.GetField("SendRate", 0.1f); + writePermissions = WritePermission.ServerOnly; + readPermissions = attribute.GetField("ReadPermissions", ReadPermission.Observers); + channel = Channel.Reliable; //attribute.GetField("Channel", Channel.Reliable); + } + + //This import shouldn't be needed but cecil is stingy so rather be safe than sorry. + CodegenSession.ImportReference(originalFieldDef); + + //Set needed methods from syncbase. + MethodReference setSyncIndexMr; + MethodReference initializeInstanceMr; + if (!SetSyncBaseMethods(originalFieldDef.FieldType.CachedResolve(), out setSyncIndexMr, out initializeInstanceMr)) + return false; + + MethodDefinition injectionMethodDef; + ILProcessor processor; + + uint hash = (uint)syncCount; + List insts = new List(); + + /* Initialize with attribute settings. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + + //InitializeInstance. + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this again for NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)hash)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)writePermissions)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)readPermissions)); + insts.Add(processor.Create(OpCodes.Ldc_R4, sendRate)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)channel)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); //true for syncObject. + insts.Add(processor.Create(OpCodes.Call, initializeInstanceMr)); + processor.InsertFirst(insts); + + insts.Clear(); + /* Set NetworkBehaviour and SyncIndex to use. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_LATE_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Callvirt, setSyncIndexMr)); + + processor.InsertLast(insts); + + return true; + } + + + + /// + /// Initializes a SyncDictionary. + /// + internal bool InitializeSyncDictionary(uint syncCount, TypeDefinition typeDef, FieldDefinition originalFieldDef, CustomAttribute attribute) + { + float sendRate = 0.1f; + WritePermission writePermissions = WritePermission.ServerOnly; + ReadPermission readPermissions = ReadPermission.Observers; + Channel channel = Channel.Reliable; + //If attribute isn't null then override values. + if (attribute != null) + { + sendRate = attribute.GetField("SendRate", 0.1f); + writePermissions = WritePermission.ServerOnly; + readPermissions = attribute.GetField("ReadPermissions", ReadPermission.Observers); + channel = Channel.Reliable; //attribute.GetField("Channel", Channel.Reliable); + } + + //This import shouldn't be needed but cecil is stingy so rather be safe than sorry. + CodegenSession.ImportReference(originalFieldDef); + + //Set needed methods from syncbase. + MethodReference setRegisteredMr; + MethodReference initializeInstanceMr; + if (!SetSyncBaseMethods(originalFieldDef.FieldType.CachedResolve(), out setRegisteredMr, out initializeInstanceMr)) + return false; + + MethodDefinition injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = injectionMethodDef.Body.GetILProcessor(); + + uint hash = (uint)syncCount; + List insts = new List(); + + /* Initialize with attribute settings. */ + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this again for NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)hash)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)writePermissions)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)readPermissions)); + insts.Add(processor.Create(OpCodes.Ldc_R4, sendRate)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)channel)); + insts.Add(processor.Create(OpCodes.Ldc_I4_1)); //true for syncObject. + insts.Add(processor.Create(OpCodes.Call, initializeInstanceMr)); + processor.InsertFirst(insts); + + insts.Clear(); + /* Set NetworkBehaviour and SyncIndex to use. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_LATE_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFieldDef)); + insts.Add(processor.Create(OpCodes.Callvirt, setRegisteredMr)); + + processor.InsertFirst(insts); + + return true; + } + + + /// + /// Initializes a SyncVar<>. + /// + internal void InitializeSyncVar(uint syncCount, FieldDefinition createdFd, TypeDefinition typeDef, FieldDefinition originalFd, CustomAttribute attribute, CreatedSyncVar createdSyncVar) + { + //Get all possible attributes. + float sendRate = attribute.GetField("SendRate", 0.1f); + WritePermission writePermissions = WritePermission.ServerOnly; + ReadPermission readPermissions = attribute.GetField("ReadPermissions", ReadPermission.Observers); + Channel channel = attribute.GetField("Channel", Channel.Reliable); + + MethodDefinition injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME); + ILProcessor processor = injectionMethodDef.Body.GetILProcessor(); + + uint hash = (uint)syncCount; + List insts = new List(); + //Initialize fieldDef with values from attribute. + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this again for NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)hash)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)writePermissions)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)readPermissions)); + insts.Add(processor.Create(OpCodes.Ldc_R4, sendRate)); + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)channel)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, originalFd)); //initial value. + insts.Add(processor.Create(OpCodes.Newobj, createdSyncVar.ConstructorMr)); + insts.Add(processor.Create(OpCodes.Stfld, createdFd)); + + //If there is a hook method. + if (createdSyncVar.HookMr != null) + { + //SyncVar.add_OnChanged (event). + TypeDefinition svTd = CodegenSession.CreatedSyncVarGenerator.SyncVar_TypeRef.CachedResolve(); + GenericInstanceType svGit = svTd.MakeGenericInstanceType(new TypeReference[] { originalFd.FieldType }); + MethodDefinition addMd = svTd.GetMethod("add_OnChange"); + MethodReference genericAddMr = addMd.MakeHostInstanceGeneric(svGit); + + //Action constructor. + GenericInstanceType actionGit = CodegenSession.GenericWriterHelper.ActionT3TypeRef.MakeGenericInstanceType( + originalFd.FieldType, originalFd.FieldType, + CodegenSession.GeneralHelper.GetTypeReference(typeof(bool))); + MethodReference gitActionCtorMr = CodegenSession.GenericWriterHelper.ActionT3ConstructorMethodRef.MakeHostInstanceGeneric(actionGit); + + // syncVar___field.OnChanged += UserHookMethod; + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldfld, createdFd)); + insts.Add(processor.Create(OpCodes.Ldarg_0)); + insts.Add(processor.Create(OpCodes.Ldftn, createdSyncVar.HookMr.CachedResolve())); + insts.Add(processor.Create(OpCodes.Newobj, gitActionCtorMr)); + insts.Add(processor.Create(OpCodes.Callvirt, genericAddMr)); + } + processor.InsertFirst(insts); + + insts.Clear(); + /* Set NetworkBehaviour and SyncIndex to use. */ + injectionMethodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_LATE_INTERNAL_NAME); + processor = injectionMethodDef.Body.GetILProcessor(); + + //uint hash = originalFieldDef.FullName.GetStableHash32(); + //Set NB and SyncIndex to SyncVar<>. + insts.Add(processor.Create(OpCodes.Ldarg_0)); //this. + insts.Add(processor.Create(OpCodes.Ldfld, createdFd)); + insts.Add(processor.Create(OpCodes.Callvirt, createdSyncVar.SetSyncIndexMr)); + + processor.InsertFirst(insts); + } + + /// + /// Replaces GetSets for methods which may use a SyncType. + /// + /// + /// + internal bool ReplaceGetSetDirties(List modifiableMethods, List<(SyncType, ProcessedSync)> processedSyncs) + { + //Build processed syncs into dictionary for quicker loookups. + Dictionary> processedLookup = new Dictionary>(); + foreach ((SyncType st, ProcessedSync ps) in processedSyncs) + { + if (st != SyncType.Variable) + continue; + + List result; + if (!processedLookup.TryGetValue(ps.OriginalFieldRef, out result)) + { + result = new List() { ps }; + processedLookup.Add(ps.OriginalFieldRef, result); + } + + result.Add(ps); + } + + bool modified = false; + foreach (MethodDefinition methodDef in modifiableMethods) + modified |= ReplaceGetSetDirty(methodDef, processedLookup); + + return modified; + } + + /// + /// Replaces GetSets for a method which may use a SyncType. + /// + /// + /// + private bool ReplaceGetSetDirty(MethodDefinition methodDef, Dictionary> processedLookup) + { + if (methodDef == null) + { + CodegenSession.LogError($"An object expecting value was null. Please try saving your script again."); + return false; + } + if (methodDef.IsAbstract) + return false; + if (_createdSyncTypeMethodDefinitions.Contains(methodDef)) + return false; + if (methodDef.Name == NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME) + return false; + + + bool modified = false; + + for (int i = 0; i < methodDef.Body.Instructions.Count; i++) + { + Instruction inst = methodDef.Body.Instructions[i]; + + /* Loading a field. (Getter) */ + if (inst.OpCode == OpCodes.Ldfld && inst.Operand is FieldReference opFieldld) + { + FieldReference resolvedOpField = opFieldld.CachedResolve(); + if (resolvedOpField == null) + resolvedOpField = opFieldld.DeclaringType.CachedResolve().GetField(opFieldld.Name); + + modified |= ProcessGetField(methodDef, i, resolvedOpField, processedLookup); + } + /* Load address, reference field. */ + else if (inst.OpCode == OpCodes.Ldflda && inst.Operand is FieldReference opFieldlda) + { + FieldReference resolvedOpField = opFieldlda.CachedResolve(); + if (resolvedOpField == null) + resolvedOpField = opFieldlda.DeclaringType.CachedResolve().GetField(opFieldlda.Name); + + modified |= ProcessAddressField(methodDef, i, resolvedOpField, processedLookup); + } + /* Setting a field. (Setter) */ + else if (inst.OpCode == OpCodes.Stfld && inst.Operand is FieldReference opFieldst) + { + FieldReference resolvedOpField = opFieldst.CachedResolve(); + if (resolvedOpField == null) + resolvedOpField = opFieldst.DeclaringType.CachedResolve().GetField(opFieldst.Name); + + modified |= ProcessSetField(methodDef, i, resolvedOpField, processedLookup); + } + + } + + return modified; + } + + /// + /// Replaces Gets for a method which may use a SyncType. + /// + /// + /// + /// + /// + private bool ProcessGetField(MethodDefinition methodDef, int instructionIndex, FieldReference resolvedOpField, Dictionary> processedLookup) + { + Instruction inst = methodDef.Body.Instructions[instructionIndex]; + + //If was a replaced field. + if (processedLookup.TryGetValue(resolvedOpField, out List psLst)) + { + ProcessedSync ps = GetProcessedSync(resolvedOpField, psLst); + if (ps == null) + return false; + //Don't modify the accessor method. + if (ps.GetMethodRef.CachedResolve() == methodDef) + return false; + + //Generic type. + if (resolvedOpField.DeclaringType.IsGenericInstance || resolvedOpField.DeclaringType.HasGenericParameters) + { + FieldReference newField = inst.Operand as FieldReference; + GenericInstanceType genericType = (GenericInstanceType)newField.DeclaringType; + inst.OpCode = OpCodes.Callvirt; + inst.Operand = ps.GetMethodRef.MakeHostInstanceGeneric(genericType); + } + //Strong type. + else + { + inst.OpCode = OpCodes.Call; + inst.Operand = ps.GetMethodRef; + } + + return true; + } + else + { + return false; + } + } + + + /// + /// Replaces Sets for a method which may use a SyncType. + /// + /// + /// + /// + /// + private bool ProcessSetField(MethodDefinition methodDef, int instructionIndex, FieldReference resolvedOpField, Dictionary> processedLookup) + { + Instruction inst = methodDef.Body.Instructions[instructionIndex]; + + /* Find any instructions that are jmp/breaking to the one we are modifying. + * These need to be modified to call changed instruction. */ + HashSet brInstructions = new HashSet(); + foreach (Instruction item in methodDef.Body.Instructions) + { + bool canJmp = (item.OpCode == OpCodes.Br || item.OpCode == OpCodes.Brfalse || item.OpCode == OpCodes.Brfalse_S || item.OpCode == OpCodes.Brtrue || item.OpCode == OpCodes.Brtrue_S || item.OpCode == OpCodes.Br_S); + if (!canJmp) + continue; + if (item.Operand == null) + continue; + if (item.Operand is Instruction jmpInst && jmpInst == inst) + brInstructions.Add(item); + } + + //If was a replaced field. + if (processedLookup.TryGetValue(resolvedOpField, out List psLst)) + { + ProcessedSync ps = GetProcessedSync(resolvedOpField, psLst); + if (ps == null) + return false; + //Don't modify the accessor method. + if (ps.SetMethodRef.CachedResolve() == methodDef) + return false; + ILProcessor processor = methodDef.Body.GetILProcessor(); + //Generic type. + if (resolvedOpField.DeclaringType.IsGenericInstance || resolvedOpField.DeclaringType.HasGenericParameters) + { + //Pass in true for as server. + Instruction boolTrueInst = processor.Create(OpCodes.Ldc_I4_1); + methodDef.Body.Instructions.Insert(instructionIndex, boolTrueInst); + + FieldReference newField = inst.Operand as FieldReference; + GenericInstanceType genericType = (GenericInstanceType)newField.DeclaringType; + inst.OpCode = OpCodes.Callvirt; + inst.Operand = ps.SetMethodRef.MakeHostInstanceGeneric(genericType); + } + //Strong typed. + else + { + //Pass in true for as server. + Instruction boolTrueInst = processor.Create(OpCodes.Ldc_I4_1); + methodDef.Body.Instructions.Insert(instructionIndex, boolTrueInst); + + inst.OpCode = OpCodes.Call; + inst.Operand = ps.SetMethodRef; + } + + /* If any instructions are still pointing + * to modified value then they need to be + * redirected to the instruction right above it. + * This is because the boolTrueInst, to indicate + * value is being set as server. */ + foreach (Instruction item in brInstructions) + { + if (item.Operand is Instruction jmpInst && jmpInst == inst) + { + //Use the same index that was passed in, which is now one before modified instruction. + Instruction newInst = methodDef.Body.Instructions[instructionIndex]; + item.Operand = newInst; + } + } + + return true; + } + else + { + return false; + } + } + + /// + /// Replaces address Sets for a method which may use a SyncType. + /// + /// + /// + /// + /// + private bool ProcessAddressField(MethodDefinition methodDef, int instructionIndex, FieldReference resolvedOpField, Dictionary> processedLookup) + { + Instruction inst = methodDef.Body.Instructions[instructionIndex]; + //Check if next instruction is Initobj, which would be setting a new instance. + Instruction nextInstr = inst.Next; + if (nextInstr.OpCode != OpCodes.Initobj) + return false; + + //If was a replaced field. + if (processedLookup.TryGetValue(resolvedOpField, out List psLst)) + { + ProcessedSync ps = GetProcessedSync(resolvedOpField, psLst); + if (ps == null) + return false; + //Don't modify the accessor method. + if (ps.GetMethodRef.CachedResolve() == methodDef || ps.SetMethodRef.CachedResolve() == methodDef) + return false; + + ILProcessor processor = methodDef.Body.GetILProcessor(); + + VariableDefinition tmpVariableDef = CodegenSession.GeneralHelper.CreateVariable(methodDef, resolvedOpField.FieldType); + processor.InsertBefore(inst, processor.Create(OpCodes.Ldloca, tmpVariableDef)); + processor.InsertBefore(inst, processor.Create(OpCodes.Initobj, resolvedOpField.FieldType)); + processor.InsertBefore(inst, processor.Create(OpCodes.Ldloc, tmpVariableDef)); + Instruction newInstr = processor.Create(OpCodes.Call, ps.SetMethodRef); + processor.InsertBefore(inst, newInstr); + + /* Pass in true for as server. + * The instruction index is 3 past ld. */ + Instruction boolTrueInst = processor.Create(OpCodes.Ldc_I4_1); + methodDef.Body.Instructions.Insert(instructionIndex + 3, boolTrueInst); + + processor.Remove(inst); + processor.Remove(nextInstr); + + return true; + } + else + { + return false; + } + } + + /// + /// Calls ReadSyncVar going up the hierarchy. + /// + /// + internal void CallBaseReadSyncVar(TypeDefinition firstTypeDef) + { + //TypeDef which needs to make the base call. + MethodDefinition callerMd = null; + TypeDefinition copyTd = firstTypeDef; + do + { + MethodDefinition readMd; + + readMd = copyTd.GetMethod(CodegenSession.NetworkBehaviourHelper.ReadSyncVar_MethodRef.Name); + if (readMd != null) + callerMd = readMd; + + /* If baseType exist and it's not networkbehaviour + * look into calling the ReadSyncVar method. */ + if (copyTd.BaseType != null && copyTd.BaseType.FullName != CodegenSession.NetworkBehaviourHelper.FullName) + { + readMd = copyTd.BaseType.CachedResolve().GetMethod(CodegenSession.NetworkBehaviourHelper.ReadSyncVar_MethodRef.Name); + //Not all classes will have syncvars to read. + if (!_baseCalledReadSyncVars.Contains(callerMd) && readMd != null && callerMd != null) + { + MethodReference baseReadMr = CodegenSession.ImportReference(readMd); + ILProcessor processor = callerMd.Body.GetILProcessor(); + /* Calls base.ReadSyncVar and if result is true + * then exit methods. This is because a true return means the base + * was able to process the syncvar. */ + List baseCallInsts = new List(); + Instruction skipBaseReturn = processor.Create(OpCodes.Nop); + baseCallInsts.Add(processor.Create(OpCodes.Ldarg_0)); + baseCallInsts.Add(processor.Create(OpCodes.Ldarg_1)); + baseCallInsts.Add(processor.Create(OpCodes.Ldarg_2)); + baseCallInsts.Add(processor.Create(OpCodes.Call, baseReadMr)); + baseCallInsts.Add(processor.Create(OpCodes.Brfalse_S, skipBaseReturn)); + baseCallInsts.Add(processor.Create(OpCodes.Ldc_I4_1)); + baseCallInsts.Add(processor.Create(OpCodes.Ret)); + baseCallInsts.Add(skipBaseReturn); + processor.InsertFirst(baseCallInsts); + + _baseCalledReadSyncVars.Add(callerMd); + } + } + + copyTd = TypeDefinitionExtensionsOld.GetNextBaseClassToProcess(copyTd); + + } while (copyTd != null); + + + } + + /// + /// Reads a PooledReader locally then sets value to the SyncVars accessor. + /// + /// + /// + /// + private MethodDefinition CreateSyncVarRead(TypeDefinition typeDef, uint syncIndex, FieldDefinition originalFieldDef, MethodReference accessorSetMethodRef) + { + Instruction jmpGoalInst; + ILProcessor processor; + + //Get the read sync method, or create it if not present. + MethodDefinition readSyncMethodDef = typeDef.GetMethod(CodegenSession.NetworkBehaviourHelper.ReadSyncVar_MethodRef.Name); + if (readSyncMethodDef == null) + { + readSyncMethodDef = new MethodDefinition(CodegenSession.NetworkBehaviourHelper.ReadSyncVar_MethodRef.Name, + (MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual), + typeDef.Module.TypeSystem.Void); + readSyncMethodDef.ReturnType = CodegenSession.GeneralHelper.GetTypeReference(typeof(bool)); + + CodegenSession.GeneralHelper.CreateParameter(readSyncMethodDef, typeof(PooledReader)); + CodegenSession.GeneralHelper.CreateParameter(readSyncMethodDef, typeof(uint)); + readSyncMethodDef.Body.InitLocals = true; + + processor = readSyncMethodDef.Body.GetILProcessor(); + //Return false as fall through. + processor.Emit(OpCodes.Ldc_I4_0); + processor.Emit(OpCodes.Ret); + + typeDef.Methods.Add(readSyncMethodDef); + } + //Already created. + else + { + processor = readSyncMethodDef.Body.GetILProcessor(); + } + + ParameterDefinition pooledReaderParameterDef = readSyncMethodDef.Parameters[0]; + ParameterDefinition indexParameterDef = readSyncMethodDef.Parameters[1]; + VariableDefinition nextValueVariableDef; + List readInsts; + + /* Create a nop instruction placed at the first index of the method. + * All instructions will be added before this, then the nop will be + * removed afterwards. This ensures the newer instructions will + * be above the previous. This let's the IL jump to a previously + * created read instruction when the latest one fails conditions. */ + Instruction nopPlaceHolderInst = processor.Create(OpCodes.Nop); + + readSyncMethodDef.Body.Instructions.Insert(0, nopPlaceHolderInst); + + /* If there was a previously made read then set jmp goal to the first + * condition for it. Otherwise set it to the last instruction, which would + * be a ret. Keep in mind if ret has a value we must go back 2 index + * rather than one. */ + jmpGoalInst = (_lastReadInstruction != null) ? _lastReadInstruction : + readSyncMethodDef.Body.Instructions[readSyncMethodDef.Body.Instructions.Count - 2]; + + //Check index first. if (index != syncIndex) return + Instruction nextLastReadInstruction = processor.Create(OpCodes.Ldarg, indexParameterDef); + processor.InsertBefore(jmpGoalInst, nextLastReadInstruction); + + uint hash = (uint)syncIndex; + //uint hash = originalFieldDef.FullName.GetStableHash32(); + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldc_I4, (int)hash)); + //processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldc_I4, syncIndex)); + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Bne_Un, jmpGoalInst)); + //PooledReader.ReadXXXX() + readInsts = CodegenSession.ReaderHelper.CreateRead(readSyncMethodDef, pooledReaderParameterDef, + originalFieldDef.FieldType, out nextValueVariableDef); + if (readInsts == null) + return null; + //Add each instruction from CreateRead. + foreach (Instruction i in readInsts) + processor.InsertBefore(jmpGoalInst, i); + + //Call accessor with new value and false for asServer + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldarg_0)); //this. + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldloc, nextValueVariableDef)); + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldc_I4_0)); + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Call, accessorSetMethodRef)); + //Return true when able to process. + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ldc_I4_1)); + processor.InsertBefore(jmpGoalInst, processor.Create(OpCodes.Ret)); + + _lastReadInstruction = nextLastReadInstruction; + processor.Remove(nopPlaceHolderInst); + + return readSyncMethodDef; + } + + /// + /// Returns methods which may be modified by code generation. + /// + /// + /// + private List GetModifiableMethods(TypeDefinition typeDef) + { + List results = new List(); + + CheckTypeDefinition(typeDef); + //Have to add nested types because this are where courotines are stored. + foreach (TypeDefinition nestedTd in typeDef.NestedTypes) + CheckTypeDefinition(nestedTd); + + void CheckTypeDefinition(TypeDefinition td) + { + foreach (MethodDefinition methodDef in td.Methods) + { + if (methodDef.Name == ".cctor") + continue; + if (methodDef.IsConstructor) + continue; + if (methodDef.Body == null) + continue; + + results.Add(methodDef); + } + + foreach (PropertyDefinition propertyDef in td.Properties) + { + if (propertyDef.GetMethod != null) + results.Add(propertyDef.GetMethod); + if (propertyDef.SetMethod != null) + results.Add(propertyDef.SetMethod); + } + } + + return results; + } + + /// + /// Returns the ProcessedSync entry for resolvedOpField. + /// + /// + /// + /// + private ProcessedSync GetProcessedSync(FieldReference resolvedOpField, List psLst) + { + for (int i = 0; i < psLst.Count; i++) + { + if (psLst[i].OriginalFieldRef == resolvedOpField) + return psLst[i]; + } + + /* Fall through, not found. */ + CodegenSession.LogError($"Unable to find user referenced field for {resolvedOpField.Name}."); + return null; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs.meta new file mode 100644 index 0000000..1ee148f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/NetworkBehaviourSyncProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec95af37f78b9e340b5eaa199c1af94a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs new file mode 100644 index 0000000..9f9ba0b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs @@ -0,0 +1,164 @@ +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.CodeGenerating.Processing.Rpc; +using FishNet.Configuring; +using FishNet.Managing.Logging; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.Collections.Generic; +using System.Linq; + +namespace FishNet.CodeGenerating.Processing +{ + internal class QolAttributeProcessor + { + + internal bool Process(TypeDefinition typeDef, bool moveStrippedCalls) + { + bool modified = false; + List methods = typeDef.Methods.ToList(); + + + + foreach (MethodDefinition md in methods) + { + //Has RPC attribute, doesn't quality for a quality of life attribute. + if (CodegenSession.RpcProcessor.Attributes.HasRpcAttributes(md)) + continue; + + QolAttributeType qolType; + CustomAttribute qolAttribute = GetQOLAttribute(md, out qolType); + if (qolAttribute == null) + continue; + + /* This is a one time check to make sure the qolType is + * a supported value. Multiple methods beyond this rely on the + * value being supported. Rather than check in each method a + * single check is performed here. */ + if (qolType != QolAttributeType.Server && qolType != QolAttributeType.Client) + { + CodegenSession.LogError($"QolAttributeType of {qolType.ToString()} is unhandled."); + continue; + } + + CreateAttributeMethod(md, qolAttribute, qolType); + modified = true; + } + + return modified; + } + + /// + /// Returns the RPC attribute on a method, if one exist. Otherwise returns null. + /// + /// + /// + /// + private CustomAttribute GetQOLAttribute(MethodDefinition methodDef, out QolAttributeType qolType) + { + CustomAttribute foundAttribute = null; + qolType = QolAttributeType.None; + //Becomes true if an error occurred during this process. + bool error = false; + //Nothing to check. + if (methodDef == null || methodDef.CustomAttributes == null) + return null; + + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + QolAttributeType thisQolType = CodegenSession.AttributeHelper.GetQolAttributeType(customAttribute.AttributeType.FullName); + if (thisQolType != QolAttributeType.None) + { + //A qol attribute already exist. + if (foundAttribute != null) + { + CodegenSession.LogError($"{methodDef.Name} {thisQolType.ToString()} method cannot have multiple quality of life attributes."); + error = true; + } + ////Static method. + //if (methodDef.IsStatic) + //{ + // CodegenSession.AddError($"{methodDef.Name} {thisQolType.ToString()} method cannot be static."); + // error = true; + //} + //Abstract method. + if (methodDef.IsAbstract) + { + CodegenSession.LogError($"{methodDef.Name} {thisQolType.ToString()} method cannot be abstract."); + error = true; + } + + //If all checks passed. + if (!error) + { + foundAttribute = customAttribute; + qolType = thisQolType; + } + } + } + + //If an error occurred then reset results. + if (error) + { + foundAttribute = null; + qolType = QolAttributeType.None; + } + + return foundAttribute; + } + + /// + /// Modifies the specified method to use QolType. + /// + private void CreateAttributeMethod(MethodDefinition methodDef, CustomAttribute qolAttribute, QolAttributeType qolType) + { + bool inheritsNetworkBehaviour = methodDef.DeclaringType.InheritsNetworkBehaviour(); + + //True to use InstanceFInder. + bool useStatic = (methodDef.IsStatic || !inheritsNetworkBehaviour); + + if (qolType == QolAttributeType.Client) + { + if (!StripMethod(methodDef)) + { + LoggingType logging = qolAttribute.GetField("Logging", LoggingType.Warning); + /* Since isClient also uses insert first + * it will be put ahead of the IsOwner check, since the + * codegen processes it after IsOwner. EG... + * IsOwner will be added first, then IsClient will be added first over IsOwner. */ + bool requireOwnership = qolAttribute.GetField("RequireOwnership", false); + if (requireOwnership && useStatic) + { + CodegenSession.LogError($"Method {methodDef.Name} has a [Client] attribute which requires ownership but the method may not use this attribute. Either the method is static, or the script does not inherit from NetworkBehaviour."); + return; + } + //If (!base.IsOwner); + if (requireOwnership) + CodegenSession.NetworkBehaviourHelper.CreateLocalClientIsOwnerCheck(methodDef, logging, true, false, true); + //Otherwise normal IsClient check. + else + CodegenSession.NetworkBehaviourHelper.CreateIsClientCheck(methodDef, logging, useStatic, true); + } + } + else if (qolType == QolAttributeType.Server) + { + if (!StripMethod(methodDef)) + { + LoggingType logging = qolAttribute.GetField("Logging", LoggingType.Warning); + CodegenSession.NetworkBehaviourHelper.CreateIsServerCheck(methodDef, logging, useStatic, true); + } + } + + bool StripMethod(MethodDefinition md) + { + + + //Fall through. + return false; + } + } + + + } + +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs.meta new file mode 100644 index 0000000..ff1a0e7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/QOLAttributeProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5080d7597ffca904b9a9fd5926e4e5a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc.meta new file mode 100644 index 0000000..a1e3948 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de5f90c539e844445be428ff2a2fdf29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs new file mode 100644 index 0000000..b8f39cb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs @@ -0,0 +1,68 @@ +using FishNet.CodeGenerating.Helping; +using FishNet.Object.Helping; +using MonoFN.Cecil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Processing.Rpc +{ + internal static class AttributeDataExtensions + { + + /// + /// Returns RpcTypes in datas. + /// + public static List GetRpcTypes(this List datas) + { + //RpcTypes for originalMd. + List rpcTypes = new List(); + foreach (AttributeData ad in datas) + rpcTypes.Add(ad.RpcType); + + return rpcTypes; + } + + /// + /// Gets CustomAttribute for rpcType + /// + public static CustomAttribute GetAttribute(this List datas, RpcType rpcType) + { + for (int i = 0; i < datas.Count; i++) + { + if (datas[i].RpcType == rpcType) + return datas[i].Attribute; + } + + CodegenSession.LogError($"RpcType {rpcType} not found in datas."); + return null; + } + + + /// + /// Returns RpcType as flag through combining datas. + /// + /// + /// + public static RpcType GetCombinedRpcType(this List datas) + { + RpcType result = RpcType.None; + for (int i = 0; i < datas.Count; i++) + result |= datas[i].RpcType; + + return result; + } + } + + internal class AttributeData + { + public readonly CustomAttribute Attribute; + public readonly RpcType RpcType; + + public AttributeData(CustomAttribute attribute, RpcType rpcType) + { + Attribute = attribute; + RpcType = rpcType; + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs.meta new file mode 100644 index 0000000..69cbe34 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/AttributeData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91f84e00db3d1ad448fb6a760afb6927 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs new file mode 100644 index 0000000..8c2283f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs @@ -0,0 +1,166 @@ +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Connection; +using FishNet.Object.Helping; +using MonoFN.Cecil; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace FishNet.CodeGenerating.Processing.Rpc +{ + internal class Attributes + { + + /// + /// Returns if methodDef has any Rpc attribute. + /// + public bool HasRpcAttributes(MethodDefinition methodDef) + { + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + RpcType rt = CodegenSession.AttributeHelper.GetRpcAttributeType(customAttribute); + if (rt != RpcType.None) + return true; + } + + //Fall through, nothing found. + return false; + } + + /// + /// Returns a collection of RpcAttribute for methodDef. + /// + public List GetRpcAttributes(MethodDefinition methodDef) + { + List results = new List(); + string asyncAttributeFullName = typeof(AsyncStateMachineAttribute).FullName; + bool isAsync = false; + + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + RpcType rt = CodegenSession.AttributeHelper.GetRpcAttributeType(customAttribute); + if (rt != RpcType.None) + { + results.Add(new AttributeData(customAttribute, rt)); + } + //Not a rpc attribute. + else + { + //Check if async. + if (customAttribute.Is(asyncAttributeFullName)) + isAsync = true; + } + } + + //Nothing found, exit early. + if (results.Count == 0) + { + return results; + } + //If has at least one RPC attrivbute and is an async method. + else if (isAsync) + { + CodegenSession.LogError($"{methodDef.Name} is an async RPC. This feature is not currently supported. You may instead run an async method from this RPC."); + return new List(); + } + //If more than one attribute make sure the combination is allowed. + else if (results.Count >= 2) + { + RpcType allRpcTypes = results.GetCombinedRpcType(); + if (allRpcTypes != (RpcType.Observers | RpcType.Target)) + { + CodegenSession.LogError($"{methodDef.Name} contains multiple RPC attributes. Only ObserversRpc and TargetRpc attributes may be combined."); + return new List(); + } + } + + //Next validate that the method is setup properly for each rpcType. + foreach (AttributeData ad in results) + { + //If not valid then return empty list. + if (!IsRpcMethodValid(methodDef, ad.RpcType)) + return new List(); + } + + return results; + } + + /// + /// Returns if a RpcMethod can be serialized and has a proper signature. + /// + private bool IsRpcMethodValid(MethodDefinition methodDef, RpcType rpcType) + { + //Static method. + if (methodDef.IsStatic) + { + CodegenSession.LogError($"{methodDef.Name} RPC method cannot be static."); + return false; + } + //Is generic type. + else if (methodDef.HasGenericParameters) + { + CodegenSession.LogError($"{methodDef.Name} RPC method cannot contain generic parameters."); + return false; + } + //Abstract method. + else if (methodDef.IsAbstract) + { + CodegenSession.LogError($"{methodDef.Name} RPC method cannot be abstract."); + return false; + } + //Non void return. + else if (methodDef.ReturnType != methodDef.Module.TypeSystem.Void) + { + CodegenSession.LogError($"{methodDef.Name} RPC method must return void."); + return false; + } + //Misc failing conditions. + else + { + //Check for async attribute. + foreach (CustomAttribute ca in methodDef.CustomAttributes) + { + + } + } + //TargetRpc but missing correct parameters. + if (rpcType == RpcType.Target) + { + if (methodDef.Parameters.Count == 0 || !methodDef.Parameters[0].Is(typeof(NetworkConnection))) + { + CodegenSession.LogError($"Target RPC {methodDef.Name} must have a NetworkConnection as the first parameter."); + return false; + } + } + + //Make sure all parameters can be serialized. + for (int i = 0; i < methodDef.Parameters.Count; i++) + { + ParameterDefinition parameterDef = methodDef.Parameters[i]; + + //If NetworkConnection, TargetRpc, and first parameter. + if ((i == 0) && (rpcType == RpcType.Target) && parameterDef.Is(typeof(NetworkConnection))) + continue; + + if (parameterDef.ParameterType.IsGenericParameter) + { + CodegenSession.LogError($"RPC method{methodDef.Name} contains a generic parameter. This is currently not supported."); + return false; + } + + //Can be serialized/deserialized. + bool canSerialize = CodegenSession.GeneralHelper.HasSerializerAndDeserializer(parameterDef.ParameterType, true); + if (!canSerialize) + { + CodegenSession.LogError($"RPC method {methodDef.Name} parameter type {parameterDef.ParameterType.FullName} does not support serialization. Use a supported type or create a custom serializer."); + return false; + } + + } + + //Fall through, success. + return true; + } + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs.meta new file mode 100644 index 0000000..e0ab4ab --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/Attributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 974ebf09757267941a86f92e5072258c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs new file mode 100644 index 0000000..c2bd411 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs @@ -0,0 +1,58 @@ +using FishNet.Object.Helping; +using MonoFN.Cecil; +using System.Collections.Generic; + +namespace FishNet.CodeGenerating.Processing.Rpc +{ + + internal class CreatedRpc + { + public MethodDefinition OriginalMethodDef; + public uint MethodHash; + public AttributeData AttributeData; + public MethodDefinition WriterMethodDef; + public MethodDefinition ReaderMethodDef; + public MethodDefinition LogicMethodDef; + public MethodDefinition RedirectMethodDef; + public bool RunLocally; + + public RpcType RpcType => AttributeData.RpcType; + public CustomAttribute Attribute => AttributeData.Attribute; + public TypeDefinition TypeDef => OriginalMethodDef.DeclaringType; + public ModuleDefinition Module => OriginalMethodDef.Module; + } + + + internal static class CreatedRpcExtensions + { + /// + /// Returns CreatedRpc for rpcType. + /// + /// + public static CreatedRpc GetCreatedRpc(this List lst, RpcType rpcType) + { + for (int i = 0; i < lst.Count; i++) + { + if (lst[i].RpcType == rpcType) + return lst[i]; + } + //Fall through. + return null; + } + + /// + /// Returns combined RpcType for all entries. + /// + /// + public static RpcType GetCombinedRpcType(this List lst) + { + RpcType result = RpcType.None; + for (int i = 0; i < lst.Count; i++) + result |= lst[i].RpcType; + + return result; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs.meta new file mode 100644 index 0000000..bc68749 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/CreatedRpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2176b6bfcc49934d8f36fba3df74d0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs new file mode 100644 index 0000000..785f6b3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs @@ -0,0 +1,1052 @@ + +using FishNet.CodeGenerating.Extension; +using FishNet.CodeGenerating.Helping; +using FishNet.CodeGenerating.Helping.Extension; +using FishNet.Configuring; +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Object.Helping; +using FishNet.Transporting; +using MonoFN.Cecil; +using MonoFN.Cecil.Cil; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace FishNet.CodeGenerating.Processing.Rpc +{ + internal class RpcProcessor + { + + #region Types. + private struct DelegateData + { + public RpcType RpcType; + public bool RunLocally; + public MethodDefinition OriginalMethodDef; + public MethodDefinition ReaderMethodDef; + public uint MethodHash; + public CustomAttribute RpcAttribute; + + public DelegateData(RpcType rpcType, bool runLocally, MethodDefinition originalMethodDef, MethodDefinition readerMethodDef, uint methodHash, CustomAttribute rpcAttribute) + { + RpcType = rpcType; + RunLocally = runLocally; + OriginalMethodDef = originalMethodDef; + ReaderMethodDef = readerMethodDef; + MethodHash = methodHash; + RpcAttribute = rpcAttribute; + } + } + + #endregion + + #region Public. + /// + /// Attribute helper. + /// + public Attributes Attributes = new Attributes(); + #endregion + + private List<(MethodDefinition, MethodDefinition)> _virtualRpcs = new List<(MethodDefinition createdLogicMd, MethodDefinition originalRpcMd)>(); + + #region Const. + private const string LOGIC_PREFIX = "RpcLogic___"; + private const string WRITER_PREFIX = "RpcWriter___"; + private const string READER_PREFIX = "RpcReader___"; + private const string REQUIREOWNERSHIP_NAME = "RequireOwnership"; + private const string RUNLOCALLY_NAME = "RunLocally"; + private const string INCLUDEOWNER_NAME = "IncludeOwner"; + private const string BUFFERLAST_NAME = "BufferLast"; + #endregion + + internal bool Process(TypeDefinition typeDef, ref uint rpcCount) + { + bool modified = false; + + //All createdRpcs for typeDef. + List typeDefCeatedRpcs = new List(); + List methodDefs = typeDef.Methods.ToList(); + foreach (MethodDefinition md in methodDefs) + { + if (rpcCount >= NetworkBehaviourHelper.MAX_RPC_ALLOWANCE) + { + CodegenSession.LogError($"{typeDef.FullName} and inherited types exceed {NetworkBehaviourHelper.MAX_RPC_ALLOWANCE} RPC methods. Only {NetworkBehaviourHelper.MAX_RPC_ALLOWANCE} RPC methods are supported per inheritance hierarchy."); + return false; + } + + //Rpcs created for this method. + List createdRpcs = new List(); + List attributeDatas = Attributes.GetRpcAttributes(md); + bool success = true; + foreach (AttributeData ad in attributeDatas) + { + CreatedRpc cr = new CreatedRpc(); + cr.OriginalMethodDef = md; + cr.AttributeData = ad; + cr.MethodHash = rpcCount; + + /* This is a one time check to make sure the rpcType is + * a supported value. Multiple methods beyond this rely on the + * value being supported. Rather than check in each method a + * single check is performed here. */ + if (cr.RpcType != RpcType.Observers && cr.RpcType != RpcType.Server && cr.RpcType != RpcType.Target) + { + CodegenSession.LogError($"RpcType of {cr.RpcType.ToString()} is unhandled."); + break; + } + + bool created = CreateRpcMethods(attributeDatas, cr); + if (created) + { + modified = true; + + typeDefCeatedRpcs.Add(cr); + createdRpcs.Add(cr); + + if (cr.LogicMethodDef != null && cr.LogicMethodDef.IsVirtual) + _virtualRpcs.Add((cr.LogicMethodDef, md)); + + rpcCount++; + } + else + { + success = false; + } + } + + //If at least one attribute was found and all rpc methods were made. + if (createdRpcs.Count > 0 && success) + RedirectOriginalToWriter(createdRpcs); + + } + + if (modified) + { + foreach (CreatedRpc cr in typeDefCeatedRpcs) + { + CodegenSession.NetworkBehaviourHelper.CreateRpcDelegate(cr.RunLocally, cr.TypeDef, + cr.ReaderMethodDef, cr.RpcType, cr.MethodHash, + cr.Attribute); + } + return true; + } + else + { + return false; + } + } + + /// + /// Returns the name to use for a RpcMethod. + /// + private string GetRpcMethodName(CreatedRpc cr) + { + return GetRpcMethodName(cr.RpcType, cr.OriginalMethodDef); + } + + /// + /// Returns the name to use for a RpcMethod. + /// + private string GetRpcMethodName(RpcType rpcType, MethodDefinition originalMd) + { + return $"{rpcType}_{GetMethodNameAsParameters(originalMd)}"; + } + + /// + /// Returns the method name with parameter types included within the name. + /// + public static string GetMethodNameAsParameters(MethodDefinition methodDef) + { + StringBuilder sb = new StringBuilder(); + foreach (ParameterDefinition pd in methodDef.Parameters) + sb.Append(pd.ParameterType.FullName); + + return $"{methodDef.Name}_{sb.ToString().GetStableHash32()}"; + } + + /// + /// Redirects base calls for overriden RPCs. + /// + internal void RedirectBaseCalls() + { + foreach ((MethodDefinition logicMd, MethodDefinition originalMd) in _virtualRpcs) + RedirectBaseCall(logicMd, originalMd); + } + + /// + /// Gets number of RPCs by checking for RPC attributes. This does not perform error checking. + /// + /// + /// + internal uint GetRpcCount(TypeDefinition typeDef) + { + uint count = 0; + foreach (MethodDefinition methodDef in typeDef.Methods) + { + foreach (CustomAttribute customAttribute in methodDef.CustomAttributes) + { + RpcType rpcType = CodegenSession.AttributeHelper.GetRpcAttributeType(customAttribute); + if (rpcType != RpcType.None) + { + count++; + break; + } + } + } + + return count; + } + + /// + /// Creates all methods needed for a RPC. + /// + /// + /// + /// True if successful. + private bool CreateRpcMethods(List datas, CreatedRpc cr) + { + cr.RunLocally = cr.Attribute.GetField(RUNLOCALLY_NAME, false); + bool intentionallyNull; + + List serializedParameters = GetSerializedParamters(cr.RpcType, datas, cr); + + cr.WriterMethodDef = CreateRpcWriterMethod(serializedParameters, datas, cr, out intentionallyNull); + if (!intentionallyNull && cr.WriterMethodDef == null) + return false; + + cr.LogicMethodDef = CreateRpcLogicMethod(datas, cr, out intentionallyNull); + if (!intentionallyNull && cr.LogicMethodDef == null) + return false; + + cr.ReaderMethodDef = CreateRpcReaderMethod(serializedParameters, datas, cr, out intentionallyNull); + if (!intentionallyNull && cr.ReaderMethodDef == null) + return false; + + + return true; + } + + + + /// + /// Creates a writer for a RPC. + /// + /// + /// + /// + private MethodDefinition CreateRpcWriterMethod(List serializedParameters, List datas, CreatedRpc cr, out bool intentionallyNull) + { + intentionallyNull = false; + + + + string methodName = $"{WRITER_PREFIX}{GetRpcMethodName(cr)}"; + /* If method already exist then clear it. This + * can occur when a method needs to be rebuilt due to + * inheritence, and renumbering the RPC method names. */ + MethodDefinition createdMd = cr.TypeDef.GetMethod(methodName); + //If found. + if (createdMd != null) + { + createdMd.Parameters.Clear(); + createdMd.Body.Instructions.Clear(); + } + //Doesn't exist, create it. + else + { + //Create the method body. + createdMd = new MethodDefinition(methodName, + MethodAttributes.Private, + cr.Module.TypeSystem.Void); + cr.TypeDef.Methods.Add(createdMd); + createdMd.Body.InitLocals = true; + } + cr.WriterMethodDef = createdMd; + + bool result; + if (cr.RpcType == RpcType.Server) + result = CreateServerRpcWriterMethod(serializedParameters, cr); + else if (cr.RpcType == RpcType.Target || cr.RpcType == RpcType.Observers) + result = CreateClientRpcWriterMethod(serializedParameters, datas, cr); + else + result = false; + + return (result) ? cr.WriterMethodDef : null; + } + + /// + /// Returns serializable parameters for originalMd. + /// + private List GetSerializedParamters(RpcType rpcType, List attributeDatas, CreatedRpc cr) + { + MethodDefinition originalMd = cr.OriginalMethodDef; + + //RpcTypes for originalMd. + List attributeRpcTypes = attributeDatas.GetRpcTypes(); + + //Parameters to be serialized. + List serializedParameters = new List(); + /* Parameters which won't be serialized, such as channel. + * It's safe to add parameters which are null or + * not used. */ + HashSet nonserializedParameters = new HashSet(); + + //Get channel if it exist, and get target parameter. + ParameterDefinition channelParameterDef = GetChannelParameter(originalMd, rpcType); + + /* RpcType specific parameters. */ + ParameterDefinition targetConnectionParameterDef = null; + if (attributeRpcTypes.Contains(RpcType.Target)) + targetConnectionParameterDef = originalMd.Parameters[0]; + + if (rpcType == RpcType.Server) + { + //The network connection parameter might be added as null, this is okay. + nonserializedParameters.Add(GetNetworkConnectionParameter(originalMd)); + nonserializedParameters.Add(channelParameterDef); + } + else + { + nonserializedParameters.Add(channelParameterDef); + nonserializedParameters.Add(targetConnectionParameterDef); + } + + //Add all parameters which are NOT nonserialized to serializedParameters. + foreach (ParameterDefinition pd in originalMd.Parameters) + { + if (!nonserializedParameters.Contains(pd)) + serializedParameters.Add(pd); + } + + return serializedParameters; + } + + /// + /// Creates Writer method for a TargetRpc. + /// + private bool CreateClientRpcWriterMethod(List serializedParameters, List attributeDatas, CreatedRpc cr) + { + MethodDefinition writerMd = cr.WriterMethodDef; + MethodDefinition originalMd = cr.OriginalMethodDef; + + ILProcessor processor = writerMd.Body.GetILProcessor(); + //Add all parameters from the original. + for (int i = 0; i < originalMd.Parameters.Count; i++) + writerMd.Parameters.Add(originalMd.Parameters[i]); + //Get channel if it exist, and get target parameter. + ParameterDefinition channelParameterDef = GetChannelParameter(writerMd, RpcType.None); + + List rpcTypes = attributeDatas.GetRpcTypes(); + + /* RpcType specific parameters. */ + ParameterDefinition targetConnectionParameterDef = null; + if (rpcTypes.Contains(RpcType.Target)) + targetConnectionParameterDef = writerMd.Parameters[0]; + + /* Creates basic ServerRpc and ClientRpc + * conditions such as if requireOwnership ect.. + * or if (!base.isClient) */ + + CreateClientRpcConditionsForServer(writerMd); + + VariableDefinition channelVariableDef = CreateAndPopulateChannelVariable(writerMd, channelParameterDef); + //Create a local PooledWriter variable. + VariableDefinition pooledWriterVariableDef = CodegenSession.WriterHelper.CreatePooledWriter(writerMd); + //Create all writer.WriteType() calls. + for (int i = 0; i < serializedParameters.Count; i++) + { + MethodReference writeMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(serializedParameters[i].ParameterType, true); + if (writeMethodRef == null) + return false; + + CodegenSession.WriterHelper.CreateWrite(writerMd, pooledWriterVariableDef, serializedParameters[i], writeMethodRef); + } + + /* Call the method on NetworkBehaviour responsible for sending out the rpc. */ + if (cr.RpcType == RpcType.Observers) + processor.Add(CreateSendObserversRpc(writerMd, cr.MethodHash, pooledWriterVariableDef, channelVariableDef, cr.Attribute)); + else if (cr.RpcType == RpcType.Target) + processor.Add(CreateSendTargetRpc(writerMd, cr.MethodHash, pooledWriterVariableDef, channelVariableDef, targetConnectionParameterDef)); + //Dispose of writer. + processor.Add(CodegenSession.WriterHelper.DisposePooledWriter(writerMd, pooledWriterVariableDef)); + //Add end of method. + processor.Emit(OpCodes.Ret); + + return true; + } + + /// + /// Creates Writer method for a ServerRpc. + /// + private bool CreateServerRpcWriterMethod(List serializedParameters, CreatedRpc cr) + { + MethodDefinition writerMd = cr.WriterMethodDef; + MethodDefinition originalMd = cr.OriginalMethodDef; + ILProcessor processor = writerMd.Body.GetILProcessor(); + + //Add all parameters from the original. + for (int i = 0; i < originalMd.Parameters.Count; i++) + writerMd.Parameters.Add(originalMd.Parameters[i]); + //Add in channel if it doesnt exist. + ParameterDefinition channelParameterDef = GetChannelParameter(writerMd, RpcType.Server); + + /* Creates basic ServerRpc + * conditions such as if requireOwnership ect.. + * or if (!base.isClient) */ + + CreateServerRpcConditionsForClient(writerMd, cr.Attribute); + + VariableDefinition channelVariableDef = CreateAndPopulateChannelVariable(writerMd, channelParameterDef); + //Create a local PooledWriter variable. + VariableDefinition pooledWriterVariableDef = CodegenSession.WriterHelper.CreatePooledWriter(writerMd); + //Create all writer.WriteType() calls. + for (int i = 0; i < serializedParameters.Count; i++) + { + MethodReference writeMethodRef = CodegenSession.WriterHelper.GetOrCreateFavoredWriteMethodReference(serializedParameters[i].ParameterType, true); + if (writeMethodRef == null) + return false; + + CodegenSession.WriterHelper.CreateWrite(writerMd, pooledWriterVariableDef, serializedParameters[i], writeMethodRef); + } + + //uint methodHash = originalMethodDef.FullName.GetStableHash32(); + //Call the method on NetworkBehaviour responsible for sending out the rpc. + processor.Add(CreateSendServerRpc(writerMd, cr.MethodHash, pooledWriterVariableDef, channelVariableDef)); + //Dispose of writer. + processor.Add(CodegenSession.WriterHelper.DisposePooledWriter(writerMd, pooledWriterVariableDef)); + //Add end of method. + processor.Emit(OpCodes.Ret); + + return true; + } + + /// + /// Creates a Channel VariableDefinition and populates it with parameterDef value if available, otherwise uses Channel.Reliable. + /// + /// + /// + /// + private VariableDefinition CreateAndPopulateChannelVariable(MethodDefinition methodDef, ParameterDefinition parameterDef) + { + ILProcessor processor = methodDef.Body.GetILProcessor(); + + VariableDefinition localChannelVariableDef = CodegenSession.GeneralHelper.CreateVariable(methodDef, typeof(Channel)); + if (parameterDef != null) + processor.Emit(OpCodes.Ldarg, parameterDef); + else + processor.Emit(OpCodes.Ldc_I4, (int)Channel.Reliable); + + //Set to local value. + processor.Emit(OpCodes.Stloc, localChannelVariableDef); + return localChannelVariableDef; + } + + + /// + /// Creates a reader for a RPC. + /// + /// + /// + /// + private MethodDefinition CreateRpcReaderMethod(List serializedParameters, List datas, CreatedRpc cr, out bool intentionallyNull) + { + intentionallyNull = false; + + RpcType rpcType = cr.RpcType; + MethodDefinition originalMd = cr.OriginalMethodDef; + TypeDefinition typeDef = cr.TypeDef; + bool runLocally = cr.RunLocally; + MethodDefinition logicMd = cr.LogicMethodDef; + CustomAttribute rpcAttribute = cr.Attribute; + + + + string methodName = $"{READER_PREFIX}{GetRpcMethodName(cr)}"; + /* If method already exist then just return it. This + * can occur when a method needs to be rebuilt due to + * inheritence, and renumbering the RPC method names. + * The reader method however does not need to be rewritten. */ + MethodDefinition createdMd = typeDef.GetMethod(methodName); + //If found. + if (createdMd != null) + { + cr.ReaderMethodDef = createdMd; + return createdMd; + } + else + { + //Create the method body. + createdMd = new MethodDefinition( + methodName, + MethodAttributes.Private, + originalMd.Module.TypeSystem.Void); + typeDef.Methods.Add(createdMd); + createdMd.Body.InitLocals = true; + cr.ReaderMethodDef = createdMd; + } + + if (rpcType == RpcType.Server) + return CreateServerRpcReaderMethod(typeDef, runLocally, originalMd, createdMd, serializedParameters, logicMd, rpcAttribute); + else if (rpcType == RpcType.Target || rpcType == RpcType.Observers) + return CreateClientRpcReaderMethod(serializedParameters, datas, cr); + else + return null; + } + + + /// + /// Creates a reader for ServerRpc. + /// + /// + /// + /// + private MethodDefinition CreateServerRpcReaderMethod(TypeDefinition typeDef, bool runLocally, MethodDefinition originalMd, MethodDefinition createdMd, List serializedParameters, MethodDefinition logicMd, CustomAttribute rpcAttribute) + { + ILProcessor processor = createdMd.Body.GetILProcessor(); + + bool requireOwnership = rpcAttribute.GetField(REQUIREOWNERSHIP_NAME, true); + //Create PooledReader parameter. + ParameterDefinition readerParameterDef = CodegenSession.GeneralHelper.CreateParameter(createdMd, CodegenSession.ReaderHelper.PooledReader_TypeRef); + + //Add connection parameter to the read method. Internals pass the connection into this. + ParameterDefinition channelParameterDef = GetOrCreateChannelParameter(createdMd, RpcType.Server); + ParameterDefinition connectionParameterDef = GetOrCreateNetworkConnectionParameter(createdMd); + /* It's very important to read everything + * from the PooledReader before applying any + * exit logic. Should the method return before + * reading the data then anything after the rpc + * packet will be malformed due to invalid index. */ + VariableDefinition[] readVariableDefs; + List allReadInsts; + CreateRpcReadInstructions(createdMd, readerParameterDef, serializedParameters, out readVariableDefs, out allReadInsts); + + //Read to clear pooledreader. + processor.Add(allReadInsts); + + /* Don't continue if server is not active. + * This can happen if an object is deinitializing + * as a RPC arrives. When separate server and client + * this should not occur but there's a chance as host + * because deinitializations are slightly delayed to support + * the clientHost deinitializing the object as well. */ + CodegenSession.NetworkBehaviourHelper.CreateIsServerCheck(createdMd, LoggingType.Off, false, false); + // + CreateServerRpcConditionsForServer(processor, requireOwnership, connectionParameterDef); + + //Block from running twice as host. + if (runLocally) + { + //The connection calling is always passed into the reader method as the last parameter. + ParameterDefinition ncPd = createdMd.Parameters[createdMd.Parameters.Count - 1]; + Instruction afterConnectionRet = processor.Create(OpCodes.Nop); + processor.Emit(OpCodes.Ldarg, ncPd); + processor.Emit(OpCodes.Callvirt, CodegenSession.ObjectHelper.NetworkConnection_GetIsLocalClient_MethodRef); + processor.Emit(OpCodes.Brfalse_S, afterConnectionRet); + processor.Emit(OpCodes.Ret); + processor.Append(afterConnectionRet); + } + + //this.Logic + processor.Emit(OpCodes.Ldarg_0); + //Add each read variable as an argument. + foreach (VariableDefinition vd in readVariableDefs) + processor.Emit(OpCodes.Ldloc, vd); + + /* Pass in channel and connection if original + * method supports them. */ + ParameterDefinition originalChannelParameterDef = GetChannelParameter(originalMd, RpcType.Server); + ParameterDefinition originalConnectionParameterDef = GetNetworkConnectionParameter(originalMd); + if (originalChannelParameterDef != null) + processor.Emit(OpCodes.Ldarg, channelParameterDef); + if (originalConnectionParameterDef != null) + processor.Emit(OpCodes.Ldarg, connectionParameterDef); + //Call __Logic method. + processor.Emit(OpCodes.Call, logicMd); + processor.Emit(OpCodes.Ret); + + return createdMd; + } + + /// + /// Creates a reader for ObserversRpc. + /// + /// + /// + /// + private MethodDefinition CreateClientRpcReaderMethod(List serializedParameters, List attributeDatas, CreatedRpc cr) + { + MethodDefinition originalMd = cr.OriginalMethodDef; + MethodDefinition createdMd = cr.ReaderMethodDef; + RpcType rpcType = cr.RpcType; + CustomAttribute rpcAttribute = cr.Attribute; + bool runLocally = cr.RunLocally; + + ILProcessor processor = createdMd.Body.GetILProcessor(); + + //Create PooledReader parameter. + ParameterDefinition readerParameterDef = CodegenSession.GeneralHelper.CreateParameter(createdMd, CodegenSession.ReaderHelper.PooledReader_TypeRef); + ParameterDefinition channelParameterDef = GetOrCreateChannelParameter(createdMd, rpcType); + /* It's very important to read everything + * from the PooledReader before applying any + * exit logic. Should the method return before + * reading the data then anything after the rpc + * packet will be malformed due to invalid index. */ + VariableDefinition[] readVariableDefs; + List allReadInsts; + CreateRpcReadInstructions(createdMd, readerParameterDef, serializedParameters, out readVariableDefs, out allReadInsts); + //Read instructions even if not to include owner. + processor.Add(allReadInsts); + + /* Don't continue if client is not active. + * This can happen if an object is deinitializing + * as a RPC arrives. When separate server and client + * this should not occur but there's a chance as host + * because deinitializations are slightly delayed to support + * the clientHost deinitializing the object as well. */ + CodegenSession.NetworkBehaviourHelper.CreateIsClientCheck(createdMd, LoggingType.Off, false, false); + + /* ObserversRpc IncludeOwnerCheck. */ + if (rpcType == RpcType.Observers) + { + //If to not include owner then don't call logic if owner. + bool includeOwner = rpcAttribute.GetField(INCLUDEOWNER_NAME, true); + if (!includeOwner) + { + //Create return if owner. + Instruction retInst = CodegenSession.NetworkBehaviourHelper.CreateLocalClientIsOwnerCheck(createdMd, LoggingType.Off, true, true, true); + processor.InsertBefore(retInst, allReadInsts); + } + } + + //Block from running twice as host. + if (runLocally) + processor.Add(CreateIsHostBlock(createdMd)); + + processor.Emit(OpCodes.Ldarg_0); //this. + /* TargetRpc passes in localconnection + * as receiver for connection. */ + if (rpcType == RpcType.Target) + { + processor.Emit(OpCodes.Ldarg_0); //this. + processor.Emit(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.LocalConnection_MethodRef); + } + else + { + //If this method uses target/observerRpc combined then load null for the connection. + RpcType allRpcTypes = attributeDatas.GetCombinedRpcType(); + if (allRpcTypes == (RpcType.Observers | RpcType.Target)) + processor.Emit(OpCodes.Ldnull); + } + //Add each read variable as an argument. + foreach (VariableDefinition vd in readVariableDefs) + processor.Emit(OpCodes.Ldloc, vd); + //Channel. + ParameterDefinition originalChannelParameterDef = GetChannelParameter(originalMd, rpcType); + if (originalChannelParameterDef != null) + processor.Emit(OpCodes.Ldarg, channelParameterDef); + //Call __Logic method. + processor.Emit(OpCodes.Call, cr.LogicMethodDef); + processor.Emit(OpCodes.Ret); + + return createdMd; + } + + + /// + /// Appends a block to the method if running as host. + /// + /// + private List CreateIsHostBlock(MethodDefinition md) + { + List ints = new List(); + ILProcessor processor = md.Body.GetILProcessor(); + + Instruction endIfInst = processor.Create(OpCodes.Nop); + ints.Add(processor.Create(OpCodes.Ldarg_0)); + ints.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.IsHost_MethodRef)); + ints.Add(processor.Create(OpCodes.Brfalse_S, endIfInst)); + ints.Add(processor.Create(OpCodes.Ret)); + ints.Add(endIfInst); + + return ints; + } + + /// + /// Gets the optional NetworkConnection parameter for ServerRpc, if it exists. + /// + /// + /// + private ParameterDefinition GetNetworkConnectionParameter(MethodDefinition methodDef) + { + + ParameterDefinition result = methodDef.GetEndParameter(0); + //Is null, not networkconnection, or doesn't have default. + if (result == null || !result.Is(typeof(NetworkConnection)) || !result.HasDefault) + return null; + + return result; + } + + /// + /// Creates a NetworkConnection parameter if it's not the last or second to last parameter. + /// + /// + private ParameterDefinition GetOrCreateNetworkConnectionParameter(MethodDefinition methodDef) + { + ParameterDefinition result = GetNetworkConnectionParameter(methodDef); + if (result == null) + return CodegenSession.GeneralHelper.CreateParameter(methodDef, typeof(NetworkConnection), "conn"); + else + return result; + } + + /// + /// Returns the Channel parameter if it exist. + /// + /// + private ParameterDefinition GetChannelParameter(MethodDefinition methodDef, RpcType rpcType) + { + ParameterDefinition result = null; + ParameterDefinition pd = methodDef.GetEndParameter(0); + if (pd != null) + { + //Last parameter is channel. + if (pd.Is(typeof(Channel))) + { + result = pd; + } + /* Only other end parameter may be networkconnection. + * This can only be checked if a ServerRpc. */ + else if (rpcType == RpcType.Server) + { + //If last parameter is networkconnection and its default then can check second to last. + if (pd.Is(typeof(NetworkConnection)) && pd.HasDefault) + { + pd = methodDef.GetEndParameter(1); + if (pd != null && pd.Is(typeof(Channel))) + result = pd; + } + } + else + { + result = null; + } + } + + return result; + } + + /// + /// Creates a channel parameter if missing. + /// + /// + private ParameterDefinition GetOrCreateChannelParameter(MethodDefinition methodDef, RpcType rpcType) + { + ParameterDefinition result = GetChannelParameter(methodDef, rpcType); + //Add channel parameter if not included. + if (result == null) + { + ParameterDefinition connParameter = GetNetworkConnectionParameter(methodDef); + //If the connection parameter is specified then channel has to go before it. + if (connParameter != null) + return CodegenSession.GeneralHelper.CreateParameter(methodDef, typeof(Channel), "channel", ParameterAttributes.None, connParameter.Index); + //Not specified, add channel at end. + else + return CodegenSession.GeneralHelper.CreateParameter(methodDef, typeof(Channel), "channel"); + } + else + { + return result; + } + } + + /// + /// Creates a read for every writtenParameters and outputs variables read into, and instructions. + /// + /// + /// + /// + /// + /// + /// + private void CreateRpcReadInstructions(MethodDefinition methodDef, ParameterDefinition readerParameterDef, List serializedParameters, out VariableDefinition[] readVariableDefs, out List allReadInsts) + { + /* It's very important to read everything + * from the PooledReader before applying any + * exit logic. Should the method return before + * reading the data then anything after the rpc + * packet will be malformed due to invalid index. */ + readVariableDefs = new VariableDefinition[serializedParameters.Count]; + allReadInsts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + //True if last parameter is a connection and a server rpc. + for (int i = 0; i < serializedParameters.Count; i++) + { + //Get read instructions and insert it before the return. + List insts = CodegenSession.ReaderHelper.CreateRead(methodDef, readerParameterDef, serializedParameters[i].ParameterType, out readVariableDefs[i]); + allReadInsts.AddRange(insts); + } + + } + /// + /// Creates conditions that clients must pass to send a ServerRpc. + /// + /// + /// + private void CreateServerRpcConditionsForClient(MethodDefinition methodDef, CustomAttribute rpcAttribute) + { + bool requireOwnership = rpcAttribute.GetField(REQUIREOWNERSHIP_NAME, true); + //If (!base.IsOwner); + if (requireOwnership) + CodegenSession.NetworkBehaviourHelper.CreateLocalClientIsOwnerCheck(methodDef, LoggingType.Warning, false, false, true); + //If (!base.IsClient) + CodegenSession.NetworkBehaviourHelper.CreateIsClientCheck(methodDef, LoggingType.Warning, false, true); + } + + /// + /// Creates conditions that server must pass to process a ServerRpc. + /// + /// + /// + /// Ret instruction. + private Instruction CreateServerRpcConditionsForServer(ILProcessor createdProcessor, bool requireOwnership, ParameterDefinition connectionParametereDef) + { + /* Don't need to check if server on receiving end. + * Next compare connection with owner. */ + //If (!base.CompareOwner); + if (requireOwnership) + return CodegenSession.NetworkBehaviourHelper.CreateRemoteClientIsOwnerCheck(createdProcessor, connectionParametereDef); + else + return null; + } + + /// + /// Creates conditions that server must pass to process a ClientRpc. + /// + /// + private void CreateClientRpcConditionsForServer(MethodDefinition methodDef) + { + //If (!base.IsServer) + CodegenSession.NetworkBehaviourHelper.CreateIsServerCheck(methodDef, LoggingType.Warning, false, false); + } + + /// + /// Creates a method containing the logic which will run when receiving the Rpc. + /// + /// + /// + private MethodDefinition CreateRpcLogicMethod(List datas, CreatedRpc cr, out bool intentionallyNull) + { + intentionallyNull = false; + + RpcType rpcType = cr.RpcType; + TypeDefinition typeDef = cr.TypeDef; + MethodDefinition originalMd = cr.OriginalMethodDef; + + + + //Methodname for logic methods do not use prefixes because there can be only one. + string methodName = $"{LOGIC_PREFIX}{GetMethodNameAsParameters(originalMd)}"; + /* If method already exist then just return it. This + * can occur when a method needs to be rebuilt due to + * inheritence, and renumbering the RPC method names. + * The logic method however does not need to be rewritten. */ + MethodDefinition logicMd = CodegenSession.GeneralHelper.CopyMethod(originalMd, methodName, out _); + + cr.LogicMethodDef = logicMd; + return logicMd; + } + + /// + /// Finds and fixes call to base methods within remote calls + /// For example, changes `base.CmdDoSomething` to `base.UserCode_CmdDoSomething` within `this.UserCode_CmdDoSomething` + /// + /// + /// + private void RedirectBaseCall(MethodDefinition createdMethodDef, MethodDefinition originalMethodDef) + { + //All logic RPCs end with the logic suffix. + if (!createdMethodDef.Name.StartsWith(LOGIC_PREFIX)) + return; + //Not virtual, no need to check. + if (!createdMethodDef.IsVirtual) + return; + + foreach (Instruction instruction in createdMethodDef.Body.Instructions) + { + // if call to base.RpcDoSomething within this.RpcDoSOmething. + if (CodegenSession.GeneralHelper.IsCallToMethod(instruction, out MethodDefinition calledMethod) && calledMethod.Name == originalMethodDef.Name) + { + MethodReference baseLogicMd = createdMethodDef.DeclaringType.GetMethodDefinitionInAnyBase(createdMethodDef.Name); + if (baseLogicMd == null) + { + CodegenSession.LogError($"Could not find base method for {createdMethodDef.Name}."); + return; + } + + instruction.Operand = CodegenSession.ImportReference(baseLogicMd); + } + } + } + + + /// + /// Redirects calls from the original Rpc method to the writer method. + /// + private void RedirectOriginalToWriter(List createdRpcs) + { + /* If there are multiple attributes/createdRpcs they will + * share the same originalMd so it's fine to take the first + * entry. */ + MethodDefinition originalMd = createdRpcs[0].OriginalMethodDef; + + + + ILProcessor processor = originalMd.Body.GetILProcessor(); + originalMd.Body.Instructions.Clear(); + + //If only one rpc type. + if (createdRpcs.Count == 1) + { + processor.Emit(OpCodes.Ldarg_0); //this. + //Parameters. + foreach (ParameterDefinition pd in originalMd.Parameters) + processor.Emit(OpCodes.Ldarg, pd); + + //Call method. + MethodReference writerMr = CodegenSession.ImportReference(createdRpcs[0].WriterMethodDef); + processor.Emit(OpCodes.Call, writerMr); + } + //More than one which means it's an observer/targetRpc combo. + else + { + MethodReference observerWriterMr = CodegenSession.ImportReference(createdRpcs.GetCreatedRpc(RpcType.Observers).WriterMethodDef); + MethodReference targetWriterMr = CodegenSession.ImportReference(createdRpcs.GetCreatedRpc(RpcType.Target).WriterMethodDef); + + Instruction targetRpcInst = processor.Create(OpCodes.Nop); + Instruction afterTargetRpcInst = processor.Create(OpCodes.Nop); + /* if (targetConn == null) + * WriteObserverRpc + * else + * WriteTargetRpc */ + processor.Emit(OpCodes.Ldarg, originalMd.Parameters[0]); + processor.Emit(OpCodes.Brtrue_S, targetRpcInst); + //Insert parameters. + processor.Emit(OpCodes.Ldarg_0); + foreach (ParameterDefinition pd in originalMd.Parameters) + processor.Emit(OpCodes.Ldarg, pd); + processor.Emit(OpCodes.Call, observerWriterMr); + //else (target). + processor.Emit(OpCodes.Br_S, afterTargetRpcInst); + processor.Append(targetRpcInst); + //Insert parameters. + processor.Emit(OpCodes.Ldarg_0); + foreach (ParameterDefinition pd in originalMd.Parameters) + processor.Emit(OpCodes.Ldarg, pd); + processor.Emit(OpCodes.Call, targetWriterMr); + processor.Append(afterTargetRpcInst); + } + + //Runlocally. + if (createdRpcs[0].RunLocally) + { + processor.Emit(OpCodes.Ldarg_0); //this. + //Parameters. + foreach (ParameterDefinition pd in originalMd.Parameters) + processor.Emit(OpCodes.Ldarg, pd); + processor.Emit(OpCodes.Call, createdRpcs[0].LogicMethodDef); + } + + processor.Emit(OpCodes.Ret); + } + + + #region CreateSend + /// + /// Creates a call to SendServerRpc on NetworkBehaviour. + /// + /// + /// + private List CreateSendServerRpc(MethodDefinition methodDef, uint methodHash, VariableDefinition writerVariableDef, VariableDefinition channelVariableDef) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.AddRange(CreateSendRpcCommon(processor, methodHash, writerVariableDef, channelVariableDef)); + //Call NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.SendServerRpc_MethodRef)); + + return insts; + } + + /// + /// Creates a call to SendObserversRpc on NetworkBehaviour. + /// + private List CreateSendObserversRpc(MethodDefinition methodDef, uint methodHash, VariableDefinition writerVariableDef, VariableDefinition channelVariableDef, CustomAttribute rpcAttribute) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.AddRange(CreateSendRpcCommon(processor, methodHash, writerVariableDef, channelVariableDef)); + //Also add if buffered. + bool bufferLast = rpcAttribute.GetField(BUFFERLAST_NAME, false); + int buffered = (bufferLast) ? 1 : 0; + + //Warn user if any values are byref. + bool usedByref = false; + foreach (ParameterDefinition item in methodDef.Parameters) + { + if (item.IsIn) + { + usedByref = true; + break; + } + } + if (usedByref) + CodegenSession.LogWarning($"Method {methodDef.FullName} takes an argument by reference. While this is supported, using BufferLast in addition to by reference arguements will buffer the value as it was serialized, not as it is when sending buffered."); + + insts.Add(processor.Create(OpCodes.Ldc_I4, buffered)); + //Call NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.SendObserversRpc_MethodRef)); + + return insts; + } + /// + /// Creates a call to SendTargetRpc on NetworkBehaviour. + /// + private List CreateSendTargetRpc(MethodDefinition methodDef, uint methodHash, VariableDefinition writerVariableDef, VariableDefinition channelVariableDef, ParameterDefinition targetConnectionParameterDef) + { + List insts = new List(); + ILProcessor processor = methodDef.Body.GetILProcessor(); + + insts.AddRange(CreateSendRpcCommon(processor, methodHash, writerVariableDef, channelVariableDef)); + //Reference to NetworkConnection that RPC is going to. + insts.Add(processor.Create(OpCodes.Ldarg, targetConnectionParameterDef)); + //Call NetworkBehaviour. + insts.Add(processor.Create(OpCodes.Call, CodegenSession.NetworkBehaviourHelper.SendTargetRpc_MethodRef)); + + return insts; + } + + /// + /// Writes common properties that all SendRpc methods use. + /// + private List CreateSendRpcCommon(ILProcessor processor, uint methodHash, VariableDefinition writerVariableDef, VariableDefinition channelVariableDef) + { + List insts = new List(); + + insts.Add(processor.Create(OpCodes.Ldarg_0)); // argument: this + insts.Add(processor.Create(OpCodes.Ldc_I4, (int)methodHash)); + //reference to PooledWriter. + insts.Add(processor.Create(OpCodes.Ldloc, writerVariableDef)); + //reference to Channel. + insts.Add(processor.Create(OpCodes.Ldloc, channelVariableDef)); + + return insts; + } + #endregion + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs.meta new file mode 100644 index 0000000..e87895d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d4adb5891ee44f4397cd07ac2df0ce0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed.meta new file mode 100644 index 0000000..8481191 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c24efb514a41fb41b4eb883a5f51fb5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs new file mode 100644 index 0000000..5cc1130 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs @@ -0,0 +1,24 @@ +using MonoFN.Cecil; + +namespace FishNet.CodeGenerating.Processing +{ + + public class ProcessedSync + { + public FieldReference OriginalFieldRef; + public FieldReference GeneratedFieldRef; + public MethodReference SetMethodRef; + public MethodReference GetMethodRef; + + public ProcessedSync(FieldReference originalFieldRef,FieldReference generatedFieldRef, MethodReference setMethodRef, MethodReference getMethodRef) + { + OriginalFieldRef = originalFieldRef; + GeneratedFieldRef = generatedFieldRef; + SetMethodRef = setMethodRef; + GetMethodRef = getMethodRef; + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs.meta new file mode 100644 index 0000000..1d82e02 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Processing/Typed/ProcessedSync.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0dc2fea60bfe1341b04e7165251d36f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef b/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef new file mode 100644 index 0000000..98f05d6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef @@ -0,0 +1,18 @@ +{ + "name": "Unity.FishNet.Codegen", + "references": [ + "FishNet.Runtime", + "FishNet.Codegen.Cecil" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": true, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef.meta b/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef.meta new file mode 100644 index 0000000..a6d9d76 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/Unity.FishNet.CodeGen.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9341dc36b33c3984e97b22dac619ca50 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4.meta new file mode 100644 index 0000000..ec9a868 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f482f18100f20045bd2188d839d9217 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props new file mode 100644 index 0000000..ee63f7a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props @@ -0,0 +1,30 @@ + + + false + false + false + Debug;Release + true + true + $(MSBuildThisFileDirectory)\cecil.snk + $(DefineConstants);NET_CORE + + + + true + + + + + + + + + + + + + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), Mono.Cecil.overrides))\Mono.Cecil.overrides + + + diff --git a/UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props.meta similarity index 74% rename from UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity.meta rename to UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props.meta index b9c9a89..6f127c1 100644 --- a/UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity.meta +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Directory.Build.props.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 41ad25598d342f240bd8830833bfb1c5 +guid: c3a066bef0608d24987201601e20a905 DefaultImporter: externalObjects: {} userData: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt new file mode 100644 index 0000000..afd0ae6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) 2008 - 2015 Jb Evain +Copyright (c) 2008 - 2011 Novell, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt.meta similarity index 75% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt.meta rename to UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt.meta index 968eafe..da1734e 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt.meta +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/LICENSE.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a28193472bc84d341ab4aee18c471a93 +guid: 65323af257ddec3409ed36503b853604 TextScriptImporter: externalObjects: {} userData: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil.meta new file mode 100644 index 0000000..c287230 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 952f0fa3545cde844afce313f2b2f3b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs new file mode 100644 index 0000000..ce5c6e0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs @@ -0,0 +1,234 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Cil { + + public enum Code { + Nop, + Break, + Ldarg_0, + Ldarg_1, + Ldarg_2, + Ldarg_3, + Ldloc_0, + Ldloc_1, + Ldloc_2, + Ldloc_3, + Stloc_0, + Stloc_1, + Stloc_2, + Stloc_3, + Ldarg_S, + Ldarga_S, + Starg_S, + Ldloc_S, + Ldloca_S, + Stloc_S, + Ldnull, + Ldc_I4_M1, + Ldc_I4_0, + Ldc_I4_1, + Ldc_I4_2, + Ldc_I4_3, + Ldc_I4_4, + Ldc_I4_5, + Ldc_I4_6, + Ldc_I4_7, + Ldc_I4_8, + Ldc_I4_S, + Ldc_I4, + Ldc_I8, + Ldc_R4, + Ldc_R8, + Dup, + Pop, + Jmp, + Call, + Calli, + Ret, + Br_S, + Brfalse_S, + Brtrue_S, + Beq_S, + Bge_S, + Bgt_S, + Ble_S, + Blt_S, + Bne_Un_S, + Bge_Un_S, + Bgt_Un_S, + Ble_Un_S, + Blt_Un_S, + Br, + Brfalse, + Brtrue, + Beq, + Bge, + Bgt, + Ble, + Blt, + Bne_Un, + Bge_Un, + Bgt_Un, + Ble_Un, + Blt_Un, + Switch, + Ldind_I1, + Ldind_U1, + Ldind_I2, + Ldind_U2, + Ldind_I4, + Ldind_U4, + Ldind_I8, + Ldind_I, + Ldind_R4, + Ldind_R8, + Ldind_Ref, + Stind_Ref, + Stind_I1, + Stind_I2, + Stind_I4, + Stind_I8, + Stind_R4, + Stind_R8, + Add, + Sub, + Mul, + Div, + Div_Un, + Rem, + Rem_Un, + And, + Or, + Xor, + Shl, + Shr, + Shr_Un, + Neg, + Not, + Conv_I1, + Conv_I2, + Conv_I4, + Conv_I8, + Conv_R4, + Conv_R8, + Conv_U4, + Conv_U8, + Callvirt, + Cpobj, + Ldobj, + Ldstr, + Newobj, + Castclass, + Isinst, + Conv_R_Un, + Unbox, + Throw, + Ldfld, + Ldflda, + Stfld, + Ldsfld, + Ldsflda, + Stsfld, + Stobj, + Conv_Ovf_I1_Un, + Conv_Ovf_I2_Un, + Conv_Ovf_I4_Un, + Conv_Ovf_I8_Un, + Conv_Ovf_U1_Un, + Conv_Ovf_U2_Un, + Conv_Ovf_U4_Un, + Conv_Ovf_U8_Un, + Conv_Ovf_I_Un, + Conv_Ovf_U_Un, + Box, + Newarr, + Ldlen, + Ldelema, + Ldelem_I1, + Ldelem_U1, + Ldelem_I2, + Ldelem_U2, + Ldelem_I4, + Ldelem_U4, + Ldelem_I8, + Ldelem_I, + Ldelem_R4, + Ldelem_R8, + Ldelem_Ref, + Stelem_I, + Stelem_I1, + Stelem_I2, + Stelem_I4, + Stelem_I8, + Stelem_R4, + Stelem_R8, + Stelem_Ref, + Ldelem_Any, + Stelem_Any, + Unbox_Any, + Conv_Ovf_I1, + Conv_Ovf_U1, + Conv_Ovf_I2, + Conv_Ovf_U2, + Conv_Ovf_I4, + Conv_Ovf_U4, + Conv_Ovf_I8, + Conv_Ovf_U8, + Refanyval, + Ckfinite, + Mkrefany, + Ldtoken, + Conv_U2, + Conv_U1, + Conv_I, + Conv_Ovf_I, + Conv_Ovf_U, + Add_Ovf, + Add_Ovf_Un, + Mul_Ovf, + Mul_Ovf_Un, + Sub_Ovf, + Sub_Ovf_Un, + Endfinally, + Leave, + Leave_S, + Stind_I, + Conv_U, + Arglist, + Ceq, + Cgt, + Cgt_Un, + Clt, + Clt_Un, + Ldftn, + Ldvirtftn, + Ldarg, + Ldarga, + Starg, + Ldloc, + Ldloca, + Stloc, + Localloc, + Endfilter, + Unaligned, + Volatile, + Tail, + Initobj, + Constrained, + Cpblk, + Initblk, + No, + Rethrow, + Sizeof, + Refanytype, + Readonly, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs.meta new file mode 100644 index 0000000..087491a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Code.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2619210c5ef352b4aac70d8e5fab7a43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs new file mode 100644 index 0000000..206b49a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs @@ -0,0 +1,663 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil.Cil { + + sealed class CodeReader : BinaryStreamReader { + + readonly internal MetadataReader reader; + + int start; + + MethodDefinition method; + MethodBody body; + + int Offset { + get { return Position - start; } + } + + public CodeReader (MetadataReader reader) + : base (reader.image.Stream.value) + { + this.reader = reader; + } + + public int MoveTo (MethodDefinition method) + { + this.method = method; + this.reader.context = method; + var position = this.Position; + this.Position = (int)reader.image.ResolveVirtualAddress ((uint)method.RVA); + return position; + } + + public void MoveBackTo (int position) + { + this.reader.context = null; + this.Position = position; + } + + public MethodBody ReadMethodBody (MethodDefinition method) + { + var position = MoveTo (method); + this.body = new MethodBody (method); + + ReadMethodBody (); + + MoveBackTo (position); + return this.body; + } + + public int ReadCodeSize (MethodDefinition method) + { + var position = MoveTo (method); + + var code_size = ReadCodeSize (); + + MoveBackTo (position); + return code_size; + } + + int ReadCodeSize () + { + var flags = ReadByte (); + switch (flags & 0x3) { + case 0x2: // tiny + return flags >> 2; + case 0x3: // fat + Advance (-1 + 2 + 2); // go back, 2 bytes flags, 2 bytes stack size + return (int)ReadUInt32 (); + default: + throw new InvalidOperationException (); + } + } + + void ReadMethodBody () + { + var flags = ReadByte (); + switch (flags & 0x3) { + case 0x2: // tiny + body.code_size = flags >> 2; + body.MaxStackSize = 8; + ReadCode (); + break; + case 0x3: // fat + Advance (-1); + ReadFatMethod (); + break; + default: + throw new InvalidOperationException (); + } + + var symbol_reader = reader.module.symbol_reader; + + if (symbol_reader != null && method.debug_info == null) + method.debug_info = symbol_reader.Read (method); + + if (method.debug_info != null) + ReadDebugInfo (); + } + + void ReadFatMethod () + { + var flags = ReadUInt16 (); + body.max_stack_size = ReadUInt16 (); + body.code_size = (int)ReadUInt32 (); + body.local_var_token = new MetadataToken (ReadUInt32 ()); + body.init_locals = (flags & 0x10) != 0; + + if (body.local_var_token.RID != 0) + body.variables = ReadVariables (body.local_var_token); + + ReadCode (); + + if ((flags & 0x8) != 0) + ReadSection (); + } + + public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token) + { + var position = reader.position; + var variables = reader.ReadVariables (local_var_token, method); + reader.position = position; + + return variables; + } + + void ReadCode () + { + start = Position; + var code_size = body.code_size; + + if (code_size < 0 || Length <= (uint)(code_size + Position)) + code_size = 0; + + var end = start + code_size; + var instructions = body.instructions = new InstructionCollection (method, (code_size + 1) / 2); + + while (Position < end) { + var offset = Position - start; + var opcode = ReadOpCode (); + var current = new Instruction (offset, opcode); + + if (opcode.OperandType != OperandType.InlineNone) + current.operand = ReadOperand (current); + + instructions.Add (current); + } + + ResolveBranches (instructions); + } + + OpCode ReadOpCode () + { + var il_opcode = ReadByte (); + return il_opcode != 0xfe + ? OpCodes.OneByteOpCode [il_opcode] + : OpCodes.TwoBytesOpCode [ReadByte ()]; + } + + object ReadOperand (Instruction instruction) + { + switch (instruction.opcode.OperandType) { + case OperandType.InlineSwitch: + var length = ReadInt32 (); + var base_offset = Offset + (4 * length); + var branches = new int [length]; + for (int i = 0; i < length; i++) + branches [i] = base_offset + ReadInt32 (); + return branches; + case OperandType.ShortInlineBrTarget: + return ReadSByte () + Offset; + case OperandType.InlineBrTarget: + return ReadInt32 () + Offset; + case OperandType.ShortInlineI: + if (instruction.opcode == OpCodes.Ldc_I4_S) + return ReadSByte (); + + return ReadByte (); + case OperandType.InlineI: + return ReadInt32 (); + case OperandType.ShortInlineR: + return ReadSingle (); + case OperandType.InlineR: + return ReadDouble (); + case OperandType.InlineI8: + return ReadInt64 (); + case OperandType.ShortInlineVar: + return GetVariable (ReadByte ()); + case OperandType.InlineVar: + return GetVariable (ReadUInt16 ()); + case OperandType.ShortInlineArg: + return GetParameter (ReadByte ()); + case OperandType.InlineArg: + return GetParameter (ReadUInt16 ()); + case OperandType.InlineSig: + return GetCallSite (ReadToken ()); + case OperandType.InlineString: + return GetString (ReadToken ()); + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineMethod: + case OperandType.InlineField: + return reader.LookupToken (ReadToken ()); + default: + throw new NotSupportedException (); + } + } + + public string GetString (MetadataToken token) + { + return reader.image.UserStringHeap.Read (token.RID); + } + + public ParameterDefinition GetParameter (int index) + { + return body.GetParameter (index); + } + + public VariableDefinition GetVariable (int index) + { + return body.GetVariable (index); + } + + public CallSite GetCallSite (MetadataToken token) + { + return reader.ReadCallSite (token); + } + + void ResolveBranches (Collection instructions) + { + var items = instructions.items; + var size = instructions.size; + + for (int i = 0; i < size; i++) { + var instruction = items [i]; + switch (instruction.opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + instruction.operand = GetInstruction ((int)instruction.operand); + break; + case OperandType.InlineSwitch: + var offsets = (int [])instruction.operand; + var branches = new Instruction [offsets.Length]; + for (int j = 0; j < offsets.Length; j++) + branches [j] = GetInstruction (offsets [j]); + + instruction.operand = branches; + break; + } + } + } + + Instruction GetInstruction (int offset) + { + return GetInstruction (body.Instructions, offset); + } + + static Instruction GetInstruction (Collection instructions, int offset) + { + var size = instructions.size; + var items = instructions.items; + if (offset < 0 || offset > items [size - 1].offset) + return null; + + int min = 0; + int max = size - 1; + while (min <= max) { + int mid = min + ((max - min) / 2); + var instruction = items [mid]; + var instruction_offset = instruction.offset; + + if (offset == instruction_offset) + return instruction; + + if (offset < instruction_offset) + max = mid - 1; + else + min = mid + 1; + } + + return null; + } + + void ReadSection () + { + Align (4); + + const byte fat_format = 0x40; + const byte more_sects = 0x80; + + var flags = ReadByte (); + if ((flags & fat_format) == 0) + ReadSmallSection (); + else + ReadFatSection (); + + if ((flags & more_sects) != 0) + ReadSection (); + } + + void ReadSmallSection () + { + var count = ReadByte () / 12; + Advance (2); + + ReadExceptionHandlers ( + count, + () => (int)ReadUInt16 (), + () => (int)ReadByte ()); + } + + void ReadFatSection () + { + Advance (-1); + var count = (ReadInt32 () >> 8) / 24; + + ReadExceptionHandlers ( + count, + ReadInt32, + ReadInt32); + } + + // inline ? + void ReadExceptionHandlers (int count, Func read_entry, Func read_length) + { + for (int i = 0; i < count; i++) { + var handler = new ExceptionHandler ( + (ExceptionHandlerType)(read_entry () & 0x7)); + + handler.TryStart = GetInstruction (read_entry ()); + handler.TryEnd = GetInstruction (handler.TryStart.Offset + read_length ()); + + handler.HandlerStart = GetInstruction (read_entry ()); + handler.HandlerEnd = GetInstruction (handler.HandlerStart.Offset + read_length ()); + + ReadExceptionHandlerSpecific (handler); + + this.body.ExceptionHandlers.Add (handler); + } + } + + void ReadExceptionHandlerSpecific (ExceptionHandler handler) + { + switch (handler.HandlerType) { + case ExceptionHandlerType.Catch: + handler.CatchType = (TypeReference)reader.LookupToken (ReadToken ()); + break; + case ExceptionHandlerType.Filter: + handler.FilterStart = GetInstruction (ReadInt32 ()); + break; + default: + Advance (4); + break; + } + } + + public MetadataToken ReadToken () + { + return new MetadataToken (ReadUInt32 ()); + } + + void ReadDebugInfo () + { + if (method.debug_info.sequence_points != null) + ReadSequencePoints (); + + if (method.debug_info.scope != null) + ReadScope (method.debug_info.scope); + + if (method.custom_infos != null) + ReadCustomDebugInformations (method); + } + + void ReadCustomDebugInformations (MethodDefinition method) + { + var custom_infos = method.custom_infos; + + for (int i = 0; i < custom_infos.Count; i++) { + var state_machine_scope = custom_infos [i] as StateMachineScopeDebugInformation; + if (state_machine_scope != null) + ReadStateMachineScope (state_machine_scope); + + var async_method = custom_infos [i] as AsyncMethodBodyDebugInformation; + if (async_method != null) + ReadAsyncMethodBody (async_method); + } + } + + void ReadAsyncMethodBody (AsyncMethodBodyDebugInformation async_method) + { + if (async_method.catch_handler.Offset > -1) + async_method.catch_handler = new InstructionOffset (GetInstruction (async_method.catch_handler.Offset)); + + if (!async_method.yields.IsNullOrEmpty ()) + for (int i = 0; i < async_method.yields.Count; i++) + async_method.yields [i] = new InstructionOffset (GetInstruction (async_method.yields [i].Offset)); + + if (!async_method.resumes.IsNullOrEmpty ()) + for (int i = 0; i < async_method.resumes.Count; i++) + async_method.resumes [i] = new InstructionOffset (GetInstruction (async_method.resumes [i].Offset)); + } + + void ReadStateMachineScope (StateMachineScopeDebugInformation state_machine_scope) + { + if (state_machine_scope.scopes.IsNullOrEmpty ()) + return; + + foreach (var scope in state_machine_scope.scopes) { + scope.start = new InstructionOffset (GetInstruction (scope.start.Offset)); + + var end_instruction = GetInstruction (scope.end.Offset); + scope.end = end_instruction == null + ? new InstructionOffset () + : new InstructionOffset (end_instruction); + } + } + + void ReadSequencePoints () + { + var symbol = method.debug_info; + + for (int i = 0; i < symbol.sequence_points.Count; i++) { + var sequence_point = symbol.sequence_points [i]; + var instruction = GetInstruction (sequence_point.Offset); + if (instruction != null) + sequence_point.offset = new InstructionOffset (instruction); + } + } + + void ReadScopes (Collection scopes) + { + for (int i = 0; i < scopes.Count; i++) + ReadScope (scopes [i]); + } + + void ReadScope (ScopeDebugInformation scope) + { + var start_instruction = GetInstruction (scope.Start.Offset); + if (start_instruction != null) + scope.Start = new InstructionOffset (start_instruction); + + var end_instruction = GetInstruction (scope.End.Offset); + scope.End = end_instruction != null + ? new InstructionOffset (end_instruction) + : new InstructionOffset (); + + if (!scope.variables.IsNullOrEmpty ()) { + for (int i = 0; i < scope.variables.Count; i++) { + var variable_info = scope.variables [i]; + var variable = GetVariable (variable_info.Index); + if (variable != null) + variable_info.index = new VariableIndex (variable); + } + } + + if (!scope.scopes.IsNullOrEmpty ()) + ReadScopes (scope.scopes); + } + + public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out int code_size, out MetadataToken local_var_token) + { + var position = MoveTo (method); + + var buffer = new ByteBuffer (); + + var flags = ReadByte (); + + switch (flags & 0x3) { + case 0x2: // tiny + buffer.WriteByte (flags); + local_var_token = MetadataToken.Zero; + code_size = flags >> 2; + PatchRawCode (buffer, code_size, writer); + break; + case 0x3: // fat + Advance (-1); + PatchRawFatMethod (buffer, writer, out code_size, out local_var_token); + break; + default: + throw new NotSupportedException (); + } + + MoveBackTo (position); + + return buffer; + } + + void PatchRawFatMethod (ByteBuffer buffer, CodeWriter writer, out int code_size, out MetadataToken local_var_token) + { + var flags = ReadUInt16 (); + buffer.WriteUInt16 (flags); + buffer.WriteUInt16 (ReadUInt16 ()); + code_size = ReadInt32 (); + buffer.WriteInt32 (code_size); + local_var_token = ReadToken (); + + if (local_var_token.RID > 0) { + var variables = ReadVariables (local_var_token); + buffer.WriteUInt32 (variables != null + ? writer.GetStandAloneSignature (variables).ToUInt32 () + : 0); + } else + buffer.WriteUInt32 (0); + + PatchRawCode (buffer, code_size, writer); + + if ((flags & 0x8) != 0) + PatchRawSection (buffer, writer.metadata); + } + + void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer) + { + var metadata = writer.metadata; + buffer.WriteBytes (ReadBytes (code_size)); + var end = buffer.position; + buffer.position -= code_size; + + while (buffer.position < end) { + OpCode opcode; + var il_opcode = buffer.ReadByte (); + if (il_opcode != 0xfe) { + opcode = OpCodes.OneByteOpCode [il_opcode]; + } else { + var il_opcode2 = buffer.ReadByte (); + opcode = OpCodes.TwoBytesOpCode [il_opcode2]; + } + + switch (opcode.OperandType) { + case OperandType.ShortInlineI: + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineVar: + case OperandType.ShortInlineArg: + buffer.position += 1; + break; + case OperandType.InlineVar: + case OperandType.InlineArg: + buffer.position += 2; + break; + case OperandType.InlineBrTarget: + case OperandType.ShortInlineR: + case OperandType.InlineI: + buffer.position += 4; + break; + case OperandType.InlineI8: + case OperandType.InlineR: + buffer.position += 8; + break; + case OperandType.InlineSwitch: + var length = buffer.ReadInt32 (); + buffer.position += length * 4; + break; + case OperandType.InlineString: + var @string = GetString (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 ( + new MetadataToken ( + TokenType.String, + metadata.user_string_heap.GetStringIndex (@string)).ToUInt32 ()); + break; + case OperandType.InlineSig: + var call_site = GetCallSite (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 (writer.GetStandAloneSignature (call_site).ToUInt32 ()); + break; + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineMethod: + case OperandType.InlineField: + var provider = reader.LookupToken (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 (metadata.LookupToken (provider).ToUInt32 ()); + break; + } + } + } + + void PatchRawSection (ByteBuffer buffer, MetadataBuilder metadata) + { + var position = Position; + Align (4); + buffer.WriteBytes (Position - position); + + const byte fat_format = 0x40; + const byte more_sects = 0x80; + + var flags = ReadByte (); + if ((flags & fat_format) == 0) { + buffer.WriteByte (flags); + PatchRawSmallSection (buffer, metadata); + } else + PatchRawFatSection (buffer, metadata); + + if ((flags & more_sects) != 0) + PatchRawSection (buffer, metadata); + } + + void PatchRawSmallSection (ByteBuffer buffer, MetadataBuilder metadata) + { + var length = ReadByte (); + buffer.WriteByte (length); + Advance (2); + + buffer.WriteUInt16 (0); + + var count = length / 12; + + PatchRawExceptionHandlers (buffer, metadata, count, false); + } + + void PatchRawFatSection (ByteBuffer buffer, MetadataBuilder metadata) + { + Advance (-1); + var length = ReadInt32 (); + buffer.WriteInt32 (length); + + var count = (length >> 8) / 24; + + PatchRawExceptionHandlers (buffer, metadata, count, true); + } + + void PatchRawExceptionHandlers (ByteBuffer buffer, MetadataBuilder metadata, int count, bool fat_entry) + { + const int fat_entry_size = 16; + const int small_entry_size = 6; + + for (int i = 0; i < count; i++) { + ExceptionHandlerType handler_type; + if (fat_entry) { + var type = ReadUInt32 (); + handler_type = (ExceptionHandlerType)(type & 0x7); + buffer.WriteUInt32 (type); + } else { + var type = ReadUInt16 (); + handler_type = (ExceptionHandlerType)(type & 0x7); + buffer.WriteUInt16 (type); + } + + buffer.WriteBytes (ReadBytes (fat_entry ? fat_entry_size : small_entry_size)); + + switch (handler_type) { + case ExceptionHandlerType.Catch: + var exception = reader.LookupToken (ReadToken ()); + buffer.WriteUInt32 (metadata.LookupToken (exception).ToUInt32 ()); + break; + default: + buffer.WriteUInt32 (ReadUInt32 ()); + break; + } + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs.meta new file mode 100644 index 0000000..4bf35a7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 451f6a2407c53554f9a16eeb62d806ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs new file mode 100644 index 0000000..e7126e8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs @@ -0,0 +1,651 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using RVA = System.UInt32; + +namespace MonoFN.Cecil.Cil { + + sealed class CodeWriter : ByteBuffer { + + readonly RVA code_base; + internal readonly MetadataBuilder metadata; + readonly Dictionary standalone_signatures; + readonly Dictionary tiny_method_bodies; + + MethodBody body; + + public CodeWriter (MetadataBuilder metadata) + : base (0) + { + this.code_base = metadata.text_map.GetNextRVA (TextSegment.CLIHeader); + this.metadata = metadata; + this.standalone_signatures = new Dictionary (); + this.tiny_method_bodies = new Dictionary (new ByteBufferEqualityComparer ()); + } + + public RVA WriteMethodBody (MethodDefinition method) + { + RVA rva; + + if (IsUnresolved (method)) { + if (method.rva == 0) + return 0; + + rva = WriteUnresolvedMethodBody (method); + } else { + if (IsEmptyMethodBody (method.Body)) + return 0; + + rva = WriteResolvedMethodBody (method); + } + + return rva; + } + + static bool IsEmptyMethodBody (MethodBody body) + { + return body.instructions.IsNullOrEmpty () + && body.variables.IsNullOrEmpty (); + } + + static bool IsUnresolved (MethodDefinition method) + { + return method.HasBody && method.HasImage && method.body == null; + } + + RVA WriteUnresolvedMethodBody (MethodDefinition method) + { + var code_reader = metadata.module.reader.code; + + int code_size; + MetadataToken local_var_token; + var raw_body = code_reader.PatchRawMethodBody (method, this, out code_size, out local_var_token); + var fat_header = (raw_body.buffer [0] & 0x3) == 0x3; + if (fat_header) + Align (4); + + var rva = BeginMethod (); + + if (fat_header || !GetOrMapTinyMethodBody (raw_body, ref rva)) { + WriteBytes (raw_body); + } + + if (method.debug_info == null) + return rva; + + var symbol_writer = metadata.symbol_writer; + if (symbol_writer != null) { + method.debug_info.code_size = code_size; + method.debug_info.local_var_token = local_var_token; + symbol_writer.Write (method.debug_info); + } + + return rva; + } + + RVA WriteResolvedMethodBody (MethodDefinition method) + { + RVA rva; + + body = method.Body; + ComputeHeader (); + if (RequiresFatHeader ()) { + Align (4); + rva = BeginMethod (); + WriteFatHeader (); + WriteInstructions (); + + if (body.HasExceptionHandlers) + WriteExceptionHandlers (); + } else { + rva = BeginMethod (); + WriteByte ((byte)(0x2 | (body.CodeSize << 2))); // tiny + WriteInstructions (); + + var start_position = (int)(rva - code_base); + var body_size = position - start_position; + var body_bytes = new byte [body_size]; + + Array.Copy (buffer, start_position, body_bytes, 0, body_size); + + if (GetOrMapTinyMethodBody (new ByteBuffer (body_bytes), ref rva)) + position = start_position; + } + + var symbol_writer = metadata.symbol_writer; + if (symbol_writer != null && method.debug_info != null) { + method.debug_info.code_size = body.CodeSize; + method.debug_info.local_var_token = body.local_var_token; + symbol_writer.Write (method.debug_info); + } + + return rva; + } + + bool GetOrMapTinyMethodBody (ByteBuffer body, ref RVA rva) + { + RVA existing_rva; + if (tiny_method_bodies.TryGetValue (body, out existing_rva)) { + rva = existing_rva; + return true; + } + + tiny_method_bodies.Add (body, rva); + return false; + } + + void WriteFatHeader () + { + var body = this.body; + byte flags = 0x3; // fat + if (body.InitLocals) + flags |= 0x10; // init locals + if (body.HasExceptionHandlers) + flags |= 0x8; // more sections + + WriteByte (flags); + WriteByte (0x30); + WriteInt16 ((short)body.max_stack_size); + WriteInt32 (body.code_size); + body.local_var_token = body.HasVariables + ? GetStandAloneSignature (body.Variables) + : MetadataToken.Zero; + WriteMetadataToken (body.local_var_token); + } + + void WriteInstructions () + { + var instructions = body.Instructions; + var items = instructions.items; + var size = instructions.size; + + for (int i = 0; i < size; i++) { + var instruction = items [i]; + WriteOpCode (instruction.opcode); + WriteOperand (instruction); + } + } + + void WriteOpCode (OpCode opcode) + { + if (opcode.Size == 1) { + WriteByte (opcode.Op2); + } else { + WriteByte (opcode.Op1); + WriteByte (opcode.Op2); + } + } + + void WriteOperand (Instruction instruction) + { + var opcode = instruction.opcode; + var operand_type = opcode.OperandType; + if (operand_type == OperandType.InlineNone) + return; + + var operand = instruction.operand; + if (operand == null && !(operand_type == OperandType.InlineBrTarget || operand_type == OperandType.ShortInlineBrTarget)) { + throw new ArgumentException (); + } + + switch (operand_type) { + case OperandType.InlineSwitch: { + var targets = (Instruction [])operand; + WriteInt32 (targets.Length); + var diff = instruction.Offset + opcode.Size + (4 * (targets.Length + 1)); + for (int i = 0; i < targets.Length; i++) + WriteInt32 (GetTargetOffset (targets [i]) - diff); + break; + } + case OperandType.ShortInlineBrTarget: { + var target = (Instruction)operand; + var offset = target != null ? GetTargetOffset (target) : body.code_size; + WriteSByte ((sbyte)(offset - (instruction.Offset + opcode.Size + 1))); + break; + } + case OperandType.InlineBrTarget: { + var target = (Instruction)operand; + var offset = target != null ? GetTargetOffset (target) : body.code_size; + WriteInt32 (offset - (instruction.Offset + opcode.Size + 4)); + break; + } + case OperandType.ShortInlineVar: + WriteByte ((byte)GetVariableIndex ((VariableDefinition)operand)); + break; + case OperandType.ShortInlineArg: + WriteByte ((byte)GetParameterIndex ((ParameterDefinition)operand)); + break; + case OperandType.InlineVar: + WriteInt16 ((short)GetVariableIndex ((VariableDefinition)operand)); + break; + case OperandType.InlineArg: + WriteInt16 ((short)GetParameterIndex ((ParameterDefinition)operand)); + break; + case OperandType.InlineSig: + WriteMetadataToken (GetStandAloneSignature ((CallSite)operand)); + break; + case OperandType.ShortInlineI: + if (opcode == OpCodes.Ldc_I4_S) + WriteSByte ((sbyte)operand); + else + WriteByte ((byte)operand); + break; + case OperandType.InlineI: + WriteInt32 ((int)operand); + break; + case OperandType.InlineI8: + WriteInt64 ((long)operand); + break; + case OperandType.ShortInlineR: + WriteSingle ((float)operand); + break; + case OperandType.InlineR: + WriteDouble ((double)operand); + break; + case OperandType.InlineString: + WriteMetadataToken ( + new MetadataToken ( + TokenType.String, + GetUserStringIndex ((string)operand))); + break; + case OperandType.InlineType: + case OperandType.InlineField: + case OperandType.InlineMethod: + case OperandType.InlineTok: + WriteMetadataToken (metadata.LookupToken ((IMetadataTokenProvider)operand)); + break; + default: + throw new ArgumentException (); + } + } + + int GetTargetOffset (Instruction instruction) + { + if (instruction == null) { + var last = body.instructions [body.instructions.size - 1]; + return last.offset + last.GetSize (); + } + + return instruction.offset; + } + + uint GetUserStringIndex (string @string) + { + if (@string == null) + return 0; + + return metadata.user_string_heap.GetStringIndex (@string); + } + + static int GetVariableIndex (VariableDefinition variable) + { + return variable.Index; + } + + int GetParameterIndex (ParameterDefinition parameter) + { + if (body.method.HasThis) { + if (parameter == body.this_parameter) + return 0; + + return parameter.Index + 1; + } + + return parameter.Index; + } + + bool RequiresFatHeader () + { + var body = this.body; + return body.CodeSize >= 64 + || body.InitLocals + || body.HasVariables + || body.HasExceptionHandlers + || body.MaxStackSize > 8; + } + + void ComputeHeader () + { + int offset = 0; + var instructions = body.instructions; + var items = instructions.items; + var count = instructions.size; + var stack_size = 0; + var max_stack = 0; + Dictionary stack_sizes = null; + + if (body.HasExceptionHandlers) + ComputeExceptionHandlerStackSize (ref stack_sizes); + + for (int i = 0; i < count; i++) { + var instruction = items [i]; + instruction.offset = offset; + offset += instruction.GetSize (); + + ComputeStackSize (instruction, ref stack_sizes, ref stack_size, ref max_stack); + } + + body.code_size = offset; + body.max_stack_size = max_stack; + } + + void ComputeExceptionHandlerStackSize (ref Dictionary stack_sizes) + { + var exception_handlers = body.ExceptionHandlers; + + for (int i = 0; i < exception_handlers.Count; i++) { + var exception_handler = exception_handlers [i]; + + switch (exception_handler.HandlerType) { + case ExceptionHandlerType.Catch: + AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes); + break; + case ExceptionHandlerType.Filter: + AddExceptionStackSize (exception_handler.FilterStart, ref stack_sizes); + AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes); + break; + } + } + } + + static void AddExceptionStackSize (Instruction handler_start, ref Dictionary stack_sizes) + { + if (handler_start == null) + return; + + if (stack_sizes == null) + stack_sizes = new Dictionary (); + + stack_sizes [handler_start] = 1; + } + + static void ComputeStackSize (Instruction instruction, ref Dictionary stack_sizes, ref int stack_size, ref int max_stack) + { + int computed_size; + if (stack_sizes != null && stack_sizes.TryGetValue (instruction, out computed_size)) + stack_size = computed_size; + + max_stack = System.Math.Max (max_stack, stack_size); + ComputeStackDelta (instruction, ref stack_size); + max_stack = System.Math.Max (max_stack, stack_size); + + CopyBranchStackSize (instruction, ref stack_sizes, stack_size); + ComputeStackSize (instruction, ref stack_size); + } + + static void CopyBranchStackSize (Instruction instruction, ref Dictionary stack_sizes, int stack_size) + { + if (stack_size == 0) + return; + + switch (instruction.opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + CopyBranchStackSize (ref stack_sizes, (Instruction)instruction.operand, stack_size); + break; + case OperandType.InlineSwitch: + var targets = (Instruction [])instruction.operand; + for (int i = 0; i < targets.Length; i++) + CopyBranchStackSize (ref stack_sizes, targets [i], stack_size); + break; + } + } + + static void CopyBranchStackSize (ref Dictionary stack_sizes, Instruction target, int stack_size) + { + if (stack_sizes == null) + stack_sizes = new Dictionary (); + + int branch_stack_size = stack_size; + + int computed_size; + if (stack_sizes.TryGetValue (target, out computed_size)) + branch_stack_size = System.Math.Max (branch_stack_size, computed_size); + + stack_sizes [target] = branch_stack_size; + } + + static void ComputeStackSize (Instruction instruction, ref int stack_size) + { + switch (instruction.opcode.FlowControl) { + case FlowControl.Branch: + case FlowControl.Throw: + case FlowControl.Return: + stack_size = 0; + break; + } + } + + static void ComputeStackDelta (Instruction instruction, ref int stack_size) + { + switch (instruction.opcode.FlowControl) { + case FlowControl.Call: { + var method = (IMethodSignature)instruction.operand; + // pop 'this' argument + if (method.HasImplicitThis () && instruction.opcode.Code != Code.Newobj) + stack_size--; + // pop normal arguments + if (method.HasParameters) + stack_size -= method.Parameters.Count; + // pop function pointer + if (instruction.opcode.Code == Code.Calli) + stack_size--; + // push return value + if (method.ReturnType.etype != ElementType.Void || instruction.opcode.Code == Code.Newobj) + stack_size++; + break; + } + default: + ComputePopDelta (instruction.opcode.StackBehaviourPop, ref stack_size); + ComputePushDelta (instruction.opcode.StackBehaviourPush, ref stack_size); + break; + } + } + + static void ComputePopDelta (StackBehaviour pop_behavior, ref int stack_size) + { + switch (pop_behavior) { + case StackBehaviour.Popi: + case StackBehaviour.Popref: + case StackBehaviour.Pop1: + stack_size--; + break; + case StackBehaviour.Pop1_pop1: + case StackBehaviour.Popi_pop1: + case StackBehaviour.Popi_popi: + case StackBehaviour.Popi_popi8: + case StackBehaviour.Popi_popr4: + case StackBehaviour.Popi_popr8: + case StackBehaviour.Popref_pop1: + case StackBehaviour.Popref_popi: + stack_size -= 2; + break; + case StackBehaviour.Popi_popi_popi: + case StackBehaviour.Popref_popi_popi: + case StackBehaviour.Popref_popi_popi8: + case StackBehaviour.Popref_popi_popr4: + case StackBehaviour.Popref_popi_popr8: + case StackBehaviour.Popref_popi_popref: + stack_size -= 3; + break; + case StackBehaviour.PopAll: + stack_size = 0; + break; + } + } + + static void ComputePushDelta (StackBehaviour push_behaviour, ref int stack_size) + { + switch (push_behaviour) { + case StackBehaviour.Push1: + case StackBehaviour.Pushi: + case StackBehaviour.Pushi8: + case StackBehaviour.Pushr4: + case StackBehaviour.Pushr8: + case StackBehaviour.Pushref: + stack_size++; + break; + case StackBehaviour.Push1_push1: + stack_size += 2; + break; + } + } + + void WriteExceptionHandlers () + { + Align (4); + + var handlers = body.ExceptionHandlers; + + if (handlers.Count < 0x15 && !RequiresFatSection (handlers)) + WriteSmallSection (handlers); + else + WriteFatSection (handlers); + } + + static bool RequiresFatSection (Collection handlers) + { + for (int i = 0; i < handlers.Count; i++) { + var handler = handlers [i]; + + if (IsFatRange (handler.TryStart, handler.TryEnd)) + return true; + + if (IsFatRange (handler.HandlerStart, handler.HandlerEnd)) + return true; + + if (handler.HandlerType == ExceptionHandlerType.Filter + && IsFatRange (handler.FilterStart, handler.HandlerStart)) + return true; + } + + return false; + } + + static bool IsFatRange (Instruction start, Instruction end) + { + if (start == null) + throw new ArgumentException (); + + if (end == null) + return true; + + return end.Offset - start.Offset > 255 || start.Offset > 65535; + } + + void WriteSmallSection (Collection handlers) + { + const byte eh_table = 0x1; + + WriteByte (eh_table); + WriteByte ((byte)(handlers.Count * 12 + 4)); + WriteBytes (2); + + WriteExceptionHandlers ( + handlers, + i => WriteUInt16 ((ushort)i), + i => WriteByte ((byte)i)); + } + + void WriteFatSection (Collection handlers) + { + const byte eh_table = 0x1; + const byte fat_format = 0x40; + + WriteByte (eh_table | fat_format); + + int size = handlers.Count * 24 + 4; + WriteByte ((byte)(size & 0xff)); + WriteByte ((byte)((size >> 8) & 0xff)); + WriteByte ((byte)((size >> 16) & 0xff)); + + WriteExceptionHandlers (handlers, WriteInt32, WriteInt32); + } + + void WriteExceptionHandlers (Collection handlers, Action write_entry, Action write_length) + { + for (int i = 0; i < handlers.Count; i++) { + var handler = handlers [i]; + + write_entry ((int)handler.HandlerType); + + write_entry (handler.TryStart.Offset); + write_length (GetTargetOffset (handler.TryEnd) - handler.TryStart.Offset); + + write_entry (handler.HandlerStart.Offset); + write_length (GetTargetOffset (handler.HandlerEnd) - handler.HandlerStart.Offset); + + WriteExceptionHandlerSpecific (handler); + } + } + + void WriteExceptionHandlerSpecific (ExceptionHandler handler) + { + switch (handler.HandlerType) { + case ExceptionHandlerType.Catch: + WriteMetadataToken (metadata.LookupToken (handler.CatchType)); + break; + case ExceptionHandlerType.Filter: + WriteInt32 (handler.FilterStart.Offset); + break; + default: + WriteInt32 (0); + break; + } + } + + public MetadataToken GetStandAloneSignature (Collection variables) + { + var signature = metadata.GetLocalVariableBlobIndex (variables); + + return GetStandAloneSignatureToken (signature); + } + + public MetadataToken GetStandAloneSignature (CallSite call_site) + { + var signature = metadata.GetCallSiteBlobIndex (call_site); + var token = GetStandAloneSignatureToken (signature); + call_site.MetadataToken = token; + return token; + } + + MetadataToken GetStandAloneSignatureToken (uint signature) + { + MetadataToken token; + if (standalone_signatures.TryGetValue (signature, out token)) + return token; + + token = new MetadataToken (TokenType.Signature, metadata.AddStandAloneSignature (signature)); + standalone_signatures.Add (signature, token); + return token; + } + + RVA BeginMethod () + { + return (RVA)(code_base + position); + } + + void WriteMetadataToken (MetadataToken token) + { + WriteUInt32 (token.ToUInt32 ()); + } + + void Align (int align) + { + align--; + WriteBytes (((position + align) & ~align) - position); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs.meta new file mode 100644 index 0000000..e4cccca --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/CodeWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 278f89c983a1bc6429c65a1d49dff091 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs new file mode 100644 index 0000000..ce30188 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs @@ -0,0 +1,123 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Cil { + + public enum DocumentType { + Other, + Text, + } + + public enum DocumentHashAlgorithm { + None, + MD5, + SHA1, + SHA256, + } + + public enum DocumentLanguage { + Other, + C, + Cpp, + CSharp, + Basic, + Java, + Cobol, + Pascal, + Cil, + JScript, + Smc, + MCpp, + FSharp, + } + + public enum DocumentLanguageVendor { + Other, + Microsoft, + } + + public sealed class Document : DebugInformation { + + string url; + + Guid type; + Guid hash_algorithm; + Guid language; + Guid language_vendor; + + byte [] hash; + byte [] embedded_source; + + public string Url { + get { return url; } + set { url = value; } + } + + public DocumentType Type { + get { return type.ToType (); } + set { type = value.ToGuid (); } + } + + public Guid TypeGuid { + get { return type; } + set { type = value; } + } + + public DocumentHashAlgorithm HashAlgorithm { + get { return hash_algorithm.ToHashAlgorithm (); } + set { hash_algorithm = value.ToGuid (); } + } + + public Guid HashAlgorithmGuid { + get { return hash_algorithm; } + set { hash_algorithm = value; } + } + + public DocumentLanguage Language { + get { return language.ToLanguage (); } + set { language = value.ToGuid (); } + } + + public Guid LanguageGuid { + get { return language; } + set { language = value; } + } + + public DocumentLanguageVendor LanguageVendor { + get { return language_vendor.ToVendor (); } + set { language_vendor = value.ToGuid (); } + } + + public Guid LanguageVendorGuid { + get { return language_vendor; } + set { language_vendor = value; } + } + + public byte [] Hash { + get { return hash; } + set { hash = value; } + } + + public byte [] EmbeddedSource { + get { return embedded_source; } + set { embedded_source = value; } + } + + public Document (string url) + { + this.url = url; + this.hash = Empty.Array; + this.embedded_source = Empty.Array; + this.token = new MetadataToken (TokenType.Document); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs.meta new file mode 100644 index 0000000..2a3915d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Document.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86b3083301304a341b6059ea8c29be7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs new file mode 100644 index 0000000..c017553 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs @@ -0,0 +1,71 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Cil { + + public enum ExceptionHandlerType { + Catch = 0, + Filter = 1, + Finally = 2, + Fault = 4, + } + + public sealed class ExceptionHandler { + + Instruction try_start; + Instruction try_end; + Instruction filter_start; + Instruction handler_start; + Instruction handler_end; + + TypeReference catch_type; + ExceptionHandlerType handler_type; + + public Instruction TryStart { + get { return try_start; } + set { try_start = value; } + } + + public Instruction TryEnd { + get { return try_end; } + set { try_end = value; } + } + + public Instruction FilterStart { + get { return filter_start; } + set { filter_start = value; } + } + + public Instruction HandlerStart { + get { return handler_start; } + set { handler_start = value; } + } + + public Instruction HandlerEnd { + get { return handler_end; } + set { handler_end = value; } + } + + public TypeReference CatchType { + get { return catch_type; } + set { catch_type = value; } + } + + public ExceptionHandlerType HandlerType { + get { return handler_type; } + set { handler_type = value; } + } + + public ExceptionHandler (ExceptionHandlerType handlerType) + { + this.handler_type = handlerType; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs.meta new file mode 100644 index 0000000..f26784f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ExceptionHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb17bcae1a67ec344b65d6ed78ffb704 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs new file mode 100644 index 0000000..48944a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs @@ -0,0 +1,291 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil.Cil { + + public sealed class ILProcessor { + + readonly MethodBody body; + readonly Collection instructions; + + public MethodBody Body { + get { return body; } + } + + internal ILProcessor (MethodBody body) + { + this.body = body; + this.instructions = body.Instructions; + } + + public Instruction Create (OpCode opcode) + { + return Instruction.Create (opcode); + } + + public Instruction Create (OpCode opcode, TypeReference type) + { + return Instruction.Create (opcode, type); + } + + public Instruction Create (OpCode opcode, CallSite site) + { + return Instruction.Create (opcode, site); + } + + public Instruction Create (OpCode opcode, MethodReference method) + { + return Instruction.Create (opcode, method); + } + + public Instruction Create (OpCode opcode, FieldReference field) + { + return Instruction.Create (opcode, field); + } + + public Instruction Create (OpCode opcode, string value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, sbyte value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, byte value) + { + if (opcode.OperandType == OperandType.ShortInlineVar) + return Instruction.Create (opcode, body.Variables [value]); + + if (opcode.OperandType == OperandType.ShortInlineArg) + return Instruction.Create (opcode, body.GetParameter (value)); + + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, int value) + { + if (opcode.OperandType == OperandType.InlineVar) + return Instruction.Create (opcode, body.Variables [value]); + + if (opcode.OperandType == OperandType.InlineArg) + return Instruction.Create (opcode, body.GetParameter (value)); + + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, long value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, float value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, double value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, Instruction target) + { + return Instruction.Create (opcode, target); + } + + public Instruction Create (OpCode opcode, Instruction [] targets) + { + return Instruction.Create (opcode, targets); + } + + public Instruction Create (OpCode opcode, VariableDefinition variable) + { + return Instruction.Create (opcode, variable); + } + + public Instruction Create (OpCode opcode, ParameterDefinition parameter) + { + return Instruction.Create (opcode, parameter); + } + + public void Emit (OpCode opcode) + { + Append (Create (opcode)); + } + + public void Emit (OpCode opcode, TypeReference type) + { + Append (Create (opcode, type)); + } + + public void Emit (OpCode opcode, MethodReference method) + { + Append (Create (opcode, method)); + } + + public void Emit (OpCode opcode, CallSite site) + { + Append (Create (opcode, site)); + } + + public void Emit (OpCode opcode, FieldReference field) + { + Append (Create (opcode, field)); + } + + public void Emit (OpCode opcode, string value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, byte value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, sbyte value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, int value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, long value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, float value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, double value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, Instruction target) + { + Append (Create (opcode, target)); + } + + public void Emit (OpCode opcode, Instruction [] targets) + { + Append (Create (opcode, targets)); + } + + public void Emit (OpCode opcode, VariableDefinition variable) + { + Append (Create (opcode, variable)); + } + + public void Emit (OpCode opcode, ParameterDefinition parameter) + { + Append (Create (opcode, parameter)); + } + + public void InsertBefore (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + var index = instructions.IndexOf (target); + if (index == -1) + throw new ArgumentOutOfRangeException ("target"); + + instructions.Insert (index, instruction); + } + + public void InsertAfter (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + var index = instructions.IndexOf (target); + if (index == -1) + throw new ArgumentOutOfRangeException ("target"); + + instructions.Insert (index + 1, instruction); + } + + public void InsertAfter (int index, Instruction instruction) + { + if (index < 0 || index >= instructions.Count) + throw new ArgumentOutOfRangeException ("index"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + instructions.Insert (index + 1, instruction); + } + + public void Append (Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + instructions.Add (instruction); + } + + public void Replace (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + InsertAfter (target, instruction); + Remove (target); + } + + public void Replace (int index, Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + InsertAfter (index, instruction); + RemoveAt (index); + } + + public void Remove (Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + if (!instructions.Remove (instruction)) + throw new ArgumentOutOfRangeException ("instruction"); + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= instructions.Count) + throw new ArgumentOutOfRangeException ("index"); + + instructions.RemoveAt (index); + } + + public void Clear () + { + instructions.Clear (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs.meta new file mode 100644 index 0000000..5964570 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/ILProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26902ea42064c624d82727d9ef9a8f5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs new file mode 100644 index 0000000..93afafe --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs @@ -0,0 +1,296 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Text; + +namespace MonoFN.Cecil.Cil { + + public sealed class Instruction { + + internal int offset; + internal OpCode opcode; + internal object operand; + + internal Instruction previous; + internal Instruction next; + + public int Offset { + get { return offset; } + set { offset = value; } + } + + public OpCode OpCode { + get { return opcode; } + set { opcode = value; } + } + + public object Operand { + get { return operand; } + set { operand = value; } + } + + public Instruction Previous { + get { return previous; } + set { previous = value; } + } + + public Instruction Next { + get { return next; } + set { next = value; } + } + + internal Instruction (int offset, OpCode opCode) + { + this.offset = offset; + this.opcode = opCode; + } + + internal Instruction (OpCode opcode, object operand) + { + this.opcode = opcode; + this.operand = operand; + } + + public int GetSize () + { + int size = opcode.Size; + + switch (opcode.OperandType) { + case OperandType.InlineSwitch: + return size + (1 + ((Instruction [])operand).Length) * 4; + case OperandType.InlineI8: + case OperandType.InlineR: + return size + 8; + case OperandType.InlineBrTarget: + case OperandType.InlineField: + case OperandType.InlineI: + case OperandType.InlineMethod: + case OperandType.InlineString: + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.ShortInlineR: + case OperandType.InlineSig: + return size + 4; + case OperandType.InlineArg: + case OperandType.InlineVar: + return size + 2; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineI: + case OperandType.ShortInlineArg: + case OperandType.ShortInlineVar: + return size + 1; + default: + return size; + } + } + + public override string ToString () + { + var instruction = new StringBuilder (); + + AppendLabel (instruction, this); + instruction.Append (':'); + instruction.Append (' '); + instruction.Append (opcode.Name); + + if (operand == null) + return instruction.ToString (); + + instruction.Append (' '); + + switch (opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + AppendLabel (instruction, (Instruction)operand); + break; + case OperandType.InlineSwitch: + var labels = (Instruction [])operand; + for (int i = 0; i < labels.Length; i++) { + if (i > 0) + instruction.Append (','); + + AppendLabel (instruction, labels [i]); + } + break; + case OperandType.InlineString: + instruction.Append ('\"'); + instruction.Append (operand); + instruction.Append ('\"'); + break; + default: + instruction.Append (operand); + break; + } + + return instruction.ToString (); + } + + static void AppendLabel (StringBuilder builder, Instruction instruction) + { + builder.Append ("IL_"); + builder.Append (instruction.offset.ToString ("x4")); + } + + public static Instruction Create (OpCode opcode) + { + if (opcode.OperandType != OperandType.InlineNone) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, null); + } + + public static Instruction Create (OpCode opcode, TypeReference type) + { + if (type == null) + throw new ArgumentNullException ("type"); + if (opcode.OperandType != OperandType.InlineType && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, type); + } + + public static Instruction Create (OpCode opcode, CallSite site) + { + if (site == null) + throw new ArgumentNullException ("site"); + if (opcode.Code != Code.Calli) + throw new ArgumentException ("code"); + + return new Instruction (opcode, site); + } + + public static Instruction Create (OpCode opcode, MethodReference method) + { + if (method == null) + throw new ArgumentNullException ("method"); + if (opcode.OperandType != OperandType.InlineMethod && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, method); + } + + public static Instruction Create (OpCode opcode, FieldReference field) + { + if (field == null) + throw new ArgumentNullException ("field"); + if (opcode.OperandType != OperandType.InlineField && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, field); + } + + public static Instruction Create (OpCode opcode, string value) + { + if (value == null) + throw new ArgumentNullException ("value"); + if (opcode.OperandType != OperandType.InlineString) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, sbyte value) + { + if (opcode.OperandType != OperandType.ShortInlineI && + opcode != OpCodes.Ldc_I4_S) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, byte value) + { + if (opcode.OperandType != OperandType.ShortInlineI || + opcode == OpCodes.Ldc_I4_S) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, int value) + { + if (opcode.OperandType != OperandType.InlineI) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, long value) + { + if (opcode.OperandType != OperandType.InlineI8) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, float value) + { + if (opcode.OperandType != OperandType.ShortInlineR) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, double value) + { + if (opcode.OperandType != OperandType.InlineR) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, Instruction target) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (opcode.OperandType != OperandType.InlineBrTarget && + opcode.OperandType != OperandType.ShortInlineBrTarget) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, target); + } + + public static Instruction Create (OpCode opcode, Instruction [] targets) + { + if (targets == null) + throw new ArgumentNullException ("targets"); + if (opcode.OperandType != OperandType.InlineSwitch) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, targets); + } + + public static Instruction Create (OpCode opcode, VariableDefinition variable) + { + if (variable == null) + throw new ArgumentNullException ("variable"); + if (opcode.OperandType != OperandType.ShortInlineVar && + opcode.OperandType != OperandType.InlineVar) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, variable); + } + + public static Instruction Create (OpCode opcode, ParameterDefinition parameter) + { + if (parameter == null) + throw new ArgumentNullException ("parameter"); + if (opcode.OperandType != OperandType.ShortInlineArg && + opcode.OperandType != OperandType.InlineArg) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, parameter); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs.meta new file mode 100644 index 0000000..fc5ea61 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Instruction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d1536adbd2ca174abbd624473e722c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs new file mode 100644 index 0000000..9a49f12 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs @@ -0,0 +1,426 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Threading; + +namespace MonoFN.Cecil.Cil { + + public sealed class MethodBody { + + readonly internal MethodDefinition method; + + internal ParameterDefinition this_parameter; + internal int max_stack_size; + internal int code_size; + internal bool init_locals; + internal MetadataToken local_var_token; + + internal Collection instructions; + internal Collection exceptions; + internal Collection variables; + + public MethodDefinition Method { + get { return method; } + } + + public int MaxStackSize { + get { return max_stack_size; } + set { max_stack_size = value; } + } + + public int CodeSize { + get { return code_size; } + } + + public bool InitLocals { + get { return init_locals; } + set { init_locals = value; } + } + + public MetadataToken LocalVarToken { + get { return local_var_token; } + set { local_var_token = value; } + } + + public Collection Instructions { + get { + if (instructions == null) + Interlocked.CompareExchange (ref instructions, new InstructionCollection (method), null); + + return instructions; + } + } + + public bool HasExceptionHandlers { + get { return !exceptions.IsNullOrEmpty (); } + } + + public Collection ExceptionHandlers { + get { + if (exceptions == null) + Interlocked.CompareExchange (ref exceptions, new Collection (), null); + + return exceptions; + } + } + + public bool HasVariables { + get { return !variables.IsNullOrEmpty (); } + } + + public Collection Variables { + get { + if (variables == null) + Interlocked.CompareExchange (ref variables, new VariableDefinitionCollection (this.method), null); + + return variables; + } + } + + public ParameterDefinition ThisParameter { + get { + if (method == null || method.DeclaringType == null) + throw new NotSupportedException (); + + if (!method.HasThis) + return null; + + if (this_parameter == null) + Interlocked.CompareExchange (ref this_parameter, CreateThisParameter (method), null); + + return this_parameter; + } + } + + static ParameterDefinition CreateThisParameter (MethodDefinition method) + { + var parameter_type = method.DeclaringType as TypeReference; + + if (parameter_type.HasGenericParameters) { + var instance = new GenericInstanceType (parameter_type, parameter_type.GenericParameters.Count); + for (int i = 0; i < parameter_type.GenericParameters.Count; i++) + instance.GenericArguments.Add (parameter_type.GenericParameters [i]); + + parameter_type = instance; + + } + + if (parameter_type.IsValueType || parameter_type.IsPrimitive) + parameter_type = new ByReferenceType (parameter_type); + + return new ParameterDefinition (parameter_type, method); + } + + public MethodBody (MethodDefinition method) + { + this.method = method; + } + + public ILProcessor GetILProcessor () + { + return new ILProcessor (this); + } + } + + sealed class VariableDefinitionCollection : Collection { + + readonly MethodDefinition method; + + internal VariableDefinitionCollection (MethodDefinition method) + { + this.method = method; + } + + internal VariableDefinitionCollection (MethodDefinition method, int capacity) + : base (capacity) + { + this.method = method; + } + + protected override void OnAdd (VariableDefinition item, int index) + { + item.index = index; + } + + protected override void OnInsert (VariableDefinition item, int index) + { + item.index = index; + UpdateVariableIndices (index, 1); + } + + protected override void OnSet (VariableDefinition item, int index) + { + item.index = index; + } + + protected override void OnRemove (VariableDefinition item, int index) + { + UpdateVariableIndices (index + 1, -1, item); + item.index = -1; + } + + void UpdateVariableIndices (int startIndex, int offset, VariableDefinition variableToRemove = null) + { + for (int i = startIndex; i < size; i++) + items [i].index = i + offset; + + var debug_info = method == null ? null : method.debug_info; + if (debug_info == null || debug_info.Scope == null) + return; + + foreach (var scope in debug_info.GetScopes ()) { + if (!scope.HasVariables) + continue; + + var variables = scope.Variables; + int variableDebugInfoIndexToRemove = -1; + for (int i = 0; i < variables.Count; i++) { + var variable = variables [i]; + + // If a variable is being removed detect if it has debug info counterpart, if so remove that as well. + // Note that the debug info can be either resolved (has direct reference to the VariableDefinition) + // or unresolved (has only the number index of the variable) - this needs to handle both cases. + if (variableToRemove != null && + ((variable.index.IsResolved && variable.index.ResolvedVariable == variableToRemove) || + (!variable.index.IsResolved && variable.Index == variableToRemove.Index))) { + variableDebugInfoIndexToRemove = i; + continue; + } + + // For unresolved debug info updates indeces to keep them pointing to the same variable. + if (!variable.index.IsResolved && variable.Index >= startIndex) { + variable.index = new VariableIndex (variable.Index + offset); + } + } + + if (variableDebugInfoIndexToRemove >= 0) + variables.RemoveAt (variableDebugInfoIndexToRemove); + } + } + } + + class InstructionCollection : Collection { + + readonly MethodDefinition method; + + internal InstructionCollection (MethodDefinition method) + { + this.method = method; + } + + internal InstructionCollection (MethodDefinition method, int capacity) + : base (capacity) + { + this.method = method; + } + + protected override void OnAdd (Instruction item, int index) + { + if (index == 0) + return; + + var previous = items [index - 1]; + previous.next = item; + item.previous = previous; + } + + protected override void OnInsert (Instruction item, int index) + { + int startOffset = 0; + if (size != 0) { + var current = items [index]; + if (current == null) { + var last = items [index - 1]; + last.next = item; + item.previous = last; + return; + } + + startOffset = current.Offset; + + var previous = current.previous; + if (previous != null) { + previous.next = item; + item.previous = previous; + } + + current.previous = item; + item.next = current; + } + + UpdateLocalScopes (null, null); + } + + protected override void OnSet (Instruction item, int index) + { + var current = items [index]; + + item.previous = current.previous; + item.next = current.next; + + current.previous = null; + current.next = null; + + UpdateLocalScopes (item, current); + } + + protected override void OnRemove (Instruction item, int index) + { + var previous = item.previous; + if (previous != null) + previous.next = item.next; + + var next = item.next; + if (next != null) + next.previous = item.previous; + + RemoveSequencePoint (item); + UpdateLocalScopes (item, next ?? previous); + + item.previous = null; + item.next = null; + } + + void RemoveSequencePoint (Instruction instruction) + { + var debug_info = method.debug_info; + if (debug_info == null || !debug_info.HasSequencePoints) + return; + + var sequence_points = debug_info.sequence_points; + for (int i = 0; i < sequence_points.Count; i++) { + if (sequence_points [i].Offset == instruction.offset) { + sequence_points.RemoveAt (i); + return; + } + } + } + + void UpdateLocalScopes (Instruction removedInstruction, Instruction existingInstruction) + { + var debug_info = method.debug_info; + if (debug_info == null) + return; + + // Local scopes store start/end pair of "instruction offsets". Instruction offset can be either resolved, in which case it + // has a reference to Instruction, or unresolved in which case it stores numerical offset (instruction offset in the body). + // Typically local scopes loaded from PE/PDB files will be resolved, but it's not a requirement. + // Each instruction has its own offset, which is populated on load, but never updated (this would be pretty expensive to do). + // Instructions created during the editting will typically have offset 0 (so incorrect). + // Local scopes created during editing will also likely be resolved (so no numerical offsets). + // So while local scopes which are unresolved are relatively rare if they appear, manipulating them based + // on the offsets allone is pretty hard (since we can't rely on correct offsets of instructions). + // On the other hand resolved local scopes are easy to maintain, since they point to instructions and thus inserting + // instructions is basically a no-op and removing instructions is as easy as changing the pointer. + // For this reason the algorithm here is: + // - First make sure that all instruction offsets are resolved - if not - resolve them + // - First time this will be relatively expensinve as it will walk the entire method body to convert offsets to instruction pointers + // Almost all local scopes are stored in the "right" order (sequentially per start offsets), so the code uses a simple one-item + // cache instruction<->offset to avoid walking instructions multiple times (that would only happen for scopes which are out of order). + // - Subsequent calls should be cheap as it will only walk all local scopes without doing anything + // - If there was an edit on local scope which makes some of them unresolved, the cost is proportional + // - Then update as necessary by manipulaitng instruction references alone + + InstructionOffsetCache cache = new InstructionOffsetCache () { + Offset = 0, + Index = 0, + Instruction = items [0] + }; + + UpdateLocalScope (debug_info.Scope, removedInstruction, existingInstruction, ref cache); + } + + void UpdateLocalScope (ScopeDebugInformation scope, Instruction removedInstruction, Instruction existingInstruction, ref InstructionOffsetCache cache) + { + if (scope == null) + return; + + if (!scope.Start.IsResolved) + scope.Start = ResolveInstructionOffset (scope.Start, ref cache); + + if (!scope.Start.IsEndOfMethod && scope.Start.ResolvedInstruction == removedInstruction) + scope.Start = new InstructionOffset (existingInstruction); + + if (scope.HasScopes) { + foreach (var subScope in scope.Scopes) + UpdateLocalScope (subScope, removedInstruction, existingInstruction, ref cache); + } + + if (!scope.End.IsResolved) + scope.End = ResolveInstructionOffset (scope.End, ref cache); + + if (!scope.End.IsEndOfMethod && scope.End.ResolvedInstruction == removedInstruction) + scope.End = new InstructionOffset (existingInstruction); + } + + struct InstructionOffsetCache { + public int Offset; + public int Index; + public Instruction Instruction; + } + + InstructionOffset ResolveInstructionOffset (InstructionOffset inputOffset, ref InstructionOffsetCache cache) + { + if (inputOffset.IsResolved) + return inputOffset; + + int offset = inputOffset.Offset; + + if (cache.Offset == offset) + return new InstructionOffset (cache.Instruction); + + if (cache.Offset > offset) { + // This should be rare - we're resolving offset pointing to a place before the current cache position + // resolve by walking the instructions from start and don't cache the result. + int size = 0; + for (int i = 0; i < items.Length; i++) { + if (size == offset) + return new InstructionOffset (items [i]); + + if (size > offset) + return new InstructionOffset (items [i - 1]); + + size += items [i].GetSize (); + } + + // Offset is larger than the size of the body - so it points after the end + return new InstructionOffset (); + } else { + // The offset points after the current cache position - so continue counting and update the cache + int size = cache.Offset; + for (int i = cache.Index; i < items.Length; i++) { + cache.Index = i; + cache.Offset = size; + + var item = items [i]; + + // Allow for trailing null values in the case of + // instructions.Size < instructions.Capacity + if (item == null) + break; + + cache.Instruction = item; + + if (cache.Offset == offset) + return new InstructionOffset (cache.Instruction); + + if (cache.Offset > offset) + return new InstructionOffset (items [i - 1]); + + size += item.GetSize (); + } + + return new InstructionOffset (); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs.meta new file mode 100644 index 0000000..6bfd730 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/MethodBody.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4be4045de2c6a0e428e5910f4e76cfac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs new file mode 100644 index 0000000..6db5b62 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs @@ -0,0 +1,439 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Cil { + + public enum FlowControl { + Branch, + Break, + Call, + Cond_Branch, + Meta, + Next, + Phi, + Return, + Throw, + } + + public enum OpCodeType { + Annotation, + Macro, + Nternal, + Objmodel, + Prefix, + Primitive, + } + + public enum OperandType { + InlineBrTarget, + InlineField, + InlineI, + InlineI8, + InlineMethod, + InlineNone, + InlinePhi, + InlineR, + InlineSig, + InlineString, + InlineSwitch, + InlineTok, + InlineType, + InlineVar, + InlineArg, + ShortInlineBrTarget, + ShortInlineI, + ShortInlineR, + ShortInlineVar, + ShortInlineArg, + } + + public enum StackBehaviour { + Pop0, + Pop1, + Pop1_pop1, + Popi, + Popi_pop1, + Popi_popi, + Popi_popi8, + Popi_popi_popi, + Popi_popr4, + Popi_popr8, + Popref, + Popref_pop1, + Popref_popi, + Popref_popi_popi, + Popref_popi_popi8, + Popref_popi_popr4, + Popref_popi_popr8, + Popref_popi_popref, + PopAll, + Push0, + Push1, + Push1_push1, + Pushi, + Pushi8, + Pushr4, + Pushr8, + Pushref, + Varpop, + Varpush, + } + + public struct OpCode : IEquatable { + + readonly byte op1; + readonly byte op2; + readonly byte code; + readonly byte flow_control; + readonly byte opcode_type; + readonly byte operand_type; + readonly byte stack_behavior_pop; + readonly byte stack_behavior_push; + + public string Name { + get { return OpCodeNames.names [(int)Code]; } + } + + public int Size { + get { return op1 == 0xff ? 1 : 2; } + } + + public byte Op1 { + get { return op1; } + } + + public byte Op2 { + get { return op2; } + } + + public short Value { + get { return op1 == 0xff ? op2 : (short)((op1 << 8) | op2); } + } + + public Code Code { + get { return (Code)code; } + } + + public FlowControl FlowControl { + get { return (FlowControl)flow_control; } + } + + public OpCodeType OpCodeType { + get { return (OpCodeType)opcode_type; } + } + + public OperandType OperandType { + get { return (OperandType)operand_type; } + } + + public StackBehaviour StackBehaviourPop { + get { return (StackBehaviour)stack_behavior_pop; } + } + + public StackBehaviour StackBehaviourPush { + get { return (StackBehaviour)stack_behavior_push; } + } + + internal OpCode (int x, int y) + { + this.op1 = (byte)((x >> 0) & 0xff); + this.op2 = (byte)((x >> 8) & 0xff); + this.code = (byte)((x >> 16) & 0xff); + this.flow_control = (byte)((x >> 24) & 0xff); + + this.opcode_type = (byte)((y >> 0) & 0xff); + this.operand_type = (byte)((y >> 8) & 0xff); + this.stack_behavior_pop = (byte)((y >> 16) & 0xff); + this.stack_behavior_push = (byte)((y >> 24) & 0xff); + + if (op1 == 0xff) + OpCodes.OneByteOpCode [op2] = this; + else + OpCodes.TwoBytesOpCode [op2] = this; + } + + public override int GetHashCode () + { + return Value; + } + + public override bool Equals (object obj) + { + if (!(obj is OpCode)) + return false; + + var opcode = (OpCode)obj; + return op1 == opcode.op1 && op2 == opcode.op2; + } + + public bool Equals (OpCode opcode) + { + return op1 == opcode.op1 && op2 == opcode.op2; + } + + public static bool operator == (OpCode one, OpCode other) + { + return one.op1 == other.op1 && one.op2 == other.op2; + } + + public static bool operator != (OpCode one, OpCode other) + { + return one.op1 != other.op1 || one.op2 != other.op2; + } + + public override string ToString () + { + return Name; + } + } + + static class OpCodeNames { + + internal static readonly string [] names; + + static OpCodeNames () + { + var table = new byte [] { + 3, 110, 111, 112, + 5, 98, 114, 101, 97, 107, + 7, 108, 100, 97, 114, 103, 46, 48, + 7, 108, 100, 97, 114, 103, 46, 49, + 7, 108, 100, 97, 114, 103, 46, 50, + 7, 108, 100, 97, 114, 103, 46, 51, + 7, 108, 100, 108, 111, 99, 46, 48, + 7, 108, 100, 108, 111, 99, 46, 49, + 7, 108, 100, 108, 111, 99, 46, 50, + 7, 108, 100, 108, 111, 99, 46, 51, + 7, 115, 116, 108, 111, 99, 46, 48, + 7, 115, 116, 108, 111, 99, 46, 49, + 7, 115, 116, 108, 111, 99, 46, 50, + 7, 115, 116, 108, 111, 99, 46, 51, + 7, 108, 100, 97, 114, 103, 46, 115, + 8, 108, 100, 97, 114, 103, 97, 46, 115, + 7, 115, 116, 97, 114, 103, 46, 115, + 7, 108, 100, 108, 111, 99, 46, 115, + 8, 108, 100, 108, 111, 99, 97, 46, 115, + 7, 115, 116, 108, 111, 99, 46, 115, + 6, 108, 100, 110, 117, 108, 108, + 9, 108, 100, 99, 46, 105, 52, 46, 109, 49, + 8, 108, 100, 99, 46, 105, 52, 46, 48, + 8, 108, 100, 99, 46, 105, 52, 46, 49, + 8, 108, 100, 99, 46, 105, 52, 46, 50, + 8, 108, 100, 99, 46, 105, 52, 46, 51, + 8, 108, 100, 99, 46, 105, 52, 46, 52, + 8, 108, 100, 99, 46, 105, 52, 46, 53, + 8, 108, 100, 99, 46, 105, 52, 46, 54, + 8, 108, 100, 99, 46, 105, 52, 46, 55, + 8, 108, 100, 99, 46, 105, 52, 46, 56, + 8, 108, 100, 99, 46, 105, 52, 46, 115, + 6, 108, 100, 99, 46, 105, 52, + 6, 108, 100, 99, 46, 105, 56, + 6, 108, 100, 99, 46, 114, 52, + 6, 108, 100, 99, 46, 114, 56, + 3, 100, 117, 112, + 3, 112, 111, 112, + 3, 106, 109, 112, + 4, 99, 97, 108, 108, + 5, 99, 97, 108, 108, 105, + 3, 114, 101, 116, + 4, 98, 114, 46, 115, + 9, 98, 114, 102, 97, 108, 115, 101, 46, 115, + 8, 98, 114, 116, 114, 117, 101, 46, 115, + 5, 98, 101, 113, 46, 115, + 5, 98, 103, 101, 46, 115, + 5, 98, 103, 116, 46, 115, + 5, 98, 108, 101, 46, 115, + 5, 98, 108, 116, 46, 115, + 8, 98, 110, 101, 46, 117, 110, 46, 115, + 8, 98, 103, 101, 46, 117, 110, 46, 115, + 8, 98, 103, 116, 46, 117, 110, 46, 115, + 8, 98, 108, 101, 46, 117, 110, 46, 115, + 8, 98, 108, 116, 46, 117, 110, 46, 115, + 2, 98, 114, + 7, 98, 114, 102, 97, 108, 115, 101, + 6, 98, 114, 116, 114, 117, 101, + 3, 98, 101, 113, + 3, 98, 103, 101, + 3, 98, 103, 116, + 3, 98, 108, 101, + 3, 98, 108, 116, + 6, 98, 110, 101, 46, 117, 110, + 6, 98, 103, 101, 46, 117, 110, + 6, 98, 103, 116, 46, 117, 110, + 6, 98, 108, 101, 46, 117, 110, + 6, 98, 108, 116, 46, 117, 110, + 6, 115, 119, 105, 116, 99, 104, + 8, 108, 100, 105, 110, 100, 46, 105, 49, + 8, 108, 100, 105, 110, 100, 46, 117, 49, + 8, 108, 100, 105, 110, 100, 46, 105, 50, + 8, 108, 100, 105, 110, 100, 46, 117, 50, + 8, 108, 100, 105, 110, 100, 46, 105, 52, + 8, 108, 100, 105, 110, 100, 46, 117, 52, + 8, 108, 100, 105, 110, 100, 46, 105, 56, + 7, 108, 100, 105, 110, 100, 46, 105, + 8, 108, 100, 105, 110, 100, 46, 114, 52, + 8, 108, 100, 105, 110, 100, 46, 114, 56, + 9, 108, 100, 105, 110, 100, 46, 114, 101, 102, + 9, 115, 116, 105, 110, 100, 46, 114, 101, 102, + 8, 115, 116, 105, 110, 100, 46, 105, 49, + 8, 115, 116, 105, 110, 100, 46, 105, 50, + 8, 115, 116, 105, 110, 100, 46, 105, 52, + 8, 115, 116, 105, 110, 100, 46, 105, 56, + 8, 115, 116, 105, 110, 100, 46, 114, 52, + 8, 115, 116, 105, 110, 100, 46, 114, 56, + 3, 97, 100, 100, + 3, 115, 117, 98, + 3, 109, 117, 108, + 3, 100, 105, 118, + 6, 100, 105, 118, 46, 117, 110, + 3, 114, 101, 109, + 6, 114, 101, 109, 46, 117, 110, + 3, 97, 110, 100, + 2, 111, 114, + 3, 120, 111, 114, + 3, 115, 104, 108, + 3, 115, 104, 114, + 6, 115, 104, 114, 46, 117, 110, + 3, 110, 101, 103, + 3, 110, 111, 116, + 7, 99, 111, 110, 118, 46, 105, 49, + 7, 99, 111, 110, 118, 46, 105, 50, + 7, 99, 111, 110, 118, 46, 105, 52, + 7, 99, 111, 110, 118, 46, 105, 56, + 7, 99, 111, 110, 118, 46, 114, 52, + 7, 99, 111, 110, 118, 46, 114, 56, + 7, 99, 111, 110, 118, 46, 117, 52, + 7, 99, 111, 110, 118, 46, 117, 56, + 8, 99, 97, 108, 108, 118, 105, 114, 116, + 5, 99, 112, 111, 98, 106, + 5, 108, 100, 111, 98, 106, + 5, 108, 100, 115, 116, 114, + 6, 110, 101, 119, 111, 98, 106, + 9, 99, 97, 115, 116, 99, 108, 97, 115, 115, + 6, 105, 115, 105, 110, 115, 116, + 9, 99, 111, 110, 118, 46, 114, 46, 117, 110, + 5, 117, 110, 98, 111, 120, + 5, 116, 104, 114, 111, 119, + 5, 108, 100, 102, 108, 100, + 6, 108, 100, 102, 108, 100, 97, + 5, 115, 116, 102, 108, 100, + 6, 108, 100, 115, 102, 108, 100, + 7, 108, 100, 115, 102, 108, 100, 97, + 6, 115, 116, 115, 102, 108, 100, + 5, 115, 116, 111, 98, 106, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 49, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 50, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 52, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 56, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 49, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 50, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 52, 46, 117, 110, + 14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 56, 46, 117, 110, + 13, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 46, 117, 110, + 13, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 46, 117, 110, + 3, 98, 111, 120, + 6, 110, 101, 119, 97, 114, 114, + 5, 108, 100, 108, 101, 110, + 7, 108, 100, 101, 108, 101, 109, 97, + 9, 108, 100, 101, 108, 101, 109, 46, 105, 49, + 9, 108, 100, 101, 108, 101, 109, 46, 117, 49, + 9, 108, 100, 101, 108, 101, 109, 46, 105, 50, + 9, 108, 100, 101, 108, 101, 109, 46, 117, 50, + 9, 108, 100, 101, 108, 101, 109, 46, 105, 52, + 9, 108, 100, 101, 108, 101, 109, 46, 117, 52, + 9, 108, 100, 101, 108, 101, 109, 46, 105, 56, + 8, 108, 100, 101, 108, 101, 109, 46, 105, + 9, 108, 100, 101, 108, 101, 109, 46, 114, 52, + 9, 108, 100, 101, 108, 101, 109, 46, 114, 56, + 10, 108, 100, 101, 108, 101, 109, 46, 114, 101, 102, + 8, 115, 116, 101, 108, 101, 109, 46, 105, + 9, 115, 116, 101, 108, 101, 109, 46, 105, 49, + 9, 115, 116, 101, 108, 101, 109, 46, 105, 50, + 9, 115, 116, 101, 108, 101, 109, 46, 105, 52, + 9, 115, 116, 101, 108, 101, 109, 46, 105, 56, + 9, 115, 116, 101, 108, 101, 109, 46, 114, 52, + 9, 115, 116, 101, 108, 101, 109, 46, 114, 56, + 10, 115, 116, 101, 108, 101, 109, 46, 114, 101, 102, + 10, 108, 100, 101, 108, 101, 109, 46, 97, 110, 121, + 10, 115, 116, 101, 108, 101, 109, 46, 97, 110, 121, + 9, 117, 110, 98, 111, 120, 46, 97, 110, 121, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 49, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 49, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 50, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 50, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 52, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 52, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 56, + 11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 56, + 9, 114, 101, 102, 97, 110, 121, 118, 97, 108, + 8, 99, 107, 102, 105, 110, 105, 116, 101, + 8, 109, 107, 114, 101, 102, 97, 110, 121, + 7, 108, 100, 116, 111, 107, 101, 110, + 7, 99, 111, 110, 118, 46, 117, 50, + 7, 99, 111, 110, 118, 46, 117, 49, + 6, 99, 111, 110, 118, 46, 105, + 10, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, + 10, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, + 7, 97, 100, 100, 46, 111, 118, 102, + 10, 97, 100, 100, 46, 111, 118, 102, 46, 117, 110, + 7, 109, 117, 108, 46, 111, 118, 102, + 10, 109, 117, 108, 46, 111, 118, 102, 46, 117, 110, + 7, 115, 117, 98, 46, 111, 118, 102, + 10, 115, 117, 98, 46, 111, 118, 102, 46, 117, 110, + 10, 101, 110, 100, 102, 105, 110, 97, 108, 108, 121, + 5, 108, 101, 97, 118, 101, + 7, 108, 101, 97, 118, 101, 46, 115, + 7, 115, 116, 105, 110, 100, 46, 105, + 6, 99, 111, 110, 118, 46, 117, + 7, 97, 114, 103, 108, 105, 115, 116, + 3, 99, 101, 113, + 3, 99, 103, 116, + 6, 99, 103, 116, 46, 117, 110, + 3, 99, 108, 116, + 6, 99, 108, 116, 46, 117, 110, + 5, 108, 100, 102, 116, 110, + 9, 108, 100, 118, 105, 114, 116, 102, 116, 110, + 5, 108, 100, 97, 114, 103, + 6, 108, 100, 97, 114, 103, 97, + 5, 115, 116, 97, 114, 103, + 5, 108, 100, 108, 111, 99, + 6, 108, 100, 108, 111, 99, 97, + 5, 115, 116, 108, 111, 99, + 8, 108, 111, 99, 97, 108, 108, 111, 99, + 9, 101, 110, 100, 102, 105, 108, 116, 101, 114, + 10, 117, 110, 97, 108, 105, 103, 110, 101, 100, 46, + 9, 118, 111, 108, 97, 116, 105, 108, 101, 46, + 5, 116, 97, 105, 108, 46, + 7, 105, 110, 105, 116, 111, 98, 106, + 12, 99, 111, 110, 115, 116, 114, 97, 105, 110, 101, 100, 46, + 5, 99, 112, 98, 108, 107, + 7, 105, 110, 105, 116, 98, 108, 107, + 3, 110, 111, 46, + 7, 114, 101, 116, 104, 114, 111, 119, + 6, 115, 105, 122, 101, 111, 102, + 10, 114, 101, 102, 97, 110, 121, 116, 121, 112, 101, + 9, 114, 101, 97, 100, 111, 110, 108, 121, 46, + }; + + names = new string [219]; + + for (int i = 0, p = 0; i < names.Length; i++) { + var buffer = new char [table [p++]]; + + for (int j = 0; j < buffer.Length; j++) + buffer [j] = (char)table [p++]; + + names [i] = new string (buffer); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs.meta new file mode 100644 index 0000000..21d9966 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d8b234c106529441912c10b87502175 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs new file mode 100644 index 0000000..f05d164 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs @@ -0,0 +1,894 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Cil { + + public static class OpCodes { + + internal static readonly OpCode [] OneByteOpCode = new OpCode [0xe0 + 1]; + internal static readonly OpCode [] TwoBytesOpCode = new OpCode [0x1e + 1]; + + public static readonly OpCode Nop = new OpCode ( + 0xff << 0 | 0x00 << 8 | (byte)Code.Nop << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Break = new OpCode ( + 0xff << 0 | 0x01 << 8 | (byte)Code.Break << 16 | (byte)FlowControl.Break << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldarg_0 = new OpCode ( + 0xff << 0 | 0x02 << 8 | (byte)Code.Ldarg_0 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_1 = new OpCode ( + 0xff << 0 | 0x03 << 8 | (byte)Code.Ldarg_1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_2 = new OpCode ( + 0xff << 0 | 0x04 << 8 | (byte)Code.Ldarg_2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_3 = new OpCode ( + 0xff << 0 | 0x05 << 8 | (byte)Code.Ldarg_3 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_0 = new OpCode ( + 0xff << 0 | 0x06 << 8 | (byte)Code.Ldloc_0 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_1 = new OpCode ( + 0xff << 0 | 0x07 << 8 | (byte)Code.Ldloc_1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_2 = new OpCode ( + 0xff << 0 | 0x08 << 8 | (byte)Code.Ldloc_2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_3 = new OpCode ( + 0xff << 0 | 0x09 << 8 | (byte)Code.Ldloc_3 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Stloc_0 = new OpCode ( + 0xff << 0 | 0x0a << 8 | (byte)Code.Stloc_0 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_1 = new OpCode ( + 0xff << 0 | 0x0b << 8 | (byte)Code.Stloc_1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_2 = new OpCode ( + 0xff << 0 | 0x0c << 8 | (byte)Code.Stloc_2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_3 = new OpCode ( + 0xff << 0 | 0x0d << 8 | (byte)Code.Stloc_3 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldarg_S = new OpCode ( + 0xff << 0 | 0x0e << 8 | (byte)Code.Ldarg_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineArg << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarga_S = new OpCode ( + 0xff << 0 | 0x0f << 8 | (byte)Code.Ldarga_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineArg << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Starg_S = new OpCode ( + 0xff << 0 | 0x10 << 8 | (byte)Code.Starg_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineArg << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldloc_S = new OpCode ( + 0xff << 0 | 0x11 << 8 | (byte)Code.Ldloc_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineVar << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloca_S = new OpCode ( + 0xff << 0 | 0x12 << 8 | (byte)Code.Ldloca_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineVar << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Stloc_S = new OpCode ( + 0xff << 0 | 0x13 << 8 | (byte)Code.Stloc_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineVar << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldnull = new OpCode ( + 0xff << 0 | 0x14 << 8 | (byte)Code.Ldnull << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Ldc_I4_M1 = new OpCode ( + 0xff << 0 | 0x15 << 8 | (byte)Code.Ldc_I4_M1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_0 = new OpCode ( + 0xff << 0 | 0x16 << 8 | (byte)Code.Ldc_I4_0 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_1 = new OpCode ( + 0xff << 0 | 0x17 << 8 | (byte)Code.Ldc_I4_1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_2 = new OpCode ( + 0xff << 0 | 0x18 << 8 | (byte)Code.Ldc_I4_2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_3 = new OpCode ( + 0xff << 0 | 0x19 << 8 | (byte)Code.Ldc_I4_3 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_4 = new OpCode ( + 0xff << 0 | 0x1a << 8 | (byte)Code.Ldc_I4_4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_5 = new OpCode ( + 0xff << 0 | 0x1b << 8 | (byte)Code.Ldc_I4_5 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_6 = new OpCode ( + 0xff << 0 | 0x1c << 8 | (byte)Code.Ldc_I4_6 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_7 = new OpCode ( + 0xff << 0 | 0x1d << 8 | (byte)Code.Ldc_I4_7 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_8 = new OpCode ( + 0xff << 0 | 0x1e << 8 | (byte)Code.Ldc_I4_8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_S = new OpCode ( + 0xff << 0 | 0x1f << 8 | (byte)Code.Ldc_I4_S << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineI << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4 = new OpCode ( + 0xff << 0 | 0x20 << 8 | (byte)Code.Ldc_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineI << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I8 = new OpCode ( + 0xff << 0 | 0x21 << 8 | (byte)Code.Ldc_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineI8 << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldc_R4 = new OpCode ( + 0xff << 0 | 0x22 << 8 | (byte)Code.Ldc_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.ShortInlineR << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldc_R8 = new OpCode ( + 0xff << 0 | 0x23 << 8 | (byte)Code.Ldc_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineR << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Dup = new OpCode ( + 0xff << 0 | 0x25 << 8 | (byte)Code.Dup << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push1_push1 << 24); + + public static readonly OpCode Pop = new OpCode ( + 0xff << 0 | 0x26 << 8 | (byte)Code.Pop << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Jmp = new OpCode ( + 0xff << 0 | 0x27 << 8 | (byte)Code.Jmp << 16 | (byte)FlowControl.Call << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Call = new OpCode ( + 0xff << 0 | 0x28 << 8 | (byte)Code.Call << 16 | (byte)FlowControl.Call << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Varpop << 16 | (byte)StackBehaviour.Varpush << 24); + + public static readonly OpCode Calli = new OpCode ( + 0xff << 0 | 0x29 << 8 | (byte)Code.Calli << 16 | (byte)FlowControl.Call << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineSig << 8 | (byte)StackBehaviour.Varpop << 16 | (byte)StackBehaviour.Varpush << 24); + + public static readonly OpCode Ret = new OpCode ( + 0xff << 0 | 0x2a << 8 | (byte)Code.Ret << 16 | (byte)FlowControl.Return << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Varpop << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Br_S = new OpCode ( + 0xff << 0 | 0x2b << 8 | (byte)Code.Br_S << 16 | (byte)FlowControl.Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Brfalse_S = new OpCode ( + 0xff << 0 | 0x2c << 8 | (byte)Code.Brfalse_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Brtrue_S = new OpCode ( + 0xff << 0 | 0x2d << 8 | (byte)Code.Brtrue_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Beq_S = new OpCode ( + 0xff << 0 | 0x2e << 8 | (byte)Code.Beq_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_S = new OpCode ( + 0xff << 0 | 0x2f << 8 | (byte)Code.Bge_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_S = new OpCode ( + 0xff << 0 | 0x30 << 8 | (byte)Code.Bgt_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_S = new OpCode ( + 0xff << 0 | 0x31 << 8 | (byte)Code.Ble_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_S = new OpCode ( + 0xff << 0 | 0x32 << 8 | (byte)Code.Blt_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bne_Un_S = new OpCode ( + 0xff << 0 | 0x33 << 8 | (byte)Code.Bne_Un_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_Un_S = new OpCode ( + 0xff << 0 | 0x34 << 8 | (byte)Code.Bge_Un_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_Un_S = new OpCode ( + 0xff << 0 | 0x35 << 8 | (byte)Code.Bgt_Un_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_Un_S = new OpCode ( + 0xff << 0 | 0x36 << 8 | (byte)Code.Ble_Un_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_Un_S = new OpCode ( + 0xff << 0 | 0x37 << 8 | (byte)Code.Blt_Un_S << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Br = new OpCode ( + 0xff << 0 | 0x38 << 8 | (byte)Code.Br << 16 | (byte)FlowControl.Branch << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Brfalse = new OpCode ( + 0xff << 0 | 0x39 << 8 | (byte)Code.Brfalse << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Brtrue = new OpCode ( + 0xff << 0 | 0x3a << 8 | (byte)Code.Brtrue << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Beq = new OpCode ( + 0xff << 0 | 0x3b << 8 | (byte)Code.Beq << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge = new OpCode ( + 0xff << 0 | 0x3c << 8 | (byte)Code.Bge << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt = new OpCode ( + 0xff << 0 | 0x3d << 8 | (byte)Code.Bgt << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble = new OpCode ( + 0xff << 0 | 0x3e << 8 | (byte)Code.Ble << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt = new OpCode ( + 0xff << 0 | 0x3f << 8 | (byte)Code.Blt << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bne_Un = new OpCode ( + 0xff << 0 | 0x40 << 8 | (byte)Code.Bne_Un << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_Un = new OpCode ( + 0xff << 0 | 0x41 << 8 | (byte)Code.Bge_Un << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_Un = new OpCode ( + 0xff << 0 | 0x42 << 8 | (byte)Code.Bgt_Un << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_Un = new OpCode ( + 0xff << 0 | 0x43 << 8 | (byte)Code.Ble_Un << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_Un = new OpCode ( + 0xff << 0 | 0x44 << 8 | (byte)Code.Blt_Un << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Switch = new OpCode ( + 0xff << 0 | 0x45 << 8 | (byte)Code.Switch << 16 | (byte)FlowControl.Cond_Branch << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineSwitch << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldind_I1 = new OpCode ( + 0xff << 0 | 0x46 << 8 | (byte)Code.Ldind_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U1 = new OpCode ( + 0xff << 0 | 0x47 << 8 | (byte)Code.Ldind_U1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I2 = new OpCode ( + 0xff << 0 | 0x48 << 8 | (byte)Code.Ldind_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U2 = new OpCode ( + 0xff << 0 | 0x49 << 8 | (byte)Code.Ldind_U2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I4 = new OpCode ( + 0xff << 0 | 0x4a << 8 | (byte)Code.Ldind_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U4 = new OpCode ( + 0xff << 0 | 0x4b << 8 | (byte)Code.Ldind_U4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I8 = new OpCode ( + 0xff << 0 | 0x4c << 8 | (byte)Code.Ldind_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldind_I = new OpCode ( + 0xff << 0 | 0x4d << 8 | (byte)Code.Ldind_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_R4 = new OpCode ( + 0xff << 0 | 0x4e << 8 | (byte)Code.Ldind_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldind_R8 = new OpCode ( + 0xff << 0 | 0x4f << 8 | (byte)Code.Ldind_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Ldind_Ref = new OpCode ( + 0xff << 0 | 0x50 << 8 | (byte)Code.Ldind_Ref << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Stind_Ref = new OpCode ( + 0xff << 0 | 0x51 << 8 | (byte)Code.Stind_Ref << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I1 = new OpCode ( + 0xff << 0 | 0x52 << 8 | (byte)Code.Stind_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I2 = new OpCode ( + 0xff << 0 | 0x53 << 8 | (byte)Code.Stind_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I4 = new OpCode ( + 0xff << 0 | 0x54 << 8 | (byte)Code.Stind_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I8 = new OpCode ( + 0xff << 0 | 0x55 << 8 | (byte)Code.Stind_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi8 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_R4 = new OpCode ( + 0xff << 0 | 0x56 << 8 | (byte)Code.Stind_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popr4 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_R8 = new OpCode ( + 0xff << 0 | 0x57 << 8 | (byte)Code.Stind_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popr8 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Add = new OpCode ( + 0xff << 0 | 0x58 << 8 | (byte)Code.Add << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub = new OpCode ( + 0xff << 0 | 0x59 << 8 | (byte)Code.Sub << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul = new OpCode ( + 0xff << 0 | 0x5a << 8 | (byte)Code.Mul << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Div = new OpCode ( + 0xff << 0 | 0x5b << 8 | (byte)Code.Div << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Div_Un = new OpCode ( + 0xff << 0 | 0x5c << 8 | (byte)Code.Div_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Rem = new OpCode ( + 0xff << 0 | 0x5d << 8 | (byte)Code.Rem << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Rem_Un = new OpCode ( + 0xff << 0 | 0x5e << 8 | (byte)Code.Rem_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode And = new OpCode ( + 0xff << 0 | 0x5f << 8 | (byte)Code.And << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Or = new OpCode ( + 0xff << 0 | 0x60 << 8 | (byte)Code.Or << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Xor = new OpCode ( + 0xff << 0 | 0x61 << 8 | (byte)Code.Xor << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Shl = new OpCode ( + 0xff << 0 | 0x62 << 8 | (byte)Code.Shl << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Shr = new OpCode ( + 0xff << 0 | 0x63 << 8 | (byte)Code.Shr << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Shr_Un = new OpCode ( + 0xff << 0 | 0x64 << 8 | (byte)Code.Shr_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Neg = new OpCode ( + 0xff << 0 | 0x65 << 8 | (byte)Code.Neg << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Not = new OpCode ( + 0xff << 0 | 0x66 << 8 | (byte)Code.Not << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Conv_I1 = new OpCode ( + 0xff << 0 | 0x67 << 8 | (byte)Code.Conv_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I2 = new OpCode ( + 0xff << 0 | 0x68 << 8 | (byte)Code.Conv_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I4 = new OpCode ( + 0xff << 0 | 0x69 << 8 | (byte)Code.Conv_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I8 = new OpCode ( + 0xff << 0 | 0x6a << 8 | (byte)Code.Conv_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_R4 = new OpCode ( + 0xff << 0 | 0x6b << 8 | (byte)Code.Conv_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Conv_R8 = new OpCode ( + 0xff << 0 | 0x6c << 8 | (byte)Code.Conv_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Conv_U4 = new OpCode ( + 0xff << 0 | 0x6d << 8 | (byte)Code.Conv_U4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U8 = new OpCode ( + 0xff << 0 | 0x6e << 8 | (byte)Code.Conv_U8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Callvirt = new OpCode ( + 0xff << 0 | 0x6f << 8 | (byte)Code.Callvirt << 16 | (byte)FlowControl.Call << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Varpop << 16 | (byte)StackBehaviour.Varpush << 24); + + public static readonly OpCode Cpobj = new OpCode ( + 0xff << 0 | 0x70 << 8 | (byte)Code.Cpobj << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldobj = new OpCode ( + 0xff << 0 | 0x71 << 8 | (byte)Code.Ldobj << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldstr = new OpCode ( + 0xff << 0 | 0x72 << 8 | (byte)Code.Ldstr << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineString << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Newobj = new OpCode ( + 0xff << 0 | 0x73 << 8 | (byte)Code.Newobj << 16 | (byte)FlowControl.Call << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Varpop << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Castclass = new OpCode ( + 0xff << 0 | 0x74 << 8 | (byte)Code.Castclass << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Isinst = new OpCode ( + 0xff << 0 | 0x75 << 8 | (byte)Code.Isinst << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_R_Un = new OpCode ( + 0xff << 0 | 0x76 << 8 | (byte)Code.Conv_R_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Unbox = new OpCode ( + 0xff << 0 | 0x79 << 8 | (byte)Code.Unbox << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Throw = new OpCode ( + 0xff << 0 | 0x7a << 8 | (byte)Code.Throw << 16 | (byte)FlowControl.Throw << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldfld = new OpCode ( + 0xff << 0 | 0x7b << 8 | (byte)Code.Ldfld << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldflda = new OpCode ( + 0xff << 0 | 0x7c << 8 | (byte)Code.Ldflda << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Stfld = new OpCode ( + 0xff << 0 | 0x7d << 8 | (byte)Code.Stfld << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Popref_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldsfld = new OpCode ( + 0xff << 0 | 0x7e << 8 | (byte)Code.Ldsfld << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldsflda = new OpCode ( + 0xff << 0 | 0x7f << 8 | (byte)Code.Ldsflda << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Stsfld = new OpCode ( + 0xff << 0 | 0x80 << 8 | (byte)Code.Stsfld << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineField << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stobj = new OpCode ( + 0xff << 0 | 0x81 << 8 | (byte)Code.Stobj << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi_pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Conv_Ovf_I1_Un = new OpCode ( + 0xff << 0 | 0x82 << 8 | (byte)Code.Conv_Ovf_I1_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I2_Un = new OpCode ( + 0xff << 0 | 0x83 << 8 | (byte)Code.Conv_Ovf_I2_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I4_Un = new OpCode ( + 0xff << 0 | 0x84 << 8 | (byte)Code.Conv_Ovf_I4_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I8_Un = new OpCode ( + 0xff << 0 | 0x85 << 8 | (byte)Code.Conv_Ovf_I8_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_U1_Un = new OpCode ( + 0xff << 0 | 0x86 << 8 | (byte)Code.Conv_Ovf_U1_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U2_Un = new OpCode ( + 0xff << 0 | 0x87 << 8 | (byte)Code.Conv_Ovf_U2_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U4_Un = new OpCode ( + 0xff << 0 | 0x88 << 8 | (byte)Code.Conv_Ovf_U4_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U8_Un = new OpCode ( + 0xff << 0 | 0x89 << 8 | (byte)Code.Conv_Ovf_U8_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_I_Un = new OpCode ( + 0xff << 0 | 0x8a << 8 | (byte)Code.Conv_Ovf_I_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U_Un = new OpCode ( + 0xff << 0 | 0x8b << 8 | (byte)Code.Conv_Ovf_U_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Box = new OpCode ( + 0xff << 0 | 0x8c << 8 | (byte)Code.Box << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Newarr = new OpCode ( + 0xff << 0 | 0x8d << 8 | (byte)Code.Newarr << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Ldlen = new OpCode ( + 0xff << 0 | 0x8e << 8 | (byte)Code.Ldlen << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelema = new OpCode ( + 0xff << 0 | 0x8f << 8 | (byte)Code.Ldelema << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I1 = new OpCode ( + 0xff << 0 | 0x90 << 8 | (byte)Code.Ldelem_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U1 = new OpCode ( + 0xff << 0 | 0x91 << 8 | (byte)Code.Ldelem_U1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I2 = new OpCode ( + 0xff << 0 | 0x92 << 8 | (byte)Code.Ldelem_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U2 = new OpCode ( + 0xff << 0 | 0x93 << 8 | (byte)Code.Ldelem_U2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I4 = new OpCode ( + 0xff << 0 | 0x94 << 8 | (byte)Code.Ldelem_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U4 = new OpCode ( + 0xff << 0 | 0x95 << 8 | (byte)Code.Ldelem_U4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I8 = new OpCode ( + 0xff << 0 | 0x96 << 8 | (byte)Code.Ldelem_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldelem_I = new OpCode ( + 0xff << 0 | 0x97 << 8 | (byte)Code.Ldelem_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_R4 = new OpCode ( + 0xff << 0 | 0x98 << 8 | (byte)Code.Ldelem_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldelem_R8 = new OpCode ( + 0xff << 0 | 0x99 << 8 | (byte)Code.Ldelem_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Ldelem_Ref = new OpCode ( + 0xff << 0 | 0x9a << 8 | (byte)Code.Ldelem_Ref << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Pushref << 24); + + public static readonly OpCode Stelem_I = new OpCode ( + 0xff << 0 | 0x9b << 8 | (byte)Code.Stelem_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I1 = new OpCode ( + 0xff << 0 | 0x9c << 8 | (byte)Code.Stelem_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I2 = new OpCode ( + 0xff << 0 | 0x9d << 8 | (byte)Code.Stelem_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I4 = new OpCode ( + 0xff << 0 | 0x9e << 8 | (byte)Code.Stelem_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I8 = new OpCode ( + 0xff << 0 | 0x9f << 8 | (byte)Code.Stelem_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popi8 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_R4 = new OpCode ( + 0xff << 0 | 0xa0 << 8 | (byte)Code.Stelem_R4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popr4 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_R8 = new OpCode ( + 0xff << 0 | 0xa1 << 8 | (byte)Code.Stelem_R8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popr8 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_Ref = new OpCode ( + 0xff << 0 | 0xa2 << 8 | (byte)Code.Stelem_Ref << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popref_popi_popref << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldelem_Any = new OpCode ( + 0xff << 0 | 0xa3 << 8 | (byte)Code.Ldelem_Any << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref_popi << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Stelem_Any = new OpCode ( + 0xff << 0 | 0xa4 << 8 | (byte)Code.Stelem_Any << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref_popi_popref << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Unbox_Any = new OpCode ( + 0xff << 0 | 0xa5 << 8 | (byte)Code.Unbox_Any << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Conv_Ovf_I1 = new OpCode ( + 0xff << 0 | 0xb3 << 8 | (byte)Code.Conv_Ovf_I1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U1 = new OpCode ( + 0xff << 0 | 0xb4 << 8 | (byte)Code.Conv_Ovf_U1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I2 = new OpCode ( + 0xff << 0 | 0xb5 << 8 | (byte)Code.Conv_Ovf_I2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U2 = new OpCode ( + 0xff << 0 | 0xb6 << 8 | (byte)Code.Conv_Ovf_U2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I4 = new OpCode ( + 0xff << 0 | 0xb7 << 8 | (byte)Code.Conv_Ovf_I4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U4 = new OpCode ( + 0xff << 0 | 0xb8 << 8 | (byte)Code.Conv_Ovf_U4 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I8 = new OpCode ( + 0xff << 0 | 0xb9 << 8 | (byte)Code.Conv_Ovf_I8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_U8 = new OpCode ( + 0xff << 0 | 0xba << 8 | (byte)Code.Conv_Ovf_U8 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Refanyval = new OpCode ( + 0xff << 0 | 0xc2 << 8 | (byte)Code.Refanyval << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ckfinite = new OpCode ( + 0xff << 0 | 0xc3 << 8 | (byte)Code.Ckfinite << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Mkrefany = new OpCode ( + 0xff << 0 | 0xc6 << 8 | (byte)Code.Mkrefany << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldtoken = new OpCode ( + 0xff << 0 | 0xd0 << 8 | (byte)Code.Ldtoken << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineTok << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U2 = new OpCode ( + 0xff << 0 | 0xd1 << 8 | (byte)Code.Conv_U2 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U1 = new OpCode ( + 0xff << 0 | 0xd2 << 8 | (byte)Code.Conv_U1 << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I = new OpCode ( + 0xff << 0 | 0xd3 << 8 | (byte)Code.Conv_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I = new OpCode ( + 0xff << 0 | 0xd4 << 8 | (byte)Code.Conv_Ovf_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U = new OpCode ( + 0xff << 0 | 0xd5 << 8 | (byte)Code.Conv_Ovf_U << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Add_Ovf = new OpCode ( + 0xff << 0 | 0xd6 << 8 | (byte)Code.Add_Ovf << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Add_Ovf_Un = new OpCode ( + 0xff << 0 | 0xd7 << 8 | (byte)Code.Add_Ovf_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul_Ovf = new OpCode ( + 0xff << 0 | 0xd8 << 8 | (byte)Code.Mul_Ovf << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul_Ovf_Un = new OpCode ( + 0xff << 0 | 0xd9 << 8 | (byte)Code.Mul_Ovf_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub_Ovf = new OpCode ( + 0xff << 0 | 0xda << 8 | (byte)Code.Sub_Ovf << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub_Ovf_Un = new OpCode ( + 0xff << 0 | 0xdb << 8 | (byte)Code.Sub_Ovf_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Endfinally = new OpCode ( + 0xff << 0 | 0xdc << 8 | (byte)Code.Endfinally << 16 | (byte)FlowControl.Return << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Leave = new OpCode ( + 0xff << 0 | 0xdd << 8 | (byte)Code.Leave << 16 | (byte)FlowControl.Branch << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineBrTarget << 8 | (byte)StackBehaviour.PopAll << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Leave_S = new OpCode ( + 0xff << 0 | 0xde << 8 | (byte)Code.Leave_S << 16 | (byte)FlowControl.Branch << 24, + (byte)OpCodeType.Macro << 0 | (byte)OperandType.ShortInlineBrTarget << 8 | (byte)StackBehaviour.PopAll << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I = new OpCode ( + 0xff << 0 | 0xdf << 8 | (byte)Code.Stind_I << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Conv_U = new OpCode ( + 0xff << 0 | 0xe0 << 8 | (byte)Code.Conv_U << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Arglist = new OpCode ( + 0xfe << 0 | 0x00 << 8 | (byte)Code.Arglist << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ceq = new OpCode ( + 0xfe << 0 | 0x01 << 8 | (byte)Code.Ceq << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Cgt = new OpCode ( + 0xfe << 0 | 0x02 << 8 | (byte)Code.Cgt << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Cgt_Un = new OpCode ( + 0xfe << 0 | 0x03 << 8 | (byte)Code.Cgt_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Clt = new OpCode ( + 0xfe << 0 | 0x04 << 8 | (byte)Code.Clt << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Clt_Un = new OpCode ( + 0xfe << 0 | 0x05 << 8 | (byte)Code.Clt_Un << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1_pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldftn = new OpCode ( + 0xfe << 0 | 0x06 << 8 | (byte)Code.Ldftn << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldvirtftn = new OpCode ( + 0xfe << 0 | 0x07 << 8 | (byte)Code.Ldvirtftn << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineMethod << 8 | (byte)StackBehaviour.Popref << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldarg = new OpCode ( + 0xfe << 0 | 0x09 << 8 | (byte)Code.Ldarg << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineArg << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarga = new OpCode ( + 0xfe << 0 | 0x0a << 8 | (byte)Code.Ldarga << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineArg << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Starg = new OpCode ( + 0xfe << 0 | 0x0b << 8 | (byte)Code.Starg << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineArg << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldloc = new OpCode ( + 0xfe << 0 | 0x0c << 8 | (byte)Code.Ldloc << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineVar << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloca = new OpCode ( + 0xfe << 0 | 0x0d << 8 | (byte)Code.Ldloca << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineVar << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Stloc = new OpCode ( + 0xfe << 0 | 0x0e << 8 | (byte)Code.Stloc << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineVar << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Localloc = new OpCode ( + 0xfe << 0 | 0x0f << 8 | (byte)Code.Localloc << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Endfilter = new OpCode ( + 0xfe << 0 | 0x11 << 8 | (byte)Code.Endfilter << 16 | (byte)FlowControl.Return << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Unaligned = new OpCode ( + 0xfe << 0 | 0x12 << 8 | (byte)Code.Unaligned << 16 | (byte)FlowControl.Meta << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.ShortInlineI << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Volatile = new OpCode ( + 0xfe << 0 | 0x13 << 8 | (byte)Code.Volatile << 16 | (byte)FlowControl.Meta << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Tail = new OpCode ( + 0xfe << 0 | 0x14 << 8 | (byte)Code.Tail << 16 | (byte)FlowControl.Meta << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Initobj = new OpCode ( + 0xfe << 0 | 0x15 << 8 | (byte)Code.Initobj << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Constrained = new OpCode ( + 0xfe << 0 | 0x16 << 8 | (byte)Code.Constrained << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Cpblk = new OpCode ( + 0xfe << 0 | 0x17 << 8 | (byte)Code.Cpblk << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Initblk = new OpCode ( + 0xfe << 0 | 0x18 << 8 | (byte)Code.Initblk << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Popi_popi_popi << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode No = new OpCode ( + 0xfe << 0 | 0x19 << 8 | (byte)Code.No << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.ShortInlineI << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Rethrow = new OpCode ( + 0xfe << 0 | 0x1a << 8 | (byte)Code.Rethrow << 16 | (byte)FlowControl.Throw << 24, + (byte)OpCodeType.Objmodel << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + + public static readonly OpCode Sizeof = new OpCode ( + 0xfe << 0 | 0x1c << 8 | (byte)Code.Sizeof << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineType << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Refanytype = new OpCode ( + 0xfe << 0 | 0x1d << 8 | (byte)Code.Refanytype << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Primitive << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop1 << 16 | (byte)StackBehaviour.Pushi << 24); + + public static readonly OpCode Readonly = new OpCode ( + 0xfe << 0 | 0x1e << 8 | (byte)Code.Readonly << 16 | (byte)FlowControl.Next << 24, + (byte)OpCodeType.Prefix << 0 | (byte)OperandType.InlineNone << 8 | (byte)StackBehaviour.Pop0 << 16 | (byte)StackBehaviour.Push0 << 24); + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs.meta new file mode 100644 index 0000000..422968a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/OpCodes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52c19a62321778c438d2f6b483f18e73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs new file mode 100644 index 0000000..64b7ad7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs @@ -0,0 +1,591 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Cecil.PE; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; + +namespace MonoFN.Cecil.Cil { + + public sealed class PortablePdbReaderProvider : ISymbolReaderProvider { + + public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName) + { + Mixin.CheckModule (module); + Mixin.CheckFileName (fileName); + + var file = File.OpenRead (Mixin.GetPdbFileName (fileName)); + return GetSymbolReader (module, Disposable.Owned (file as Stream), file.Name); + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream) + { + Mixin.CheckModule (module); + Mixin.CheckStream (symbolStream); + + return GetSymbolReader (module, Disposable.NotOwned (symbolStream), symbolStream.GetFileName ()); + } + + ISymbolReader GetSymbolReader (ModuleDefinition module, Disposable symbolStream, string fileName) + { + return new PortablePdbReader (ImageReader.ReadPortablePdb (symbolStream, fileName), module); + } + } + + public sealed class PortablePdbReader : ISymbolReader { + + readonly Image image; + readonly ModuleDefinition module; + readonly MetadataReader reader; + readonly MetadataReader debug_reader; + + bool IsEmbedded { get { return reader.image == debug_reader.image; } } + + internal PortablePdbReader (Image image, ModuleDefinition module) + { + this.image = image; + this.module = module; + this.reader = module.reader; + this.debug_reader = new MetadataReader (image, module, this.reader); + } + + public ISymbolWriterProvider GetWriterProvider () + { + return new PortablePdbWriterProvider (); + } + + public bool ProcessDebugHeader (ImageDebugHeader header) + { + if (image == module.Image) + return true; + + foreach (var entry in header.Entries) { + if (!IsMatchingEntry (image.PdbHeap, entry)) + continue; + + ReadModule (); + return true; + } + + return false; + } + + static bool IsMatchingEntry (PdbHeap heap, ImageDebugHeaderEntry entry) + { + if (entry.Directory.Type != ImageDebugType.CodeView) + return false; + + var data = entry.Data; + + if (data.Length < 24) + return false; + + var magic = ReadInt32 (data, 0); + if (magic != 0x53445352) + return false; + + var buffer = new byte [16]; + Buffer.BlockCopy (data, 4, buffer, 0, 16); + + var module_guid = new Guid (buffer); + + Buffer.BlockCopy (heap.Id, 0, buffer, 0, 16); + + var pdb_guid = new Guid (buffer); + + return module_guid == pdb_guid; + } + + static int ReadInt32 (byte [] bytes, int start) + { + return (bytes [start] + | (bytes [start + 1] << 8) + | (bytes [start + 2] << 16) + | (bytes [start + 3] << 24)); + } + + void ReadModule () + { + module.custom_infos = debug_reader.GetCustomDebugInformation (module); + } + + public MethodDebugInformation Read (MethodDefinition method) + { + var info = new MethodDebugInformation (method); + ReadSequencePoints (info); + ReadScope (info); + ReadStateMachineKickOffMethod (info); + ReadCustomDebugInformations (info); + return info; + } + + void ReadSequencePoints (MethodDebugInformation method_info) + { + method_info.sequence_points = debug_reader.ReadSequencePoints (method_info.method); + } + + void ReadScope (MethodDebugInformation method_info) + { + method_info.scope = debug_reader.ReadScope (method_info.method); + } + + void ReadStateMachineKickOffMethod (MethodDebugInformation method_info) + { + method_info.kickoff_method = debug_reader.ReadStateMachineKickoffMethod (method_info.method); + } + + void ReadCustomDebugInformations (MethodDebugInformation info) + { + info.method.custom_infos = debug_reader.GetCustomDebugInformation (info.method); + } + + public void Dispose () + { + if (IsEmbedded) + return; + + image.Dispose (); + } + } + + public sealed class EmbeddedPortablePdbReaderProvider : ISymbolReaderProvider { + + public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName) + { + Mixin.CheckModule (module); + + var header = module.GetDebugHeader (); + var entry = header.GetEmbeddedPortablePdbEntry (); + if (entry == null) + throw new InvalidOperationException (); + + return new EmbeddedPortablePdbReader ( + (PortablePdbReader)new PortablePdbReaderProvider ().GetSymbolReader (module, GetPortablePdbStream (entry))); + } + + static Stream GetPortablePdbStream (ImageDebugHeaderEntry entry) + { + var compressed_stream = new MemoryStream (entry.Data); + var reader = new BinaryStreamReader (compressed_stream); + reader.ReadInt32 (); // signature + var length = reader.ReadInt32 (); + var decompressed_stream = new MemoryStream (length); + + using (var deflate_stream = new DeflateStream (compressed_stream, CompressionMode.Decompress, leaveOpen: true)) + deflate_stream.CopyTo (decompressed_stream); + + return decompressed_stream; + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream) + { + throw new NotSupportedException (); + } + } + + public sealed class EmbeddedPortablePdbReader : ISymbolReader { + private readonly PortablePdbReader reader; + + internal EmbeddedPortablePdbReader (PortablePdbReader reader) + { + if (reader == null) + throw new ArgumentNullException (); + + this.reader = reader; + } + + public ISymbolWriterProvider GetWriterProvider () + { + return new EmbeddedPortablePdbWriterProvider (); + } + + public bool ProcessDebugHeader (ImageDebugHeader header) + { + return reader.ProcessDebugHeader (header); + } + + public MethodDebugInformation Read (MethodDefinition method) + { + return reader.Read (method); + } + + public void Dispose () + { + reader.Dispose (); + } + } + + public sealed class PortablePdbWriterProvider : ISymbolWriterProvider { + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) + { + Mixin.CheckModule (module); + Mixin.CheckFileName (fileName); + + var file = File.OpenWrite (Mixin.GetPdbFileName (fileName)); + return GetSymbolWriter (module, Disposable.Owned (file as Stream)); + } + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) + { + Mixin.CheckModule (module); + Mixin.CheckStream (symbolStream); + + return GetSymbolWriter (module, Disposable.NotOwned (symbolStream)); + } + + ISymbolWriter GetSymbolWriter (ModuleDefinition module, Disposable stream) + { + var metadata = new MetadataBuilder (module, this); + var writer = ImageWriter.CreateDebugWriter (module, metadata, stream); + + return new PortablePdbWriter (metadata, module, writer); + } + } + + public sealed class PortablePdbWriter : ISymbolWriter { + + readonly MetadataBuilder pdb_metadata; + readonly ModuleDefinition module; + readonly ImageWriter writer; + + MetadataBuilder module_metadata; + + bool IsEmbedded { get { return writer == null; } } + + internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module) + { + this.pdb_metadata = pdb_metadata; + this.module = module; + + this.module_metadata = module.metadata_builder; + + if (module_metadata != pdb_metadata) + this.pdb_metadata.metadata_builder = this.module_metadata; + + pdb_metadata.AddCustomDebugInformations (module); + } + + internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer) + : this (pdb_metadata, module) + { + this.writer = writer; + } + + public ISymbolReaderProvider GetReaderProvider () + { + return new PortablePdbReaderProvider (); + } + + public ImageDebugHeader GetDebugHeader () + { + if (IsEmbedded) + return new ImageDebugHeader (); + + var directory = new ImageDebugDirectory () { + MajorVersion = 256, + MinorVersion = 20557, + Type = ImageDebugType.CodeView, + TimeDateStamp = (int)module.timestamp, + }; + + var buffer = new ByteBuffer (); + // RSDS + buffer.WriteUInt32 (0x53445352); + // Module ID + buffer.WriteBytes (module.Mvid.ToByteArray ()); + // PDB Age + buffer.WriteUInt32 (1); + // PDB Path + var fileName = writer.BaseStream.GetFileName (); + if (string.IsNullOrEmpty (fileName)) { + fileName = module.Assembly.Name.Name + ".pdb"; + } + buffer.WriteBytes (System.Text.Encoding.UTF8.GetBytes (fileName)); + buffer.WriteByte (0); + + var data = new byte [buffer.length]; + Buffer.BlockCopy (buffer.buffer, 0, data, 0, buffer.length); + directory.SizeOfData = data.Length; + + return new ImageDebugHeader (new ImageDebugHeaderEntry (directory, data)); + } + + public void Write (MethodDebugInformation info) + { + CheckMethodDebugInformationTable (); + + pdb_metadata.AddMethodDebugInformation (info); + } + + void CheckMethodDebugInformationTable () + { + var mdi = pdb_metadata.table_heap.GetTable (Table.MethodDebugInformation); + if (mdi.length > 0) + return; + + // The MethodDebugInformation table has the same length as the Method table + mdi.rows = new Row [module_metadata.method_rid - 1]; + mdi.length = mdi.rows.Length; + } + + public void Dispose () + { + if (IsEmbedded) + return; + + WritePdbFile (); + } + + void WritePdbFile () + { + WritePdbHeap (); + + WriteTableHeap (); + + writer.BuildMetadataTextMap (); + writer.WriteMetadataHeader (); + writer.WriteMetadata (); + + writer.Flush (); + writer.stream.Dispose (); + } + + void WritePdbHeap () + { + var pdb_heap = pdb_metadata.pdb_heap; + + pdb_heap.WriteBytes (module.Mvid.ToByteArray ()); + pdb_heap.WriteUInt32 (module_metadata.timestamp); + + pdb_heap.WriteUInt32 (module_metadata.entry_point.ToUInt32 ()); + + var table_heap = module_metadata.table_heap; + var tables = table_heap.tables; + + ulong valid = 0; + for (int i = 0; i < tables.Length; i++) { + if (tables [i] == null || tables [i].Length == 0) + continue; + + valid |= (1UL << i); + } + + pdb_heap.WriteUInt64 (valid); + + for (int i = 0; i < tables.Length; i++) { + if (tables [i] == null || tables [i].Length == 0) + continue; + + pdb_heap.WriteUInt32 ((uint)tables [i].Length); + } + } + + void WriteTableHeap () + { + pdb_metadata.table_heap.string_offsets = pdb_metadata.string_heap.WriteStrings (); + pdb_metadata.table_heap.ComputeTableInformations (); + pdb_metadata.table_heap.WriteTableHeap (); + } + } + + public sealed class EmbeddedPortablePdbWriterProvider : ISymbolWriterProvider { + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) + { + Mixin.CheckModule (module); + Mixin.CheckFileName (fileName); + + var stream = new MemoryStream (); + var pdb_writer = (PortablePdbWriter)new PortablePdbWriterProvider ().GetSymbolWriter (module, stream); + return new EmbeddedPortablePdbWriter (stream, pdb_writer); + } + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) + { + throw new NotSupportedException (); + } + } + + public sealed class EmbeddedPortablePdbWriter : ISymbolWriter { + + readonly Stream stream; + readonly PortablePdbWriter writer; + + internal EmbeddedPortablePdbWriter (Stream stream, PortablePdbWriter writer) + { + this.stream = stream; + this.writer = writer; + } + + public ISymbolReaderProvider GetReaderProvider () + { + return new EmbeddedPortablePdbReaderProvider (); + } + + public ImageDebugHeader GetDebugHeader () + { + writer.Dispose (); + + var directory = new ImageDebugDirectory { + Type = ImageDebugType.EmbeddedPortablePdb, + MajorVersion = 0x0100, + MinorVersion = 0x0100, + }; + + var data = new MemoryStream (); + + var w = new BinaryStreamWriter (data); + w.WriteByte (0x4d); + w.WriteByte (0x50); + w.WriteByte (0x44); + w.WriteByte (0x42); + + w.WriteInt32 ((int)stream.Length); + + stream.Position = 0; + + using (var compress_stream = new DeflateStream (data, CompressionMode.Compress, leaveOpen: true)) + stream.CopyTo (compress_stream); + + directory.SizeOfData = (int)data.Length; + + return new ImageDebugHeader (new [] { + writer.GetDebugHeader ().Entries [0], + new ImageDebugHeaderEntry (directory, data.ToArray ()) + }); + } + + public void Write (MethodDebugInformation info) + { + writer.Write (info); + } + + public void Dispose () + { + } + } + + static class PdbGuidMapping { + + static readonly Dictionary guid_language = new Dictionary (); + static readonly Dictionary language_guid = new Dictionary (); + + static PdbGuidMapping () + { + AddMapping (DocumentLanguage.C, new Guid ("63a08714-fc37-11d2-904c-00c04fa302a1")); + AddMapping (DocumentLanguage.Cpp, new Guid ("3a12d0b7-c26c-11d0-b442-00a0244a1dd2")); + AddMapping (DocumentLanguage.CSharp, new Guid ("3f5162f8-07c6-11d3-9053-00c04fa302a1")); + AddMapping (DocumentLanguage.Basic, new Guid ("3a12d0b8-c26c-11d0-b442-00a0244a1dd2")); + AddMapping (DocumentLanguage.Java, new Guid ("3a12d0b4-c26c-11d0-b442-00a0244a1dd2")); + AddMapping (DocumentLanguage.Cobol, new Guid ("af046cd1-d0e1-11d2-977c-00a0c9b4d50c")); + AddMapping (DocumentLanguage.Pascal, new Guid ("af046cd2-d0e1-11d2-977c-00a0c9b4d50c")); + AddMapping (DocumentLanguage.Cil, new Guid ("af046cd3-d0e1-11d2-977c-00a0c9b4d50c")); + AddMapping (DocumentLanguage.JScript, new Guid ("3a12d0b6-c26c-11d0-b442-00a0244a1dd2")); + AddMapping (DocumentLanguage.Smc, new Guid ("0d9b9f7b-6611-11d3-bd2a-0000f80849bd")); + AddMapping (DocumentLanguage.MCpp, new Guid ("4b35fde8-07c6-11d3-9053-00c04fa302a1")); + AddMapping (DocumentLanguage.FSharp, new Guid ("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3")); + } + + static void AddMapping (DocumentLanguage language, Guid guid) + { + guid_language.Add (guid, language); + language_guid.Add (language, guid); + } + + static readonly Guid type_text = new Guid ("5a869d0b-6611-11d3-bd2a-0000f80849bd"); + + public static DocumentType ToType (this Guid guid) + { + if (guid == type_text) + return DocumentType.Text; + + return DocumentType.Other; + } + + public static Guid ToGuid (this DocumentType type) + { + if (type == DocumentType.Text) + return type_text; + + return new Guid (); + } + + static readonly Guid hash_md5 = new Guid ("406ea660-64cf-4c82-b6f0-42d48172a799"); + static readonly Guid hash_sha1 = new Guid ("ff1816ec-aa5e-4d10-87f7-6f4963833460"); + static readonly Guid hash_sha256 = new Guid ("8829d00f-11b8-4213-878b-770e8597ac16"); + + public static DocumentHashAlgorithm ToHashAlgorithm (this Guid guid) + { + if (guid == hash_md5) + return DocumentHashAlgorithm.MD5; + + if (guid == hash_sha1) + return DocumentHashAlgorithm.SHA1; + + if (guid == hash_sha256) + return DocumentHashAlgorithm.SHA256; + + return DocumentHashAlgorithm.None; + } + + public static Guid ToGuid (this DocumentHashAlgorithm hash_algo) + { + if (hash_algo == DocumentHashAlgorithm.MD5) + return hash_md5; + + if (hash_algo == DocumentHashAlgorithm.SHA1) + return hash_sha1; + + if (hash_algo == DocumentHashAlgorithm.SHA256) + return hash_sha256; + + return new Guid (); + } + + public static DocumentLanguage ToLanguage (this Guid guid) + { + DocumentLanguage language; + if (!guid_language.TryGetValue (guid, out language)) + return DocumentLanguage.Other; + + return language; + } + + public static Guid ToGuid (this DocumentLanguage language) + { + Guid guid; + if (!language_guid.TryGetValue (language, out guid)) + return new Guid (); + + return guid; + } + + static readonly Guid vendor_ms = new Guid ("994b45c4-e6e9-11d2-903f-00c04fa302a1"); + + public static DocumentLanguageVendor ToVendor (this Guid guid) + { + if (guid == vendor_ms) + return DocumentLanguageVendor.Microsoft; + + return DocumentLanguageVendor.Other; + } + + public static Guid ToGuid (this DocumentLanguageVendor vendor) + { + if (vendor == DocumentLanguageVendor.Microsoft) + return vendor_ms; + + return new Guid (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs.meta new file mode 100644 index 0000000..8b260c9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/PortablePdb.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34e2f5d4b9b9ea542bec15f2d9acc3ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs new file mode 100644 index 0000000..591815a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs @@ -0,0 +1,76 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Cil { + + public sealed class SequencePoint { + + internal InstructionOffset offset; + Document document; + + int start_line; + int start_column; + int end_line; + int end_column; + + public int Offset { + get { return offset.Offset; } + } + + public int StartLine { + get { return start_line; } + set { start_line = value; } + } + + public int StartColumn { + get { return start_column; } + set { start_column = value; } + } + + public int EndLine { + get { return end_line; } + set { end_line = value; } + } + + public int EndColumn { + get { return end_column; } + set { end_column = value; } + } + + public bool IsHidden { + get { return start_line == 0xfeefee && start_line == end_line; } + } + + public Document Document { + get { return document; } + set { document = value; } + } + + internal SequencePoint (int offset, Document document) + { + if (document == null) + throw new ArgumentNullException ("document"); + + this.offset = new InstructionOffset (offset); + this.document = document; + } + + public SequencePoint (Instruction instruction, Document document) + { + if (document == null) + throw new ArgumentNullException ("document"); + + this.offset = new InstructionOffset (instruction); + this.document = document; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs.meta new file mode 100644 index 0000000..bac78ab --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/SequencePoint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 612e6675dca63a84b9e8aaeb3e3b9ec6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs new file mode 100644 index 0000000..4e75a0c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs @@ -0,0 +1,1226 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using SR = System.Reflection; + +namespace MonoFN.Cecil.Cil { + + [StructLayout (LayoutKind.Sequential)] + public struct ImageDebugDirectory { + public const int Size = 28; + + public int Characteristics; + public int TimeDateStamp; + public short MajorVersion; + public short MinorVersion; + public ImageDebugType Type; + public int SizeOfData; + public int AddressOfRawData; + public int PointerToRawData; + } + + public enum ImageDebugType { + CodeView = 2, + Deterministic = 16, + EmbeddedPortablePdb = 17, + } + + public sealed class ImageDebugHeader { + + readonly ImageDebugHeaderEntry [] entries; + + public bool HasEntries { + get { return !entries.IsNullOrEmpty (); } + } + + public ImageDebugHeaderEntry [] Entries { + get { return entries; } + } + + public ImageDebugHeader (ImageDebugHeaderEntry [] entries) + { + this.entries = entries ?? Empty.Array; + } + + public ImageDebugHeader () + : this (Empty.Array) + { + } + + public ImageDebugHeader (ImageDebugHeaderEntry entry) + : this (new [] { entry }) + { + } + } + + public sealed class ImageDebugHeaderEntry { + + ImageDebugDirectory directory; + readonly byte [] data; + + public ImageDebugDirectory Directory { + get { return directory; } + internal set { directory = value; } + } + + public byte [] Data { + get { return data; } + } + + public ImageDebugHeaderEntry (ImageDebugDirectory directory, byte [] data) + { + this.directory = directory; + this.data = data ?? Empty.Array; + } + } + + public sealed class ScopeDebugInformation : DebugInformation { + + internal InstructionOffset start; + internal InstructionOffset end; + internal ImportDebugInformation import; + internal Collection scopes; + internal Collection variables; + internal Collection constants; + + public InstructionOffset Start { + get { return start; } + set { start = value; } + } + + public InstructionOffset End { + get { return end; } + set { end = value; } + } + + public ImportDebugInformation Import { + get { return import; } + set { import = value; } + } + + public bool HasScopes { + get { return !scopes.IsNullOrEmpty (); } + } + + public Collection Scopes { + get { + if (scopes == null) + Interlocked.CompareExchange (ref scopes, new Collection (), null); + + return scopes; + } + } + + public bool HasVariables { + get { return !variables.IsNullOrEmpty (); } + } + + public Collection Variables { + get { + if (variables == null) + Interlocked.CompareExchange (ref variables, new Collection (), null); + + return variables; + } + } + + public bool HasConstants { + get { return !constants.IsNullOrEmpty (); } + } + + public Collection Constants { + get { + if (constants == null) + Interlocked.CompareExchange (ref constants, new Collection (), null); + + return constants; + } + } + + internal ScopeDebugInformation () + { + this.token = new MetadataToken (TokenType.LocalScope); + } + + public ScopeDebugInformation (Instruction start, Instruction end) + : this () + { + if (start == null) + throw new ArgumentNullException ("start"); + + this.start = new InstructionOffset (start); + + if (end != null) + this.end = new InstructionOffset (end); + } + + public bool TryGetName (VariableDefinition variable, out string name) + { + name = null; + if (variables == null || variables.Count == 0) + return false; + + for (int i = 0; i < variables.Count; i++) { + if (variables [i].Index == variable.Index) { + name = variables [i].Name; + return true; + } + } + + return false; + } + } + + public struct InstructionOffset { + + readonly Instruction instruction; + readonly int? offset; + + public int Offset { + get { + if (instruction != null) + return instruction.Offset; + if (offset.HasValue) + return offset.Value; + + throw new NotSupportedException (); + } + } + + public bool IsEndOfMethod { + get { return instruction == null && !offset.HasValue; } + } + + internal bool IsResolved => instruction != null || !offset.HasValue; + + internal Instruction ResolvedInstruction => instruction; + + public InstructionOffset (Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + this.instruction = instruction; + this.offset = null; + } + + public InstructionOffset (int offset) + { + this.instruction = null; + this.offset = offset; + } + } + + [Flags] + public enum VariableAttributes : ushort { + None = 0, + DebuggerHidden = 1, + } + + public struct VariableIndex { + readonly VariableDefinition variable; + readonly int? index; + + public int Index { + get { + if (variable != null) + return variable.Index; + if (index.HasValue) + return index.Value; + + throw new NotSupportedException (); + } + } + + internal bool IsResolved => variable != null; + + internal VariableDefinition ResolvedVariable => variable; + + public VariableIndex (VariableDefinition variable) + { + if (variable == null) + throw new ArgumentNullException ("variable"); + + this.variable = variable; + this.index = null; + } + + public VariableIndex (int index) + { + this.variable = null; + this.index = index; + } + } + + public abstract class DebugInformation : ICustomDebugInformationProvider { + + internal MetadataToken token; + internal Collection custom_infos; + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + public bool HasCustomDebugInformations { + get { return !custom_infos.IsNullOrEmpty (); } + } + + public Collection CustomDebugInformations { + get { + if (custom_infos == null) + Interlocked.CompareExchange (ref custom_infos, new Collection (), null); + + return custom_infos; + } + } + + internal DebugInformation () + { + } + } + + public sealed class VariableDebugInformation : DebugInformation { + + string name; + ushort attributes; + internal VariableIndex index; + + public int Index { + get { return index.Index; } + } + + public string Name { + get { return name; } + set { name = value; } + } + + public VariableAttributes Attributes { + get { return (VariableAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public bool IsDebuggerHidden { + get { return attributes.GetAttributes ((ushort)VariableAttributes.DebuggerHidden); } + set { attributes = attributes.SetAttributes ((ushort)VariableAttributes.DebuggerHidden, value); } + } + + internal VariableDebugInformation (int index, string name) + { + if (name == null) + throw new ArgumentNullException ("name"); + + this.index = new VariableIndex (index); + this.name = name; + } + + public VariableDebugInformation (VariableDefinition variable, string name) + { + if (variable == null) + throw new ArgumentNullException ("variable"); + if (name == null) + throw new ArgumentNullException ("name"); + + this.index = new VariableIndex (variable); + this.name = name; + this.token = new MetadataToken (TokenType.LocalVariable); + } + } + + public sealed class ConstantDebugInformation : DebugInformation { + + string name; + TypeReference constant_type; + object value; + + public string Name { + get { return name; } + set { name = value; } + } + + public TypeReference ConstantType { + get { return constant_type; } + set { constant_type = value; } + } + + public object Value { + get { return value; } + set { this.value = value; } + } + + public ConstantDebugInformation (string name, TypeReference constant_type, object value) + { + if (name == null) + throw new ArgumentNullException ("name"); + + this.name = name; + this.constant_type = constant_type; + this.value = value; + this.token = new MetadataToken (TokenType.LocalConstant); + } + } + + public enum ImportTargetKind : byte { + ImportNamespace = 1, + ImportNamespaceInAssembly = 2, + ImportType = 3, + ImportXmlNamespaceWithAlias = 4, + ImportAlias = 5, + DefineAssemblyAlias = 6, + DefineNamespaceAlias = 7, + DefineNamespaceInAssemblyAlias = 8, + DefineTypeAlias = 9, + } + + public sealed class ImportTarget { + + internal ImportTargetKind kind; + + internal string @namespace; + internal TypeReference type; + internal AssemblyNameReference reference; + internal string alias; + + public string Namespace { + get { return @namespace; } + set { @namespace = value; } + } + + public TypeReference Type { + get { return type; } + set { type = value; } + } + + public AssemblyNameReference AssemblyReference { + get { return reference; } + set { reference = value; } + } + + public string Alias { + get { return alias; } + set { alias = value; } + } + + public ImportTargetKind Kind { + get { return kind; } + set { kind = value; } + } + + public ImportTarget (ImportTargetKind kind) + { + this.kind = kind; + } + } + + public sealed class ImportDebugInformation : DebugInformation { + + internal ImportDebugInformation parent; + internal Collection targets; + + public bool HasTargets { + get { return !targets.IsNullOrEmpty (); } + } + + public Collection Targets { + get { + if (targets == null) + Interlocked.CompareExchange (ref targets, new Collection (), null); + + return targets; + } + } + + public ImportDebugInformation Parent { + get { return parent; } + set { parent = value; } + } + + public ImportDebugInformation () + { + this.token = new MetadataToken (TokenType.ImportScope); + } + } + + public interface ICustomDebugInformationProvider : IMetadataTokenProvider { + bool HasCustomDebugInformations { get; } + Collection CustomDebugInformations { get; } + } + + public enum CustomDebugInformationKind { + Binary, + StateMachineScope, + DynamicVariable, + DefaultNamespace, + AsyncMethodBody, + EmbeddedSource, + SourceLink, + } + + public abstract class CustomDebugInformation : DebugInformation { + + Guid identifier; + + public Guid Identifier { + get { return identifier; } + } + + public abstract CustomDebugInformationKind Kind { get; } + + internal CustomDebugInformation (Guid identifier) + { + this.identifier = identifier; + this.token = new MetadataToken (TokenType.CustomDebugInformation); + } + } + + public sealed class BinaryCustomDebugInformation : CustomDebugInformation { + + byte [] data; + + public byte [] Data { + get { return data; } + set { data = value; } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.Binary; } + } + + public BinaryCustomDebugInformation (Guid identifier, byte [] data) + : base (identifier) + { + this.data = data; + } + } + + public sealed class AsyncMethodBodyDebugInformation : CustomDebugInformation { + + internal InstructionOffset catch_handler; + internal Collection yields; + internal Collection resumes; + internal Collection resume_methods; + + public InstructionOffset CatchHandler { + get { return catch_handler; } + set { catch_handler = value; } + } + + public Collection Yields { + get { + if (yields == null) + Interlocked.CompareExchange (ref yields, new Collection (), null); + + return yields; + } + } + + public Collection Resumes { + get { + if (resumes == null) + Interlocked.CompareExchange (ref resumes, new Collection (), null); + + return resumes; + } + } + + public Collection ResumeMethods { + get { return resume_methods ?? (resume_methods = new Collection ()); } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.AsyncMethodBody; } + } + + public static Guid KindIdentifier = new Guid ("{54FD2AC5-E925-401A-9C2A-F94F171072F8}"); + + internal AsyncMethodBodyDebugInformation (int catchHandler) + : base (KindIdentifier) + { + this.catch_handler = new InstructionOffset (catchHandler); + } + + public AsyncMethodBodyDebugInformation (Instruction catchHandler) + : base (KindIdentifier) + { + this.catch_handler = new InstructionOffset (catchHandler); + } + + public AsyncMethodBodyDebugInformation () + : base (KindIdentifier) + { + this.catch_handler = new InstructionOffset (-1); + } + } + + public sealed class StateMachineScope { + + internal InstructionOffset start; + internal InstructionOffset end; + + public InstructionOffset Start { + get { return start; } + set { start = value; } + } + + public InstructionOffset End { + get { return end; } + set { end = value; } + } + + internal StateMachineScope (int start, int end) + { + this.start = new InstructionOffset (start); + this.end = new InstructionOffset (end); + } + + public StateMachineScope (Instruction start, Instruction end) + { + this.start = new InstructionOffset (start); + this.end = end != null ? new InstructionOffset (end) : new InstructionOffset (); + } + } + + public sealed class StateMachineScopeDebugInformation : CustomDebugInformation { + + internal Collection scopes; + + public Collection Scopes { + get { return scopes ?? (scopes = new Collection ()); } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.StateMachineScope; } + } + + public static Guid KindIdentifier = new Guid ("{6DA9A61E-F8C7-4874-BE62-68BC5630DF71}"); + + public StateMachineScopeDebugInformation () + : base (KindIdentifier) + { + } + } + + public sealed class EmbeddedSourceDebugInformation : CustomDebugInformation { + + internal uint index; + internal MetadataReader debug_reader; + internal bool resolved; + internal byte [] content; + internal bool compress; + + public byte [] Content { + get { + if (!resolved) + Resolve (); + + return content; + } + set { + content = value; + resolved = true; + } + } + + public bool Compress { + get { + if (!resolved) + Resolve (); + + return compress; + } + set { + compress = value; + resolved = true; + } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.EmbeddedSource; } + } + + public static Guid KindIdentifier = new Guid ("{0E8A571B-6926-466E-B4AD-8AB04611F5FE}"); + + internal EmbeddedSourceDebugInformation (uint index, MetadataReader debug_reader) + : base (KindIdentifier) + { + this.index = index; + this.debug_reader = debug_reader; + } + + public EmbeddedSourceDebugInformation (byte [] content, bool compress) + : base (KindIdentifier) + { + this.resolved = true; + this.content = content; + this.compress = compress; + } + + internal byte [] ReadRawEmbeddedSourceDebugInformation () + { + if (debug_reader == null) + throw new InvalidOperationException (); + + return debug_reader.ReadRawEmbeddedSourceDebugInformation (index); + } + + void Resolve () + { + if (resolved) + return; + + if (debug_reader == null) + throw new InvalidOperationException (); + + var row = debug_reader.ReadEmbeddedSourceDebugInformation (index); + content = row.Col1; + compress = row.Col2; + resolved = true; + } + } + + public sealed class SourceLinkDebugInformation : CustomDebugInformation { + + internal string content; + + public string Content { + get { return content; } + set { content = value; } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.SourceLink; } + } + + public static Guid KindIdentifier = new Guid ("{CC110556-A091-4D38-9FEC-25AB9A351A6A}"); + + public SourceLinkDebugInformation (string content) + : base (KindIdentifier) + { + this.content = content; + } + } + + public sealed class MethodDebugInformation : DebugInformation { + + internal MethodDefinition method; + internal Collection sequence_points; + internal ScopeDebugInformation scope; + internal MethodDefinition kickoff_method; + internal int code_size; + internal MetadataToken local_var_token; + + public MethodDefinition Method { + get { return method; } + } + + public bool HasSequencePoints { + get { return !sequence_points.IsNullOrEmpty (); } + } + + public Collection SequencePoints { + get { + if (sequence_points == null) + Interlocked.CompareExchange (ref sequence_points, new Collection (), null); + + return sequence_points; + } + } + + public ScopeDebugInformation Scope { + get { return scope; } + set { scope = value; } + } + + public MethodDefinition StateMachineKickOffMethod { + get { return kickoff_method; } + set { kickoff_method = value; } + } + + internal MethodDebugInformation (MethodDefinition method) + { + if (method == null) + throw new ArgumentNullException ("method"); + + this.method = method; + this.token = new MetadataToken (TokenType.MethodDebugInformation, method.MetadataToken.RID); + } + + public SequencePoint GetSequencePoint (Instruction instruction) + { + if (!HasSequencePoints) + return null; + + for (int i = 0; i < sequence_points.Count; i++) + if (sequence_points [i].Offset == instruction.Offset) + return sequence_points [i]; + + return null; + } + + public IDictionary GetSequencePointMapping () + { + var instruction_mapping = new Dictionary (); + if (!HasSequencePoints || !method.HasBody) + return instruction_mapping; + + var offset_mapping = new Dictionary (sequence_points.Count); + + for (int i = 0; i < sequence_points.Count; i++) { + if (!offset_mapping.ContainsKey (sequence_points [i].Offset)) + offset_mapping.Add (sequence_points [i].Offset, sequence_points [i]); + } + + var instructions = method.Body.Instructions; + + for (int i = 0; i < instructions.Count; i++) { + SequencePoint sequence_point; + if (offset_mapping.TryGetValue (instructions [i].Offset, out sequence_point)) + instruction_mapping.Add (instructions [i], sequence_point); + } + + return instruction_mapping; + } + + public IEnumerable GetScopes () + { + if (scope == null) + return Empty.Array; + + return GetScopes (new [] { scope }); + } + + static IEnumerable GetScopes (IList scopes) + { + for (int i = 0; i < scopes.Count; i++) { + var scope = scopes [i]; + + yield return scope; + + if (!scope.HasScopes) + continue; + + foreach (var sub_scope in GetScopes (scope.Scopes)) + yield return sub_scope; + } + } + + public bool TryGetName (VariableDefinition variable, out string name) + { + name = null; + + var has_name = false; + var unique_name = ""; + + foreach (var scope in GetScopes ()) { + string slot_name; + if (!scope.TryGetName (variable, out slot_name)) + continue; + + if (!has_name) { + has_name = true; + unique_name = slot_name; + continue; + } + + if (unique_name != slot_name) + return false; + } + + name = unique_name; + return has_name; + } + } + + public interface ISymbolReader : IDisposable { + + ISymbolWriterProvider GetWriterProvider (); + bool ProcessDebugHeader (ImageDebugHeader header); + MethodDebugInformation Read (MethodDefinition method); + } + + public interface ISymbolReaderProvider { + ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName); + ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream); + } + +#if !NET_CORE + [Serializable] +#endif + public sealed class SymbolsNotFoundException : FileNotFoundException { + + public SymbolsNotFoundException (string message) : base (message) + { + } + +#if !NET_CORE + SymbolsNotFoundException ( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base (info, context) + { + } +#endif + } + +#if !NET_CORE + [Serializable] +#endif + public sealed class SymbolsNotMatchingException : InvalidOperationException { + + public SymbolsNotMatchingException (string message) : base (message) + { + } + +#if !NET_CORE + SymbolsNotMatchingException ( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base (info, context) + { + } +#endif + } + + public class DefaultSymbolReaderProvider : ISymbolReaderProvider { + + readonly bool throw_if_no_symbol; + + public DefaultSymbolReaderProvider () + : this (throwIfNoSymbol: true) + { + } + + public DefaultSymbolReaderProvider (bool throwIfNoSymbol) + { + throw_if_no_symbol = throwIfNoSymbol; + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName) + { + if (module.Image.HasDebugTables ()) + return null; + + if (module.HasDebugHeader) { + var header = module.GetDebugHeader (); + var entry = header.GetEmbeddedPortablePdbEntry (); + if (entry != null) + return new EmbeddedPortablePdbReaderProvider ().GetSymbolReader (module, fileName); + } + + var pdb_file_name = Mixin.GetPdbFileName (fileName); + + if (File.Exists (pdb_file_name)) { + if (Mixin.IsPortablePdb (Mixin.GetPdbFileName (fileName))) + return new PortablePdbReaderProvider ().GetSymbolReader (module, fileName); + + try { + return SymbolProvider.GetReaderProvider (SymbolKind.NativePdb).GetSymbolReader (module, fileName); + } + catch (Exception) { + // We might not include support for native pdbs. + } + } + + var mdb_file_name = Mixin.GetMdbFileName (fileName); + if (File.Exists (mdb_file_name)) { + try { + return SymbolProvider.GetReaderProvider (SymbolKind.Mdb).GetSymbolReader (module, fileName); + } + catch (Exception) { + // We might not include support for mdbs. + } + } + + if (throw_if_no_symbol) + throw new SymbolsNotFoundException (string.Format ("No symbol found for file: {0}", fileName)); + + return null; + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream) + { + if (module.Image.HasDebugTables ()) + return null; + + if (module.HasDebugHeader) { + var header = module.GetDebugHeader (); + var entry = header.GetEmbeddedPortablePdbEntry (); + if (entry != null) + return new EmbeddedPortablePdbReaderProvider ().GetSymbolReader (module, ""); + } + + Mixin.CheckStream (symbolStream); + Mixin.CheckReadSeek (symbolStream); + + var position = symbolStream.Position; + + const int portablePdbHeader = 0x424a5342; + + var reader = new BinaryStreamReader (symbolStream); + var intHeader = reader.ReadInt32 (); + symbolStream.Position = position; + + if (intHeader == portablePdbHeader) { + return new PortablePdbReaderProvider ().GetSymbolReader (module, symbolStream); + } + + const string nativePdbHeader = "Microsoft C/C++ MSF 7.00"; + + var bytesHeader = reader.ReadBytes (nativePdbHeader.Length); + symbolStream.Position = position; + var isNativePdb = true; + + for (var i = 0; i < bytesHeader.Length; i++) { + if (bytesHeader [i] != (byte)nativePdbHeader [i]) { + isNativePdb = false; + break; + } + } + + if (isNativePdb) { + try { + return SymbolProvider.GetReaderProvider (SymbolKind.NativePdb).GetSymbolReader (module, symbolStream); + } + catch (Exception) { + // We might not include support for native pdbs. + } + } + + const long mdbHeader = 0x45e82623fd7fa614; + + var longHeader = reader.ReadInt64 (); + symbolStream.Position = position; + + if (longHeader == mdbHeader) { + try { + return SymbolProvider.GetReaderProvider (SymbolKind.Mdb).GetSymbolReader (module, symbolStream); + } + catch (Exception) { + // We might not include support for mdbs. + } + } + + if (throw_if_no_symbol) + throw new SymbolsNotFoundException (string.Format ("No symbols found in stream")); + + return null; + } + } + + enum SymbolKind { + NativePdb, + PortablePdb, + EmbeddedPortablePdb, + Mdb, + } + + static class SymbolProvider { + + static SR.AssemblyName GetSymbolAssemblyName (SymbolKind kind) + { + if (kind == SymbolKind.PortablePdb) + throw new ArgumentException (); + + var suffix = GetSymbolNamespace (kind); + + var cecil_name = typeof (SymbolProvider).Assembly.GetName (); + + var name = new SR.AssemblyName { + Name = cecil_name.Name + "." + suffix, + Version = cecil_name.Version, +#if NET_CORE + CultureName = cecil_name.CultureName, +#else + CultureInfo = cecil_name.CultureInfo, +#endif + }; + + name.SetPublicKeyToken (cecil_name.GetPublicKeyToken ()); + + return name; + } + + static Type GetSymbolType (SymbolKind kind, string fullname) + { + var type = Type.GetType (fullname); + if (type != null) + return type; + + var assembly_name = GetSymbolAssemblyName (kind); + + type = Type.GetType (fullname + ", " + assembly_name.FullName); + if (type != null) + return type; + + try { + var assembly = SR.Assembly.Load (assembly_name); + if (assembly != null) + return assembly.GetType (fullname); + } + catch (FileNotFoundException) { + } + catch (FileLoadException) { + } + + return null; + } + + public static ISymbolReaderProvider GetReaderProvider (SymbolKind kind) + { + if (kind == SymbolKind.PortablePdb) + return new PortablePdbReaderProvider (); + if (kind == SymbolKind.EmbeddedPortablePdb) + return new EmbeddedPortablePdbReaderProvider (); + + var provider_name = GetSymbolTypeName (kind, "ReaderProvider"); + var type = GetSymbolType (kind, provider_name); + if (type == null) + throw new TypeLoadException ("Could not find symbol provider type " + provider_name); + + return (ISymbolReaderProvider)Activator.CreateInstance (type); + } + + static string GetSymbolTypeName (SymbolKind kind, string name) + { + return "MonoFN.Cecil" + "." + GetSymbolNamespace (kind) + "." + kind + name; + } + + static string GetSymbolNamespace (SymbolKind kind) + { + if (kind == SymbolKind.PortablePdb || kind == SymbolKind.EmbeddedPortablePdb) + return "Cil"; + if (kind == SymbolKind.NativePdb) + return "Pdb"; + if (kind == SymbolKind.Mdb) + return "Mdb"; + + throw new ArgumentException (); + } + } + + public interface ISymbolWriter : IDisposable { + + ISymbolReaderProvider GetReaderProvider (); + ImageDebugHeader GetDebugHeader (); + void Write (MethodDebugInformation info); + } + + public interface ISymbolWriterProvider { + + ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName); + ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream); + } + + public class DefaultSymbolWriterProvider : ISymbolWriterProvider { + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) + { + var reader = module.SymbolReader; + if (reader == null) + throw new InvalidOperationException (); + + if (module.Image != null && module.Image.HasDebugTables ()) + return null; + + return reader.GetWriterProvider ().GetSymbolWriter (module, fileName); + } + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) + { + throw new NotSupportedException (); + } + } +} + +namespace MonoFN.Cecil { + + static partial class Mixin { + + public static ImageDebugHeaderEntry GetCodeViewEntry (this ImageDebugHeader header) + { + return GetEntry (header, ImageDebugType.CodeView); + } + + public static ImageDebugHeaderEntry GetDeterministicEntry (this ImageDebugHeader header) + { + return GetEntry (header, ImageDebugType.Deterministic); + } + + public static ImageDebugHeader AddDeterministicEntry (this ImageDebugHeader header) + { + var entry = new ImageDebugHeaderEntry (new ImageDebugDirectory { Type = ImageDebugType.Deterministic }, Empty.Array); + if (header == null) + return new ImageDebugHeader (entry); + + var entries = new ImageDebugHeaderEntry [header.Entries.Length + 1]; + Array.Copy (header.Entries, entries, header.Entries.Length); + entries [entries.Length - 1] = entry; + return new ImageDebugHeader (entries); + } + + public static ImageDebugHeaderEntry GetEmbeddedPortablePdbEntry (this ImageDebugHeader header) + { + return GetEntry (header, ImageDebugType.EmbeddedPortablePdb); + } + + private static ImageDebugHeaderEntry GetEntry (this ImageDebugHeader header, ImageDebugType type) + { + if (!header.HasEntries) + return null; + + for (var i = 0; i < header.Entries.Length; i++) { + var entry = header.Entries [i]; + if (entry.Directory.Type == type) + return entry; + } + + return null; + } + + public static string GetPdbFileName (string assemblyFileName) + { + return Path.ChangeExtension (assemblyFileName, ".pdb"); + } + + public static string GetMdbFileName (string assemblyFileName) + { + return assemblyFileName + ".mdb"; + } + + public static bool IsPortablePdb (string fileName) + { + using (var file = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + return IsPortablePdb (file); + } + + public static bool IsPortablePdb (Stream stream) + { + const uint ppdb_signature = 0x424a5342; + + if (stream.Length < 4) return false; + var position = stream.Position; + try { + var reader = new BinaryReader (stream); + return reader.ReadUInt32 () == ppdb_signature; + } + finally { + stream.Position = position; + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs.meta new file mode 100644 index 0000000..f82ee9b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de9ae158807f471449a81d9b8b3e3c4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs new file mode 100644 index 0000000..b3da0a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs @@ -0,0 +1,29 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Cil { + + public sealed class VariableDefinition : VariableReference { + + public bool IsPinned { + get { return variable_type.IsPinned; } + } + + public VariableDefinition (TypeReference variableType) + : base (variableType) + { + } + + public override VariableDefinition Resolve () + { + return this; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs.meta new file mode 100644 index 0000000..b4e1886 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1346fa5ba8ac9e8418cc20d2d7d0ad21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs new file mode 100644 index 0000000..1957d8d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs @@ -0,0 +1,42 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Cil { + + public abstract class VariableReference { + + internal int index = -1; + protected TypeReference variable_type; + + public TypeReference VariableType { + get { return variable_type; } + set { variable_type = value; } + } + + public int Index { + get { return index; } + } + + internal VariableReference (TypeReference variable_type) + { + this.variable_type = variable_type; + } + + public abstract VariableDefinition Resolve (); + + public override string ToString () + { + if (index >= 0) + return "V_" + index; + + return string.Empty; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs.meta new file mode 100644 index 0000000..e951cc3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/VariableReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5dca1eaac23bfd4ba8e881302a72e33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata.meta new file mode 100644 index 0000000..8b4cde1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b0e9c3e91af12a4db473e2b25f2d8bd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs new file mode 100644 index 0000000..63dcd4d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs @@ -0,0 +1,54 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Metadata { + + sealed class BlobHeap : Heap { + + public BlobHeap (byte [] data) + : base (data) + { + } + + public byte [] Read (uint index) + { + if (index == 0 || index > this.data.Length - 1) + return Empty.Array; + + int position = (int)index; + int length = (int)data.ReadCompressedUInt32 (ref position); + + if (length > data.Length - position) + return Empty.Array; + + var buffer = new byte [length]; + + Buffer.BlockCopy (data, position, buffer, 0, length); + + return buffer; + } + + public void GetView (uint signature, out byte [] buffer, out int index, out int length) + { + if (signature == 0 || signature > data.Length - 1) { + buffer = null; + index = length = 0; + return; + } + + buffer = data; + + index = (int)signature; + length = (int)buffer.ReadCompressedUInt32 (ref index); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs.meta new file mode 100644 index 0000000..b6ef813 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/BlobHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33eef67f4a74e1c40a6bdb3da9d22d00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs new file mode 100644 index 0000000..7ab352c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs @@ -0,0 +1,499 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.PE; +using System; +using System.Collections.Generic; +using System.Text; +using RVA = System.UInt32; + +namespace MonoFN.Cecil.Metadata { + + sealed class TableHeapBuffer : HeapBuffer { + + readonly ModuleDefinition module; + readonly MetadataBuilder metadata; + + readonly internal TableInformation [] table_infos = new TableInformation [Mixin.TableCount]; + readonly internal MetadataTable [] tables = new MetadataTable [Mixin.TableCount]; + + bool large_string; + bool large_blob; + bool large_guid; + + readonly int [] coded_index_sizes = new int [Mixin.CodedIndexCount]; + readonly Func counter; + + internal uint [] string_offsets; + + public override bool IsEmpty { + get { return false; } + } + + public TableHeapBuffer (ModuleDefinition module, MetadataBuilder metadata) + : base (24) + { + this.module = module; + this.metadata = metadata; + this.counter = GetTableLength; + } + + int GetTableLength (Table table) + { + return (int)table_infos [(int)table].Length; + } + + public TTable GetTable (Table table) where TTable : MetadataTable, new() + { + var md_table = (TTable)tables [(int)table]; + if (md_table != null) + return md_table; + + md_table = new TTable (); + tables [(int)table] = md_table; + return md_table; + } + + public void WriteBySize (uint value, int size) + { + if (size == 4) + WriteUInt32 (value); + else + WriteUInt16 ((ushort)value); + } + + public void WriteBySize (uint value, bool large) + { + if (large) + WriteUInt32 (value); + else + WriteUInt16 ((ushort)value); + } + + public void WriteString (uint @string) + { + WriteBySize (string_offsets [@string], large_string); + } + + public void WriteBlob (uint blob) + { + WriteBySize (blob, large_blob); + } + + public void WriteGuid (uint guid) + { + WriteBySize (guid, large_guid); + } + + public void WriteRID (uint rid, Table table) + { + WriteBySize (rid, table_infos [(int)table].IsLarge); + } + + int GetCodedIndexSize (CodedIndex coded_index) + { + var index = (int)coded_index; + var size = coded_index_sizes [index]; + if (size != 0) + return size; + + return coded_index_sizes [index] = coded_index.GetSize (counter); + } + + public void WriteCodedRID (uint rid, CodedIndex coded_index) + { + WriteBySize (rid, GetCodedIndexSize (coded_index)); + } + + public void WriteTableHeap () + { + WriteUInt32 (0); // Reserved + WriteByte (GetTableHeapVersion ()); // MajorVersion + WriteByte (0); // MinorVersion + WriteByte (GetHeapSizes ()); // HeapSizes + WriteByte (10); // Reserved2 + WriteUInt64 (GetValid ()); // Valid + WriteUInt64 (0xc416003301fa00); // Sorted + + WriteRowCount (); + WriteTables (); + } + + void WriteRowCount () + { + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + WriteUInt32 ((uint)table.Length); + } + } + + void WriteTables () + { + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + table.Write (this); + } + } + + ulong GetValid () + { + ulong valid = 0; + + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + table.Sort (); + valid |= (1UL << i); + } + + return valid; + } + + public void ComputeTableInformations () + { + if (metadata.metadata_builder != null) + ComputeTableInformations (metadata.metadata_builder.table_heap); + + ComputeTableInformations (metadata.table_heap); + } + + void ComputeTableInformations (TableHeapBuffer table_heap) + { + var tables = table_heap.tables; + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table != null && table.Length > 0) + table_infos [i].Length = (uint)table.Length; + } + } + + byte GetHeapSizes () + { + byte heap_sizes = 0; + + if (metadata.string_heap.IsLarge) { + large_string = true; + heap_sizes |= 0x01; + } + + if (metadata.guid_heap.IsLarge) { + large_guid = true; + heap_sizes |= 0x02; + } + + if (metadata.blob_heap.IsLarge) { + large_blob = true; + heap_sizes |= 0x04; + } + + return heap_sizes; + } + + byte GetTableHeapVersion () + { + switch (module.Runtime) { + case TargetRuntime.Net_1_0: + case TargetRuntime.Net_1_1: + return 1; + default: + return 2; + } + } + + public void FixupData (RVA data_rva) + { + var table = GetTable (Table.FieldRVA); + if (table.length == 0) + return; + + var field_idx_size = GetTable (Table.Field).IsLarge ? 4 : 2; + var previous = this.position; + + base.position = table.position; + for (int i = 0; i < table.length; i++) { + var rva = ReadUInt32 (); + base.position -= 4; + WriteUInt32 (rva + data_rva); + base.position += field_idx_size; + } + + base.position = previous; + } + } + + sealed class ResourceBuffer : ByteBuffer { + + public ResourceBuffer () + : base (0) + { + } + + public uint AddResource (byte [] resource) + { + var offset = (uint)this.position; + WriteInt32 (resource.Length); + WriteBytes (resource); + return offset; + } + } + + sealed class DataBuffer : ByteBuffer { + + public DataBuffer () + : base (0) + { + } + + public RVA AddData (byte [] data) + { + var rva = (RVA)position; + WriteBytes (data); + return rva; + } + } + + abstract class HeapBuffer : ByteBuffer { + + public bool IsLarge { + get { return base.length > 65535; } + } + + public abstract bool IsEmpty { get; } + + protected HeapBuffer (int length) + : base (length) + { + } + } + + sealed class GuidHeapBuffer : HeapBuffer { + + readonly Dictionary guids = new Dictionary (); + + public override bool IsEmpty { + get { return length == 0; } + } + + public GuidHeapBuffer () + : base (16) + { + } + + public uint GetGuidIndex (Guid guid) + { + uint index; + if (guids.TryGetValue (guid, out index)) + return index; + + index = (uint)guids.Count + 1; + WriteGuid (guid); + guids.Add (guid, index); + return index; + } + + void WriteGuid (Guid guid) + { + WriteBytes (guid.ToByteArray ()); + } + } + + class StringHeapBuffer : HeapBuffer { + + protected Dictionary strings = new Dictionary (StringComparer.Ordinal); + + public sealed override bool IsEmpty { + get { return length <= 1; } + } + + public StringHeapBuffer () + : base (1) + { + WriteByte (0); + } + + public virtual uint GetStringIndex (string @string) + { + uint index; + if (strings.TryGetValue (@string, out index)) + return index; + + index = (uint)strings.Count + 1; + strings.Add (@string, index); + return index; + } + + public uint [] WriteStrings () + { + var sorted = SortStrings (strings); + strings = null; + + // Add 1 for empty string whose index and offset are both 0 + var string_offsets = new uint [sorted.Count + 1]; + string_offsets [0] = 0; + + // Find strings that can be folded + var previous = string.Empty; + foreach (var entry in sorted) { + var @string = entry.Key; + var index = entry.Value; + var position = base.position; + + if (previous.EndsWith (@string, StringComparison.Ordinal) && !IsLowSurrogateChar (entry.Key [0])) { + // Map over the tail of prev string. Watch for null-terminator of prev string. + string_offsets [index] = (uint)(position - (Encoding.UTF8.GetByteCount (entry.Key) + 1)); + } else { + string_offsets [index] = (uint)position; + WriteString (@string); + } + + previous = entry.Key; + } + + return string_offsets; + } + + static List> SortStrings (Dictionary strings) + { + var sorted = new List> (strings); + sorted.Sort (new SuffixSort ()); + return sorted; + } + + static bool IsLowSurrogateChar (int c) + { + return unchecked((uint)(c - 0xDC00)) <= 0xDFFF - 0xDC00; + } + + protected virtual void WriteString (string @string) + { + WriteBytes (Encoding.UTF8.GetBytes (@string)); + WriteByte (0); + } + + // Sorts strings such that a string is followed immediately by all strings + // that are a suffix of it. + private class SuffixSort : IComparer> { + + public int Compare (KeyValuePair xPair, KeyValuePair yPair) + { + var x = xPair.Key; + var y = yPair.Key; + + for (int i = x.Length - 1, j = y.Length - 1; i >= 0 & j >= 0; i--, j--) { + if (x [i] < y [j]) { + return -1; + } + + if (x [i] > y [j]) { + return +1; + } + } + + return y.Length.CompareTo (x.Length); + } + } + } + + sealed class BlobHeapBuffer : HeapBuffer { + + readonly Dictionary blobs = new Dictionary (new ByteBufferEqualityComparer ()); + + public override bool IsEmpty { + get { return length <= 1; } + } + + public BlobHeapBuffer () + : base (1) + { + WriteByte (0); + } + + public uint GetBlobIndex (ByteBuffer blob) + { + uint index; + if (blobs.TryGetValue (blob, out index)) + return index; + + index = (uint)base.position; + WriteBlob (blob); + blobs.Add (blob, index); + return index; + } + + void WriteBlob (ByteBuffer blob) + { + WriteCompressedUInt32 ((uint)blob.length); + WriteBytes (blob); + } + } + + sealed class UserStringHeapBuffer : StringHeapBuffer { + + public override uint GetStringIndex (string @string) + { + uint index; + if (strings.TryGetValue (@string, out index)) + return index; + + index = (uint)base.position; + WriteString (@string); + strings.Add (@string, index); + return index; + } + + protected override void WriteString (string @string) + { + WriteCompressedUInt32 ((uint)@string.Length * 2 + 1); + + byte special = 0; + + for (int i = 0; i < @string.Length; i++) { + var @char = @string [i]; + WriteUInt16 (@char); + + if (special == 1) + continue; + + if (@char < 0x20 || @char > 0x7e) { + if (@char > 0x7e + || (@char >= 0x01 && @char <= 0x08) + || (@char >= 0x0e && @char <= 0x1f) + || @char == 0x27 + || @char == 0x2d) { + + special = 1; + } + } + } + + WriteByte (special); + } + } + + sealed class PdbHeapBuffer : HeapBuffer { + + public override bool IsEmpty { + get { return false; } + } + + public PdbHeapBuffer () + : base (0) + { + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs.meta new file mode 100644 index 0000000..480046a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Buffers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b1d0a81b66e78341ab77acdd3b15234 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs new file mode 100644 index 0000000..601a347 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs @@ -0,0 +1,29 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Metadata { + + enum CodedIndex { + TypeDefOrRef, + HasConstant, + HasCustomAttribute, + HasFieldMarshal, + HasDeclSecurity, + MemberRefParent, + HasSemantics, + MethodDefOrRef, + MemberForwarded, + Implementation, + CustomAttributeType, + ResolutionScope, + TypeOrMethodDef, + HasCustomDebugInformation, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs.meta new file mode 100644 index 0000000..553ef4d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/CodedIndex.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd50ffa8272dac444831e33b1b9d7f56 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs new file mode 100644 index 0000000..8351286 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs @@ -0,0 +1,55 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Metadata { + + enum ElementType : byte { + None = 0x00, + Void = 0x01, + Boolean = 0x02, + Char = 0x03, + I1 = 0x04, + U1 = 0x05, + I2 = 0x06, + U2 = 0x07, + I4 = 0x08, + U4 = 0x09, + I8 = 0x0a, + U8 = 0x0b, + R4 = 0x0c, + R8 = 0x0d, + String = 0x0e, + Ptr = 0x0f, // Followed by token + ByRef = 0x10, // Followed by token + ValueType = 0x11, // Followed by token + Class = 0x12, // Followed by token + Var = 0x13, // Followed by generic parameter number + Array = 0x14, // + GenericInst = 0x15, // ... */ + TypedByRef = 0x16, + I = 0x18, // System.IntPtr + U = 0x19, // System.UIntPtr + FnPtr = 0x1b, // Followed by full method signature + Object = 0x1c, // System.Object + SzArray = 0x1d, // Single-dim array with 0 lower bound + MVar = 0x1e, // Followed by generic parameter number + CModReqD = 0x1f, // Required modifier : followed by a TypeDef or TypeRef token + CModOpt = 0x20, // Optional modifier : followed by a TypeDef or TypeRef token + Internal = 0x21, // Implemented within the CLI + Modifier = 0x40, // Or'd with following element types + Sentinel = 0x41, // Sentinel for varargs method signature + Pinned = 0x45, // Denotes a local variable that points at a pinned object + + // special undocumented constants + Type = 0x50, + Boxed = 0x51, + Enum = 0x55 + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs.meta new file mode 100644 index 0000000..58173f6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/ElementType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94c4cb498ef60034d83bb60d3f743832 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs new file mode 100644 index 0000000..ec9c644 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs @@ -0,0 +1,36 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Metadata { + + sealed class GuidHeap : Heap { + + public GuidHeap (byte [] data) + : base (data) + { + } + + public Guid Read (uint index) + { + const int guid_size = 16; + + if (index == 0 || ((index - 1) + guid_size) > data.Length) + return new Guid (); + + var buffer = new byte [guid_size]; + + Buffer.BlockCopy (this.data, (int)((index - 1) * guid_size), buffer, 0, guid_size); + + return new Guid (buffer); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs.meta new file mode 100644 index 0000000..eaabe77 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/GuidHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bb39ab6484eb114b91a85d4b53f0f28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs new file mode 100644 index 0000000..3cbb026 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs @@ -0,0 +1,24 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Metadata { + + abstract class Heap { + + public int IndexSize; + + readonly internal byte [] data; + + protected Heap (byte [] data) + { + this.data = data; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs.meta new file mode 100644 index 0000000..c0d849b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Heap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c343466f40d68574499155a2acd05e6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs new file mode 100644 index 0000000..50b2556 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs @@ -0,0 +1,94 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public struct MetadataToken : IEquatable { + + readonly uint token; + + public uint RID { + get { return token & 0x00ffffff; } + } + + public TokenType TokenType { + get { return (TokenType)(token & 0xff000000); } + } + + public static readonly MetadataToken Zero = new MetadataToken ((uint)0); + + public MetadataToken (uint token) + { + this.token = token; + } + + public MetadataToken (TokenType type) + : this (type, 0) + { + } + + public MetadataToken (TokenType type, uint rid) + { + token = (uint)type | rid; + } + + public MetadataToken (TokenType type, int rid) + { + token = (uint)type | (uint)rid; + } + + public int ToInt32 () + { + return (int)token; + } + + public uint ToUInt32 () + { + return token; + } + + public override int GetHashCode () + { + return (int)token; + } + + public bool Equals (MetadataToken other) + { + return other.token == token; + } + + public override bool Equals (object obj) + { + if (obj is MetadataToken) { + var other = (MetadataToken)obj; + return other.token == token; + } + + return false; + } + + public static bool operator == (MetadataToken one, MetadataToken other) + { + return one.token == other.token; + } + + public static bool operator != (MetadataToken one, MetadataToken other) + { + return one.token != other.token; + } + + public override string ToString () + { + return string.Format ("[{0}:0x{1}]", TokenType, RID.ToString ("x4")); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs.meta new file mode 100644 index 0000000..3026242 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/MetadataToken.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 755d1954236c374458be77d93493faf8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs new file mode 100644 index 0000000..6b56710 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs @@ -0,0 +1,32 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using RID = System.UInt32; + +namespace MonoFN.Cecil.Metadata { + + sealed class PdbHeap : Heap { + + public byte [] Id; + public RID EntryPoint; + public long TypeSystemTables; + public uint [] TypeSystemTableRows; + + public PdbHeap (byte [] data) + : base (data) + { + } + + public bool HasTable (Table table) + { + return (TypeSystemTables & (1L << (int)table)) != 0; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs.meta new file mode 100644 index 0000000..6505525 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/PdbHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c64dd6e20a2b11c44ad424d29380c14c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs new file mode 100644 index 0000000..880eeb3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs @@ -0,0 +1,152 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.Collections.Generic; + +namespace MonoFN.Cecil.Metadata { + + struct Row { + internal T1 Col1; + internal T2 Col2; + + public Row (T1 col1, T2 col2) + { + Col1 = col1; + Col2 = col2; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + + public Row (T1 col1, T2 col2, T3 col3) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + internal T6 Col6; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5, T6 col6) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + Col6 = col6; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + internal T6 Col6; + internal T7 Col7; + internal T8 Col8; + internal T9 Col9; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5, T6 col6, T7 col7, T8 col8, T9 col9) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + Col6 = col6; + Col7 = col7; + Col8 = col8; + Col9 = col9; + } + } + + sealed class RowEqualityComparer : IEqualityComparer>, IEqualityComparer>, IEqualityComparer> { + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2; + } + + public int GetHashCode (Row obj) + { + string x = obj.Col1, y = obj.Col2; + return (x != null ? x.GetHashCode () : 0) ^ (y != null ? y.GetHashCode () : 0); + } + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2; + } + + public int GetHashCode (Row obj) + { + return (int)(obj.Col1 ^ obj.Col2); + } + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2 + && x.Col3 == y.Col3; + } + + public int GetHashCode (Row obj) + { + return (int)(obj.Col1 ^ obj.Col2 ^ obj.Col3); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs.meta new file mode 100644 index 0000000..dc7d118 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Row.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89fd184bcc2b97840a2c0dfeec671be2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs new file mode 100644 index 0000000..22559df --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs @@ -0,0 +1,59 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.Collections.Generic; +using System.Text; + +namespace MonoFN.Cecil.Metadata { + + class StringHeap : Heap { + + readonly Dictionary strings = new Dictionary (); + + public StringHeap (byte [] data) + : base (data) + { + } + + public string Read (uint index) + { + if (index == 0) + return string.Empty; + + string @string; + if (strings.TryGetValue (index, out @string)) + return @string; + + if (index > data.Length - 1) + return string.Empty; + + @string = ReadStringAt (index); + if (@string.Length != 0) + strings.Add (index, @string); + + return @string; + } + + protected virtual string ReadStringAt (uint index) + { + int length = 0; + int start = (int)index; + + for (int i = start; ; i++) { + if (data [i] == 0) + break; + + length++; + } + + return Encoding.UTF8.GetString (data, start, length); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs.meta new file mode 100644 index 0000000..9e51e42 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/StringHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0fc64863ca825b4e994640b0be9a938 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs new file mode 100644 index 0000000..e4f206b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs @@ -0,0 +1,101 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Metadata { + + enum Table : byte { + Module = 0x00, + TypeRef = 0x01, + TypeDef = 0x02, + FieldPtr = 0x03, + Field = 0x04, + MethodPtr = 0x05, + Method = 0x06, + ParamPtr = 0x07, + Param = 0x08, + InterfaceImpl = 0x09, + MemberRef = 0x0a, + Constant = 0x0b, + CustomAttribute = 0x0c, + FieldMarshal = 0x0d, + DeclSecurity = 0x0e, + ClassLayout = 0x0f, + FieldLayout = 0x10, + StandAloneSig = 0x11, + EventMap = 0x12, + EventPtr = 0x13, + Event = 0x14, + PropertyMap = 0x15, + PropertyPtr = 0x16, + Property = 0x17, + MethodSemantics = 0x18, + MethodImpl = 0x19, + ModuleRef = 0x1a, + TypeSpec = 0x1b, + ImplMap = 0x1c, + FieldRVA = 0x1d, + EncLog = 0x1e, + EncMap = 0x1f, + Assembly = 0x20, + AssemblyProcessor = 0x21, + AssemblyOS = 0x22, + AssemblyRef = 0x23, + AssemblyRefProcessor = 0x24, + AssemblyRefOS = 0x25, + File = 0x26, + ExportedType = 0x27, + ManifestResource = 0x28, + NestedClass = 0x29, + GenericParam = 0x2a, + MethodSpec = 0x2b, + GenericParamConstraint = 0x2c, + + Document = 0x30, + MethodDebugInformation = 0x31, + LocalScope = 0x32, + LocalVariable = 0x33, + LocalConstant = 0x34, + ImportScope = 0x35, + StateMachineMethod = 0x36, + CustomDebugInformation = 0x37, + } + + struct TableInformation { + public uint Offset; + public uint Length; + public uint RowSize; + + public bool IsLarge { + get { return Length > ushort.MaxValue; } + } + } + + sealed class TableHeap : Heap { + + public long Valid; + public long Sorted; + + public readonly TableInformation [] Tables = new TableInformation [Mixin.TableCount]; + + public TableInformation this [Table table] { + get { return Tables [(int)table]; } + } + + public TableHeap (byte [] data) + : base (data) + { + } + + public bool HasTable (Table table) + { + return (Valid & (1L << (int)table)) != 0; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs.meta new file mode 100644 index 0000000..64fe6ce --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TableHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 978b1609b2ddc0c4baf628cc608456a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs new file mode 100644 index 0000000..e527181 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs @@ -0,0 +1,49 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum TokenType : uint { + Module = 0x00000000, + TypeRef = 0x01000000, + TypeDef = 0x02000000, + Field = 0x04000000, + Method = 0x06000000, + Param = 0x08000000, + InterfaceImpl = 0x09000000, + MemberRef = 0x0a000000, + CustomAttribute = 0x0c000000, + Permission = 0x0e000000, + Signature = 0x11000000, + Event = 0x14000000, + Property = 0x17000000, + ModuleRef = 0x1a000000, + TypeSpec = 0x1b000000, + Assembly = 0x20000000, + AssemblyRef = 0x23000000, + File = 0x26000000, + ExportedType = 0x27000000, + ManifestResource = 0x28000000, + GenericParam = 0x2a000000, + MethodSpec = 0x2b000000, + GenericParamConstraint = 0x2c000000, + + Document = 0x30000000, + MethodDebugInformation = 0x31000000, + LocalScope = 0x32000000, + LocalVariable = 0x33000000, + LocalConstant = 0x34000000, + ImportScope = 0x35000000, + StateMachineMethod = 0x36000000, + CustomDebugInformation = 0x37000000, + + String = 0x70000000, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs.meta new file mode 100644 index 0000000..7dd9eb4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/TokenType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dba0af6138c6a084b8787e88b20b142a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs new file mode 100644 index 0000000..afdaa2c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs @@ -0,0 +1,36 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil.Metadata { + + sealed class UserStringHeap : StringHeap { + + public UserStringHeap (byte [] data) + : base (data) + { + } + + protected override string ReadStringAt (uint index) + { + int start = (int)index; + + uint length = (uint)(data.ReadCompressedUInt32 (ref start) & ~1); + if (length < 1) + return string.Empty; + + var chars = new char [length / 2]; + + for (int i = start, j = 0; i < start + length; i += 2) + chars [j++] = (char)(data [i] | (data [i + 1] << 8)); + + return new string (chars); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs.meta new file mode 100644 index 0000000..40594bf --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/UserStringHeap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d89100b382ef8e4ea67917917d04db6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs new file mode 100644 index 0000000..c5a3b03 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs @@ -0,0 +1,649 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using System; + +namespace MonoFN.Cecil { + + static partial class Mixin { + + public const int TableCount = 58; + public const int CodedIndexCount = 14; + + public static uint ReadCompressedUInt32 (this byte [] data, ref int position) + { + uint integer; + if ((data [position] & 0x80) == 0) { + integer = data [position]; + position++; + } else if ((data [position] & 0x40) == 0) { + integer = (uint)(data [position] & ~0x80) << 8; + integer |= data [position + 1]; + position += 2; + } else { + integer = (uint)(data [position] & ~0xc0) << 24; + integer |= (uint)data [position + 1] << 16; + integer |= (uint)data [position + 2] << 8; + integer |= (uint)data [position + 3]; + position += 4; + } + return integer; + } + + public static MetadataToken GetMetadataToken (this CodedIndex self, uint data) + { + uint rid; + TokenType token_type; + switch (self) { + case CodedIndex.TypeDefOrRef: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.TypeRef; goto ret; + case 2: + token_type = TokenType.TypeSpec; goto ret; + default: + goto exit; + } + case CodedIndex.HasConstant: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Param; goto ret; + case 2: + token_type = TokenType.Property; goto ret; + default: + goto exit; + } + case CodedIndex.HasCustomAttribute: + rid = data >> 5; + switch (data & 31) { + case 0: + token_type = TokenType.Method; goto ret; + case 1: + token_type = TokenType.Field; goto ret; + case 2: + token_type = TokenType.TypeRef; goto ret; + case 3: + token_type = TokenType.TypeDef; goto ret; + case 4: + token_type = TokenType.Param; goto ret; + case 5: + token_type = TokenType.InterfaceImpl; goto ret; + case 6: + token_type = TokenType.MemberRef; goto ret; + case 7: + token_type = TokenType.Module; goto ret; + case 8: + token_type = TokenType.Permission; goto ret; + case 9: + token_type = TokenType.Property; goto ret; + case 10: + token_type = TokenType.Event; goto ret; + case 11: + token_type = TokenType.Signature; goto ret; + case 12: + token_type = TokenType.ModuleRef; goto ret; + case 13: + token_type = TokenType.TypeSpec; goto ret; + case 14: + token_type = TokenType.Assembly; goto ret; + case 15: + token_type = TokenType.AssemblyRef; goto ret; + case 16: + token_type = TokenType.File; goto ret; + case 17: + token_type = TokenType.ExportedType; goto ret; + case 18: + token_type = TokenType.ManifestResource; goto ret; + case 19: + token_type = TokenType.GenericParam; goto ret; + case 20: + token_type = TokenType.GenericParamConstraint; goto ret; + case 21: + token_type = TokenType.MethodSpec; goto ret; + default: + goto exit; + } + case CodedIndex.HasFieldMarshal: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Param; goto ret; + default: + goto exit; + } + case CodedIndex.HasDeclSecurity: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + case 2: + token_type = TokenType.Assembly; goto ret; + default: + goto exit; + } + case CodedIndex.MemberRefParent: + rid = data >> 3; + switch (data & 7) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.TypeRef; goto ret; + case 2: + token_type = TokenType.ModuleRef; goto ret; + case 3: + token_type = TokenType.Method; goto ret; + case 4: + token_type = TokenType.TypeSpec; goto ret; + default: + goto exit; + } + case CodedIndex.HasSemantics: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Event; goto ret; + case 1: + token_type = TokenType.Property; goto ret; + default: + goto exit; + } + case CodedIndex.MethodDefOrRef: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Method; goto ret; + case 1: + token_type = TokenType.MemberRef; goto ret; + default: + goto exit; + } + case CodedIndex.MemberForwarded: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + default: + goto exit; + } + case CodedIndex.Implementation: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.File; goto ret; + case 1: + token_type = TokenType.AssemblyRef; goto ret; + case 2: + token_type = TokenType.ExportedType; goto ret; + default: + goto exit; + } + case CodedIndex.CustomAttributeType: + rid = data >> 3; + switch (data & 7) { + case 2: + token_type = TokenType.Method; goto ret; + case 3: + token_type = TokenType.MemberRef; goto ret; + default: + goto exit; + } + case CodedIndex.ResolutionScope: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.Module; goto ret; + case 1: + token_type = TokenType.ModuleRef; goto ret; + case 2: + token_type = TokenType.AssemblyRef; goto ret; + case 3: + token_type = TokenType.TypeRef; goto ret; + default: + goto exit; + } + case CodedIndex.TypeOrMethodDef: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + default: goto exit; + } + case CodedIndex.HasCustomDebugInformation: + rid = data >> 5; + switch (data & 31) { + case 0: + token_type = TokenType.Method; goto ret; + case 1: + token_type = TokenType.Field; goto ret; + case 2: + token_type = TokenType.TypeRef; goto ret; + case 3: + token_type = TokenType.TypeDef; goto ret; + case 4: + token_type = TokenType.Param; goto ret; + case 5: + token_type = TokenType.InterfaceImpl; goto ret; + case 6: + token_type = TokenType.MemberRef; goto ret; + case 7: + token_type = TokenType.Module; goto ret; + case 8: + token_type = TokenType.Permission; goto ret; + case 9: + token_type = TokenType.Property; goto ret; + case 10: + token_type = TokenType.Event; goto ret; + case 11: + token_type = TokenType.Signature; goto ret; + case 12: + token_type = TokenType.ModuleRef; goto ret; + case 13: + token_type = TokenType.TypeSpec; goto ret; + case 14: + token_type = TokenType.Assembly; goto ret; + case 15: + token_type = TokenType.AssemblyRef; goto ret; + case 16: + token_type = TokenType.File; goto ret; + case 17: + token_type = TokenType.ExportedType; goto ret; + case 18: + token_type = TokenType.ManifestResource; goto ret; + case 19: + token_type = TokenType.GenericParam; goto ret; + case 20: + token_type = TokenType.GenericParamConstraint; goto ret; + case 21: + token_type = TokenType.MethodSpec; goto ret; + case 22: + token_type = TokenType.Document; goto ret; + case 23: + token_type = TokenType.LocalScope; goto ret; + case 24: + token_type = TokenType.LocalVariable; goto ret; + case 25: + token_type = TokenType.LocalConstant; goto ret; + case 26: + token_type = TokenType.ImportScope; goto ret; + default: + goto exit; + } + default: + goto exit; + } + ret: + return new MetadataToken (token_type, rid); + exit: + return MetadataToken.Zero; + } + + public static uint CompressMetadataToken (this CodedIndex self, MetadataToken token) + { + uint ret = 0; + if (token.RID == 0) + return ret; + switch (self) { + case CodedIndex.TypeDefOrRef: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.TypeRef: + return ret | 1; + case TokenType.TypeSpec: + return ret | 2; + default: + goto exit; + } + case CodedIndex.HasConstant: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Param: + return ret | 1; + case TokenType.Property: + return ret | 2; + default: + goto exit; + } + case CodedIndex.HasCustomAttribute: + ret = token.RID << 5; + switch (token.TokenType) { + case TokenType.Method: + return ret | 0; + case TokenType.Field: + return ret | 1; + case TokenType.TypeRef: + return ret | 2; + case TokenType.TypeDef: + return ret | 3; + case TokenType.Param: + return ret | 4; + case TokenType.InterfaceImpl: + return ret | 5; + case TokenType.MemberRef: + return ret | 6; + case TokenType.Module: + return ret | 7; + case TokenType.Permission: + return ret | 8; + case TokenType.Property: + return ret | 9; + case TokenType.Event: + return ret | 10; + case TokenType.Signature: + return ret | 11; + case TokenType.ModuleRef: + return ret | 12; + case TokenType.TypeSpec: + return ret | 13; + case TokenType.Assembly: + return ret | 14; + case TokenType.AssemblyRef: + return ret | 15; + case TokenType.File: + return ret | 16; + case TokenType.ExportedType: + return ret | 17; + case TokenType.ManifestResource: + return ret | 18; + case TokenType.GenericParam: + return ret | 19; + case TokenType.GenericParamConstraint: + return ret | 20; + case TokenType.MethodSpec: + return ret | 21; + default: + goto exit; + } + case CodedIndex.HasFieldMarshal: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Param: + return ret | 1; + default: + goto exit; + } + case CodedIndex.HasDeclSecurity: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.Method: + return ret | 1; + case TokenType.Assembly: + return ret | 2; + default: + goto exit; + } + case CodedIndex.MemberRefParent: + ret = token.RID << 3; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.TypeRef: + return ret | 1; + case TokenType.ModuleRef: + return ret | 2; + case TokenType.Method: + return ret | 3; + case TokenType.TypeSpec: + return ret | 4; + default: + goto exit; + } + case CodedIndex.HasSemantics: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Event: + return ret | 0; + case TokenType.Property: + return ret | 1; + default: + goto exit; + } + case CodedIndex.MethodDefOrRef: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Method: + return ret | 0; + case TokenType.MemberRef: + return ret | 1; + default: + goto exit; + } + case CodedIndex.MemberForwarded: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Method: + return ret | 1; + default: + goto exit; + } + case CodedIndex.Implementation: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.File: + return ret | 0; + case TokenType.AssemblyRef: + return ret | 1; + case TokenType.ExportedType: + return ret | 2; + default: + goto exit; + } + case CodedIndex.CustomAttributeType: + ret = token.RID << 3; + switch (token.TokenType) { + case TokenType.Method: + return ret | 2; + case TokenType.MemberRef: + return ret | 3; + default: + goto exit; + } + case CodedIndex.ResolutionScope: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.Module: + return ret | 0; + case TokenType.ModuleRef: + return ret | 1; + case TokenType.AssemblyRef: + return ret | 2; + case TokenType.TypeRef: + return ret | 3; + default: + goto exit; + } + case CodedIndex.TypeOrMethodDef: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.Method: + return ret | 1; + default: + goto exit; + } + case CodedIndex.HasCustomDebugInformation: + ret = token.RID << 5; + switch (token.TokenType) { + case TokenType.Method: + return ret | 0; + case TokenType.Field: + return ret | 1; + case TokenType.TypeRef: + return ret | 2; + case TokenType.TypeDef: + return ret | 3; + case TokenType.Param: + return ret | 4; + case TokenType.InterfaceImpl: + return ret | 5; + case TokenType.MemberRef: + return ret | 6; + case TokenType.Module: + return ret | 7; + case TokenType.Permission: + return ret | 8; + case TokenType.Property: + return ret | 9; + case TokenType.Event: + return ret | 10; + case TokenType.Signature: + return ret | 11; + case TokenType.ModuleRef: + return ret | 12; + case TokenType.TypeSpec: + return ret | 13; + case TokenType.Assembly: + return ret | 14; + case TokenType.AssemblyRef: + return ret | 15; + case TokenType.File: + return ret | 16; + case TokenType.ExportedType: + return ret | 17; + case TokenType.ManifestResource: + return ret | 18; + case TokenType.GenericParam: + return ret | 19; + case TokenType.GenericParamConstraint: + return ret | 20; + case TokenType.MethodSpec: + return ret | 21; + case TokenType.Document: + return ret | 22; + case TokenType.LocalScope: + return ret | 23; + case TokenType.LocalVariable: + return ret | 24; + case TokenType.LocalConstant: + return ret | 25; + case TokenType.ImportScope: + return ret | 26; + default: + goto exit; + } + default: + goto exit; + } + exit: + throw new ArgumentException (); + } + + public static int GetSize (this CodedIndex self, Func counter) + { + int bits; + Table [] tables; + + switch (self) { + case CodedIndex.TypeDefOrRef: + bits = 2; + tables = new [] { Table.TypeDef, Table.TypeRef, Table.TypeSpec }; + break; + case CodedIndex.HasConstant: + bits = 2; + tables = new [] { Table.Field, Table.Param, Table.Property }; + break; + case CodedIndex.HasCustomAttribute: + bits = 5; + tables = new [] { + Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef, + Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef, + Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType, + Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec, + }; + break; + case CodedIndex.HasFieldMarshal: + bits = 1; + tables = new [] { Table.Field, Table.Param }; + break; + case CodedIndex.HasDeclSecurity: + bits = 2; + tables = new [] { Table.TypeDef, Table.Method, Table.Assembly }; + break; + case CodedIndex.MemberRefParent: + bits = 3; + tables = new [] { Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method, Table.TypeSpec }; + break; + case CodedIndex.HasSemantics: + bits = 1; + tables = new [] { Table.Event, Table.Property }; + break; + case CodedIndex.MethodDefOrRef: + bits = 1; + tables = new [] { Table.Method, Table.MemberRef }; + break; + case CodedIndex.MemberForwarded: + bits = 1; + tables = new [] { Table.Field, Table.Method }; + break; + case CodedIndex.Implementation: + bits = 2; + tables = new [] { Table.File, Table.AssemblyRef, Table.ExportedType }; + break; + case CodedIndex.CustomAttributeType: + bits = 3; + tables = new [] { Table.Method, Table.MemberRef }; + break; + case CodedIndex.ResolutionScope: + bits = 2; + tables = new [] { Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef }; + break; + case CodedIndex.TypeOrMethodDef: + bits = 1; + tables = new [] { Table.TypeDef, Table.Method }; + break; + case CodedIndex.HasCustomDebugInformation: + bits = 5; + tables = new [] { + Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef, + Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef, + Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType, + Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec, + Table.Document, Table.LocalScope, Table.LocalVariable, Table.LocalConstant, Table.ImportScope, + }; + break; + default: + throw new ArgumentException (); + } + + int max = 0; + + for (int i = 0; i < tables.Length; i++) { + max = System.Math.Max (counter (tables [i]), max); + } + + return max < (1 << (16 - bits)) ? 2 : 4; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs.meta new file mode 100644 index 0000000..6fab64b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Metadata/Utilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4785957c0c546de4680e1196a57f66d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE.meta new file mode 100644 index 0000000..9797d0a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c654da31387b0a4ea2a1128a28ef87d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs new file mode 100644 index 0000000..c584ff8 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs @@ -0,0 +1,53 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.IO; + +namespace MonoFN.Cecil.PE { + + class BinaryStreamReader : BinaryReader { + + public int Position { + get { return (int)BaseStream.Position; } + set { BaseStream.Position = value; } + } + + public int Length { + get { return (int)BaseStream.Length; } + } + + public BinaryStreamReader (Stream stream) + : base (stream) + { + } + + public void Advance (int bytes) + { + BaseStream.Seek (bytes, SeekOrigin.Current); + } + + public void MoveTo (uint position) + { + BaseStream.Seek (position, SeekOrigin.Begin); + } + + public void Align (int align) + { + align--; + var position = Position; + Advance (((position + align) & ~align) - position); + } + + public DataDirectory ReadDataDirectory () + { + return new DataDirectory (ReadUInt32 (), ReadUInt32 ()); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs.meta new file mode 100644 index 0000000..a1d4c1d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7492ed3a048237443b99d7a25e806ce6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs new file mode 100644 index 0000000..34ad11a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs @@ -0,0 +1,88 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.IO; + +namespace MonoFN.Cecil.PE { + + class BinaryStreamWriter : BinaryWriter { + + public int Position { + get { return (int)BaseStream.Position; } + set { BaseStream.Position = value; } + } + + public BinaryStreamWriter (Stream stream) + : base (stream) + { + } + + public void WriteByte (byte value) + { + Write (value); + } + + public void WriteUInt16 (ushort value) + { + Write (value); + } + + public void WriteInt16 (short value) + { + Write (value); + } + + public void WriteUInt32 (uint value) + { + Write (value); + } + + public void WriteInt32 (int value) + { + Write (value); + } + + public void WriteUInt64 (ulong value) + { + Write (value); + } + + public void WriteBytes (byte [] bytes) + { + Write (bytes); + } + + public void WriteDataDirectory (DataDirectory directory) + { + Write (directory.VirtualAddress); + Write (directory.Size); + } + + public void WriteBuffer (ByteBuffer buffer) + { + Write (buffer.buffer, 0, buffer.length); + } + + protected void Advance (int bytes) + { + BaseStream.Seek (bytes, SeekOrigin.Current); + } + + public void Align (int align) + { + align--; + var position = Position; + var bytes = ((position + align) & ~align) - position; + + for (int i = 0; i < bytes; i++) + WriteByte (0); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs.meta new file mode 100644 index 0000000..2c0e298 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/BinaryStreamWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26d384e0dd0e44549a9faf09adbd0a41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs new file mode 100644 index 0000000..8e5c947 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs @@ -0,0 +1,335 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.PE { + + class ByteBuffer { + + internal byte [] buffer; + internal int length; + internal int position; + + public ByteBuffer () + { + this.buffer = Empty.Array; + } + + public ByteBuffer (int length) + { + this.buffer = new byte [length]; + } + + public ByteBuffer (byte [] buffer) + { + this.buffer = buffer ?? Empty.Array; + this.length = this.buffer.Length; + } + + public void Advance (int length) + { + position += length; + } + + public byte ReadByte () + { + return buffer [position++]; + } + + public sbyte ReadSByte () + { + return (sbyte)ReadByte (); + } + + public byte [] ReadBytes (int length) + { + var bytes = new byte [length]; + Buffer.BlockCopy (buffer, position, bytes, 0, length); + position += length; + return bytes; + } + + public ushort ReadUInt16 () + { + ushort value = (ushort)(buffer [position] + | (buffer [position + 1] << 8)); + position += 2; + return value; + } + + public short ReadInt16 () + { + return (short)ReadUInt16 (); + } + + public uint ReadUInt32 () + { + uint value = (uint)(buffer [position] + | (buffer [position + 1] << 8) + | (buffer [position + 2] << 16) + | (buffer [position + 3] << 24)); + position += 4; + return value; + } + + public int ReadInt32 () + { + return (int)ReadUInt32 (); + } + + public ulong ReadUInt64 () + { + uint low = ReadUInt32 (); + uint high = ReadUInt32 (); + + return (((ulong)high) << 32) | low; + } + + public long ReadInt64 () + { + return (long)ReadUInt64 (); + } + + public uint ReadCompressedUInt32 () + { + byte first = ReadByte (); + if ((first & 0x80) == 0) + return first; + + if ((first & 0x40) == 0) + return ((uint)(first & ~0x80) << 8) + | ReadByte (); + + return ((uint)(first & ~0xc0) << 24) + | (uint)ReadByte () << 16 + | (uint)ReadByte () << 8 + | ReadByte (); + } + + public int ReadCompressedInt32 () + { + var b = buffer [position]; + var u = (int)ReadCompressedUInt32 (); + var v = u >> 1; + if ((u & 1) == 0) + return v; + + switch (b & 0xc0) { + case 0: + case 0x40: + return v - 0x40; + case 0x80: + return v - 0x2000; + default: + return v - 0x10000000; + } + } + + public float ReadSingle () + { + if (!BitConverter.IsLittleEndian) { + var bytes = ReadBytes (4); + Array.Reverse (bytes); + return BitConverter.ToSingle (bytes, 0); + } + + float value = BitConverter.ToSingle (buffer, position); + position += 4; + return value; + } + + public double ReadDouble () + { + if (!BitConverter.IsLittleEndian) { + var bytes = ReadBytes (8); + Array.Reverse (bytes); + return BitConverter.ToDouble (bytes, 0); + } + + double value = BitConverter.ToDouble (buffer, position); + position += 8; + return value; + } + + public void WriteByte (byte value) + { + if (position == buffer.Length) + Grow (1); + + buffer [position++] = value; + + if (position > length) + length = position; + } + + public void WriteSByte (sbyte value) + { + WriteByte ((byte)value); + } + + public void WriteUInt16 (ushort value) + { + if (position + 2 > buffer.Length) + Grow (2); + + buffer [position++] = (byte)value; + buffer [position++] = (byte)(value >> 8); + + if (position > length) + length = position; + } + + public void WriteInt16 (short value) + { + WriteUInt16 ((ushort)value); + } + + public void WriteUInt32 (uint value) + { + if (position + 4 > buffer.Length) + Grow (4); + + buffer [position++] = (byte)value; + buffer [position++] = (byte)(value >> 8); + buffer [position++] = (byte)(value >> 16); + buffer [position++] = (byte)(value >> 24); + + if (position > length) + length = position; + } + + public void WriteInt32 (int value) + { + WriteUInt32 ((uint)value); + } + + public void WriteUInt64 (ulong value) + { + if (position + 8 > buffer.Length) + Grow (8); + + buffer [position++] = (byte)value; + buffer [position++] = (byte)(value >> 8); + buffer [position++] = (byte)(value >> 16); + buffer [position++] = (byte)(value >> 24); + buffer [position++] = (byte)(value >> 32); + buffer [position++] = (byte)(value >> 40); + buffer [position++] = (byte)(value >> 48); + buffer [position++] = (byte)(value >> 56); + + if (position > length) + length = position; + } + + public void WriteInt64 (long value) + { + WriteUInt64 ((ulong)value); + } + + public void WriteCompressedUInt32 (uint value) + { + if (value < 0x80) + WriteByte ((byte)value); + else if (value < 0x4000) { + WriteByte ((byte)(0x80 | (value >> 8))); + WriteByte ((byte)(value & 0xff)); + } else { + WriteByte ((byte)((value >> 24) | 0xc0)); + WriteByte ((byte)((value >> 16) & 0xff)); + WriteByte ((byte)((value >> 8) & 0xff)); + WriteByte ((byte)(value & 0xff)); + } + } + + public void WriteCompressedInt32 (int value) + { + if (value >= 0) { + WriteCompressedUInt32 ((uint)(value << 1)); + return; + } + + if (value > -0x40) + value = 0x40 + value; + else if (value >= -0x2000) + value = 0x2000 + value; + else if (value >= -0x20000000) + value = 0x20000000 + value; + + WriteCompressedUInt32 ((uint)((value << 1) | 1)); + } + + public void WriteBytes (byte [] bytes) + { + var length = bytes.Length; + if (position + length > buffer.Length) + Grow (length); + + Buffer.BlockCopy (bytes, 0, buffer, position, length); + position += length; + + if (position > this.length) + this.length = position; + } + + public void WriteBytes (int length) + { + if (position + length > buffer.Length) + Grow (length); + + position += length; + + if (position > this.length) + this.length = position; + } + + public void WriteBytes (ByteBuffer buffer) + { + if (position + buffer.length > this.buffer.Length) + Grow (buffer.length); + + Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length); + position += buffer.length; + + if (position > this.length) + this.length = position; + } + + public void WriteSingle (float value) + { + var bytes = BitConverter.GetBytes (value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse (bytes); + + WriteBytes (bytes); + } + + public void WriteDouble (double value) + { + var bytes = BitConverter.GetBytes (value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse (bytes); + + WriteBytes (bytes); + } + + void Grow (int desired) + { + var current = this.buffer; + var current_length = current.Length; + + var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)]; + Buffer.BlockCopy (current, 0, buffer, 0, current_length); + this.buffer = buffer; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs.meta new file mode 100644 index 0000000..15415a1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3752816249ea16e4aba70adb03f01673 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs new file mode 100644 index 0000000..25caec1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs @@ -0,0 +1,47 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.Collections.Generic; + +namespace MonoFN.Cecil.PE { + + sealed class ByteBufferEqualityComparer : IEqualityComparer { + + public bool Equals (ByteBuffer x, ByteBuffer y) + { + if (x.length != y.length) + return false; + + var x_buffer = x.buffer; + var y_buffer = y.buffer; + + for (int i = 0; i < x.length; i++) + if (x_buffer [i] != y_buffer [i]) + return false; + + return true; + } + + public int GetHashCode (ByteBuffer buffer) + { + // See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + const int fnv_offset_bias = unchecked((int)2166136261); + const int fnv_prime = 16777619; + + var hash_code = fnv_offset_bias; + var bytes = buffer.buffer; + + for (int i = 0; i < buffer.length; i++) + hash_code = unchecked((hash_code ^ bytes [i]) * fnv_prime); + + return hash_code; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs.meta new file mode 100644 index 0000000..402b21d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ByteBufferEqualityComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0db5f2f7f9a349d4d89e2329ffd563b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs new file mode 100644 index 0000000..81121af --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs @@ -0,0 +1,30 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using RVA = System.UInt32; + +namespace MonoFN.Cecil.PE { + + struct DataDirectory { + + public readonly RVA VirtualAddress; + public readonly uint Size; + + public bool IsZero { + get { return VirtualAddress == 0 && Size == 0; } + } + + public DataDirectory (RVA rva, uint size) + { + this.VirtualAddress = rva; + this.Size = size; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs.meta new file mode 100644 index 0000000..b196baa --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/DataDirectory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7cd272a7ff953734bbacab398dfc9fe8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs new file mode 100644 index 0000000..a129178 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs @@ -0,0 +1,169 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using System; +using System.IO; +using RVA = System.UInt32; + +namespace MonoFN.Cecil.PE { + + sealed class Image : IDisposable { + + public Disposable Stream; + public string FileName; + + public ModuleKind Kind; + public uint Characteristics; + public string RuntimeVersion; + public TargetArchitecture Architecture; + public ModuleCharacteristics DllCharacteristics; + public ushort LinkerVersion; + public ushort SubSystemMajor; + public ushort SubSystemMinor; + + public ImageDebugHeader DebugHeader; + + public Section [] Sections; + + public Section MetadataSection; + + public uint EntryPointToken; + public uint Timestamp; + public ModuleAttributes Attributes; + + public DataDirectory Win32Resources; + public DataDirectory Debug; + public DataDirectory Resources; + public DataDirectory StrongName; + + public StringHeap StringHeap; + public BlobHeap BlobHeap; + public UserStringHeap UserStringHeap; + public GuidHeap GuidHeap; + public TableHeap TableHeap; + public PdbHeap PdbHeap; + + readonly int [] coded_index_sizes = new int [14]; + + readonly Func counter; + + public Image () + { + counter = GetTableLength; + } + + public bool HasTable (Table table) + { + return GetTableLength (table) > 0; + } + + public int GetTableLength (Table table) + { + return (int)TableHeap [table].Length; + } + + public int GetTableIndexSize (Table table) + { + return GetTableLength (table) < 65536 ? 2 : 4; + } + + public int GetCodedIndexSize (CodedIndex coded_index) + { + var index = (int)coded_index; + var size = coded_index_sizes [index]; + if (size != 0) + return size; + + return coded_index_sizes [index] = coded_index.GetSize (counter); + } + + public uint ResolveVirtualAddress (RVA rva) + { + var section = GetSectionAtVirtualAddress (rva); + if (section == null) + throw new ArgumentOutOfRangeException (); + + return ResolveVirtualAddressInSection (rva, section); + } + + public uint ResolveVirtualAddressInSection (RVA rva, Section section) + { + return rva + section.PointerToRawData - section.VirtualAddress; + } + + public Section GetSection (string name) + { + var sections = this.Sections; + for (int i = 0; i < sections.Length; i++) { + var section = sections [i]; + if (section.Name == name) + return section; + } + + return null; + } + + public Section GetSectionAtVirtualAddress (RVA rva) + { + var sections = this.Sections; + for (int i = 0; i < sections.Length; i++) { + var section = sections [i]; + if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.SizeOfRawData) + return section; + } + + return null; + } + + BinaryStreamReader GetReaderAt (RVA rva) + { + var section = GetSectionAtVirtualAddress (rva); + if (section == null) + return null; + + var reader = new BinaryStreamReader (Stream.value); + reader.MoveTo (ResolveVirtualAddressInSection (rva, section)); + return reader; + } + + public TRet GetReaderAt (RVA rva, TItem item, Func read) where TRet : class + { + var position = Stream.value.Position; + try { + var reader = GetReaderAt (rva); + if (reader == null) + return null; + + return read (item, reader); + } + finally { + Stream.value.Position = position; + } + } + + public bool HasDebugTables () + { + return HasTable (Table.Document) + || HasTable (Table.MethodDebugInformation) + || HasTable (Table.LocalScope) + || HasTable (Table.LocalVariable) + || HasTable (Table.LocalConstant) + || HasTable (Table.StateMachineMethod) + || HasTable (Table.CustomDebugInformation); + } + + public void Dispose () + { + Stream.Dispose (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs.meta new file mode 100644 index 0000000..2978245 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Image.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be7f3ca6a9f5ad34db68702bd99778fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs new file mode 100644 index 0000000..8837e6b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs @@ -0,0 +1,793 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using System; +using System.IO; + +namespace MonoFN.Cecil.PE { + + sealed class ImageReader : BinaryStreamReader { + + readonly Image image; + + DataDirectory cli; + DataDirectory metadata; + + uint table_heap_offset; + + public ImageReader (Disposable stream, string file_name) + : base (stream.value) + { + image = new Image (); + image.Stream = stream; + image.FileName = file_name; + } + + void MoveTo (DataDirectory directory) + { + BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress); + } + + void ReadImage () + { + if (BaseStream.Length < 128) + throw new BadImageFormatException (); + + // - DOSHeader + + // PE 2 + // Start 58 + // Lfanew 4 + // End 64 + + if (ReadUInt16 () != 0x5a4d) + throw new BadImageFormatException (); + + Advance (58); + + MoveTo (ReadUInt32 ()); + + if (ReadUInt32 () != 0x00004550) + throw new BadImageFormatException (); + + // - PEFileHeader + + // Machine 2 + image.Architecture = ReadArchitecture (); + + // NumberOfSections 2 + ushort sections = ReadUInt16 (); + + // TimeDateStamp 4 + image.Timestamp = ReadUInt32 (); + // PointerToSymbolTable 4 + // NumberOfSymbols 4 + // OptionalHeaderSize 2 + Advance (10); + + // Characteristics 2 + ushort characteristics = ReadUInt16 (); + + ushort subsystem, dll_characteristics; + ReadOptionalHeaders (out subsystem, out dll_characteristics); + ReadSections (sections); + ReadCLIHeader (); + ReadMetadata (); + ReadDebugHeader (); + + image.Characteristics = characteristics; + image.Kind = GetModuleKind (characteristics, subsystem); + image.DllCharacteristics = (ModuleCharacteristics)dll_characteristics; + } + + TargetArchitecture ReadArchitecture () + { + return (TargetArchitecture)ReadUInt16 (); + } + + static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem) + { + if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll + return ModuleKind.Dll; + + if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui + return ModuleKind.Windows; + + return ModuleKind.Console; + } + + void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics) + { + // - PEOptionalHeader + // - StandardFieldsHeader + + // Magic 2 + bool pe64 = ReadUInt16 () == 0x20b; + + // pe32 || pe64 + + image.LinkerVersion = ReadUInt16 (); + // CodeSize 4 + // InitializedDataSize 4 + // UninitializedDataSize4 + // EntryPointRVA 4 + // BaseOfCode 4 + // BaseOfData 4 || 0 + + // - NTSpecificFieldsHeader + + // ImageBase 4 || 8 + // SectionAlignment 4 + // FileAlignement 4 + // OSMajor 2 + // OSMinor 2 + // UserMajor 2 + // UserMinor 2 + // SubSysMajor 2 + // SubSysMinor 2 + Advance (44); + + image.SubSystemMajor = ReadUInt16 (); + image.SubSystemMinor = ReadUInt16 (); + + // Reserved 4 + // ImageSize 4 + // HeaderSize 4 + // FileChecksum 4 + Advance (16); + + // SubSystem 2 + subsystem = ReadUInt16 (); + + // DLLFlags 2 + dll_characteristics = ReadUInt16 (); + // StackReserveSize 4 || 8 + // StackCommitSize 4 || 8 + // HeapReserveSize 4 || 8 + // HeapCommitSize 4 || 8 + // LoaderFlags 4 + // NumberOfDataDir 4 + + // - DataDirectoriesHeader + + // ExportTable 8 + // ImportTable 8 + + Advance (pe64 ? 56 : 40); + + // ResourceTable 8 + + image.Win32Resources = ReadDataDirectory (); + + // ExceptionTable 8 + // CertificateTable 8 + // BaseRelocationTable 8 + + Advance (24); + + // Debug 8 + image.Debug = ReadDataDirectory (); + + // Copyright 8 + // GlobalPtr 8 + // TLSTable 8 + // LoadConfigTable 8 + // BoundImport 8 + // IAT 8 + // DelayImportDescriptor8 + Advance (56); + + // CLIHeader 8 + cli = ReadDataDirectory (); + + if (cli.IsZero) + throw new BadImageFormatException (); + + // Reserved 8 + Advance (8); + } + + string ReadAlignedString (int length) + { + int read = 0; + var buffer = new char [length]; + while (read < length) { + var current = ReadByte (); + if (current == 0) + break; + + buffer [read++] = (char)current; + } + + Advance (-1 + ((read + 4) & ~3) - read); + + return new string (buffer, 0, read); + } + + string ReadZeroTerminatedString (int length) + { + int read = 0; + var buffer = new char [length]; + var bytes = ReadBytes (length); + while (read < length) { + var current = bytes [read]; + if (current == 0) + break; + + buffer [read++] = (char)current; + } + + return new string (buffer, 0, read); + } + + void ReadSections (ushort count) + { + var sections = new Section [count]; + + for (int i = 0; i < count; i++) { + var section = new Section (); + + // Name + section.Name = ReadZeroTerminatedString (8); + + // VirtualSize 4 + Advance (4); + + // VirtualAddress 4 + section.VirtualAddress = ReadUInt32 (); + // SizeOfRawData 4 + section.SizeOfRawData = ReadUInt32 (); + // PointerToRawData 4 + section.PointerToRawData = ReadUInt32 (); + + // PointerToRelocations 4 + // PointerToLineNumbers 4 + // NumberOfRelocations 2 + // NumberOfLineNumbers 2 + // Characteristics 4 + Advance (16); + + sections [i] = section; + } + + image.Sections = sections; + } + + void ReadCLIHeader () + { + MoveTo (cli); + + // - CLIHeader + + // Cb 4 + // MajorRuntimeVersion 2 + // MinorRuntimeVersion 2 + Advance (8); + + // Metadata 8 + metadata = ReadDataDirectory (); + // Flags 4 + image.Attributes = (ModuleAttributes)ReadUInt32 (); + // EntryPointToken 4 + image.EntryPointToken = ReadUInt32 (); + // Resources 8 + image.Resources = ReadDataDirectory (); + // StrongNameSignature 8 + image.StrongName = ReadDataDirectory (); + // CodeManagerTable 8 + // VTableFixups 8 + // ExportAddressTableJumps 8 + // ManagedNativeHeader 8 + } + + void ReadMetadata () + { + MoveTo (metadata); + + if (ReadUInt32 () != 0x424a5342) + throw new BadImageFormatException (); + + // MajorVersion 2 + // MinorVersion 2 + // Reserved 4 + Advance (8); + + image.RuntimeVersion = ReadZeroTerminatedString (ReadInt32 ()); + + // Flags 2 + Advance (2); + + var streams = ReadUInt16 (); + + var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress); + if (section == null) + throw new BadImageFormatException (); + + image.MetadataSection = section; + + for (int i = 0; i < streams; i++) + ReadMetadataStream (section); + + if (image.PdbHeap != null) + ReadPdbHeap (); + + if (image.TableHeap != null) + ReadTableHeap (); + } + + void ReadDebugHeader () + { + if (image.Debug.IsZero) { + image.DebugHeader = new ImageDebugHeader (Empty.Array); + return; + } + + MoveTo (image.Debug); + + var entries = new ImageDebugHeaderEntry [(int)image.Debug.Size / ImageDebugDirectory.Size]; + + for (int i = 0; i < entries.Length; i++) { + var directory = new ImageDebugDirectory { + Characteristics = ReadInt32 (), + TimeDateStamp = ReadInt32 (), + MajorVersion = ReadInt16 (), + MinorVersion = ReadInt16 (), + Type = (ImageDebugType)ReadInt32 (), + SizeOfData = ReadInt32 (), + AddressOfRawData = ReadInt32 (), + PointerToRawData = ReadInt32 (), + }; + + if (directory.PointerToRawData == 0 || directory.SizeOfData < 0) { + entries [i] = new ImageDebugHeaderEntry (directory, Empty.Array); + continue; + } + + var position = Position; + try { + MoveTo ((uint)directory.PointerToRawData); + var data = ReadBytes (directory.SizeOfData); + entries [i] = new ImageDebugHeaderEntry (directory, data); + } + finally { + Position = position; + } + } + + image.DebugHeader = new ImageDebugHeader (entries); + } + + void ReadMetadataStream (Section section) + { + // Offset 4 + uint offset = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start + + // Size 4 + uint size = ReadUInt32 (); + + var data = ReadHeapData (offset, size); + + var name = ReadAlignedString (16); + switch (name) { + case "#~": + case "#-": + image.TableHeap = new TableHeap (data); + table_heap_offset = offset; + break; + case "#Strings": + image.StringHeap = new StringHeap (data); + break; + case "#Blob": + image.BlobHeap = new BlobHeap (data); + break; + case "#GUID": + image.GuidHeap = new GuidHeap (data); + break; + case "#US": + image.UserStringHeap = new UserStringHeap (data); + break; + case "#Pdb": + image.PdbHeap = new PdbHeap (data); + break; + } + } + + byte [] ReadHeapData (uint offset, uint size) + { + var position = BaseStream.Position; + MoveTo (offset + image.MetadataSection.PointerToRawData); + var data = ReadBytes ((int)size); + BaseStream.Position = position; + + return data; + } + + void ReadTableHeap () + { + var heap = image.TableHeap; + + MoveTo (table_heap_offset + image.MetadataSection.PointerToRawData); + + // Reserved 4 + // MajorVersion 1 + // MinorVersion 1 + Advance (6); + + // HeapSizes 1 + var sizes = ReadByte (); + + // Reserved2 1 + Advance (1); + + // Valid 8 + heap.Valid = ReadInt64 (); + + // Sorted 8 + heap.Sorted = ReadInt64 (); + + if (image.PdbHeap != null) { + for (int i = 0; i < Mixin.TableCount; i++) { + if (!image.PdbHeap.HasTable ((Table)i)) + continue; + + heap.Tables [i].Length = image.PdbHeap.TypeSystemTableRows [i]; + } + } + + for (int i = 0; i < Mixin.TableCount; i++) { + if (!heap.HasTable ((Table)i)) + continue; + + heap.Tables [i].Length = ReadUInt32 (); + } + + SetIndexSize (image.StringHeap, sizes, 0x1); + SetIndexSize (image.GuidHeap, sizes, 0x2); + SetIndexSize (image.BlobHeap, sizes, 0x4); + + ComputeTableInformations (); + } + + static void SetIndexSize (Heap heap, uint sizes, byte flag) + { + if (heap == null) + return; + + heap.IndexSize = (sizes & flag) > 0 ? 4 : 2; + } + + int GetTableIndexSize (Table table) + { + return image.GetTableIndexSize (table); + } + + int GetCodedIndexSize (CodedIndex index) + { + return image.GetCodedIndexSize (index); + } + + void ComputeTableInformations () + { + uint offset = (uint)BaseStream.Position - table_heap_offset - image.MetadataSection.PointerToRawData; // header + + int stridx_size = image.StringHeap != null ? image.StringHeap.IndexSize : 2; + int guididx_size = image.GuidHeap != null ? image.GuidHeap.IndexSize : 2; + int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2; + + var heap = image.TableHeap; + var tables = heap.Tables; + + for (int i = 0; i < Mixin.TableCount; i++) { + var table = (Table)i; + if (!heap.HasTable (table)) + continue; + + int size; + switch (table) { + case Table.Module: + size = 2 // Generation + + stridx_size // Name + + (guididx_size * 3); // Mvid, EncId, EncBaseId + break; + case Table.TypeRef: + size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope + + (stridx_size * 2); // Name, Namespace + break; + case Table.TypeDef: + size = 4 // Flags + + (stridx_size * 2) // Name, Namespace + + GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType + + GetTableIndexSize (Table.Field) // FieldList + + GetTableIndexSize (Table.Method); // MethodList + break; + case Table.FieldPtr: + size = GetTableIndexSize (Table.Field); // Field + break; + case Table.Field: + size = 2 // Flags + + stridx_size // Name + + blobidx_size; // Signature + break; + case Table.MethodPtr: + size = GetTableIndexSize (Table.Method); // Method + break; + case Table.Method: + size = 8 // Rva 4, ImplFlags 2, Flags 2 + + stridx_size // Name + + blobidx_size // Signature + + GetTableIndexSize (Table.Param); // ParamList + break; + case Table.ParamPtr: + size = GetTableIndexSize (Table.Param); // Param + break; + case Table.Param: + size = 4 // Flags 2, Sequence 2 + + stridx_size; // Name + break; + case Table.InterfaceImpl: + size = GetTableIndexSize (Table.TypeDef) // Class + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Interface + break; + case Table.MemberRef: + size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class + + stridx_size // Name + + blobidx_size; // Signature + break; + case Table.Constant: + size = 2 // Type + + GetCodedIndexSize (CodedIndex.HasConstant) // Parent + + blobidx_size; // Value + break; + case Table.CustomAttribute: + size = GetCodedIndexSize (CodedIndex.HasCustomAttribute) // Parent + + GetCodedIndexSize (CodedIndex.CustomAttributeType) // Type + + blobidx_size; // Value + break; + case Table.FieldMarshal: + size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent + + blobidx_size; // NativeType + break; + case Table.DeclSecurity: + size = 2 // Action + + GetCodedIndexSize (CodedIndex.HasDeclSecurity) // Parent + + blobidx_size; // PermissionSet + break; + case Table.ClassLayout: + size = 6 // PackingSize 2, ClassSize 4 + + GetTableIndexSize (Table.TypeDef); // Parent + break; + case Table.FieldLayout: + size = 4 // Offset + + GetTableIndexSize (Table.Field); // Field + break; + case Table.StandAloneSig: + size = blobidx_size; // Signature + break; + case Table.EventMap: + size = GetTableIndexSize (Table.TypeDef) // Parent + + GetTableIndexSize (Table.Event); // EventList + break; + case Table.EventPtr: + size = GetTableIndexSize (Table.Event); // Event + break; + case Table.Event: + size = 2 // Flags + + stridx_size // Name + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // EventType + break; + case Table.PropertyMap: + size = GetTableIndexSize (Table.TypeDef) // Parent + + GetTableIndexSize (Table.Property); // PropertyList + break; + case Table.PropertyPtr: + size = GetTableIndexSize (Table.Property); // Property + break; + case Table.Property: + size = 2 // Flags + + stridx_size // Name + + blobidx_size; // Type + break; + case Table.MethodSemantics: + size = 2 // Semantics + + GetTableIndexSize (Table.Method) // Method + + GetCodedIndexSize (CodedIndex.HasSemantics); // Association + break; + case Table.MethodImpl: + size = GetTableIndexSize (Table.TypeDef) // Class + + GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody + + GetCodedIndexSize (CodedIndex.MethodDefOrRef); // MethodDeclaration + break; + case Table.ModuleRef: + size = stridx_size; // Name + break; + case Table.TypeSpec: + size = blobidx_size; // Signature + break; + case Table.ImplMap: + size = 2 // MappingFlags + + GetCodedIndexSize (CodedIndex.MemberForwarded) // MemberForwarded + + stridx_size // ImportName + + GetTableIndexSize (Table.ModuleRef); // ImportScope + break; + case Table.FieldRVA: + size = 4 // RVA + + GetTableIndexSize (Table.Field); // Field + break; + case Table.EncLog: + size = 8; + break; + case Table.EncMap: + size = 4; + break; + case Table.Assembly: + size = 16 // HashAlgId 4, Version 4 * 2, Flags 4 + + blobidx_size // PublicKey + + (stridx_size * 2); // Name, Culture + break; + case Table.AssemblyProcessor: + size = 4; // Processor + break; + case Table.AssemblyOS: + size = 12; // Platform 4, Version 2 * 4 + break; + case Table.AssemblyRef: + size = 12 // Version 2 * 4 + Flags 4 + + (blobidx_size * 2) // PublicKeyOrToken, HashValue + + (stridx_size * 2); // Name, Culture + break; + case Table.AssemblyRefProcessor: + size = 4 // Processor + + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef + break; + case Table.AssemblyRefOS: + size = 12 // Platform 4, Version 2 * 4 + + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef + break; + case Table.File: + size = 4 // Flags + + stridx_size // Name + + blobidx_size; // HashValue + break; + case Table.ExportedType: + size = 8 // Flags 4, TypeDefId 4 + + (stridx_size * 2) // Name, Namespace + + GetCodedIndexSize (CodedIndex.Implementation); // Implementation + break; + case Table.ManifestResource: + size = 8 // Offset, Flags + + stridx_size // Name + + GetCodedIndexSize (CodedIndex.Implementation); // Implementation + break; + case Table.NestedClass: + size = GetTableIndexSize (Table.TypeDef) // NestedClass + + GetTableIndexSize (Table.TypeDef); // EnclosingClass + break; + case Table.GenericParam: + size = 4 // Number, Flags + + GetCodedIndexSize (CodedIndex.TypeOrMethodDef) // Owner + + stridx_size; // Name + break; + case Table.MethodSpec: + size = GetCodedIndexSize (CodedIndex.MethodDefOrRef) // Method + + blobidx_size; // Instantiation + break; + case Table.GenericParamConstraint: + size = GetTableIndexSize (Table.GenericParam) // Owner + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Constraint + break; + case Table.Document: + size = blobidx_size // Name + + guididx_size // HashAlgorithm + + blobidx_size // Hash + + guididx_size; // Language + break; + case Table.MethodDebugInformation: + size = GetTableIndexSize (Table.Document) // Document + + blobidx_size; // SequencePoints + break; + case Table.LocalScope: + size = GetTableIndexSize (Table.Method) // Method + + GetTableIndexSize (Table.ImportScope) // ImportScope + + GetTableIndexSize (Table.LocalVariable) // VariableList + + GetTableIndexSize (Table.LocalConstant) // ConstantList + + 4 * 2; // StartOffset, Length + break; + case Table.LocalVariable: + size = 2 // Attributes + + 2 // Index + + stridx_size; // Name + break; + case Table.LocalConstant: + size = stridx_size // Name + + blobidx_size; // Signature + break; + case Table.ImportScope: + size = GetTableIndexSize (Table.ImportScope) // Parent + + blobidx_size; + break; + case Table.StateMachineMethod: + size = GetTableIndexSize (Table.Method) // MoveNextMethod + + GetTableIndexSize (Table.Method); // KickOffMethod + break; + case Table.CustomDebugInformation: + size = GetCodedIndexSize (CodedIndex.HasCustomDebugInformation) // Parent + + guididx_size // Kind + + blobidx_size; // Value + break; + default: + throw new NotSupportedException (); + } + + tables [i].RowSize = (uint)size; + tables [i].Offset = offset; + + offset += (uint)size * tables [i].Length; + } + } + + void ReadPdbHeap () + { + var heap = image.PdbHeap; + + var buffer = new ByteBuffer (heap.data); + + heap.Id = buffer.ReadBytes (20); + heap.EntryPoint = buffer.ReadUInt32 (); + heap.TypeSystemTables = buffer.ReadInt64 (); + heap.TypeSystemTableRows = new uint [Mixin.TableCount]; + + for (int i = 0; i < Mixin.TableCount; i++) { + var table = (Table)i; + if (!heap.HasTable (table)) + continue; + + heap.TypeSystemTableRows [i] = buffer.ReadUInt32 (); + } + } + + public static Image ReadImage (Disposable stream, string file_name) + { + try { + var reader = new ImageReader (stream, file_name); + reader.ReadImage (); + return reader.image; + } + catch (EndOfStreamException e) { + throw new BadImageFormatException (stream.value.GetFileName (), e); + } + } + + public static Image ReadPortablePdb (Disposable stream, string file_name) + { + try { + var reader = new ImageReader (stream, file_name); + var length = (uint)stream.value.Length; + + reader.image.Sections = new [] { + new Section { + PointerToRawData = 0, + SizeOfRawData = length, + VirtualAddress = 0, + VirtualSize = length, + } + }; + + reader.metadata = new DataDirectory (0, length); + reader.ReadMetadata (); + return reader.image; + } + catch (EndOfStreamException e) { + throw new BadImageFormatException (stream.value.GetFileName (), e); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs.meta new file mode 100644 index 0000000..a001d10 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba04d4e3389423e47b35aaccee205576 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs new file mode 100644 index 0000000..061a95f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs @@ -0,0 +1,860 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using System; +using System.IO; +using RVA = System.UInt32; + +namespace MonoFN.Cecil.PE { + + sealed class ImageWriter : BinaryStreamWriter { + + readonly ModuleDefinition module; + readonly MetadataBuilder metadata; + readonly TextMap text_map; + readonly internal Disposable stream; + + readonly string runtime_version; + + ImageDebugHeader debug_header; + + ByteBuffer win32_resources; + + const uint pe_header_size = 0x98u; + const uint section_header_size = 0x28u; + const uint file_alignment = 0x200; + const uint section_alignment = 0x2000; + const ulong image_base = 0x00400000; + + internal const RVA text_rva = 0x2000; + + readonly bool pe64; + readonly bool has_reloc; + + internal Section text; + internal Section rsrc; + internal Section reloc; + + ushort sections; + + ImageWriter (ModuleDefinition module, string runtime_version, MetadataBuilder metadata, Disposable stream, bool metadataOnly = false) + : base (stream.value) + { + this.module = module; + this.runtime_version = runtime_version; + this.text_map = metadata.text_map; + this.stream = stream; + this.metadata = metadata; + if (metadataOnly) + return; + + this.pe64 = module.Architecture == TargetArchitecture.AMD64 || module.Architecture == TargetArchitecture.IA64 || module.Architecture == TargetArchitecture.ARM64; + this.has_reloc = module.Architecture == TargetArchitecture.I386; + this.GetDebugHeader (); + this.GetWin32Resources (); + this.BuildTextMap (); + this.sections = (ushort)(has_reloc ? 2 : 1); // text + reloc? + } + + void GetDebugHeader () + { + var symbol_writer = metadata.symbol_writer; + if (symbol_writer != null) + debug_header = symbol_writer.GetDebugHeader (); + + if (module.HasDebugHeader) { + var header = module.GetDebugHeader (); + var deterministic = header.GetDeterministicEntry (); + if (deterministic == null) + return; + + debug_header = debug_header.AddDeterministicEntry (); + } + } + + void GetWin32Resources () + { + if (!module.HasImage) + return; + + DataDirectory win32_resources_directory = module.Image.Win32Resources; + var size = win32_resources_directory.Size; + + if (size > 0) { + win32_resources = module.Image.GetReaderAt (win32_resources_directory.VirtualAddress, size, (s, reader) => new ByteBuffer (reader.ReadBytes ((int)s))); + } + } + + public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable stream) + { + var writer = new ImageWriter (module, module.runtime_version, metadata, stream); + writer.BuildSections (); + return writer; + } + + public static ImageWriter CreateDebugWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable stream) + { + var writer = new ImageWriter (module, "PDB v1.0", metadata, stream, metadataOnly: true); + var length = metadata.text_map.GetLength (); + writer.text = new Section { SizeOfRawData = length, VirtualSize = length }; + return writer; + } + + void BuildSections () + { + var has_win32_resources = win32_resources != null; + if (has_win32_resources) + sections++; + + text = CreateSection (".text", text_map.GetLength (), null); + var previous = text; + + if (has_win32_resources) { + rsrc = CreateSection (".rsrc", (uint)win32_resources.length, previous); + + PatchWin32Resources (win32_resources); + previous = rsrc; + } + + if (has_reloc) + reloc = CreateSection (".reloc", 12u, previous); + } + + Section CreateSection (string name, uint size, Section previous) + { + return new Section { + Name = name, + VirtualAddress = previous != null + ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment) + : text_rva, + VirtualSize = size, + PointerToRawData = previous != null + ? previous.PointerToRawData + previous.SizeOfRawData + : Align (GetHeaderSize (), file_alignment), + SizeOfRawData = Align (size, file_alignment) + }; + } + + static uint Align (uint value, uint align) + { + align--; + return (value + align) & ~align; + } + + void WriteDOSHeader () + { + Write (new byte [] { + // dos header start + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + // lfanew + 0x80, 0x00, 0x00, 0x00, + // dos header end + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, + 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, + 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, + 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }); + } + + ushort SizeOfOptionalHeader () + { + return (ushort)(!pe64 ? 0xe0 : 0xf0); + } + + void WritePEFileHeader () + { + WriteUInt32 (0x00004550); // Magic + WriteUInt16 ((ushort)module.Architecture); // Machine + WriteUInt16 (sections); // NumberOfSections + WriteUInt32 (metadata.timestamp); + WriteUInt32 (0); // PointerToSymbolTable + WriteUInt32 (0); // NumberOfSymbols + WriteUInt16 (SizeOfOptionalHeader ()); // SizeOfOptionalHeader + + const ushort LargeAddressAware = 0x0020; + + // ExecutableImage | (!pe64 ? 32BitsMachine : LargeAddressAware) + var characteristics = (ushort)(0x0002 | (!pe64 ? 0x0100 : LargeAddressAware)); + if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule) + characteristics |= 0x2000; + + if (module.Image != null && (module.Image.Characteristics & LargeAddressAware) != 0) + characteristics |= LargeAddressAware; + + WriteUInt16 (characteristics); // Characteristics + } + + Section LastSection () + { + if (reloc != null) + return reloc; + + if (rsrc != null) + return rsrc; + + return text; + } + + void WriteOptionalHeaders () + { + WriteUInt16 ((ushort)(!pe64 ? 0x10b : 0x20b)); // Magic + WriteUInt16 (module.linker_version); + WriteUInt32 (text.SizeOfRawData); // CodeSize + WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0) + + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize + WriteUInt32 (0); // UninitializedDataSize + + var startub_stub = text_map.GetRange (TextSegment.StartupStub); + WriteUInt32 (startub_stub.Length > 0 ? startub_stub.Start : 0); // EntryPointRVA + WriteUInt32 (text_rva); // BaseOfCode + + if (!pe64) { + WriteUInt32 (0); // BaseOfData + WriteUInt32 ((uint)image_base); // ImageBase + } else { + WriteUInt64 (image_base); // ImageBase + } + + WriteUInt32 (section_alignment); // SectionAlignment + WriteUInt32 (file_alignment); // FileAlignment + + WriteUInt16 (4); // OSMajor + WriteUInt16 (0); // OSMinor + WriteUInt16 (0); // UserMajor + WriteUInt16 (0); // UserMinor + WriteUInt16 (module.subsystem_major); // SubSysMajor + WriteUInt16 (module.subsystem_minor); // SubSysMinor + WriteUInt32 (0); // Reserved + + var last_section = LastSection (); + WriteUInt32 (last_section.VirtualAddress + Align (last_section.VirtualSize, section_alignment)); // ImageSize + WriteUInt32 (text.PointerToRawData); // HeaderSize + + WriteUInt32 (0); // Checksum + WriteUInt16 (GetSubSystem ()); // SubSystem + WriteUInt16 ((ushort)module.Characteristics); // DLLFlags + + if (!pe64) { + const uint stack_reserve = 0x100000; + const uint stack_commit = 0x1000; + const uint heap_reserve = 0x100000; + const uint heap_commit = 0x1000; + + WriteUInt32 (stack_reserve); + WriteUInt32 (stack_commit); + WriteUInt32 (heap_reserve); + WriteUInt32 (heap_commit); + } else { + const ulong stack_reserve = 0x400000; + const ulong stack_commit = 0x4000; + const ulong heap_reserve = 0x100000; + const ulong heap_commit = 0x2000; + + WriteUInt64 (stack_reserve); + WriteUInt64 (stack_commit); + WriteUInt64 (heap_reserve); + WriteUInt64 (heap_commit); + } + + WriteUInt32 (0); // LoaderFlags + WriteUInt32 (16); // NumberOfDataDir + + WriteZeroDataDirectory (); // ExportTable + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable + if (rsrc != null) { // ResourceTable + WriteUInt32 (rsrc.VirtualAddress); + WriteUInt32 (rsrc.VirtualSize); + } else + WriteZeroDataDirectory (); + + WriteZeroDataDirectory (); // ExceptionTable + WriteZeroDataDirectory (); // CertificateTable + WriteUInt32 (reloc != null ? reloc.VirtualAddress : 0); // BaseRelocationTable + WriteUInt32 (reloc != null ? reloc.VirtualSize : 0); + + if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { + WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory)); + WriteUInt32 ((uint)(debug_header.Entries.Length * ImageDebugDirectory.Size)); + } else + WriteZeroDataDirectory (); + + WriteZeroDataDirectory (); // Copyright + WriteZeroDataDirectory (); // GlobalPtr + WriteZeroDataDirectory (); // TLSTable + WriteZeroDataDirectory (); // LoadConfigTable + WriteZeroDataDirectory (); // BoundImport + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT + WriteZeroDataDirectory (); // DelayImportDesc + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader + WriteZeroDataDirectory (); // Reserved + } + + void WriteZeroDataDirectory () + { + WriteUInt32 (0); + WriteUInt32 (0); + } + + ushort GetSubSystem () + { + switch (module.Kind) { + case ModuleKind.Console: + case ModuleKind.Dll: + case ModuleKind.NetModule: + return 0x3; + case ModuleKind.Windows: + return 0x2; + default: + throw new ArgumentOutOfRangeException (); + } + } + + void WriteSectionHeaders () + { + WriteSection (text, 0x60000020); + + if (rsrc != null) + WriteSection (rsrc, 0x40000040); + + if (reloc != null) + WriteSection (reloc, 0x42000040); + } + + void WriteSection (Section section, uint characteristics) + { + var name = new byte [8]; + var sect_name = section.Name; + for (int i = 0; i < sect_name.Length; i++) + name [i] = (byte)sect_name [i]; + + WriteBytes (name); + WriteUInt32 (section.VirtualSize); + WriteUInt32 (section.VirtualAddress); + WriteUInt32 (section.SizeOfRawData); + WriteUInt32 (section.PointerToRawData); + WriteUInt32 (0); // PointerToRelocations + WriteUInt32 (0); // PointerToLineNumbers + WriteUInt16 (0); // NumberOfRelocations + WriteUInt16 (0); // NumberOfLineNumbers + WriteUInt32 (characteristics); + } + + uint GetRVAFileOffset (Section section, RVA rva) + { + return section.PointerToRawData + rva - section.VirtualAddress; + } + + void MoveTo (uint pointer) + { + BaseStream.Seek (pointer, SeekOrigin.Begin); + } + + void MoveToRVA (Section section, RVA rva) + { + BaseStream.Seek (GetRVAFileOffset (section, rva), SeekOrigin.Begin); + } + + void MoveToRVA (TextSegment segment) + { + MoveToRVA (text, text_map.GetRVA (segment)); + } + + void WriteRVA (RVA rva) + { + if (!pe64) + WriteUInt32 (rva); + else + WriteUInt64 (rva); + } + + void PrepareSection (Section section) + { + MoveTo (section.PointerToRawData); + + const int buffer_size = 4096; + + if (section.SizeOfRawData <= buffer_size) { + Write (new byte [section.SizeOfRawData]); + MoveTo (section.PointerToRawData); + return; + } + + var written = 0; + var buffer = new byte [buffer_size]; + while (written != section.SizeOfRawData) { + var write_size = System.Math.Min ((int)section.SizeOfRawData - written, buffer_size); + Write (buffer, 0, write_size); + written += write_size; + } + + MoveTo (section.PointerToRawData); + } + + void WriteText () + { + PrepareSection (text); + + // ImportAddressTable + + if (has_reloc) { + WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable)); + WriteRVA (0); + } + + // CLIHeader + + WriteUInt32 (0x48); + WriteUInt16 (2); + WriteUInt16 ((ushort)((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5)); + + WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader)); + WriteUInt32 (GetMetadataLength ()); + WriteUInt32 ((uint)module.Attributes); + WriteUInt32 (metadata.entry_point.ToUInt32 ()); + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources)); + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature)); + WriteZeroDataDirectory (); // CodeManagerTable + WriteZeroDataDirectory (); // VTableFixups + WriteZeroDataDirectory (); // ExportAddressTableJumps + WriteZeroDataDirectory (); // ManagedNativeHeader + + // Code + + MoveToRVA (TextSegment.Code); + WriteBuffer (metadata.code); + + // Resources + + MoveToRVA (TextSegment.Resources); + WriteBuffer (metadata.resources); + + // Data + + if (metadata.data.length > 0) { + MoveToRVA (TextSegment.Data); + WriteBuffer (metadata.data); + } + + // StrongNameSignature + // stays blank + + // MetadataHeader + + MoveToRVA (TextSegment.MetadataHeader); + WriteMetadataHeader (); + + WriteMetadata (); + + // DebugDirectory + if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { + MoveToRVA (TextSegment.DebugDirectory); + WriteDebugDirectory (); + } + + if (!has_reloc) + return; + + // ImportDirectory + MoveToRVA (TextSegment.ImportDirectory); + WriteImportDirectory (); + + // StartupStub + MoveToRVA (TextSegment.StartupStub); + WriteStartupStub (); + } + + uint GetMetadataLength () + { + return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader); + } + + public void WriteMetadataHeader () + { + WriteUInt32 (0x424a5342); // Signature + WriteUInt16 (1); // MajorVersion + WriteUInt16 (1); // MinorVersion + WriteUInt32 (0); // Reserved + + var version = GetZeroTerminatedString (runtime_version); + WriteUInt32 ((uint)version.Length); + WriteBytes (version); + WriteUInt16 (0); // Flags + WriteUInt16 (GetStreamCount ()); + + uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader); + + WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~"); + WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings"); + WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US"); + WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID"); + WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob"); + WriteStreamHeader (ref offset, TextSegment.PdbHeap, "#Pdb"); + } + + ushort GetStreamCount () + { + return (ushort)( + 1 // #~ + + 1 // #Strings + + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US + + (metadata.guid_heap.IsEmpty ? 0 : 1) // GUID + + (metadata.blob_heap.IsEmpty ? 0 : 1) + + (metadata.pdb_heap == null ? 0 : 1)); // #Blob + } + + void WriteStreamHeader (ref uint offset, TextSegment heap, string name) + { + var length = (uint)text_map.GetLength (heap); + if (length == 0) + return; + + WriteUInt32 (offset); + WriteUInt32 (length); + WriteBytes (GetZeroTerminatedString (name)); + offset += length; + } + + static int GetZeroTerminatedStringLength (string @string) + { + return (@string.Length + 1 + 3) & ~3; + } + + static byte [] GetZeroTerminatedString (string @string) + { + return GetString (@string, GetZeroTerminatedStringLength (@string)); + } + + static byte [] GetSimpleString (string @string) + { + return GetString (@string, @string.Length); + } + + static byte [] GetString (string @string, int length) + { + var bytes = new byte [length]; + for (int i = 0; i < @string.Length; i++) + bytes [i] = (byte)@string [i]; + + return bytes; + } + + public void WriteMetadata () + { + WriteHeap (TextSegment.TableHeap, metadata.table_heap); + WriteHeap (TextSegment.StringHeap, metadata.string_heap); + WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap); + WriteHeap (TextSegment.GuidHeap, metadata.guid_heap); + WriteHeap (TextSegment.BlobHeap, metadata.blob_heap); + WriteHeap (TextSegment.PdbHeap, metadata.pdb_heap); + } + + void WriteHeap (TextSegment heap, HeapBuffer buffer) + { + if (buffer == null || buffer.IsEmpty) + return; + + MoveToRVA (heap); + WriteBuffer (buffer); + } + + void WriteDebugDirectory () + { + var data_start = (int)BaseStream.Position + (debug_header.Entries.Length * ImageDebugDirectory.Size); + + for (var i = 0; i < debug_header.Entries.Length; i++) { + var entry = debug_header.Entries [i]; + var directory = entry.Directory; + WriteInt32 (directory.Characteristics); + WriteInt32 (directory.TimeDateStamp); + WriteInt16 (directory.MajorVersion); + WriteInt16 (directory.MinorVersion); + WriteInt32 ((int)directory.Type); + WriteInt32 (directory.SizeOfData); + WriteInt32 (directory.AddressOfRawData); + WriteInt32 (data_start); + + data_start += entry.Data.Length; + } + + for (var i = 0; i < debug_header.Entries.Length; i++) { + var entry = debug_header.Entries [i]; + WriteBytes (entry.Data); + } + } + + void WriteImportDirectory () + { + WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable + WriteUInt32 (0); // DateTimeStamp + WriteUInt32 (0); // ForwarderChain + WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14); + WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable)); + Advance (20); + + // ImportLookupTable + WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable)); + + // ImportHintNameTable + MoveToRVA (TextSegment.ImportHintNameTable); + + WriteUInt16 (0); // Hint + WriteBytes (GetRuntimeMain ()); + WriteByte (0); + WriteBytes (GetSimpleString ("mscoree.dll")); + WriteUInt16 (0); + } + + byte [] GetRuntimeMain () + { + return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule + ? GetSimpleString ("_CorDllMain") + : GetSimpleString ("_CorExeMain"); + } + + void WriteStartupStub () + { + switch (module.Architecture) { + case TargetArchitecture.I386: + WriteUInt16 (0x25ff); + WriteUInt32 ((uint)image_base + text_map.GetRVA (TextSegment.ImportAddressTable)); + return; + default: + throw new NotSupportedException (); + } + } + + void WriteRsrc () + { + PrepareSection (rsrc); + WriteBuffer (win32_resources); + } + + void WriteReloc () + { + PrepareSection (reloc); + + var reloc_rva = text_map.GetRVA (TextSegment.StartupStub); + reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2; + var page_rva = reloc_rva & ~0xfffu; + + WriteUInt32 (page_rva); // PageRVA + WriteUInt32 (0x000c); // Block Size + + switch (module.Architecture) { + case TargetArchitecture.I386: + WriteUInt32 (0x3000 + reloc_rva - page_rva); + break; + default: + throw new NotSupportedException (); + } + } + + public void WriteImage () + { + WriteDOSHeader (); + WritePEFileHeader (); + WriteOptionalHeaders (); + WriteSectionHeaders (); + WriteText (); + if (rsrc != null) + WriteRsrc (); + if (reloc != null) + WriteReloc (); + Flush (); + } + + void BuildTextMap () + { + var map = text_map; + + map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16); + map.AddMap (TextSegment.Resources, metadata.resources.length, 8); + map.AddMap (TextSegment.Data, metadata.data.length, 4); + if (metadata.data.length > 0) + metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data)); + map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4); + + BuildMetadataTextMap (); + + int debug_dir_len = 0; + if (debug_header != null && debug_header.HasEntries) { + var directories_len = debug_header.Entries.Length * ImageDebugDirectory.Size; + var data_address = (int)map.GetNextRVA (TextSegment.BlobHeap) + directories_len; + var data_len = 0; + + for (var i = 0; i < debug_header.Entries.Length; i++) { + var entry = debug_header.Entries [i]; + var directory = entry.Directory; + + directory.AddressOfRawData = entry.Data.Length == 0 ? 0 : data_address; + entry.Directory = directory; + + data_len += entry.Data.Length; + data_address += data_len; + } + + debug_dir_len = directories_len + data_len; + } + + map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4); + + if (!has_reloc) { + var start = map.GetNextRVA (TextSegment.DebugDirectory); + map.AddMap (TextSegment.ImportDirectory, new Range (start, 0)); + map.AddMap (TextSegment.ImportHintNameTable, new Range (start, 0)); + map.AddMap (TextSegment.StartupStub, new Range (start, 0)); + return; + } + + RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory); + RVA import_hnt_rva = import_dir_rva + 48u; + import_hnt_rva = (import_hnt_rva + 15u) & ~15u; + uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u; + + RVA startup_stub_rva = import_dir_rva + import_dir_len; + startup_stub_rva = module.Architecture == TargetArchitecture.IA64 + ? (startup_stub_rva + 15u) & ~15u + : 2 + ((startup_stub_rva + 3u) & ~3u); + + map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len)); + map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0)); + map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ())); + } + + public void BuildMetadataTextMap () + { + var map = text_map; + + map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength (module.RuntimeVersion)); + map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4); + map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4); + map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4); + map.AddMap (TextSegment.GuidHeap, metadata.guid_heap.length, 4); + map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4); + map.AddMap (TextSegment.PdbHeap, metadata.pdb_heap == null ? 0 : metadata.pdb_heap.length, 4); + } + + uint GetStartupStubLength () + { + switch (module.Architecture) { + case TargetArchitecture.I386: + return 6; + default: + throw new NotSupportedException (); + } + } + + int GetMetadataHeaderLength (string runtimeVersion) + { + return + // MetadataHeader + 20 + GetZeroTerminatedStringLength (runtimeVersion) + // #~ header + + 12 + // #Strings header + + 20 + // #US header + + (metadata.user_string_heap.IsEmpty ? 0 : 12) + // #GUID header + + 16 + // #Blob header + + (metadata.blob_heap.IsEmpty ? 0 : 16) + // + + (metadata.pdb_heap == null ? 0 : 16); + } + + int GetStrongNameLength () + { + if (module.kind == ModuleKind.NetModule || module.Assembly == null) + return 0; + + var public_key = module.Assembly.Name.PublicKey; + if (public_key.IsNullOrEmpty ()) + return 0; + + // in fx 2.0 the key may be from 384 to 16384 bits + // so we must calculate the signature size based on + // the size of the public key (minus the 32 byte header) + int size = public_key.Length; + if (size > 32) + return size - 32; + + // note: size == 16 for the ECMA "key" which is replaced + // by the runtime with a 1024 bits key (128 bytes) + + return 128; // default strongname signature size + } + + public DataDirectory GetStrongNameSignatureDirectory () + { + return text_map.GetDataDirectory (TextSegment.StrongNameSignature); + } + + public uint GetHeaderSize () + { + return pe_header_size + SizeOfOptionalHeader () + (sections * section_header_size); + } + + void PatchWin32Resources (ByteBuffer resources) + { + PatchResourceDirectoryTable (resources); + } + + void PatchResourceDirectoryTable (ByteBuffer resources) + { + resources.Advance (12); + + var entries = resources.ReadUInt16 () + resources.ReadUInt16 (); + + for (int i = 0; i < entries; i++) + PatchResourceDirectoryEntry (resources); + } + + void PatchResourceDirectoryEntry (ByteBuffer resources) + { + resources.Advance (4); + var child = resources.ReadUInt32 (); + + var position = resources.position; + resources.position = (int)child & 0x7fffffff; + + if ((child & 0x80000000) != 0) + PatchResourceDirectoryTable (resources); + else + PatchResourceDataEntry (resources); + + resources.position = position; + } + + void PatchResourceDataEntry (ByteBuffer resources) + { + var rva = resources.ReadUInt32 (); + resources.position -= 4; + + resources.WriteUInt32 (rva - module.Image.Win32Resources.VirtualAddress + rsrc.VirtualAddress); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs.meta new file mode 100644 index 0000000..c230acb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/ImageWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88ebae078ed1c8346be0a945ce3b03b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs new file mode 100644 index 0000000..9c52503 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs @@ -0,0 +1,22 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using RVA = System.UInt32; + +namespace MonoFN.Cecil.PE { + + sealed class Section { + public string Name; + public RVA VirtualAddress; + public uint VirtualSize; + public uint SizeOfRawData; + public uint PointerToRawData; + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs.meta new file mode 100644 index 0000000..33d91fb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/Section.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc33915bdaaf42a428f8a4694e9611a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs new file mode 100644 index 0000000..fbe06e2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs @@ -0,0 +1,106 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using RVA = System.UInt32; + +namespace MonoFN.Cecil.PE { + + enum TextSegment { + ImportAddressTable, + CLIHeader, + Code, + Resources, + Data, + StrongNameSignature, + + // Metadata + MetadataHeader, + TableHeap, + StringHeap, + UserStringHeap, + GuidHeap, + BlobHeap, + PdbHeap, + // End Metadata + + DebugDirectory, + ImportDirectory, + ImportHintNameTable, + StartupStub, + } + + sealed class TextMap { + + readonly Range [] map = new Range [17 /*Enum.GetValues (typeof (TextSegment)).Length*/]; + + public void AddMap (TextSegment segment, int length) + { + map [(int)segment] = new Range (GetStart (segment), (uint)length); + } + + public void AddMap (TextSegment segment, int length, int align) + { + align--; + + AddMap (segment, (length + align) & ~align); + } + + public void AddMap (TextSegment segment, Range range) + { + map [(int)segment] = range; + } + + public Range GetRange (TextSegment segment) + { + return map [(int)segment]; + } + + public DataDirectory GetDataDirectory (TextSegment segment) + { + var range = map [(int)segment]; + + return new DataDirectory (range.Length == 0 ? 0 : range.Start, range.Length); + } + + public RVA GetRVA (TextSegment segment) + { + return map [(int)segment].Start; + } + + public RVA GetNextRVA (TextSegment segment) + { + var i = (int)segment; + return map [i].Start + map [i].Length; + } + + public int GetLength (TextSegment segment) + { + return (int)map [(int)segment].Length; + } + + RVA GetStart (TextSegment segment) + { + var index = (int)segment; + return index == 0 ? ImageWriter.text_rva : ComputeStart (index); + } + + RVA ComputeStart (int index) + { + index--; + return map [index].Start + map [index].Length; + } + + public uint GetLength () + { + var range = map [(int)TextSegment.StartupStub]; + return range.Start - ImageWriter.text_rva + range.Length; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs.meta new file mode 100644 index 0000000..93ceea3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.PE/TextMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d36ca0589eb8014fa28bc58a88ae85f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props new file mode 100644 index 0000000..bd6df1f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props @@ -0,0 +1,16 @@ + + + true + + + + 3.11.0 + + + 15.9.0 + + + 3.12.0 + + + diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props.meta similarity index 74% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity.meta rename to UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props.meta index 32f0c43..ae02e4c 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity.meta +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Tests.props.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c63e1eea85874ae43a7fdd723a38741e +guid: 4304d9110a6c73049a70f3d001e1ac37 DefaultImporter: externalObjects: {} userData: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.meta new file mode 100644 index 0000000..835dc15 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9a32c41438af560498f0e8ae5548097a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit new file mode 100644 index 0000000..2acfc12 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit.meta new file mode 100644 index 0000000..0163c57 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nunit.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 70249fc3714c2ba43bb69eeceaf02171 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec new file mode 100644 index 0000000..626c5ac --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec @@ -0,0 +1,42 @@ + + + + Mono.Cecil + 0.11.4.0 + Mono.Cecil + Jb Evain + Jb Evain + MIT + false + http://github.com/jbevain/cecil/ + Cecil is a library written by Jb Evain to generate and inspect programs and libraries in the ECMA CIL format. + Cecil is a library written by Jb Evain to generate and inspect programs and libraries in the ECMA CIL format. It has full support for generics, and support some debugging symbol format. In simple English, with Cecil, you can load existing managed assemblies, browse all the contained types, modify them on the fly and save back to the disk the modified assembly. + en-US + assembly assemblies module modules il cil msil bytecode reflection injection cecil mono aop + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec.meta new file mode 100644 index 0000000..033480e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9ab5a3af6caf6d14da0bad821a809a27 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta new file mode 100644 index 0000000..aa8a077 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 246f31a0e00fea74a93125fec6d80da8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs new file mode 100644 index 0000000..df72aab --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs @@ -0,0 +1,145 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Text; +using System.Threading; +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public struct ArrayDimension { + + int? lower_bound; + int? upper_bound; + + public int? LowerBound { + get { return lower_bound; } + set { lower_bound = value; } + } + + public int? UpperBound { + get { return upper_bound; } + set { upper_bound = value; } + } + + public bool IsSized { + get { return lower_bound.HasValue || upper_bound.HasValue; } + } + + public ArrayDimension (int? lowerBound, int? upperBound) + { + this.lower_bound = lowerBound; + this.upper_bound = upperBound; + } + + public override string ToString () + { + return !IsSized + ? string.Empty + : lower_bound + "..." + upper_bound; + } + } + + public sealed class ArrayType : TypeSpecification { + + Collection dimensions; + + public Collection Dimensions { + get { + if (dimensions != null) + return dimensions; + + var empty_dimensions = new Collection (); + empty_dimensions.Add (new ArrayDimension ()); + + Interlocked.CompareExchange (ref dimensions, empty_dimensions, null); + + return dimensions; + } + } + + public int Rank { + get { return dimensions == null ? 1 : dimensions.Count; } + } + + public bool IsVector { + get { + if (dimensions == null) + return true; + + if (dimensions.Count > 1) + return false; + + var dimension = dimensions [0]; + + return !dimension.IsSized; + } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { + if (IsVector) + return "[]"; + + var suffix = new StringBuilder (); + suffix.Append ("["); + for (int i = 0; i < dimensions.Count; i++) { + if (i > 0) + suffix.Append (","); + + suffix.Append (dimensions [i].ToString ()); + } + suffix.Append ("]"); + + return suffix.ToString (); + } + } + + public override bool IsArray { + get { return true; } + } + + public ArrayType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Array; + } + + public ArrayType (TypeReference type, int rank) + : this (type) + { + Mixin.CheckType (type); + + if (rank == 1) + return; + + dimensions = new Collection (rank); + for (int i = 0; i < rank; i++) + dimensions.Add (new ArrayDimension ()); + this.etype = MD.ElementType.Array; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs.meta new file mode 100644 index 0000000..bace606 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ArrayType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7add098db82a032428c139b59f0878be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs new file mode 100644 index 0000000..de9ffde --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs @@ -0,0 +1,189 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.IO; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class AssemblyDefinition : ICustomAttributeProvider, ISecurityDeclarationProvider, IDisposable { + + AssemblyNameDefinition name; + + internal ModuleDefinition main_module; + Collection modules; + Collection custom_attributes; + Collection security_declarations; + + public AssemblyNameDefinition Name { + get { return name; } + set { name = value; } + } + + public string FullName { + get { return name != null ? name.FullName : string.Empty; } + } + + public MetadataToken MetadataToken { + get { return new MetadataToken (TokenType.Assembly, 1); } + set { } + } + + public Collection Modules { + get { + if (modules != null) + return modules; + + if (main_module.HasImage) + return main_module.Read (ref modules, this, (_, reader) => reader.ReadModules ()); + + Interlocked.CompareExchange (ref modules, new Collection (1) { main_module }, null); + return modules; + } + } + + public ModuleDefinition MainModule { + get { return main_module; } + } + + public MethodDefinition EntryPoint { + get { return main_module.EntryPoint; } + set { main_module.EntryPoint = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (main_module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, main_module)); } + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (main_module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, main_module)); } + } + + internal AssemblyDefinition () + { + } + + public void Dispose () + { + if (this.modules == null) { + main_module.Dispose (); + return; + } + + var modules = this.Modules; + for (int i = 0; i < modules.Count; i++) + modules [i].Dispose (); + } + public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleKind kind) + { + return CreateAssembly (assemblyName, moduleName, new ModuleParameters { Kind = kind }); + } + + public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleParameters parameters) + { + if (assemblyName == null) + throw new ArgumentNullException ("assemblyName"); + if (moduleName == null) + throw new ArgumentNullException ("moduleName"); + Mixin.CheckParameters (parameters); + if (parameters.Kind == ModuleKind.NetModule) + throw new ArgumentException ("kind"); + + var assembly = ModuleDefinition.CreateModule (moduleName, parameters).Assembly; + assembly.Name = assemblyName; + + return assembly; + } + + public static AssemblyDefinition ReadAssembly (string fileName) + { + return ReadAssembly (ModuleDefinition.ReadModule (fileName)); + } + + public static AssemblyDefinition ReadAssembly (string fileName, ReaderParameters parameters) + { + return ReadAssembly (ModuleDefinition.ReadModule (fileName, parameters)); + } + + public static AssemblyDefinition ReadAssembly (Stream stream) + { + return ReadAssembly (ModuleDefinition.ReadModule (stream)); + } + + public static AssemblyDefinition ReadAssembly (Stream stream, ReaderParameters parameters) + { + return ReadAssembly (ModuleDefinition.ReadModule (stream, parameters)); + } + + static AssemblyDefinition ReadAssembly (ModuleDefinition module) + { + var assembly = module.Assembly; + if (assembly == null) + throw new ArgumentException (); + + return assembly; + } + + public void Write (string fileName) + { + Write (fileName, new WriterParameters ()); + } + + public void Write (string fileName, WriterParameters parameters) + { + main_module.Write (fileName, parameters); + } + + public void Write () + { + main_module.Write (); + } + + public void Write (WriterParameters parameters) + { + main_module.Write (parameters); + } + + public void Write (Stream stream) + { + Write (stream, new WriterParameters ()); + } + + public void Write (Stream stream, WriterParameters parameters) + { + main_module.Write (stream, parameters); + } + + public override string ToString () + { + return this.FullName; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs.meta new file mode 100644 index 0000000..d66f03d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c1ac0fc48f2d424f9c0d9fa74b16b07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs new file mode 100644 index 0000000..a5f83a7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs @@ -0,0 +1,24 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum AssemblyAttributes : uint { + PublicKey = 0x0001, + SideBySideCompatible = 0x0000, + Retargetable = 0x0100, + WindowsRuntime = 0x0200, + DisableJITCompileOptimizer = 0x4000, + EnableJITCompileTracking = 0x8000, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs.meta new file mode 100644 index 0000000..d7c8791 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 257c8151138cda34dafbe0ca56ebedf4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs new file mode 100644 index 0000000..fb0cc5f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs @@ -0,0 +1,22 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum AssemblyHashAlgorithm : uint { + None = 0x0000, + MD5 = 0x8003, + SHA1 = 0x8004, + SHA256 = 0x800C, + SHA384 = 0x800D, + SHA512 = 0x800E, + Reserved = 0x8003, // MD5 + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs.meta new file mode 100644 index 0000000..98687b5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyHashAlgorithm.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b200bdec09584af41bd3f656e091cccf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs new file mode 100644 index 0000000..45534f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs @@ -0,0 +1,22 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle (Consts.AssemblyName)] + +[assembly: Guid ("fd225bb4-fa53-44b2-a6db-85f5e48dcb54")] + +[assembly: InternalsVisibleTo ("MonoFN.Cecil.Tests, PublicKey=" + Consts.PublicKey)] +[assembly: InternalsVisibleTo ("MonoFN.Cecil.Pdb, PublicKey=" + Consts.PublicKey)] +[assembly: InternalsVisibleTo ("MonoFN.Cecil.Mdb, PublicKey=" + Consts.PublicKey)] +[assembly: InternalsVisibleTo ("MonoFN.Cecil.Rocks, PublicKey=" + Consts.PublicKey)] diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs.meta new file mode 100644 index 0000000..715025d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff23d7231ddfa574b816532360874834 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs new file mode 100644 index 0000000..de592ae --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs @@ -0,0 +1,37 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public sealed class AssemblyLinkedResource : Resource { + + AssemblyNameReference reference; + + public AssemblyNameReference Assembly { + get { return reference; } + set { reference = value; } + } + + public override ResourceType ResourceType { + get { return ResourceType.AssemblyLinked; } + } + + public AssemblyLinkedResource (string name, ManifestResourceAttributes flags) + : base (name, flags) + { + } + + public AssemblyLinkedResource (string name, ManifestResourceAttributes flags, AssemblyNameReference reference) + : base (name, flags) + { + this.reference = reference; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs.meta new file mode 100644 index 0000000..259e540 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyLinkedResource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3d5a207fc55ac5419e42c86cef15db0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs new file mode 100644 index 0000000..b46e1b9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs @@ -0,0 +1,32 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public sealed class AssemblyNameDefinition : AssemblyNameReference { + + public override byte [] Hash { + get { return Empty.Array; } + } + + internal AssemblyNameDefinition () + { + this.token = new MetadataToken (TokenType.Assembly, 1); + } + + public AssemblyNameDefinition (string name, Version version) + : base (name, version) + { + this.token = new MetadataToken (TokenType.Assembly, 1); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs.meta new file mode 100644 index 0000000..7409717 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68b90f4f023a67e4db7ddb52802ca21e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs new file mode 100644 index 0000000..d0b0585 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs @@ -0,0 +1,269 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Globalization; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace MonoFN.Cecil { + + public class AssemblyNameReference : IMetadataScope { + + string name; + string culture; + Version version; + uint attributes; + byte [] public_key; + byte [] public_key_token; + AssemblyHashAlgorithm hash_algorithm; + byte [] hash; + + internal MetadataToken token; + + string full_name; + + public string Name { + get { return name; } + set { + name = value; + full_name = null; + } + } + + public string Culture { + get { return culture; } + set { + culture = value; + full_name = null; + } + } + + public Version Version { + get { return version; } + set { + version = Mixin.CheckVersion (value); + full_name = null; + } + } + + public AssemblyAttributes Attributes { + get { return (AssemblyAttributes)attributes; } + set { attributes = (uint)value; } + } + + public bool HasPublicKey { + get { return attributes.GetAttributes ((uint)AssemblyAttributes.PublicKey); } + set { attributes = attributes.SetAttributes ((uint)AssemblyAttributes.PublicKey, value); } + } + + public bool IsSideBySideCompatible { + get { return attributes.GetAttributes ((uint)AssemblyAttributes.SideBySideCompatible); } + set { attributes = attributes.SetAttributes ((uint)AssemblyAttributes.SideBySideCompatible, value); } + } + + public bool IsRetargetable { + get { return attributes.GetAttributes ((uint)AssemblyAttributes.Retargetable); } + set { attributes = attributes.SetAttributes ((uint)AssemblyAttributes.Retargetable, value); } + } + + public bool IsWindowsRuntime { + get { return attributes.GetAttributes ((uint)AssemblyAttributes.WindowsRuntime); } + set { attributes = attributes.SetAttributes ((uint)AssemblyAttributes.WindowsRuntime, value); } + } + + public byte [] PublicKey { + get { return public_key ?? Empty.Array; } + set { + public_key = value; + HasPublicKey = !public_key.IsNullOrEmpty (); + public_key_token = null; + full_name = null; + } + } + + public byte [] PublicKeyToken { + get { + if (public_key_token == null && !public_key.IsNullOrEmpty ()) { + var hash = HashPublicKey (); + // we need the last 8 bytes in reverse order + var local_public_key_token = new byte [8]; + Array.Copy (hash, (hash.Length - 8), local_public_key_token, 0, 8); + Array.Reverse (local_public_key_token, 0, 8); + Interlocked.CompareExchange (ref public_key_token, local_public_key_token, null); // publish only once finished (required for thread-safety) + } + return public_key_token ?? Empty.Array; + } + set { + public_key_token = value; + full_name = null; + } + } + + byte [] HashPublicKey () + { + HashAlgorithm algorithm; + + switch (hash_algorithm) { + case AssemblyHashAlgorithm.Reserved: + algorithm = MD5.Create (); + break; + default: + // None default to SHA1 + algorithm = SHA1.Create (); + break; + } + + using (algorithm) + return algorithm.ComputeHash (public_key); + } + + public virtual MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.AssemblyNameReference; } + } + + public string FullName { + get { + if (full_name != null) + return full_name; + + const string sep = ", "; + + var builder = new StringBuilder (); + builder.Append (name); + builder.Append (sep); + builder.Append ("Version="); + builder.Append (version.ToString (fieldCount: 4)); + builder.Append (sep); + builder.Append ("Culture="); + builder.Append (string.IsNullOrEmpty (culture) ? "neutral" : culture); + builder.Append (sep); + builder.Append ("PublicKeyToken="); + + var pk_token = PublicKeyToken; + if (!pk_token.IsNullOrEmpty () && pk_token.Length > 0) { + for (int i = 0; i < pk_token.Length; i++) { + builder.Append (pk_token [i].ToString ("x2")); + } + } else + builder.Append ("null"); + + if (IsRetargetable) { + builder.Append (sep); + builder.Append ("Retargetable=Yes"); + } + + Interlocked.CompareExchange (ref full_name, builder.ToString (), null); + + return full_name; + } + } + + public static AssemblyNameReference Parse (string fullName) + { + if (fullName == null) + throw new ArgumentNullException ("fullName"); + if (fullName.Length == 0) + throw new ArgumentException ("Name can not be empty"); + + var name = new AssemblyNameReference (); + var tokens = fullName.Split (','); + for (int i = 0; i < tokens.Length; i++) { + var token = tokens [i].Trim (); + + if (i == 0) { + name.Name = token; + continue; + } + + var parts = token.Split ('='); + if (parts.Length != 2) + throw new ArgumentException ("Malformed name"); + + switch (parts [0].ToLowerInvariant ()) { + case "version": + name.Version = new Version (parts [1]); + break; + case "culture": + name.Culture = parts [1] == "neutral" ? "" : parts [1]; + break; + case "publickeytoken": + var pk_token = parts [1]; + if (pk_token == "null") + break; + + name.PublicKeyToken = new byte [pk_token.Length / 2]; + for (int j = 0; j < name.PublicKeyToken.Length; j++) + name.PublicKeyToken [j] = Byte.Parse (pk_token.Substring (j * 2, 2), NumberStyles.HexNumber); + + break; + } + } + + return name; + } + + public AssemblyHashAlgorithm HashAlgorithm { + get { return hash_algorithm; } + set { hash_algorithm = value; } + } + + public virtual byte [] Hash { + get { return hash; } + set { hash = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal AssemblyNameReference () + { + this.version = Mixin.ZeroVersion; + this.token = new MetadataToken (TokenType.AssemblyRef); + } + + public AssemblyNameReference (string name, Version version) + { + Mixin.CheckName (name); + + this.name = name; + this.version = Mixin.CheckVersion (version); + this.hash_algorithm = AssemblyHashAlgorithm.None; + this.token = new MetadataToken (TokenType.AssemblyRef); + } + + public override string ToString () + { + return this.FullName; + } + } + + partial class Mixin { + + public static Version ZeroVersion = new Version (0, 0, 0, 0); + + public static Version CheckVersion (Version version) + { + if (version == null) + return ZeroVersion; + + if (version.Build == -1) + return new Version (version.Major, version.Minor, 0, 0); + + if (version.Revision == -1) + return new Version (version.Major, version.Minor, version.Build, 0); + + return version; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs.meta new file mode 100644 index 0000000..980b1fd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyNameReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdaf7563058f3f54ba3e6b32c888eb3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs new file mode 100644 index 0000000..2a3d6ef --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs @@ -0,0 +1,3889 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using RVA = System.UInt32; + +namespace MonoFN.Cecil { + + abstract class ModuleReader { + + readonly protected ModuleDefinition module; + + protected ModuleReader (Image image, ReadingMode mode) + { + this.module = new ModuleDefinition (image); + this.module.ReadingMode = mode; + } + + protected abstract void ReadModule (); + public abstract void ReadSymbols (ModuleDefinition module); + + protected void ReadModuleManifest (MetadataReader reader) + { + reader.Populate (module); + + ReadAssembly (reader); + } + + void ReadAssembly (MetadataReader reader) + { + var name = reader.ReadAssemblyNameDefinition (); + if (name == null) { + module.kind = ModuleKind.NetModule; + return; + } + + var assembly = new AssemblyDefinition (); + assembly.Name = name; + + module.assembly = assembly; + assembly.main_module = module; + } + + public static ModuleDefinition CreateModule (Image image, ReaderParameters parameters) + { + var reader = CreateModuleReader (image, parameters.ReadingMode); + var module = reader.module; + + if (parameters.assembly_resolver != null) + module.assembly_resolver = Disposable.NotOwned (parameters.assembly_resolver); + + if (parameters.metadata_resolver != null) + module.metadata_resolver = parameters.metadata_resolver; + + if (parameters.metadata_importer_provider != null) + module.metadata_importer = parameters.metadata_importer_provider.GetMetadataImporter (module); + + if (parameters.reflection_importer_provider != null) + module.reflection_importer = parameters.reflection_importer_provider.GetReflectionImporter (module); + + GetMetadataKind (module, parameters); + + reader.ReadModule (); + + ReadSymbols (module, parameters); + + reader.ReadSymbols (module); + + if (parameters.ReadingMode == ReadingMode.Immediate) + module.MetadataSystem.Clear (); + + return module; + } + + static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters) + { + var symbol_reader_provider = parameters.SymbolReaderProvider; + + if (symbol_reader_provider == null && parameters.ReadSymbols) + symbol_reader_provider = new DefaultSymbolReaderProvider (); + + if (symbol_reader_provider != null) { + module.SymbolReaderProvider = symbol_reader_provider; + + var reader = parameters.SymbolStream != null + ? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream) + : symbol_reader_provider.GetSymbolReader (module, module.FileName); + + if (reader != null) { + try { + module.ReadSymbols (reader, parameters.ThrowIfSymbolsAreNotMatching); + } + catch (Exception) { + reader.Dispose (); + throw; + } + } + } + + if (module.Image.HasDebugTables ()) + module.ReadSymbols (new PortablePdbReader (module.Image, module)); + } + + static void GetMetadataKind (ModuleDefinition module, ReaderParameters parameters) + { + if (!parameters.ApplyWindowsRuntimeProjections) { + module.MetadataKind = MetadataKind.Ecma335; + return; + } + + var runtime_version = module.RuntimeVersion; + + if (!runtime_version.Contains ("WindowsRuntime")) + module.MetadataKind = MetadataKind.Ecma335; + else if (runtime_version.Contains ("CLR")) + module.MetadataKind = MetadataKind.ManagedWindowsMetadata; + else + module.MetadataKind = MetadataKind.WindowsMetadata; + } + + static ModuleReader CreateModuleReader (Image image, ReadingMode mode) + { + switch (mode) { + case ReadingMode.Immediate: + return new ImmediateModuleReader (image); + case ReadingMode.Deferred: + return new DeferredModuleReader (image); + default: + throw new ArgumentException (); + } + } + } + + sealed class ImmediateModuleReader : ModuleReader { + + bool resolve_attributes; + + public ImmediateModuleReader (Image image) + : base (image, ReadingMode.Immediate) + { + } + + protected override void ReadModule () + { + this.module.Read (this.module, (module, reader) => { + ReadModuleManifest (reader); + ReadModule (module, resolve_attributes: true); + }); + } + + public void ReadModule (ModuleDefinition module, bool resolve_attributes) + { + this.resolve_attributes = resolve_attributes; + + if (module.HasAssemblyReferences) + Mixin.Read (module.AssemblyReferences); + if (module.HasResources) + Mixin.Read (module.Resources); + if (module.HasModuleReferences) + Mixin.Read (module.ModuleReferences); + if (module.HasTypes) + ReadTypes (module.Types); + if (module.HasExportedTypes) + Mixin.Read (module.ExportedTypes); + + ReadCustomAttributes (module); + + var assembly = module.Assembly; + if (module.kind == ModuleKind.NetModule || assembly == null) + return; + + ReadCustomAttributes (assembly); + ReadSecurityDeclarations (assembly); + } + + void ReadTypes (Collection types) + { + for (int i = 0; i < types.Count; i++) + ReadType (types [i]); + } + + void ReadType (TypeDefinition type) + { + ReadGenericParameters (type); + + if (type.HasInterfaces) + ReadInterfaces (type); + + if (type.HasNestedTypes) + ReadTypes (type.NestedTypes); + + if (type.HasLayoutInfo) + Mixin.Read (type.ClassSize); + + if (type.HasFields) + ReadFields (type); + + if (type.HasMethods) + ReadMethods (type); + + if (type.HasProperties) + ReadProperties (type); + + if (type.HasEvents) + ReadEvents (type); + + ReadSecurityDeclarations (type); + ReadCustomAttributes (type); + } + + void ReadInterfaces (TypeDefinition type) + { + var interfaces = type.Interfaces; + + for (int i = 0; i < interfaces.Count; i++) + ReadCustomAttributes (interfaces [i]); + } + + void ReadGenericParameters (IGenericParameterProvider provider) + { + if (!provider.HasGenericParameters) + return; + + var parameters = provider.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + + if (parameter.HasConstraints) + ReadGenericParameterConstraints (parameter); + + ReadCustomAttributes (parameter); + } + } + + void ReadGenericParameterConstraints (GenericParameter parameter) + { + var constraints = parameter.Constraints; + + for (int i = 0; i < constraints.Count; i++) + ReadCustomAttributes (constraints [i]); + } + + void ReadSecurityDeclarations (ISecurityDeclarationProvider provider) + { + if (!provider.HasSecurityDeclarations) + return; + + var security_declarations = provider.SecurityDeclarations; + + if (!resolve_attributes) + return; + + for (int i = 0; i < security_declarations.Count; i++) { + var security_declaration = security_declarations [i]; + + Mixin.Read (security_declaration.SecurityAttributes); + } + } + + void ReadCustomAttributes (ICustomAttributeProvider provider) + { + if (!provider.HasCustomAttributes) + return; + + var custom_attributes = provider.CustomAttributes; + + if (!resolve_attributes) + return; + + for (int i = 0; i < custom_attributes.Count; i++) { + var custom_attribute = custom_attributes [i]; + + Mixin.Read (custom_attribute.ConstructorArguments); + } + } + + void ReadFields (TypeDefinition type) + { + var fields = type.Fields; + + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + + if (field.HasConstant) + Mixin.Read (field.Constant); + + if (field.HasLayoutInfo) + Mixin.Read (field.Offset); + + if (field.RVA > 0) + Mixin.Read (field.InitialValue); + + if (field.HasMarshalInfo) + Mixin.Read (field.MarshalInfo); + + ReadCustomAttributes (field); + } + } + + void ReadMethods (TypeDefinition type) + { + var methods = type.Methods; + + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + + ReadGenericParameters (method); + + if (method.HasParameters) + ReadParameters (method); + + if (method.HasOverrides) + Mixin.Read (method.Overrides); + + if (method.IsPInvokeImpl) + Mixin.Read (method.PInvokeInfo); + + ReadSecurityDeclarations (method); + ReadCustomAttributes (method); + + var return_type = method.MethodReturnType; + if (return_type.HasConstant) + Mixin.Read (return_type.Constant); + + if (return_type.HasMarshalInfo) + Mixin.Read (return_type.MarshalInfo); + + ReadCustomAttributes (return_type); + } + } + + void ReadParameters (MethodDefinition method) + { + var parameters = method.Parameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + + if (parameter.HasConstant) + Mixin.Read (parameter.Constant); + + if (parameter.HasMarshalInfo) + Mixin.Read (parameter.MarshalInfo); + + ReadCustomAttributes (parameter); + } + } + + void ReadProperties (TypeDefinition type) + { + var properties = type.Properties; + + for (int i = 0; i < properties.Count; i++) { + var property = properties [i]; + + Mixin.Read (property.GetMethod); + + if (property.HasConstant) + Mixin.Read (property.Constant); + + ReadCustomAttributes (property); + } + } + + void ReadEvents (TypeDefinition type) + { + var events = type.Events; + + for (int i = 0; i < events.Count; i++) { + var @event = events [i]; + + Mixin.Read (@event.AddMethod); + + ReadCustomAttributes (@event); + } + } + + public override void ReadSymbols (ModuleDefinition module) + { + if (module.symbol_reader == null) + return; + + ReadTypesSymbols (module.Types, module.symbol_reader); + } + + void ReadTypesSymbols (Collection types, ISymbolReader symbol_reader) + { + for (int i = 0; i < types.Count; i++) { + var type = types [i]; + + if (type.HasNestedTypes) + ReadTypesSymbols (type.NestedTypes, symbol_reader); + + if (type.HasMethods) + ReadMethodsSymbols (type, symbol_reader); + } + } + + void ReadMethodsSymbols (TypeDefinition type, ISymbolReader symbol_reader) + { + var methods = type.Methods; + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + + if (method.HasBody && method.token.RID != 0 && method.debug_info == null) + method.debug_info = symbol_reader.Read (method); + } + } + } + + sealed class DeferredModuleReader : ModuleReader { + + public DeferredModuleReader (Image image) + : base (image, ReadingMode.Deferred) + { + } + + protected override void ReadModule () + { + this.module.Read (this.module, (_, reader) => ReadModuleManifest (reader)); + } + + public override void ReadSymbols (ModuleDefinition module) + { + } + } + + sealed class MetadataReader : ByteBuffer { + + readonly internal Image image; + readonly internal ModuleDefinition module; + readonly internal MetadataSystem metadata; + + internal CodeReader code; + internal IGenericContext context; + + readonly MetadataReader metadata_reader; + + public MetadataReader (ModuleDefinition module) + : base (module.Image.TableHeap.data) + { + this.image = module.Image; + this.module = module; + this.metadata = module.MetadataSystem; + this.code = new CodeReader (this); + } + + public MetadataReader (Image image, ModuleDefinition module, MetadataReader metadata_reader) + : base (image.TableHeap.data) + { + this.image = image; + this.module = module; + this.metadata = module.MetadataSystem; + this.metadata_reader = metadata_reader; + } + + int GetCodedIndexSize (CodedIndex index) + { + return image.GetCodedIndexSize (index); + } + + uint ReadByIndexSize (int size) + { + if (size == 4) + return ReadUInt32 (); + else + return ReadUInt16 (); + } + + byte [] ReadBlob () + { + var blob_heap = image.BlobHeap; + if (blob_heap == null) { + position += 2; + return Empty.Array; + } + + return blob_heap.Read (ReadBlobIndex ()); + } + + byte [] ReadBlob (uint signature) + { + var blob_heap = image.BlobHeap; + if (blob_heap == null) + return Empty.Array; + + return blob_heap.Read (signature); + } + + uint ReadBlobIndex () + { + var blob_heap = image.BlobHeap; + return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2); + } + + void GetBlobView (uint signature, out byte [] blob, out int index, out int count) + { + var blob_heap = image.BlobHeap; + if (blob_heap == null) { + blob = null; + index = count = 0; + return; + } + + blob_heap.GetView (signature, out blob, out index, out count); + } + + string ReadString () + { + return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize)); + } + + uint ReadStringIndex () + { + return ReadByIndexSize (image.StringHeap.IndexSize); + } + + Guid ReadGuid () + { + return image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize)); + } + + uint ReadTableIndex (Table table) + { + return ReadByIndexSize (image.GetTableIndexSize (table)); + } + + MetadataToken ReadMetadataToken (CodedIndex index) + { + return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index))); + } + + int MoveTo (Table table) + { + var info = image.TableHeap [table]; + if (info.Length != 0) + this.position = (int)info.Offset; + + return (int)info.Length; + } + + bool MoveTo (Table table, uint row) + { + var info = image.TableHeap [table]; + var length = info.Length; + if (length == 0 || row > length) + return false; + + this.position = (int)(info.Offset + (info.RowSize * (row - 1))); + return true; + } + + public AssemblyNameDefinition ReadAssemblyNameDefinition () + { + if (MoveTo (Table.Assembly) == 0) + return null; + + var name = new AssemblyNameDefinition (); + + name.HashAlgorithm = (AssemblyHashAlgorithm)ReadUInt32 (); + + PopulateVersionAndFlags (name); + + name.PublicKey = ReadBlob (); + + PopulateNameAndCulture (name); + + return name; + } + + public ModuleDefinition Populate (ModuleDefinition module) + { + if (MoveTo (Table.Module) == 0) + return module; + + Advance (2); // Generation + + module.Name = ReadString (); + module.Mvid = ReadGuid (); + + return module; + } + + void InitializeAssemblyReferences () + { + if (metadata.AssemblyReferences != null) + return; + + int length = MoveTo (Table.AssemblyRef); + var references = metadata.AssemblyReferences = new AssemblyNameReference [length]; + + for (uint i = 0; i < length; i++) { + var reference = new AssemblyNameReference (); + reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1); + + PopulateVersionAndFlags (reference); + + var key_or_token = ReadBlob (); + + if (reference.HasPublicKey) + reference.PublicKey = key_or_token; + else + reference.PublicKeyToken = key_or_token; + + PopulateNameAndCulture (reference); + + reference.Hash = ReadBlob (); + + references [i] = reference; + } + } + + public Collection ReadAssemblyReferences () + { + InitializeAssemblyReferences (); + + var references = new Collection (metadata.AssemblyReferences); + if (module.IsWindowsMetadata ()) + module.Projections.AddVirtualReferences (references); + + return references; + } + + public MethodDefinition ReadEntryPoint () + { + if (module.Image.EntryPointToken == 0) + return null; + + var token = new MetadataToken (module.Image.EntryPointToken); + return GetMethodDefinition (token.RID); + } + + public Collection ReadModules () + { + var modules = new Collection (1); + modules.Add (this.module); + + int length = MoveTo (Table.File); + for (uint i = 1; i <= length; i++) { + var attributes = (FileAttributes)ReadUInt32 (); + var name = ReadString (); + ReadBlobIndex (); + + if (attributes != FileAttributes.ContainsMetaData) + continue; + + var parameters = new ReaderParameters { + ReadingMode = module.ReadingMode, + SymbolReaderProvider = module.SymbolReaderProvider, + AssemblyResolver = module.AssemblyResolver + }; + + var netmodule = ModuleDefinition.ReadModule (GetModuleFileName (name), parameters); + netmodule.assembly = this.module.assembly; + + modules.Add (netmodule); + } + + return modules; + } + + string GetModuleFileName (string name) + { + if (module.FileName == null) + throw new NotSupportedException (); + + var path = Path.GetDirectoryName (module.FileName); + return Path.Combine (path, name); + } + + void InitializeModuleReferences () + { + if (metadata.ModuleReferences != null) + return; + + int length = MoveTo (Table.ModuleRef); + var references = metadata.ModuleReferences = new ModuleReference [length]; + + for (uint i = 0; i < length; i++) { + var reference = new ModuleReference (ReadString ()); + reference.token = new MetadataToken (TokenType.ModuleRef, i + 1); + + references [i] = reference; + } + } + + public Collection ReadModuleReferences () + { + InitializeModuleReferences (); + + return new Collection (metadata.ModuleReferences); + } + + public bool HasFileResource () + { + int length = MoveTo (Table.File); + if (length == 0) + return false; + + for (uint i = 1; i <= length; i++) + if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData) + return true; + + return false; + } + + public Collection ReadResources () + { + int length = MoveTo (Table.ManifestResource); + var resources = new Collection (length); + + for (int i = 1; i <= length; i++) { + var offset = ReadUInt32 (); + var flags = (ManifestResourceAttributes)ReadUInt32 (); + var name = ReadString (); + var implementation = ReadMetadataToken (CodedIndex.Implementation); + + Resource resource; + + if (implementation.RID == 0) { + resource = new EmbeddedResource (name, flags, offset, this); + } else if (implementation.TokenType == TokenType.AssemblyRef) { + resource = new AssemblyLinkedResource (name, flags) { + Assembly = (AssemblyNameReference)GetTypeReferenceScope (implementation), + }; + } else if (implementation.TokenType == TokenType.File) { + var file_record = ReadFileRecord (implementation.RID); + + resource = new LinkedResource (name, flags) { + File = file_record.Col2, + hash = ReadBlob (file_record.Col3) + }; + } else + continue; + + resources.Add (resource); + } + + return resources; + } + + Row ReadFileRecord (uint rid) + { + var position = this.position; + + if (!MoveTo (Table.File, rid)) + throw new ArgumentException (); + + var record = new Row ( + (FileAttributes)ReadUInt32 (), + ReadString (), + ReadBlobIndex ()); + + this.position = position; + + return record; + } + + public byte [] GetManagedResource (uint offset) + { + return image.GetReaderAt (image.Resources.VirtualAddress, offset, (o, reader) => { + reader.Advance ((int)o); + return reader.ReadBytes (reader.ReadInt32 ()); + }) ?? Empty.Array; + } + + void PopulateVersionAndFlags (AssemblyNameReference name) + { + name.Version = new Version ( + ReadUInt16 (), + ReadUInt16 (), + ReadUInt16 (), + ReadUInt16 ()); + + name.Attributes = (AssemblyAttributes)ReadUInt32 (); + } + + void PopulateNameAndCulture (AssemblyNameReference name) + { + name.Name = ReadString (); + name.Culture = ReadString (); + } + + public TypeDefinitionCollection ReadTypes () + { + InitializeTypeDefinitions (); + var mtypes = metadata.Types; + var type_count = mtypes.Length - metadata.NestedTypes.Count; + var types = new TypeDefinitionCollection (module, type_count); + + for (int i = 0; i < mtypes.Length; i++) { + var type = mtypes [i]; + if (IsNested (type.Attributes)) + continue; + + types.Add (type); + } + + if (image.HasTable (Table.MethodPtr) || image.HasTable (Table.FieldPtr)) + CompleteTypes (); + + return types; + } + + void CompleteTypes () + { + var types = metadata.Types; + + for (int i = 0; i < types.Length; i++) { + var type = types [i]; + + Mixin.Read (type.Fields); + Mixin.Read (type.Methods); + } + } + + void InitializeTypeDefinitions () + { + if (metadata.Types != null) + return; + + InitializeNestedTypes (); + InitializeFields (); + InitializeMethods (); + + int length = MoveTo (Table.TypeDef); + var types = metadata.Types = new TypeDefinition [length]; + + for (uint i = 0; i < length; i++) { + if (types [i] != null) + continue; + + types [i] = ReadType (i + 1); + } + + if (module.IsWindowsMetadata ()) { + for (uint i = 0; i < length; i++) { + WindowsRuntimeProjections.Project (types [i]); + } + } + } + + static bool IsNested (TypeAttributes attributes) + { + switch (attributes & TypeAttributes.VisibilityMask) { + case TypeAttributes.NestedAssembly: + case TypeAttributes.NestedFamANDAssem: + case TypeAttributes.NestedFamily: + case TypeAttributes.NestedFamORAssem: + case TypeAttributes.NestedPrivate: + case TypeAttributes.NestedPublic: + return true; + default: + return false; + } + } + + public bool HasNestedTypes (TypeDefinition type) + { + Collection mapping; + InitializeNestedTypes (); + + if (!metadata.TryGetNestedTypeMapping (type, out mapping)) + return false; + + return mapping.Count > 0; + } + + public Collection ReadNestedTypes (TypeDefinition type) + { + InitializeNestedTypes (); + Collection mapping; + if (!metadata.TryGetNestedTypeMapping (type, out mapping)) + return new MemberDefinitionCollection (type); + + var nested_types = new MemberDefinitionCollection (type, mapping.Count); + + for (int i = 0; i < mapping.Count; i++) { + var nested_type = GetTypeDefinition (mapping [i]); + + if (nested_type != null) + nested_types.Add (nested_type); + } + + metadata.RemoveNestedTypeMapping (type); + + return nested_types; + } + + void InitializeNestedTypes () + { + if (metadata.NestedTypes != null) + return; + + var length = MoveTo (Table.NestedClass); + + metadata.NestedTypes = new Dictionary> (length); + metadata.ReverseNestedTypes = new Dictionary (length); + + if (length == 0) + return; + + for (int i = 1; i <= length; i++) { + var nested = ReadTableIndex (Table.TypeDef); + var declaring = ReadTableIndex (Table.TypeDef); + + AddNestedMapping (declaring, nested); + } + } + + void AddNestedMapping (uint declaring, uint nested) + { + metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested)); + metadata.SetReverseNestedTypeMapping (nested, declaring); + } + + static Collection AddMapping (Dictionary> cache, TKey key, TValue value) + { + Collection mapped; + if (!cache.TryGetValue (key, out mapped)) { + mapped = new Collection (); + } + mapped.Add (value); + return mapped; + } + + TypeDefinition ReadType (uint rid) + { + if (!MoveTo (Table.TypeDef, rid)) + return null; + + var attributes = (TypeAttributes)ReadUInt32 (); + var name = ReadString (); + var @namespace = ReadString (); + var type = new TypeDefinition (@namespace, name, attributes); + type.token = new MetadataToken (TokenType.TypeDef, rid); + type.scope = module; + type.module = module; + + metadata.AddTypeDefinition (type); + + this.context = type; + + type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); + + type.fields_range = ReadListRange (rid, Table.TypeDef, Table.Field); + type.methods_range = ReadListRange (rid, Table.TypeDef, Table.Method); + + if (IsNested (attributes)) + type.DeclaringType = GetNestedTypeDeclaringType (type); + + return type; + } + + TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type) + { + uint declaring_rid; + if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid)) + return null; + + metadata.RemoveReverseNestedTypeMapping (type); + return GetTypeDefinition (declaring_rid); + } + + Range ReadListRange (uint current_index, Table current, Table target) + { + var list = new Range (); + + var start = ReadTableIndex (target); + if (start == 0) + return list; + + uint next_index; + var current_table = image.TableHeap [current]; + + if (current_index == current_table.Length) + next_index = image.TableHeap [target].Length + 1; + else { + var position = this.position; + this.position += (int)(current_table.RowSize - image.GetTableIndexSize (target)); + next_index = ReadTableIndex (target); + this.position = position; + } + + list.Start = start; + list.Length = next_index - start; + + return list; + } + + public Row ReadTypeLayout (TypeDefinition type) + { + InitializeTypeLayouts (); + Row class_layout; + var rid = type.token.RID; + if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout)) + return new Row (Mixin.NoDataMarker, Mixin.NoDataMarker); + + type.PackingSize = (short)class_layout.Col1; + type.ClassSize = (int)class_layout.Col2; + + metadata.ClassLayouts.Remove (rid); + + return new Row ((short)class_layout.Col1, (int)class_layout.Col2); + } + + void InitializeTypeLayouts () + { + if (metadata.ClassLayouts != null) + return; + + int length = MoveTo (Table.ClassLayout); + + var class_layouts = metadata.ClassLayouts = new Dictionary> (length); + + for (uint i = 0; i < length; i++) { + var packing_size = ReadUInt16 (); + var class_size = ReadUInt32 (); + + var parent = ReadTableIndex (Table.TypeDef); + + class_layouts.Add (parent, new Row (packing_size, class_size)); + } + } + + public TypeReference GetTypeDefOrRef (MetadataToken token) + { + return (TypeReference)LookupToken (token); + } + + public TypeDefinition GetTypeDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var type = metadata.GetTypeDefinition (rid); + if (type != null) + return type; + + type = ReadTypeDefinition (rid); + + if (module.IsWindowsMetadata ()) + WindowsRuntimeProjections.Project (type); + + return type; + } + + TypeDefinition ReadTypeDefinition (uint rid) + { + if (!MoveTo (Table.TypeDef, rid)) + return null; + + return ReadType (rid); + } + + void InitializeTypeReferences () + { + if (metadata.TypeReferences != null) + return; + + metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)]; + } + + public TypeReference GetTypeReference (string scope, string full_name) + { + InitializeTypeReferences (); + + var length = metadata.TypeReferences.Length; + + for (uint i = 1; i <= length; i++) { + var type = GetTypeReference (i); + + if (type.FullName != full_name) + continue; + + if (string.IsNullOrEmpty (scope)) + return type; + + if (type.Scope.Name == scope) + return type; + } + + return null; + } + + TypeReference GetTypeReference (uint rid) + { + InitializeTypeReferences (); + + var type = metadata.GetTypeReference (rid); + if (type != null) + return type; + + return ReadTypeReference (rid); + } + + TypeReference ReadTypeReference (uint rid) + { + if (!MoveTo (Table.TypeRef, rid)) + return null; + + TypeReference declaring_type = null; + IMetadataScope scope; + + var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope); + + var name = ReadString (); + var @namespace = ReadString (); + + var type = new TypeReference ( + @namespace, + name, + module, + null); + + type.token = new MetadataToken (TokenType.TypeRef, rid); + + metadata.AddTypeReference (type); + + if (scope_token.TokenType == TokenType.TypeRef) { + if (scope_token.RID != rid) { + declaring_type = GetTypeDefOrRef (scope_token); + + scope = declaring_type != null + ? declaring_type.Scope + : module; + } else // obfuscated typeref row pointing to self + scope = module; + } else + scope = GetTypeReferenceScope (scope_token); + + type.scope = scope; + type.DeclaringType = declaring_type; + + MetadataSystem.TryProcessPrimitiveTypeReference (type); + + if (type.Module.IsWindowsMetadata ()) + WindowsRuntimeProjections.Project (type); + + return type; + } + + IMetadataScope GetTypeReferenceScope (MetadataToken scope) + { + if (scope.TokenType == TokenType.Module) + return module; + + IMetadataScope [] scopes; + + switch (scope.TokenType) { + case TokenType.AssemblyRef: + InitializeAssemblyReferences (); + scopes = metadata.AssemblyReferences; + break; + case TokenType.ModuleRef: + InitializeModuleReferences (); + scopes = metadata.ModuleReferences; + break; + default: + throw new NotSupportedException (); + } + + var index = scope.RID - 1; + if (index < 0 || index >= scopes.Length) + return null; + + return scopes [index]; + } + + public IEnumerable GetTypeReferences () + { + InitializeTypeReferences (); + + var length = image.GetTableLength (Table.TypeRef); + + var type_references = new TypeReference [length]; + + for (uint i = 1; i <= length; i++) + type_references [i - 1] = GetTypeReference (i); + + return type_references; + } + + TypeReference GetTypeSpecification (uint rid) + { + if (!MoveTo (Table.TypeSpec, rid)) + return null; + + var reader = ReadSignature (ReadBlobIndex ()); + var type = reader.ReadTypeSignature (); + if (type.token.RID == 0) + type.token = new MetadataToken (TokenType.TypeSpec, rid); + + return type; + } + + SignatureReader ReadSignature (uint signature) + { + return new SignatureReader (signature, this); + } + + public bool HasInterfaces (TypeDefinition type) + { + InitializeInterfaces (); + Collection> mapping; + + return metadata.TryGetInterfaceMapping (type, out mapping); + } + + public InterfaceImplementationCollection ReadInterfaces (TypeDefinition type) + { + InitializeInterfaces (); + Collection> mapping; + + if (!metadata.TryGetInterfaceMapping (type, out mapping)) + return new InterfaceImplementationCollection (type); + + var interfaces = new InterfaceImplementationCollection (type, mapping.Count); + + this.context = type; + + for (int i = 0; i < mapping.Count; i++) { + interfaces.Add ( + new InterfaceImplementation ( + GetTypeDefOrRef (mapping [i].Col2), + new MetadataToken (TokenType.InterfaceImpl, mapping [i].Col1))); + } + + metadata.RemoveInterfaceMapping (type); + + return interfaces; + } + + void InitializeInterfaces () + { + if (metadata.Interfaces != null) + return; + + int length = MoveTo (Table.InterfaceImpl); + + metadata.Interfaces = new Dictionary>> (length); + + for (uint i = 1; i <= length; i++) { + var type = ReadTableIndex (Table.TypeDef); + var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef); + + AddInterfaceMapping (type, new Row (i, @interface)); + } + } + + void AddInterfaceMapping (uint type, Row @interface) + { + metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface)); + } + + public Collection ReadFields (TypeDefinition type) + { + var fields_range = type.fields_range; + if (fields_range.Length == 0) + return new MemberDefinitionCollection (type); + + var fields = new MemberDefinitionCollection (type, (int)fields_range.Length); + this.context = type; + + if (!MoveTo (Table.FieldPtr, fields_range.Start)) { + if (!MoveTo (Table.Field, fields_range.Start)) + return fields; + + for (uint i = 0; i < fields_range.Length; i++) + ReadField (fields_range.Start + i, fields); + } else + ReadPointers (Table.FieldPtr, Table.Field, fields_range, fields, ReadField); + + return fields; + } + + void ReadField (uint field_rid, Collection fields) + { + var attributes = (FieldAttributes)ReadUInt16 (); + var name = ReadString (); + var signature = ReadBlobIndex (); + + var field = new FieldDefinition (name, attributes, ReadFieldType (signature)); + field.token = new MetadataToken (TokenType.Field, field_rid); + metadata.AddFieldDefinition (field); + + if (IsDeleted (field)) + return; + + fields.Add (field); + + if (module.IsWindowsMetadata ()) + WindowsRuntimeProjections.Project (field); + } + + void InitializeFields () + { + if (metadata.Fields != null) + return; + + metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)]; + } + + TypeReference ReadFieldType (uint signature) + { + var reader = ReadSignature (signature); + + const byte field_sig = 0x6; + + if (reader.ReadByte () != field_sig) + throw new NotSupportedException (); + + return reader.ReadTypeSignature (); + } + + public int ReadFieldRVA (FieldDefinition field) + { + InitializeFieldRVAs (); + var rid = field.token.RID; + + RVA rva; + if (!metadata.FieldRVAs.TryGetValue (rid, out rva)) + return 0; + + var size = GetFieldTypeSize (field.FieldType); + + if (size == 0 || rva == 0) + return 0; + + metadata.FieldRVAs.Remove (rid); + + field.InitialValue = GetFieldInitializeValue (size, rva); + + return (int)rva; + } + + byte [] GetFieldInitializeValue (int size, RVA rva) + { + return image.GetReaderAt (rva, size, (s, reader) => reader.ReadBytes (s)) ?? Empty.Array; + } + + static int GetFieldTypeSize (TypeReference type) + { + int size = 0; + + switch (type.etype) { + case ElementType.Boolean: + case ElementType.U1: + case ElementType.I1: + size = 1; + break; + case ElementType.U2: + case ElementType.I2: + case ElementType.Char: + size = 2; + break; + case ElementType.U4: + case ElementType.I4: + case ElementType.R4: + size = 4; + break; + case ElementType.U8: + case ElementType.I8: + case ElementType.R8: + size = 8; + break; + case ElementType.Ptr: + case ElementType.FnPtr: + size = IntPtr.Size; + break; + case ElementType.CModOpt: + case ElementType.CModReqD: + return GetFieldTypeSize (((IModifierType)type).ElementType); + default: + var field_type = type.Resolve (); + if (field_type != null && field_type.HasLayoutInfo) + size = field_type.ClassSize; + + break; + } + + return size; + } + + void InitializeFieldRVAs () + { + if (metadata.FieldRVAs != null) + return; + + int length = MoveTo (Table.FieldRVA); + + var field_rvas = metadata.FieldRVAs = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var rva = ReadUInt32 (); + var field = ReadTableIndex (Table.Field); + + field_rvas.Add (field, rva); + } + } + + public int ReadFieldLayout (FieldDefinition field) + { + InitializeFieldLayouts (); + var rid = field.token.RID; + uint offset; + if (!metadata.FieldLayouts.TryGetValue (rid, out offset)) + return Mixin.NoDataMarker; + + metadata.FieldLayouts.Remove (rid); + + return (int)offset; + } + + void InitializeFieldLayouts () + { + if (metadata.FieldLayouts != null) + return; + + int length = MoveTo (Table.FieldLayout); + + var field_layouts = metadata.FieldLayouts = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var offset = ReadUInt32 (); + var field = ReadTableIndex (Table.Field); + + field_layouts.Add (field, offset); + } + } + + public bool HasEvents (TypeDefinition type) + { + InitializeEvents (); + + Range range; + if (!metadata.TryGetEventsRange (type, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadEvents (TypeDefinition type) + { + InitializeEvents (); + Range range; + + if (!metadata.TryGetEventsRange (type, out range)) + return new MemberDefinitionCollection (type); + + var events = new MemberDefinitionCollection (type, (int)range.Length); + + metadata.RemoveEventsRange (type); + + if (range.Length == 0) + return events; + + this.context = type; + + if (!MoveTo (Table.EventPtr, range.Start)) { + if (!MoveTo (Table.Event, range.Start)) + return events; + + for (uint i = 0; i < range.Length; i++) + ReadEvent (range.Start + i, events); + } else + ReadPointers (Table.EventPtr, Table.Event, range, events, ReadEvent); + + return events; + } + + void ReadEvent (uint event_rid, Collection events) + { + var attributes = (EventAttributes)ReadUInt16 (); + var name = ReadString (); + var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); + + var @event = new EventDefinition (name, attributes, event_type); + @event.token = new MetadataToken (TokenType.Event, event_rid); + + if (IsDeleted (@event)) + return; + + events.Add (@event); + } + + void InitializeEvents () + { + if (metadata.Events != null) + return; + + int length = MoveTo (Table.EventMap); + + metadata.Events = new Dictionary (length); + + for (uint i = 1; i <= length; i++) { + var type_rid = ReadTableIndex (Table.TypeDef); + Range events_range = ReadListRange (i, Table.EventMap, Table.Event); + metadata.AddEventsRange (type_rid, events_range); + } + } + + public bool HasProperties (TypeDefinition type) + { + InitializeProperties (); + + Range range; + if (!metadata.TryGetPropertiesRange (type, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadProperties (TypeDefinition type) + { + InitializeProperties (); + + Range range; + + if (!metadata.TryGetPropertiesRange (type, out range)) + return new MemberDefinitionCollection (type); + + metadata.RemovePropertiesRange (type); + + var properties = new MemberDefinitionCollection (type, (int)range.Length); + + if (range.Length == 0) + return properties; + + this.context = type; + + if (!MoveTo (Table.PropertyPtr, range.Start)) { + if (!MoveTo (Table.Property, range.Start)) + return properties; + for (uint i = 0; i < range.Length; i++) + ReadProperty (range.Start + i, properties); + } else + ReadPointers (Table.PropertyPtr, Table.Property, range, properties, ReadProperty); + + return properties; + } + + void ReadProperty (uint property_rid, Collection properties) + { + var attributes = (PropertyAttributes)ReadUInt16 (); + var name = ReadString (); + var signature = ReadBlobIndex (); + + var reader = ReadSignature (signature); + const byte property_signature = 0x8; + + var calling_convention = reader.ReadByte (); + + if ((calling_convention & property_signature) == 0) + throw new NotSupportedException (); + + var has_this = (calling_convention & 0x20) != 0; + + reader.ReadCompressedUInt32 (); // count + + var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ()); + property.HasThis = has_this; + property.token = new MetadataToken (TokenType.Property, property_rid); + + if (IsDeleted (property)) + return; + + properties.Add (property); + } + + void InitializeProperties () + { + if (metadata.Properties != null) + return; + + int length = MoveTo (Table.PropertyMap); + + metadata.Properties = new Dictionary (length); + + for (uint i = 1; i <= length; i++) { + var type_rid = ReadTableIndex (Table.TypeDef); + var properties_range = ReadListRange (i, Table.PropertyMap, Table.Property); + metadata.AddPropertiesRange (type_rid, properties_range); + } + } + + MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method) + { + InitializeMethodSemantics (); + Row row; + if (!metadata.Semantics.TryGetValue (method.token.RID, out row)) + return MethodSemanticsAttributes.None; + + var type = method.DeclaringType; + + switch (row.Col1) { + case MethodSemanticsAttributes.AddOn: + GetEvent (type, row.Col2).add_method = method; + break; + case MethodSemanticsAttributes.Fire: + GetEvent (type, row.Col2).invoke_method = method; + break; + case MethodSemanticsAttributes.RemoveOn: + GetEvent (type, row.Col2).remove_method = method; + break; + case MethodSemanticsAttributes.Getter: + GetProperty (type, row.Col2).get_method = method; + break; + case MethodSemanticsAttributes.Setter: + GetProperty (type, row.Col2).set_method = method; + break; + case MethodSemanticsAttributes.Other: + switch (row.Col2.TokenType) { + case TokenType.Event: { + var @event = GetEvent (type, row.Col2); + if (@event.other_methods == null) + @event.other_methods = new Collection (); + + @event.other_methods.Add (method); + break; + } + case TokenType.Property: { + var property = GetProperty (type, row.Col2); + if (property.other_methods == null) + property.other_methods = new Collection (); + + property.other_methods.Add (method); + + break; + } + default: + throw new NotSupportedException (); + } + break; + default: + throw new NotSupportedException (); + } + + metadata.Semantics.Remove (method.token.RID); + + return row.Col1; + } + + static EventDefinition GetEvent (TypeDefinition type, MetadataToken token) + { + if (token.TokenType != TokenType.Event) + throw new ArgumentException (); + + return GetMember (type.Events, token); + } + + static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token) + { + if (token.TokenType != TokenType.Property) + throw new ArgumentException (); + + return GetMember (type.Properties, token); + } + + static TMember GetMember (Collection members, MetadataToken token) where TMember : IMemberDefinition + { + for (int i = 0; i < members.Count; i++) { + var member = members [i]; + if (member.MetadataToken == token) + return member; + } + + throw new ArgumentException (); + } + + void InitializeMethodSemantics () + { + if (metadata.Semantics != null) + return; + + int length = MoveTo (Table.MethodSemantics); + + var semantics = metadata.Semantics = new Dictionary> (0); + + for (uint i = 0; i < length; i++) { + var attributes = (MethodSemanticsAttributes)ReadUInt16 (); + var method_rid = ReadTableIndex (Table.Method); + var association = ReadMetadataToken (CodedIndex.HasSemantics); + + semantics [method_rid] = new Row (attributes, association); + } + } + + public void ReadMethods (PropertyDefinition property) + { + ReadAllSemantics (property.DeclaringType); + } + + public void ReadMethods (EventDefinition @event) + { + ReadAllSemantics (@event.DeclaringType); + } + + public void ReadAllSemantics (MethodDefinition method) + { + ReadAllSemantics (method.DeclaringType); + } + + void ReadAllSemantics (TypeDefinition type) + { + var methods = type.Methods; + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + if (method.sem_attrs_ready) + continue; + + method.sem_attrs = ReadMethodSemantics (method); + method.sem_attrs_ready = true; + } + } + + public Collection ReadMethods (TypeDefinition type) + { + var methods_range = type.methods_range; + if (methods_range.Length == 0) + return new MemberDefinitionCollection (type); + + var methods = new MemberDefinitionCollection (type, (int)methods_range.Length); + if (!MoveTo (Table.MethodPtr, methods_range.Start)) { + if (!MoveTo (Table.Method, methods_range.Start)) + return methods; + + for (uint i = 0; i < methods_range.Length; i++) + ReadMethod (methods_range.Start + i, methods); + } else + ReadPointers (Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod); + + return methods; + } + + void ReadPointers (Table ptr, Table table, Range range, Collection members, Action> reader) + where TMember : IMemberDefinition + { + for (uint i = 0; i < range.Length; i++) { + MoveTo (ptr, range.Start + i); + + var rid = ReadTableIndex (table); + MoveTo (table, rid); + + reader (rid, members); + } + } + + static bool IsDeleted (IMemberDefinition member) + { + return member.IsSpecialName && member.Name == "_Deleted"; + } + + void InitializeMethods () + { + if (metadata.Methods != null) + return; + + metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)]; + } + + void ReadMethod (uint method_rid, Collection methods) + { + var method = new MethodDefinition (); + method.rva = ReadUInt32 (); + method.ImplAttributes = (MethodImplAttributes)ReadUInt16 (); + method.Attributes = (MethodAttributes)ReadUInt16 (); + method.Name = ReadString (); + method.token = new MetadataToken (TokenType.Method, method_rid); + + if (IsDeleted (method)) + return; + + methods.Add (method); // attach method + + var signature = ReadBlobIndex (); + var param_range = ReadListRange (method_rid, Table.Method, Table.Param); + + this.context = method; + + ReadMethodSignature (signature, method); + metadata.AddMethodDefinition (method); + + if (param_range.Length != 0) { + var position = base.position; + ReadParameters (method, param_range); + base.position = position; + } + + if (module.IsWindowsMetadata ()) + WindowsRuntimeProjections.Project (method); + } + + void ReadParameters (MethodDefinition method, Range param_range) + { + if (!MoveTo (Table.ParamPtr, param_range.Start)) { + if (!MoveTo (Table.Param, param_range.Start)) + return; + + for (uint i = 0; i < param_range.Length; i++) + ReadParameter (param_range.Start + i, method); + } else + ReadParameterPointers (method, param_range); + } + + void ReadParameterPointers (MethodDefinition method, Range range) + { + for (uint i = 0; i < range.Length; i++) { + MoveTo (Table.ParamPtr, range.Start + i); + + var rid = ReadTableIndex (Table.Param); + + MoveTo (Table.Param, rid); + + ReadParameter (rid, method); + } + } + + void ReadParameter (uint param_rid, MethodDefinition method) + { + var attributes = (ParameterAttributes)ReadUInt16 (); + var sequence = ReadUInt16 (); + var name = ReadString (); + + var parameter = sequence == 0 + ? method.MethodReturnType.Parameter + : method.Parameters [sequence - 1]; + + parameter.token = new MetadataToken (TokenType.Param, param_rid); + parameter.Name = name; + parameter.Attributes = attributes; + } + + void ReadMethodSignature (uint signature, IMethodSignature method) + { + var reader = ReadSignature (signature); + reader.ReadMethodSignature (method); + } + + public PInvokeInfo ReadPInvokeInfo (MethodDefinition method) + { + InitializePInvokes (); + Row row; + + var rid = method.token.RID; + + if (!metadata.PInvokes.TryGetValue (rid, out row)) + return null; + + metadata.PInvokes.Remove (rid); + + return new PInvokeInfo ( + row.Col1, + image.StringHeap.Read (row.Col2), + module.ModuleReferences [(int)row.Col3 - 1]); + } + + void InitializePInvokes () + { + if (metadata.PInvokes != null) + return; + + int length = MoveTo (Table.ImplMap); + + var pinvokes = metadata.PInvokes = new Dictionary> (length); + + for (int i = 1; i <= length; i++) { + var attributes = (PInvokeAttributes)ReadUInt16 (); + var method = ReadMetadataToken (CodedIndex.MemberForwarded); + var name = ReadStringIndex (); + var scope = ReadTableIndex (Table.File); + + if (method.TokenType != TokenType.Method) + continue; + + pinvokes.Add (method.RID, new Row (attributes, name, scope)); + } + } + + public bool HasGenericParameters (IGenericParameterProvider provider) + { + InitializeGenericParameters (); + + Range [] ranges; + if (!metadata.TryGetGenericParameterRanges (provider, out ranges)) + return false; + + return RangesSize (ranges) > 0; + } + + public Collection ReadGenericParameters (IGenericParameterProvider provider) + { + InitializeGenericParameters (); + + Range [] ranges; + if (!metadata.TryGetGenericParameterRanges (provider, out ranges)) + return new GenericParameterCollection (provider); + + metadata.RemoveGenericParameterRange (provider); + + var generic_parameters = new GenericParameterCollection (provider, RangesSize (ranges)); + + for (int i = 0; i < ranges.Length; i++) + ReadGenericParametersRange (ranges [i], provider, generic_parameters); + + return generic_parameters; + } + + void ReadGenericParametersRange (Range range, IGenericParameterProvider provider, GenericParameterCollection generic_parameters) + { + if (!MoveTo (Table.GenericParam, range.Start)) + return; + + for (uint i = 0; i < range.Length; i++) { + ReadUInt16 (); // index + var flags = (GenericParameterAttributes)ReadUInt16 (); + ReadMetadataToken (CodedIndex.TypeOrMethodDef); + var name = ReadString (); + + var parameter = new GenericParameter (name, provider); + parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i); + parameter.Attributes = flags; + + generic_parameters.Add (parameter); + } + } + + void InitializeGenericParameters () + { + if (metadata.GenericParameters != null) + return; + + metadata.GenericParameters = InitializeRanges ( + Table.GenericParam, () => { + Advance (4); + var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef); + ReadStringIndex (); + return next; + }); + } + + Dictionary InitializeRanges (Table table, Func get_next) + { + int length = MoveTo (table); + var ranges = new Dictionary (length); + + if (length == 0) + return ranges; + + MetadataToken owner = MetadataToken.Zero; + Range range = new Range (1, 0); + + for (uint i = 1; i <= length; i++) { + var next = get_next (); + + if (i == 1) { + owner = next; + range.Length++; + } else if (next != owner) { + AddRange (ranges, owner, range); + range = new Range (i, 1); + owner = next; + } else + range.Length++; + } + + AddRange (ranges, owner, range); + + return ranges; + } + + static void AddRange (Dictionary ranges, MetadataToken owner, Range range) + { + if (owner.RID == 0) + return; + + Range [] slots; + if (!ranges.TryGetValue (owner, out slots)) { + ranges.Add (owner, new [] { range }); + return; + } + + ranges [owner] = slots.Add (range); + } + + public bool HasGenericConstraints (GenericParameter generic_parameter) + { + InitializeGenericConstraints (); + + Collection> mapping; + if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) + return false; + + return mapping.Count > 0; + } + + public GenericParameterConstraintCollection ReadGenericConstraints (GenericParameter generic_parameter) + { + InitializeGenericConstraints (); + + Collection> mapping; + if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) + return new GenericParameterConstraintCollection (generic_parameter); + + var constraints = new GenericParameterConstraintCollection (generic_parameter, mapping.Count); + + this.context = (IGenericContext)generic_parameter.Owner; + + for (int i = 0; i < mapping.Count; i++) { + constraints.Add ( + new GenericParameterConstraint ( + GetTypeDefOrRef (mapping [i].Col2), + new MetadataToken (TokenType.GenericParamConstraint, mapping [i].Col1))); + } + + metadata.RemoveGenericConstraintMapping (generic_parameter); + + return constraints; + } + + void InitializeGenericConstraints () + { + if (metadata.GenericConstraints != null) + return; + + var length = MoveTo (Table.GenericParamConstraint); + + metadata.GenericConstraints = new Dictionary>> (length); + + for (uint i = 1; i <= length; i++) { + AddGenericConstraintMapping ( + ReadTableIndex (Table.GenericParam), + new Row (i, ReadMetadataToken (CodedIndex.TypeDefOrRef))); + } + } + + void AddGenericConstraintMapping (uint generic_parameter, Row constraint) + { + metadata.SetGenericConstraintMapping ( + generic_parameter, + AddMapping (metadata.GenericConstraints, generic_parameter, constraint)); + } + + public bool HasOverrides (MethodDefinition method) + { + InitializeOverrides (); + Collection mapping; + + if (!metadata.TryGetOverrideMapping (method, out mapping)) + return false; + + return mapping.Count > 0; + } + + public Collection ReadOverrides (MethodDefinition method) + { + InitializeOverrides (); + + Collection mapping; + if (!metadata.TryGetOverrideMapping (method, out mapping)) + return new Collection (); + + var overrides = new Collection (mapping.Count); + + this.context = method; + + for (int i = 0; i < mapping.Count; i++) + overrides.Add ((MethodReference)LookupToken (mapping [i])); + + metadata.RemoveOverrideMapping (method); + + return overrides; + } + + void InitializeOverrides () + { + if (metadata.Overrides != null) + return; + + var length = MoveTo (Table.MethodImpl); + + metadata.Overrides = new Dictionary> (length); + + for (int i = 1; i <= length; i++) { + ReadTableIndex (Table.TypeDef); + + var method = ReadMetadataToken (CodedIndex.MethodDefOrRef); + if (method.TokenType != TokenType.Method) + throw new NotSupportedException (); + + var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef); + + AddOverrideMapping (method.RID, @override); + } + } + + void AddOverrideMapping (uint method_rid, MetadataToken @override) + { + metadata.SetOverrideMapping ( + method_rid, + AddMapping (metadata.Overrides, method_rid, @override)); + } + + public MethodBody ReadMethodBody (MethodDefinition method) + { + return code.ReadMethodBody (method); + } + + public int ReadCodeSize (MethodDefinition method) + { + return code.ReadCodeSize (method); + } + + public CallSite ReadCallSite (MetadataToken token) + { + if (!MoveTo (Table.StandAloneSig, token.RID)) + return null; + + var signature = ReadBlobIndex (); + + var call_site = new CallSite (); + + ReadMethodSignature (signature, call_site); + + call_site.MetadataToken = token; + + return call_site; + } + + public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token, MethodDefinition method = null) + { + if (!MoveTo (Table.StandAloneSig, local_var_token.RID)) + return null; + + var reader = ReadSignature (ReadBlobIndex ()); + const byte local_sig = 0x7; + + if (reader.ReadByte () != local_sig) + throw new NotSupportedException (); + + var count = reader.ReadCompressedUInt32 (); + if (count == 0) + return null; + + var variables = new VariableDefinitionCollection (method, (int)count); + + for (int i = 0; i < count; i++) + variables.Add (new VariableDefinition (reader.ReadTypeSignature ())); + + return variables; + } + + public IMetadataTokenProvider LookupToken (MetadataToken token) + { + var rid = token.RID; + + if (rid == 0) + return null; + + if (metadata_reader != null) + return metadata_reader.LookupToken (token); + + IMetadataTokenProvider element; + var position = this.position; + var context = this.context; + + switch (token.TokenType) { + case TokenType.TypeDef: + element = GetTypeDefinition (rid); + break; + case TokenType.TypeRef: + element = GetTypeReference (rid); + break; + case TokenType.TypeSpec: + element = GetTypeSpecification (rid); + break; + case TokenType.Field: + element = GetFieldDefinition (rid); + break; + case TokenType.Method: + element = GetMethodDefinition (rid); + break; + case TokenType.MemberRef: + element = GetMemberReference (rid); + break; + case TokenType.MethodSpec: + element = GetMethodSpecification (rid); + break; + default: + return null; + } + + this.position = position; + this.context = context; + + return element; + } + + public FieldDefinition GetFieldDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var field = metadata.GetFieldDefinition (rid); + if (field != null) + return field; + + return LookupField (rid); + } + + FieldDefinition LookupField (uint rid) + { + var type = metadata.GetFieldDeclaringType (rid); + if (type == null) + return null; + + Mixin.Read (type.Fields); + + return metadata.GetFieldDefinition (rid); + } + + public MethodDefinition GetMethodDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var method = metadata.GetMethodDefinition (rid); + if (method != null) + return method; + + return LookupMethod (rid); + } + + MethodDefinition LookupMethod (uint rid) + { + var type = metadata.GetMethodDeclaringType (rid); + if (type == null) + return null; + + Mixin.Read (type.Methods); + + return metadata.GetMethodDefinition (rid); + } + + MethodSpecification GetMethodSpecification (uint rid) + { + if (!MoveTo (Table.MethodSpec, rid)) + return null; + + var element_method = (MethodReference)LookupToken ( + ReadMetadataToken (CodedIndex.MethodDefOrRef)); + var signature = ReadBlobIndex (); + + var method_spec = ReadMethodSpecSignature (signature, element_method); + method_spec.token = new MetadataToken (TokenType.MethodSpec, rid); + return method_spec; + } + + MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method) + { + var reader = ReadSignature (signature); + const byte methodspec_sig = 0x0a; + + var call_conv = reader.ReadByte (); + + if (call_conv != methodspec_sig) + throw new NotSupportedException (); + + var arity = reader.ReadCompressedUInt32 (); + + var instance = new GenericInstanceMethod (method, (int)arity); + + reader.ReadGenericInstanceSignature (method, instance, arity); + + return instance; + } + + MemberReference GetMemberReference (uint rid) + { + InitializeMemberReferences (); + + var member = metadata.GetMemberReference (rid); + if (member != null) + return member; + + member = ReadMemberReference (rid); + if (member != null && !member.ContainsGenericParameter) + metadata.AddMemberReference (member); + return member; + } + + MemberReference ReadMemberReference (uint rid) + { + if (!MoveTo (Table.MemberRef, rid)) + return null; + + var token = ReadMetadataToken (CodedIndex.MemberRefParent); + var name = ReadString (); + var signature = ReadBlobIndex (); + + MemberReference member; + + switch (token.TokenType) { + case TokenType.TypeDef: + case TokenType.TypeRef: + case TokenType.TypeSpec: + member = ReadTypeMemberReference (token, name, signature); + break; + case TokenType.Method: + member = ReadMethodMemberReference (token, name, signature); + break; + default: + throw new NotSupportedException (); + } + + member.token = new MetadataToken (TokenType.MemberRef, rid); + return member; + } + + MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature) + { + var declaring_type = GetTypeDefOrRef (type); + + if (!declaring_type.IsArray) + this.context = declaring_type; + + var member = ReadMemberReferenceSignature (signature, declaring_type); + member.Name = name; + + return member; + } + + MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type) + { + var reader = ReadSignature (signature); + const byte field_sig = 0x6; + + if (reader.buffer [reader.position] == field_sig) { + reader.position++; + var field = new FieldReference (); + field.DeclaringType = declaring_type; + field.FieldType = reader.ReadTypeSignature (); + return field; + } else { + var method = new MethodReference (); + method.DeclaringType = declaring_type; + reader.ReadMethodSignature (method); + return method; + } + } + + MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature) + { + var method = GetMethodDefinition (token.RID); + + this.context = method; + + var member = ReadMemberReferenceSignature (signature, method.DeclaringType); + member.Name = name; + + return member; + } + + void InitializeMemberReferences () + { + if (metadata.MemberReferences != null) + return; + + metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)]; + } + + public IEnumerable GetMemberReferences () + { + InitializeMemberReferences (); + + var length = image.GetTableLength (Table.MemberRef); + + var type_system = module.TypeSystem; + + var context = new MethodDefinition (string.Empty, MethodAttributes.Static, type_system.Void); + context.DeclaringType = new TypeDefinition (string.Empty, string.Empty, TypeAttributes.Public); + + var member_references = new MemberReference [length]; + + for (uint i = 1; i <= length; i++) { + this.context = context; + member_references [i - 1] = GetMemberReference (i); + } + + return member_references; + } + + void InitializeConstants () + { + if (metadata.Constants != null) + return; + + var length = MoveTo (Table.Constant); + + var constants = metadata.Constants = new Dictionary> (length); + + for (uint i = 1; i <= length; i++) { + var type = (ElementType)ReadUInt16 (); + var owner = ReadMetadataToken (CodedIndex.HasConstant); + var signature = ReadBlobIndex (); + + constants.Add (owner, new Row (type, signature)); + } + } + + public TypeReference ReadConstantSignature (MetadataToken token) + { + if (token.TokenType != TokenType.Signature) + throw new NotSupportedException (); + + if (token.RID == 0) + return null; + + if (!MoveTo (Table.StandAloneSig, token.RID)) + return null; + + return ReadFieldType (ReadBlobIndex ()); + } + + public object ReadConstant (IConstantProvider owner) + { + InitializeConstants (); + + Row row; + if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row)) + return Mixin.NoValue; + + metadata.Constants.Remove (owner.MetadataToken); + + return ReadConstantValue (row.Col1, row.Col2); + } + + object ReadConstantValue (ElementType etype, uint signature) + { + switch (etype) { + case ElementType.Class: + case ElementType.Object: + return null; + case ElementType.String: + return ReadConstantString (signature); + default: + return ReadConstantPrimitive (etype, signature); + } + } + + string ReadConstantString (uint signature) + { + byte [] blob; + int index, count; + + GetBlobView (signature, out blob, out index, out count); + if (count == 0) + return string.Empty; + + if ((count & 1) == 1) + count--; + + return Encoding.Unicode.GetString (blob, index, count); + } + + object ReadConstantPrimitive (ElementType type, uint signature) + { + var reader = ReadSignature (signature); + return reader.ReadConstantSignature (type); + } + + internal void InitializeCustomAttributes () + { + if (metadata.CustomAttributes != null) + return; + + metadata.CustomAttributes = InitializeRanges ( + Table.CustomAttribute, () => { + var next = ReadMetadataToken (CodedIndex.HasCustomAttribute); + ReadMetadataToken (CodedIndex.CustomAttributeType); + ReadBlobIndex (); + return next; + }); + } + + public bool HasCustomAttributes (ICustomAttributeProvider owner) + { + InitializeCustomAttributes (); + + Range [] ranges; + if (!metadata.TryGetCustomAttributeRanges (owner, out ranges)) + return false; + + return RangesSize (ranges) > 0; + } + + public Collection ReadCustomAttributes (ICustomAttributeProvider owner) + { + InitializeCustomAttributes (); + + Range [] ranges; + if (!metadata.TryGetCustomAttributeRanges (owner, out ranges)) + return new Collection (); + + var custom_attributes = new Collection (RangesSize (ranges)); + + for (int i = 0; i < ranges.Length; i++) + ReadCustomAttributeRange (ranges [i], custom_attributes); + + metadata.RemoveCustomAttributeRange (owner); + + if (module.IsWindowsMetadata ()) + foreach (var custom_attribute in custom_attributes) + WindowsRuntimeProjections.Project (owner, custom_attribute); + + return custom_attributes; + } + + void ReadCustomAttributeRange (Range range, Collection custom_attributes) + { + if (!MoveTo (Table.CustomAttribute, range.Start)) + return; + + for (var i = 0; i < range.Length; i++) { + ReadMetadataToken (CodedIndex.HasCustomAttribute); + + var constructor = (MethodReference)LookupToken ( + ReadMetadataToken (CodedIndex.CustomAttributeType)); + + var signature = ReadBlobIndex (); + + custom_attributes.Add (new CustomAttribute (signature, constructor)); + } + } + + static int RangesSize (Range [] ranges) + { + uint size = 0; + for (int i = 0; i < ranges.Length; i++) + size += ranges [i].Length; + + return (int)size; + } + + public IEnumerable GetCustomAttributes () + { + InitializeTypeDefinitions (); + + var length = image.TableHeap [Table.CustomAttribute].Length; + var custom_attributes = new Collection ((int)length); + ReadCustomAttributeRange (new Range (1, length), custom_attributes); + + return custom_attributes; + } + + public byte [] ReadCustomAttributeBlob (uint signature) + { + return ReadBlob (signature); + } + + public void ReadCustomAttributeSignature (CustomAttribute attribute) + { + var reader = ReadSignature (attribute.signature); + + if (!reader.CanReadMore ()) + return; + + if (reader.ReadUInt16 () != 0x0001) + throw new InvalidOperationException (); + + var constructor = attribute.Constructor; + if (constructor.HasParameters) + reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters); + + if (!reader.CanReadMore ()) + return; + + var named = reader.ReadUInt16 (); + + if (named == 0) + return; + + reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties); + } + + void InitializeMarshalInfos () + { + if (metadata.FieldMarshals != null) + return; + + var length = MoveTo (Table.FieldMarshal); + + var marshals = metadata.FieldMarshals = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var token = ReadMetadataToken (CodedIndex.HasFieldMarshal); + var signature = ReadBlobIndex (); + if (token.RID == 0) + continue; + + marshals.Add (token, signature); + } + } + + public bool HasMarshalInfo (IMarshalInfoProvider owner) + { + InitializeMarshalInfos (); + + return metadata.FieldMarshals.ContainsKey (owner.MetadataToken); + } + + public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner) + { + InitializeMarshalInfos (); + + uint signature; + if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature)) + return null; + + var reader = ReadSignature (signature); + + metadata.FieldMarshals.Remove (owner.MetadataToken); + + return reader.ReadMarshalInfo (); + } + + void InitializeSecurityDeclarations () + { + if (metadata.SecurityDeclarations != null) + return; + + metadata.SecurityDeclarations = InitializeRanges ( + Table.DeclSecurity, () => { + ReadUInt16 (); + var next = ReadMetadataToken (CodedIndex.HasDeclSecurity); + ReadBlobIndex (); + return next; + }); + } + + public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner) + { + InitializeSecurityDeclarations (); + + Range [] ranges; + if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges)) + return false; + + return RangesSize (ranges) > 0; + } + + public Collection ReadSecurityDeclarations (ISecurityDeclarationProvider owner) + { + InitializeSecurityDeclarations (); + + Range [] ranges; + if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges)) + return new Collection (); + + var security_declarations = new Collection (RangesSize (ranges)); + + for (int i = 0; i < ranges.Length; i++) + ReadSecurityDeclarationRange (ranges [i], security_declarations); + + metadata.RemoveSecurityDeclarationRange (owner); + + return security_declarations; + } + + void ReadSecurityDeclarationRange (Range range, Collection security_declarations) + { + if (!MoveTo (Table.DeclSecurity, range.Start)) + return; + + for (int i = 0; i < range.Length; i++) { + var action = (SecurityAction)ReadUInt16 (); + ReadMetadataToken (CodedIndex.HasDeclSecurity); + var signature = ReadBlobIndex (); + + security_declarations.Add (new SecurityDeclaration (action, signature, module)); + } + } + + public byte [] ReadSecurityDeclarationBlob (uint signature) + { + return ReadBlob (signature); + } + + public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration) + { + var signature = declaration.signature; + var reader = ReadSignature (signature); + + if (reader.buffer [reader.position] != '.') { + ReadXmlSecurityDeclaration (signature, declaration); + return; + } + + reader.position++; + var count = reader.ReadCompressedUInt32 (); + var attributes = new Collection ((int)count); + + for (int i = 0; i < count; i++) + attributes.Add (reader.ReadSecurityAttribute ()); + + declaration.security_attributes = attributes; + } + + void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration) + { + var attributes = new Collection (1); + + var attribute = new SecurityAttribute ( + module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute")); + + attribute.properties = new Collection (1); + attribute.properties.Add ( + new CustomAttributeNamedArgument ( + "XML", + new CustomAttributeArgument ( + module.TypeSystem.String, + ReadUnicodeStringBlob (signature)))); + + attributes.Add (attribute); + + declaration.security_attributes = attributes; + } + + public Collection ReadExportedTypes () + { + var length = MoveTo (Table.ExportedType); + if (length == 0) + return new Collection (); + + var exported_types = new Collection (length); + + for (int i = 1; i <= length; i++) { + var attributes = (TypeAttributes)ReadUInt32 (); + var identifier = ReadUInt32 (); + var name = ReadString (); + var @namespace = ReadString (); + var implementation = ReadMetadataToken (CodedIndex.Implementation); + + ExportedType declaring_type = null; + IMetadataScope scope = null; + + switch (implementation.TokenType) { + case TokenType.AssemblyRef: + case TokenType.File: + scope = GetExportedTypeScope (implementation); + break; + case TokenType.ExportedType: + // FIXME: if the table is not properly sorted + declaring_type = exported_types [(int)implementation.RID - 1]; + break; + } + + var exported_type = new ExportedType (@namespace, name, module, scope) { + Attributes = attributes, + Identifier = (int)identifier, + DeclaringType = declaring_type, + }; + exported_type.token = new MetadataToken (TokenType.ExportedType, i); + + exported_types.Add (exported_type); + } + + return exported_types; + } + + IMetadataScope GetExportedTypeScope (MetadataToken token) + { + var position = this.position; + IMetadataScope scope; + + switch (token.TokenType) { + case TokenType.AssemblyRef: + InitializeAssemblyReferences (); + scope = metadata.GetAssemblyNameReference (token.RID); + break; + case TokenType.File: + InitializeModuleReferences (); + scope = GetModuleReferenceFromFile (token); + break; + default: + throw new NotSupportedException (); + } + + this.position = position; + return scope; + } + + ModuleReference GetModuleReferenceFromFile (MetadataToken token) + { + if (!MoveTo (Table.File, token.RID)) + return null; + + ReadUInt32 (); + var file_name = ReadString (); + var modules = module.ModuleReferences; + + ModuleReference reference; + for (int i = 0; i < modules.Count; i++) { + reference = modules [i]; + if (reference.Name == file_name) + return reference; + } + + reference = new ModuleReference (file_name); + modules.Add (reference); + return reference; + } + + void InitializeDocuments () + { + if (metadata.Documents != null) + return; + + int length = MoveTo (Table.Document); + + var documents = metadata.Documents = new Document [length]; + + for (uint i = 1; i <= length; i++) { + var name_index = ReadBlobIndex (); + var hash_algorithm = ReadGuid (); + var hash = ReadBlob (); + var language = ReadGuid (); + + var signature = ReadSignature (name_index); + var name = signature.ReadDocumentName (); + + documents [i - 1] = new Document (name) { + HashAlgorithmGuid = hash_algorithm, + Hash = hash, + LanguageGuid = language, + token = new MetadataToken (TokenType.Document, i), + }; + } + } + + public Collection ReadSequencePoints (MethodDefinition method) + { + InitializeDocuments (); + + if (!MoveTo (Table.MethodDebugInformation, method.MetadataToken.RID)) + return new Collection (0); + + var document_index = ReadTableIndex (Table.Document); + var signature = ReadBlobIndex (); + if (signature == 0) + return new Collection (0); + + var document = GetDocument (document_index); + var reader = ReadSignature (signature); + + return reader.ReadSequencePoints (document); + } + + public Document GetDocument (uint rid) + { + var document = metadata.GetDocument (rid); + if (document == null) + return null; + + document.custom_infos = GetCustomDebugInformation (document); + return document; + } + + void InitializeLocalScopes () + { + if (metadata.LocalScopes != null) + return; + + InitializeMethods (); + + int length = MoveTo (Table.LocalScope); + + metadata.LocalScopes = new Dictionary>> (); + + for (uint i = 1; i <= length; i++) { + var method = ReadTableIndex (Table.Method); + var import = ReadTableIndex (Table.ImportScope); + var variables = ReadListRange (i, Table.LocalScope, Table.LocalVariable); + var constants = ReadListRange (i, Table.LocalScope, Table.LocalConstant); + var scope_start = ReadUInt32 (); + var scope_length = ReadUInt32 (); + + metadata.SetLocalScopes (method, AddMapping (metadata.LocalScopes, method, new Row (import, variables, constants, scope_start, scope_length, i))); + } + } + + public ScopeDebugInformation ReadScope (MethodDefinition method) + { + InitializeLocalScopes (); + InitializeImportScopes (); + + Collection> records; + if (!metadata.TryGetLocalScopes (method, out records)) + return null; + + var method_scope = null as ScopeDebugInformation; + + for (int i = 0; i < records.Count; i++) { + var scope = ReadLocalScope (records [i]); + + if (i == 0) { + method_scope = scope; + continue; + } + + if (!AddScope (method_scope.scopes, scope)) + method_scope.Scopes.Add (scope); + } + + return method_scope; + } + + static bool AddScope (Collection scopes, ScopeDebugInformation scope) + { + if (scopes.IsNullOrEmpty ()) + return false; + + foreach (var sub_scope in scopes) { + if (sub_scope.HasScopes && AddScope (sub_scope.Scopes, scope)) + return true; + + if (scope.Start.Offset >= sub_scope.Start.Offset && scope.End.Offset <= sub_scope.End.Offset) { + sub_scope.Scopes.Add (scope); + return true; + } + } + + return false; + } + + ScopeDebugInformation ReadLocalScope (Row record) + { + var scope = new ScopeDebugInformation { + start = new InstructionOffset ((int)record.Col4), + end = new InstructionOffset ((int)(record.Col4 + record.Col5)), + token = new MetadataToken (TokenType.LocalScope, record.Col6), + }; + + if (record.Col1 > 0) + scope.import = metadata.GetImportScope (record.Col1); + + if (record.Col2.Length > 0) { + scope.variables = new Collection ((int)record.Col2.Length); + for (uint i = 0; i < record.Col2.Length; i++) { + var variable = ReadLocalVariable (record.Col2.Start + i); + if (variable != null) + scope.variables.Add (variable); + } + } + + if (record.Col3.Length > 0) { + scope.constants = new Collection ((int)record.Col3.Length); + for (uint i = 0; i < record.Col3.Length; i++) { + var constant = ReadLocalConstant (record.Col3.Start + i); + if (constant != null) + scope.constants.Add (constant); + } + } + + return scope; + } + + VariableDebugInformation ReadLocalVariable (uint rid) + { + if (!MoveTo (Table.LocalVariable, rid)) + return null; + + var attributes = (VariableAttributes)ReadUInt16 (); + var index = ReadUInt16 (); + var name = ReadString (); + + var variable = new VariableDebugInformation (index, name) { Attributes = attributes, token = new MetadataToken (TokenType.LocalVariable, rid) }; + variable.custom_infos = GetCustomDebugInformation (variable); + return variable; + } + + ConstantDebugInformation ReadLocalConstant (uint rid) + { + if (!MoveTo (Table.LocalConstant, rid)) + return null; + + var name = ReadString (); + var signature = ReadSignature (ReadBlobIndex ()); + var type = signature.ReadTypeSignature (); + + object value; + if (type.etype == ElementType.String) { + if (signature.CanReadMore () && signature.buffer [signature.position] != 0xff) { + var bytes = signature.ReadBytes ((int)(signature.sig_length - (signature.position - signature.start))); + value = Encoding.Unicode.GetString (bytes, 0, bytes.Length); + } else + value = null; + } else if (type.IsTypeOf ("System", "Decimal")) { + var b = signature.ReadByte (); + value = new decimal (signature.ReadInt32 (), signature.ReadInt32 (), signature.ReadInt32 (), (b & 0x80) != 0, (byte)(b & 0x7f)); + } else if (type.IsTypeOf ("System", "DateTime")) { + value = new DateTime (signature.ReadInt64 ()); + } else if (type.etype == ElementType.Object || type.etype == ElementType.None || type.etype == ElementType.Class || type.etype == ElementType.Array || type.etype == ElementType.GenericInst) { + value = null; + } else + value = signature.ReadConstantSignature (type.etype); + + var constant = new ConstantDebugInformation (name, type, value) { token = new MetadataToken (TokenType.LocalConstant, rid) }; + constant.custom_infos = GetCustomDebugInformation (constant); + return constant; + } + + void InitializeImportScopes () + { + if (metadata.ImportScopes != null) + return; + + var length = MoveTo (Table.ImportScope); + + metadata.ImportScopes = new ImportDebugInformation [length]; + + for (int i = 1; i <= length; i++) { + ReadTableIndex (Table.ImportScope); + + var import = new ImportDebugInformation (); + import.token = new MetadataToken (TokenType.ImportScope, i); + + var signature = ReadSignature (ReadBlobIndex ()); + while (signature.CanReadMore ()) + import.Targets.Add (ReadImportTarget (signature)); + + metadata.ImportScopes [i - 1] = import; + } + + MoveTo (Table.ImportScope); + + for (int i = 0; i < length; i++) { + var parent = ReadTableIndex (Table.ImportScope); + + ReadBlobIndex (); + + if (parent != 0) + metadata.ImportScopes [i].Parent = metadata.GetImportScope (parent); + } + } + + public string ReadUTF8StringBlob (uint signature) + { + return ReadStringBlob (signature, Encoding.UTF8); + } + + string ReadUnicodeStringBlob (uint signature) + { + return ReadStringBlob (signature, Encoding.Unicode); + } + + string ReadStringBlob (uint signature, Encoding encoding) + { + byte [] blob; + int index, count; + + GetBlobView (signature, out blob, out index, out count); + if (count == 0) + return string.Empty; + + return encoding.GetString (blob, index, count); + } + + ImportTarget ReadImportTarget (SignatureReader signature) + { + AssemblyNameReference reference = null; + string @namespace = null; + string alias = null; + TypeReference type = null; + + var kind = (ImportTargetKind)signature.ReadCompressedUInt32 (); + switch (kind) { + case ImportTargetKind.ImportNamespace: + @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.ImportNamespaceInAssembly: + reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); + @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.ImportType: + type = signature.ReadTypeToken (); + break; + case ImportTargetKind.ImportXmlNamespaceWithAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.ImportAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.DefineAssemblyAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.DefineNamespaceAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.DefineNamespaceInAssemblyAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); + @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + break; + case ImportTargetKind.DefineTypeAlias: + alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); + type = signature.ReadTypeToken (); + break; + } + + return new ImportTarget (kind) { + alias = alias, + type = type, + @namespace = @namespace, + reference = reference, + }; + } + + void InitializeStateMachineMethods () + { + if (metadata.StateMachineMethods != null) + return; + + var length = MoveTo (Table.StateMachineMethod); + + metadata.StateMachineMethods = new Dictionary (length); + + for (int i = 0; i < length; i++) + metadata.StateMachineMethods.Add (ReadTableIndex (Table.Method), ReadTableIndex (Table.Method)); + } + + public MethodDefinition ReadStateMachineKickoffMethod (MethodDefinition method) + { + InitializeStateMachineMethods (); + + uint rid; + if (!metadata.TryGetStateMachineKickOffMethod (method, out rid)) + return null; + + return GetMethodDefinition (rid); + } + + void InitializeCustomDebugInformations () + { + if (metadata.CustomDebugInformations != null) + return; + + var length = MoveTo (Table.CustomDebugInformation); + + metadata.CustomDebugInformations = new Dictionary []> (); + + for (uint i = 1; i <= length; i++) { + var token = ReadMetadataToken (CodedIndex.HasCustomDebugInformation); + var info = new Row (ReadGuid (), ReadBlobIndex (), i); + + Row [] infos; + metadata.CustomDebugInformations.TryGetValue (token, out infos); + metadata.CustomDebugInformations [token] = infos.Add (info); + } + } + + public Collection GetCustomDebugInformation (ICustomDebugInformationProvider provider) + { + InitializeCustomDebugInformations (); + + Row [] rows; + if (!metadata.CustomDebugInformations.TryGetValue (provider.MetadataToken, out rows)) + return null; + + var infos = new Collection (rows.Length); + + for (int i = 0; i < rows.Length; i++) { + if (rows [i].Col1 == StateMachineScopeDebugInformation.KindIdentifier) { + var signature = ReadSignature (rows [i].Col2); + var scopes = new Collection (); + + while (signature.CanReadMore ()) { + var start = signature.ReadInt32 (); + var end = start + signature.ReadInt32 (); + scopes.Add (new StateMachineScope (start, end)); + } + + var state_machine = new StateMachineScopeDebugInformation (); + state_machine.scopes = scopes; + + infos.Add (state_machine); + } else if (rows [i].Col1 == AsyncMethodBodyDebugInformation.KindIdentifier) { + var signature = ReadSignature (rows [i].Col2); + + var catch_offset = signature.ReadInt32 () - 1; + var yields = new Collection (); + var resumes = new Collection (); + var resume_methods = new Collection (); + + while (signature.CanReadMore ()) { + yields.Add (new InstructionOffset (signature.ReadInt32 ())); + resumes.Add (new InstructionOffset (signature.ReadInt32 ())); + resume_methods.Add (GetMethodDefinition (signature.ReadCompressedUInt32 ())); + } + + var async_body = new AsyncMethodBodyDebugInformation (catch_offset); + async_body.yields = yields; + async_body.resumes = resumes; + async_body.resume_methods = resume_methods; + + infos.Add (async_body); + } else if (rows [i].Col1 == EmbeddedSourceDebugInformation.KindIdentifier) { + infos.Add (new EmbeddedSourceDebugInformation (rows [i].Col2, this)); + } else if (rows [i].Col1 == SourceLinkDebugInformation.KindIdentifier) { + infos.Add (new SourceLinkDebugInformation (Encoding.UTF8.GetString (ReadBlob (rows [i].Col2)))); + } else { + infos.Add (new BinaryCustomDebugInformation (rows [i].Col1, ReadBlob (rows [i].Col2))); + } + + infos [i].token = new MetadataToken (TokenType.CustomDebugInformation, rows [i].Col3); + } + + return infos; + } + + public byte [] ReadRawEmbeddedSourceDebugInformation (uint index) + { + var signature = ReadSignature (index); + return signature.ReadBytes ((int)signature.sig_length); + } + + public Row ReadEmbeddedSourceDebugInformation (uint index) + { + var signature = ReadSignature (index); + var format = signature.ReadInt32 (); + var length = signature.sig_length - 4; + + if (format == 0) { + return new Row (signature.ReadBytes ((int)length), false); + } else if (format > 0) { + var compressed_stream = new MemoryStream (signature.ReadBytes ((int)length)); + var decompressed_document = new byte [format]; // if positive, format is the decompressed length of the document + var decompressed_stream = new MemoryStream (decompressed_document); + + using (var deflate_stream = new DeflateStream (compressed_stream, CompressionMode.Decompress, leaveOpen: true)) + deflate_stream.CopyTo (decompressed_stream); + + return new Row (decompressed_document, true); + } else + throw new NotSupportedException (); + } + } + + sealed class SignatureReader : ByteBuffer { + + readonly MetadataReader reader; + readonly internal uint start, sig_length; + + TypeSystem TypeSystem { + get { return reader.module.TypeSystem; } + } + + public SignatureReader (uint blob, MetadataReader reader) + : base (reader.image.BlobHeap.data) + { + this.reader = reader; + this.position = (int)blob; + this.sig_length = ReadCompressedUInt32 (); + this.start = (uint)this.position; + } + + MetadataToken ReadTypeTokenSignature () + { + return CodedIndex.TypeDefOrRef.GetMetadataToken (ReadCompressedUInt32 ()); + } + + GenericParameter GetGenericParameter (GenericParameterType type, uint var) + { + var context = reader.context; + int index = (int)var; + + if (context == null) + return GetUnboundGenericParameter (type, index); + + IGenericParameterProvider provider; + + switch (type) { + case GenericParameterType.Type: + provider = context.Type; + break; + case GenericParameterType.Method: + provider = context.Method; + break; + default: + throw new NotSupportedException (); + } + + if (!context.IsDefinition) + CheckGenericContext (provider, index); + + if (index >= provider.GenericParameters.Count) + return GetUnboundGenericParameter (type, index); + + return provider.GenericParameters [index]; + } + + GenericParameter GetUnboundGenericParameter (GenericParameterType type, int index) + { + return new GenericParameter (index, type, reader.module); + } + + static void CheckGenericContext (IGenericParameterProvider owner, int index) + { + var owner_parameters = owner.GenericParameters; + + for (int i = owner_parameters.Count; i <= index; i++) + owner_parameters.Add (new GenericParameter (owner)); + } + + public void ReadGenericInstanceSignature (IGenericParameterProvider provider, IGenericInstance instance, uint arity) + { + if (!provider.IsDefinition) + CheckGenericContext (provider, (int)arity - 1); + + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < arity; i++) + instance_arguments.Add (ReadTypeSignature ()); + } + + ArrayType ReadArrayTypeSignature () + { + var array = new ArrayType (ReadTypeSignature ()); + + var rank = ReadCompressedUInt32 (); + + var sizes = new uint [ReadCompressedUInt32 ()]; + for (int i = 0; i < sizes.Length; i++) + sizes [i] = ReadCompressedUInt32 (); + + var low_bounds = new int [ReadCompressedUInt32 ()]; + for (int i = 0; i < low_bounds.Length; i++) + low_bounds [i] = ReadCompressedInt32 (); + + array.Dimensions.Clear (); + + for (int i = 0; i < rank; i++) { + int? lower = null, upper = null; + + if (i < low_bounds.Length) + lower = low_bounds [i]; + + if (i < sizes.Length) + upper = lower + (int)sizes [i] - 1; + + array.Dimensions.Add (new ArrayDimension (lower, upper)); + } + + return array; + } + + TypeReference GetTypeDefOrRef (MetadataToken token) + { + return reader.GetTypeDefOrRef (token); + } + + public TypeReference ReadTypeSignature () + { + return ReadTypeSignature ((ElementType)ReadByte ()); + } + + public TypeReference ReadTypeToken () + { + return GetTypeDefOrRef (ReadTypeTokenSignature ()); + } + + TypeReference ReadTypeSignature (ElementType etype) + { + switch (etype) { + case ElementType.ValueType: { + var value_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); + value_type.KnownValueType (); + return value_type; + } + case ElementType.Class: + return GetTypeDefOrRef (ReadTypeTokenSignature ()); + case ElementType.Ptr: + return new PointerType (ReadTypeSignature ()); + case ElementType.FnPtr: { + var fptr = new FunctionPointerType (); + ReadMethodSignature (fptr); + return fptr; + } + case ElementType.ByRef: + return new ByReferenceType (ReadTypeSignature ()); + case ElementType.Pinned: + return new PinnedType (ReadTypeSignature ()); + case ElementType.SzArray: + return new ArrayType (ReadTypeSignature ()); + case ElementType.Array: + return ReadArrayTypeSignature (); + case ElementType.CModOpt: + return new OptionalModifierType ( + GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); + case ElementType.CModReqD: + return new RequiredModifierType ( + GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); + case ElementType.Sentinel: + return new SentinelType (ReadTypeSignature ()); + case ElementType.Var: + return GetGenericParameter (GenericParameterType.Type, ReadCompressedUInt32 ()); + case ElementType.MVar: + return GetGenericParameter (GenericParameterType.Method, ReadCompressedUInt32 ()); + case ElementType.GenericInst: { + var is_value_type = ReadByte () == (byte)ElementType.ValueType; + var element_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); + + var arity = ReadCompressedUInt32 (); + var generic_instance = new GenericInstanceType (element_type, (int)arity); + + ReadGenericInstanceSignature (element_type, generic_instance, arity); + + if (is_value_type) { + generic_instance.KnownValueType (); + element_type.GetElementType ().KnownValueType (); + } + + return generic_instance; + } + case ElementType.Object: return TypeSystem.Object; + case ElementType.Void: return TypeSystem.Void; + case ElementType.TypedByRef: return TypeSystem.TypedReference; + case ElementType.I: return TypeSystem.IntPtr; + case ElementType.U: return TypeSystem.UIntPtr; + default: return GetPrimitiveType (etype); + } + } + + public void ReadMethodSignature (IMethodSignature method) + { + var calling_convention = ReadByte (); + + const byte has_this = 0x20; + const byte explicit_this = 0x40; + + if ((calling_convention & has_this) != 0) { + method.HasThis = true; + calling_convention = (byte)(calling_convention & ~has_this); + } + + if ((calling_convention & explicit_this) != 0) { + method.ExplicitThis = true; + calling_convention = (byte)(calling_convention & ~explicit_this); + } + + method.CallingConvention = (MethodCallingConvention)calling_convention; + + var generic_context = method as MethodReference; + if (generic_context != null && !generic_context.DeclaringType.IsArray) + reader.context = generic_context; + + if ((calling_convention & 0x10) != 0) { + var arity = ReadCompressedUInt32 (); + + if (generic_context != null && !generic_context.IsDefinition) + CheckGenericContext (generic_context, (int)arity - 1); + } + + var param_count = ReadCompressedUInt32 (); + + method.MethodReturnType.ReturnType = ReadTypeSignature (); + + if (param_count == 0) + return; + + Collection parameters; + + var method_ref = method as MethodReference; + if (method_ref != null) + parameters = method_ref.parameters = new ParameterDefinitionCollection (method, (int)param_count); + else + parameters = method.Parameters; + + for (int i = 0; i < param_count; i++) + parameters.Add (new ParameterDefinition (ReadTypeSignature ())); + } + + public object ReadConstantSignature (ElementType type) + { + return ReadPrimitiveValue (type); + } + + public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, Collection parameters) + { + var count = parameters.Count; + if (count == 0) + return; + + attribute.arguments = new Collection (count); + + for (int i = 0; i < count; i++) + attribute.arguments.Add ( + ReadCustomAttributeFixedArgument (parameters [i].ParameterType)); + } + + CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type) + { + if (type.IsArray) + return ReadCustomAttributeFixedArrayArgument ((ArrayType)type); + + return ReadCustomAttributeElement (type); + } + + public void ReadCustomAttributeNamedArguments (ushort count, ref Collection fields, ref Collection properties) + { + for (int i = 0; i < count; i++) { + if (!CanReadMore ()) + return; + ReadCustomAttributeNamedArgument (ref fields, ref properties); + } + } + + void ReadCustomAttributeNamedArgument (ref Collection fields, ref Collection properties) + { + var kind = ReadByte (); + var type = ReadCustomAttributeFieldOrPropType (); + var name = ReadUTF8String (); + + Collection container; + switch (kind) { + case 0x53: + container = GetCustomAttributeNamedArgumentCollection (ref fields); + break; + case 0x54: + container = GetCustomAttributeNamedArgumentCollection (ref properties); + break; + default: + throw new NotSupportedException (); + } + + container.Add (new CustomAttributeNamedArgument (name, ReadCustomAttributeFixedArgument (type))); + } + + static Collection GetCustomAttributeNamedArgumentCollection (ref Collection collection) + { + if (collection != null) + return collection; + + return collection = new Collection (); + } + + CustomAttributeArgument ReadCustomAttributeFixedArrayArgument (ArrayType type) + { + var length = ReadUInt32 (); + + if (length == 0xffffffff) + return new CustomAttributeArgument (type, null); + + if (length == 0) + return new CustomAttributeArgument (type, Empty.Array); + + var arguments = new CustomAttributeArgument [length]; + var element_type = type.ElementType; + + for (int i = 0; i < length; i++) + arguments [i] = ReadCustomAttributeElement (element_type); + + return new CustomAttributeArgument (type, arguments); + } + + CustomAttributeArgument ReadCustomAttributeElement (TypeReference type) + { + if (type.IsArray) + return ReadCustomAttributeFixedArrayArgument ((ArrayType)type); + + return new CustomAttributeArgument ( + type, + type.etype == ElementType.Object + ? ReadCustomAttributeElement (ReadCustomAttributeFieldOrPropType ()) + : ReadCustomAttributeElementValue (type)); + } + + object ReadCustomAttributeElementValue (TypeReference type) + { + var etype = type.etype; + + switch (etype) { + case ElementType.String: + return ReadUTF8String (); + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + return ReadTypeReference (); + + return ReadCustomAttributeEnum (type); + default: + return ReadPrimitiveValue (etype); + } + } + + object ReadPrimitiveValue (ElementType type) + { + switch (type) { + case ElementType.Boolean: + return ReadByte () == 1; + case ElementType.I1: + return (sbyte)ReadByte (); + case ElementType.U1: + return ReadByte (); + case ElementType.Char: + return (char)ReadUInt16 (); + case ElementType.I2: + return ReadInt16 (); + case ElementType.U2: + return ReadUInt16 (); + case ElementType.I4: + return ReadInt32 (); + case ElementType.U4: + return ReadUInt32 (); + case ElementType.I8: + return ReadInt64 (); + case ElementType.U8: + return ReadUInt64 (); + case ElementType.R4: + return ReadSingle (); + case ElementType.R8: + return ReadDouble (); + default: + throw new NotImplementedException (type.ToString ()); + } + } + + TypeReference GetPrimitiveType (ElementType etype) + { + switch (etype) { + case ElementType.Boolean: + return TypeSystem.Boolean; + case ElementType.Char: + return TypeSystem.Char; + case ElementType.I1: + return TypeSystem.SByte; + case ElementType.U1: + return TypeSystem.Byte; + case ElementType.I2: + return TypeSystem.Int16; + case ElementType.U2: + return TypeSystem.UInt16; + case ElementType.I4: + return TypeSystem.Int32; + case ElementType.U4: + return TypeSystem.UInt32; + case ElementType.I8: + return TypeSystem.Int64; + case ElementType.U8: + return TypeSystem.UInt64; + case ElementType.R4: + return TypeSystem.Single; + case ElementType.R8: + return TypeSystem.Double; + case ElementType.String: + return TypeSystem.String; + default: + throw new NotImplementedException (etype.ToString ()); + } + } + + TypeReference ReadCustomAttributeFieldOrPropType () + { + var etype = (ElementType)ReadByte (); + + switch (etype) { + case ElementType.Boxed: + return TypeSystem.Object; + case ElementType.SzArray: + return new ArrayType (ReadCustomAttributeFieldOrPropType ()); + case ElementType.Enum: + return ReadTypeReference (); + case ElementType.Type: + return TypeSystem.LookupType ("System", "Type"); + default: + return GetPrimitiveType (etype); + } + } + + public TypeReference ReadTypeReference () + { + return TypeParser.ParseType (reader.module, ReadUTF8String ()); + } + + object ReadCustomAttributeEnum (TypeReference enum_type) + { + var type = enum_type.CheckedResolve (); + if (!type.IsEnum) + throw new ArgumentException (); + + return ReadCustomAttributeElementValue (type.GetEnumUnderlyingType ()); + } + + public SecurityAttribute ReadSecurityAttribute () + { + var attribute = new SecurityAttribute (ReadTypeReference ()); + + ReadCompressedUInt32 (); + + ReadCustomAttributeNamedArguments ( + (ushort)ReadCompressedUInt32 (), + ref attribute.fields, + ref attribute.properties); + + return attribute; + } + + public MarshalInfo ReadMarshalInfo () + { + var native = ReadNativeType (); + switch (native) { + case NativeType.Array: { + var array = new ArrayMarshalInfo (); + if (CanReadMore ()) + array.element_type = ReadNativeType (); + if (CanReadMore ()) + array.size_parameter_index = (int)ReadCompressedUInt32 (); + if (CanReadMore ()) + array.size = (int)ReadCompressedUInt32 (); + if (CanReadMore ()) + array.size_parameter_multiplier = (int)ReadCompressedUInt32 (); + return array; + } + case NativeType.SafeArray: { + var array = new SafeArrayMarshalInfo (); + if (CanReadMore ()) + array.element_type = ReadVariantType (); + return array; + } + case NativeType.FixedArray: { + var array = new FixedArrayMarshalInfo (); + if (CanReadMore ()) + array.size = (int)ReadCompressedUInt32 (); + if (CanReadMore ()) + array.element_type = ReadNativeType (); + return array; + } + case NativeType.FixedSysString: { + var sys_string = new FixedSysStringMarshalInfo (); + if (CanReadMore ()) + sys_string.size = (int)ReadCompressedUInt32 (); + return sys_string; + } + case NativeType.CustomMarshaler: { + var marshaler = new CustomMarshalInfo (); + var guid_value = ReadUTF8String (); + marshaler.guid = !string.IsNullOrEmpty (guid_value) ? new Guid (guid_value) : Guid.Empty; + marshaler.unmanaged_type = ReadUTF8String (); + marshaler.managed_type = ReadTypeReference (); + marshaler.cookie = ReadUTF8String (); + return marshaler; + } + default: + return new MarshalInfo (native); + } + } + + NativeType ReadNativeType () + { + return (NativeType)ReadByte (); + } + + VariantType ReadVariantType () + { + return (VariantType)ReadByte (); + } + + string ReadUTF8String () + { + if (buffer [position] == 0xff) { + position++; + return null; + } + + var length = (int)ReadCompressedUInt32 (); + if (length == 0) + return string.Empty; + + if (position + length > buffer.Length) + return string.Empty; + + var @string = Encoding.UTF8.GetString (buffer, position, length); + + position += length; + return @string; + } + + public string ReadDocumentName () + { + var separator = (char)buffer [position]; + position++; + + var builder = new StringBuilder (); + for (int i = 0; CanReadMore (); i++) { + if (i > 0 && separator != 0) + builder.Append (separator); + + uint part = ReadCompressedUInt32 (); + if (part != 0) + builder.Append (reader.ReadUTF8StringBlob (part)); + } + + return builder.ToString (); + } + + public Collection ReadSequencePoints (Document document) + { + ReadCompressedUInt32 (); // local_sig_token + + if (document == null) + document = reader.GetDocument (ReadCompressedUInt32 ()); + + var offset = 0; + var start_line = 0; + var start_column = 0; + var first_non_hidden = true; + + //there's about 5 compressed int32's per sequenec points. we don't know exactly how many + //but let's take a conservative guess so we dont end up reallocating the sequence_points collection + //as it grows. + var bytes_remaining_for_sequencepoints = sig_length - (position - start); + var estimated_sequencepoint_amount = (int)bytes_remaining_for_sequencepoints / 5; + var sequence_points = new Collection (estimated_sequencepoint_amount); + + for (var i = 0; CanReadMore (); i++) { + var delta_il = (int)ReadCompressedUInt32 (); + if (i > 0 && delta_il == 0) { + document = reader.GetDocument (ReadCompressedUInt32 ()); + continue; + } + + offset += delta_il; + + var delta_lines = (int)ReadCompressedUInt32 (); + var delta_columns = delta_lines == 0 + ? (int)ReadCompressedUInt32 () + : ReadCompressedInt32 (); + + if (delta_lines == 0 && delta_columns == 0) { + sequence_points.Add (new SequencePoint (offset, document) { + StartLine = 0xfeefee, + EndLine = 0xfeefee, + StartColumn = 0, + EndColumn = 0, + }); + continue; + } + + if (first_non_hidden) { + start_line = (int)ReadCompressedUInt32 (); + start_column = (int)ReadCompressedUInt32 (); + } else { + start_line += ReadCompressedInt32 (); + start_column += ReadCompressedInt32 (); + } + + sequence_points.Add (new SequencePoint (offset, document) { + StartLine = start_line, + StartColumn = start_column, + EndLine = start_line + delta_lines, + EndColumn = start_column + delta_columns, + }); + first_non_hidden = false; + } + + return sequence_points; + } + + public bool CanReadMore () + { + return (position - start) < sig_length; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs.meta new file mode 100644 index 0000000..810883e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8fb74d16029713429e831cb3b5b0861 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs new file mode 100644 index 0000000..5d74689 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs @@ -0,0 +1,3336 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using BlobIndex = System.UInt32; +using CodedRID = System.UInt32; +using GuidIndex = System.UInt32; +using RID = System.UInt32; +using RVA = System.UInt32; +using StringIndex = System.UInt32; + +namespace MonoFN.Cecil { + + using AssemblyRefRow = Row; + using AssemblyRow = Row; + using ClassLayoutRow = Row; + using ConstantRow = Row; + using CustomAttributeRow = Row; + using CustomDebugInformationRow = Row; + using DeclSecurityRow = Row; + using DocumentRow = Row; + using EventMapRow = Row; + using EventRow = Row; + using ExportedTypeRow = Row; + using FieldLayoutRow = Row; + using FieldMarshalRow = Row; + using FieldRow = Row; + using FieldRVARow = Row; + using FileRow = Row; + using GenericParamConstraintRow = Row; + using GenericParamRow = Row; + using ImplMapRow = Row; + using ImportScopeRow = Row; + using InterfaceImplRow = Row; + using LocalConstantRow = Row; + using LocalScopeRow = Row; + using LocalVariableRow = Row; + using ManifestResourceRow = Row; + using MemberRefRow = Row; + using MethodDebugInformationRow = Row; + using MethodImplRow = Row; + using MethodRow = Row; + using MethodSemanticsRow = Row; + using MethodSpecRow = Row; + using ModuleRow = Row; + using NestedClassRow = Row; + using ParamRow = Row; + using PropertyMapRow = Row; + using PropertyRow = Row; + using StateMachineMethodRow = Row; + using TypeDefRow = Row; + using TypeRefRow = Row; + + static class ModuleWriter { + + public static void WriteModule (ModuleDefinition module, Disposable stream, WriterParameters parameters) + { + using (stream) + Write (module, stream, parameters); + } + + static void Write (ModuleDefinition module, Disposable stream, WriterParameters parameters) + { + if ((module.Attributes & ModuleAttributes.ILOnly) == 0) + throw new NotSupportedException ("Writing mixed-mode assemblies is not supported"); + + if (module.HasImage && module.ReadingMode == ReadingMode.Deferred) { + var immediate_reader = new ImmediateModuleReader (module.Image); + immediate_reader.ReadModule (module, resolve_attributes: false); + immediate_reader.ReadSymbols (module); + } + + module.MetadataSystem.Clear (); + + if (module.symbol_reader != null) + module.symbol_reader.Dispose (); + + var name = module.assembly != null && module.kind != ModuleKind.NetModule ? module.assembly.Name : null; + var fq_name = stream.value.GetFileName (); + var timestamp = parameters.Timestamp ?? module.timestamp; + var symbol_writer_provider = parameters.SymbolWriterProvider; + + if (symbol_writer_provider == null && parameters.WriteSymbols) + symbol_writer_provider = new DefaultSymbolWriterProvider (); + + if (parameters.HasStrongNameKey && name != null) { + name.PublicKey = CryptoService.GetPublicKey (parameters); + module.Attributes |= ModuleAttributes.StrongNameSigned; + } + + if (parameters.DeterministicMvid) + module.Mvid = Guid.Empty; + + var metadata = new MetadataBuilder (module, fq_name, timestamp, symbol_writer_provider); + try { + module.metadata_builder = metadata; + + using (var symbol_writer = GetSymbolWriter (module, fq_name, symbol_writer_provider, parameters)) { + metadata.SetSymbolWriter (symbol_writer); + BuildMetadata (module, metadata); + + if (parameters.DeterministicMvid) + metadata.ComputeDeterministicMvid (); + + var writer = ImageWriter.CreateWriter (module, metadata, stream); + stream.value.SetLength (0); + writer.WriteImage (); + + if (parameters.HasStrongNameKey) + CryptoService.StrongName (stream.value, writer, parameters); + } + } + finally { + module.metadata_builder = null; + } + } + + static void BuildMetadata (ModuleDefinition module, MetadataBuilder metadata) + { + if (!module.HasImage) { + metadata.BuildMetadata (); + return; + } + + module.Read (metadata, (builder, _) => { + builder.BuildMetadata (); + return builder; + }); + } + + static ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fq_name, ISymbolWriterProvider symbol_writer_provider, WriterParameters parameters) + { + if (symbol_writer_provider == null) + return null; + + if (parameters.SymbolStream != null) + return symbol_writer_provider.GetSymbolWriter (module, parameters.SymbolStream); + + return symbol_writer_provider.GetSymbolWriter (module, fq_name); + } + } + + abstract class MetadataTable { + + public abstract int Length { get; } + + public bool IsLarge { + get { return Length > ushort.MaxValue; } + } + + public abstract void Write (TableHeapBuffer buffer); + public abstract void Sort (); + } + + abstract class OneRowTable : MetadataTable where TRow : struct { + + internal TRow row; + + public sealed override int Length { + get { return 1; } + } + + public sealed override void Sort () + { + } + } + + abstract class MetadataTable : MetadataTable where TRow : struct { + + internal TRow [] rows = new TRow [2]; + internal int length; + + public sealed override int Length { + get { return length; } + } + + public int AddRow (TRow row) + { + if (rows.Length == length) + Grow (); + + rows [length++] = row; + return length; + } + + void Grow () + { + var rows = new TRow [this.rows.Length * 2]; + Array.Copy (this.rows, rows, this.rows.Length); + this.rows = rows; + } + + public override void Sort () + { + } + } + + abstract class SortedTable : MetadataTable, IComparer where TRow : struct { + + public sealed override void Sort () + { + MergeSort.Sort (rows, 0, this.length, this); + } + + protected static int Compare (uint x, uint y) + { + return x == y ? 0 : x > y ? 1 : -1; + } + + public abstract int Compare (TRow x, TRow y); + } + + sealed class ModuleTable : OneRowTable { + + public override void Write (TableHeapBuffer buffer) + { + buffer.WriteUInt16 (0); // Generation + buffer.WriteString (row.Col1); // Name + buffer.WriteGuid (row.Col2); // Mvid + buffer.WriteUInt16 (0); // EncId + buffer.WriteUInt16 (0); // EncBaseId + } + } + + sealed class TypeRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID ( + rows [i].Col1, CodedIndex.ResolutionScope); // Scope + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteString (rows [i].Col3); // Namespace + } + } + } + + sealed class TypeDefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint)rows [i].Col1); // Attributes + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteString (rows [i].Col3); // Namespace + buffer.WriteCodedRID ( + rows [i].Col4, CodedIndex.TypeDefOrRef); // Extends + buffer.WriteRID (rows [i].Col5, Table.Field); // FieldList + buffer.WriteRID (rows [i].Col6, Table.Method); // MethodList + } + } + } + + sealed class FieldTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Attributes + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteBlob (rows [i].Col3); // Signature + } + } + } + + sealed class MethodTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // RVA + buffer.WriteUInt16 ((ushort)rows [i].Col2); // ImplFlags + buffer.WriteUInt16 ((ushort)rows [i].Col3); // Flags + buffer.WriteString (rows [i].Col4); // Name + buffer.WriteBlob (rows [i].Col5); // Signature + buffer.WriteRID (rows [i].Col6, Table.Param); // ParamList + } + } + } + + sealed class ParamTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Attributes + buffer.WriteUInt16 (rows [i].Col2); // Sequence + buffer.WriteString (rows [i].Col3); // Name + } + } + } + + sealed class InterfaceImplTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Class + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.TypeDefOrRef); // Interface + } + } + + /*public override int Compare (InterfaceImplRow x, InterfaceImplRow y) + { + return (int) (x.Col1 == y.Col1 ? y.Col2 - x.Col2 : x.Col1 - y.Col1); + }*/ + } + + sealed class MemberRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.MemberRefParent); + buffer.WriteString (rows [i].Col2); + buffer.WriteBlob (rows [i].Col3); + } + } + } + + sealed class ConstantTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.HasConstant); + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (ConstantRow x, ConstantRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class CustomAttributeTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.HasCustomAttribute); // Parent + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.CustomAttributeType); // Type + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (CustomAttributeRow x, CustomAttributeRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class FieldMarshalTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.HasFieldMarshal); + buffer.WriteBlob (rows [i].Col2); + } + } + + public override int Compare (FieldMarshalRow x, FieldMarshalRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class DeclSecurityTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.HasDeclSecurity); + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (DeclSecurityRow x, DeclSecurityRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class ClassLayoutTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // PackingSize + buffer.WriteUInt32 (rows [i].Col2); // ClassSize + buffer.WriteRID (rows [i].Col3, Table.TypeDef); // Parent + } + } + + public override int Compare (ClassLayoutRow x, ClassLayoutRow y) + { + return Compare (x.Col3, y.Col3); + } + } + + sealed class FieldLayoutTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // Offset + buffer.WriteRID (rows [i].Col2, Table.Field); // Parent + } + } + + public override int Compare (FieldLayoutRow x, FieldLayoutRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class StandAloneSigTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteBlob (rows [i]); + } + } + + sealed class EventMapTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Parent + buffer.WriteRID (rows [i].Col2, Table.Event); // EventList + } + } + } + + sealed class EventTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Flags + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.TypeDefOrRef); // EventType + } + } + } + + sealed class PropertyMapTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Parent + buffer.WriteRID (rows [i].Col2, Table.Property); // PropertyList + } + } + } + + sealed class PropertyTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Flags + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteBlob (rows [i].Col3); // Type + } + } + } + + sealed class MethodSemanticsTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Flags + buffer.WriteRID (rows [i].Col2, Table.Method); // Method + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.HasSemantics); // Association + } + } + + public override int Compare (MethodSemanticsRow x, MethodSemanticsRow y) + { + return Compare (x.Col3, y.Col3); + } + } + + sealed class MethodImplTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Class + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.MethodDefOrRef); // MethodBody + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.MethodDefOrRef); // MethodDeclaration + } + } + } + + sealed class ModuleRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteString (rows [i]); // Name + } + } + + sealed class TypeSpecTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteBlob (rows [i]); // Signature + } + } + + sealed class ImplMapTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Flags + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.MemberForwarded); // MemberForwarded + buffer.WriteString (rows [i].Col3); // ImportName + buffer.WriteRID (rows [i].Col4, Table.ModuleRef); // ImportScope + } + } + + public override int Compare (ImplMapRow x, ImplMapRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class FieldRVATable : SortedTable { + + internal int position; + + public override void Write (TableHeapBuffer buffer) + { + position = buffer.position; + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // RVA + buffer.WriteRID (rows [i].Col2, Table.Field); // Field + } + } + + public override int Compare (FieldRVARow x, FieldRVARow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class AssemblyTable : OneRowTable { + + public override void Write (TableHeapBuffer buffer) + { + buffer.WriteUInt32 ((uint)row.Col1); // AssemblyHashAlgorithm + buffer.WriteUInt16 (row.Col2); // MajorVersion + buffer.WriteUInt16 (row.Col3); // MinorVersion + buffer.WriteUInt16 (row.Col4); // Build + buffer.WriteUInt16 (row.Col5); // Revision + buffer.WriteUInt32 ((uint)row.Col6); // Flags + buffer.WriteBlob (row.Col7); // PublicKey + buffer.WriteString (row.Col8); // Name + buffer.WriteString (row.Col9); // Culture + } + } + + sealed class AssemblyRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // MajorVersion + buffer.WriteUInt16 (rows [i].Col2); // MinorVersion + buffer.WriteUInt16 (rows [i].Col3); // Build + buffer.WriteUInt16 (rows [i].Col4); // Revision + buffer.WriteUInt32 ((uint)rows [i].Col5); // Flags + buffer.WriteBlob (rows [i].Col6); // PublicKeyOrToken + buffer.WriteString (rows [i].Col7); // Name + buffer.WriteString (rows [i].Col8); // Culture + buffer.WriteBlob (rows [i].Col9); // Hash + } + } + } + + sealed class FileTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint)rows [i].Col1); + buffer.WriteString (rows [i].Col2); + buffer.WriteBlob (rows [i].Col3); + } + } + } + + sealed class ExportedTypeTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint)rows [i].Col1); + buffer.WriteUInt32 (rows [i].Col2); + buffer.WriteString (rows [i].Col3); + buffer.WriteString (rows [i].Col4); + buffer.WriteCodedRID (rows [i].Col5, CodedIndex.Implementation); + } + } + } + + sealed class ManifestResourceTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); + buffer.WriteUInt32 ((uint)rows [i].Col2); + buffer.WriteString (rows [i].Col3); + buffer.WriteCodedRID (rows [i].Col4, CodedIndex.Implementation); + } + } + } + + sealed class NestedClassTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // NestedClass + buffer.WriteRID (rows [i].Col2, Table.TypeDef); // EnclosingClass + } + } + + public override int Compare (NestedClassRow x, NestedClassRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class GenericParamTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // Number + buffer.WriteUInt16 ((ushort)rows [i].Col2); // Flags + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.TypeOrMethodDef); // Owner + buffer.WriteString (rows [i].Col4); // Name + } + } + } + + sealed class MethodSpecTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.MethodDefOrRef); // Method + buffer.WriteBlob (rows [i].Col2); // Instantiation + } + } + } + + sealed class GenericParamConstraintTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.GenericParam); // Owner + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.TypeDefOrRef); // Constraint + } + } + } + + sealed class DocumentTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteBlob (rows [i].Col1); // Name + buffer.WriteGuid (rows [i].Col2); // HashAlgorithm + buffer.WriteBlob (rows [i].Col3); // Hash + buffer.WriteGuid (rows [i].Col4); // Language + } + } + } + + sealed class MethodDebugInformationTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.Document); // Document + buffer.WriteBlob (rows [i].Col2); // SequencePoints + } + } + } + + sealed class LocalScopeTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.Method); // Method + buffer.WriteRID (rows [i].Col2, Table.ImportScope); // ImportScope + buffer.WriteRID (rows [i].Col3, Table.LocalVariable); // VariableList + buffer.WriteRID (rows [i].Col4, Table.LocalConstant); // ConstantList + buffer.WriteUInt32 (rows [i].Col5); // StartOffset + buffer.WriteUInt32 (rows [i].Col6); // Length + } + } + } + + sealed class LocalVariableTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort)rows [i].Col1); // Attributes + buffer.WriteUInt16 (rows [i].Col2); // Index + buffer.WriteString (rows [i].Col3); // Name + } + } + } + + sealed class LocalConstantTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteString (rows [i].Col1); // Name + buffer.WriteBlob (rows [i].Col2); // Signature + } + } + } + + sealed class ImportScopeTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.ImportScope); // Parent + buffer.WriteBlob (rows [i].Col2); // Imports + } + } + } + + sealed class StateMachineMethodTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.Method); // MoveNextMethod + buffer.WriteRID (rows [i].Col2, Table.Method); // KickoffMethod + } + } + } + + sealed class CustomDebugInformationTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.HasCustomDebugInformation); // Parent + buffer.WriteGuid (rows [i].Col2); // Kind + buffer.WriteBlob (rows [i].Col3); // Value + } + } + + public override int Compare (CustomDebugInformationRow x, CustomDebugInformationRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class MetadataBuilder { + + readonly internal ModuleDefinition module; + readonly internal ISymbolWriterProvider symbol_writer_provider; + internal ISymbolWriter symbol_writer; + readonly internal TextMap text_map; + readonly internal string fq_name; + readonly internal uint timestamp; + + readonly Dictionary type_ref_map; + readonly Dictionary type_spec_map; + readonly Dictionary member_ref_map; + readonly Dictionary method_spec_map; + readonly Collection generic_parameters; + + readonly internal CodeWriter code; + readonly internal DataBuffer data; + readonly internal ResourceBuffer resources; + readonly internal StringHeapBuffer string_heap; + readonly internal GuidHeapBuffer guid_heap; + readonly internal UserStringHeapBuffer user_string_heap; + readonly internal BlobHeapBuffer blob_heap; + readonly internal TableHeapBuffer table_heap; + readonly internal PdbHeapBuffer pdb_heap; + + internal MetadataToken entry_point; + + internal RID type_rid = 1; + internal RID field_rid = 1; + internal RID method_rid = 1; + internal RID param_rid = 1; + internal RID property_rid = 1; + internal RID event_rid = 1; + internal RID local_variable_rid = 1; + internal RID local_constant_rid = 1; + + readonly TypeRefTable type_ref_table; + readonly TypeDefTable type_def_table; + readonly FieldTable field_table; + readonly MethodTable method_table; + readonly ParamTable param_table; + readonly InterfaceImplTable iface_impl_table; + readonly MemberRefTable member_ref_table; + readonly ConstantTable constant_table; + readonly CustomAttributeTable custom_attribute_table; + readonly DeclSecurityTable declsec_table; + readonly StandAloneSigTable standalone_sig_table; + readonly EventMapTable event_map_table; + readonly EventTable event_table; + readonly PropertyMapTable property_map_table; + readonly PropertyTable property_table; + readonly TypeSpecTable typespec_table; + readonly MethodSpecTable method_spec_table; + + internal MetadataBuilder metadata_builder; + + readonly DocumentTable document_table; + readonly MethodDebugInformationTable method_debug_information_table; + readonly LocalScopeTable local_scope_table; + readonly LocalVariableTable local_variable_table; + readonly LocalConstantTable local_constant_table; + readonly ImportScopeTable import_scope_table; + readonly StateMachineMethodTable state_machine_method_table; + readonly CustomDebugInformationTable custom_debug_information_table; + + readonly Dictionary import_scope_map; + readonly Dictionary document_map; + + public MetadataBuilder (ModuleDefinition module, string fq_name, uint timestamp, ISymbolWriterProvider symbol_writer_provider) + { + this.module = module; + this.text_map = CreateTextMap (); + this.fq_name = fq_name; + this.timestamp = timestamp; + this.symbol_writer_provider = symbol_writer_provider; + + this.code = new CodeWriter (this); + this.data = new DataBuffer (); + this.resources = new ResourceBuffer (); + this.string_heap = new StringHeapBuffer (); + this.guid_heap = new GuidHeapBuffer (); + this.user_string_heap = new UserStringHeapBuffer (); + this.blob_heap = new BlobHeapBuffer (); + this.table_heap = new TableHeapBuffer (module, this); + + this.type_ref_table = GetTable (Table.TypeRef); + this.type_def_table = GetTable (Table.TypeDef); + this.field_table = GetTable (Table.Field); + this.method_table = GetTable (Table.Method); + this.param_table = GetTable (Table.Param); + this.iface_impl_table = GetTable (Table.InterfaceImpl); + this.member_ref_table = GetTable (Table.MemberRef); + this.constant_table = GetTable (Table.Constant); + this.custom_attribute_table = GetTable (Table.CustomAttribute); + this.declsec_table = GetTable (Table.DeclSecurity); + this.standalone_sig_table = GetTable (Table.StandAloneSig); + this.event_map_table = GetTable (Table.EventMap); + this.event_table = GetTable (Table.Event); + this.property_map_table = GetTable (Table.PropertyMap); + this.property_table = GetTable (Table.Property); + this.typespec_table = GetTable (Table.TypeSpec); + this.method_spec_table = GetTable (Table.MethodSpec); + + var row_equality_comparer = new RowEqualityComparer (); + type_ref_map = new Dictionary (row_equality_comparer); + type_spec_map = new Dictionary (); + member_ref_map = new Dictionary (row_equality_comparer); + method_spec_map = new Dictionary (row_equality_comparer); + generic_parameters = new Collection (); + + this.document_table = GetTable (Table.Document); + this.method_debug_information_table = GetTable (Table.MethodDebugInformation); + this.local_scope_table = GetTable (Table.LocalScope); + this.local_variable_table = GetTable (Table.LocalVariable); + this.local_constant_table = GetTable (Table.LocalConstant); + this.import_scope_table = GetTable (Table.ImportScope); + this.state_machine_method_table = GetTable (Table.StateMachineMethod); + this.custom_debug_information_table = GetTable (Table.CustomDebugInformation); + + this.document_map = new Dictionary (StringComparer.Ordinal); + this.import_scope_map = new Dictionary (row_equality_comparer); + } + + public MetadataBuilder (ModuleDefinition module, PortablePdbWriterProvider writer_provider) + { + this.module = module; + this.text_map = new TextMap (); + this.symbol_writer_provider = writer_provider; + + this.string_heap = new StringHeapBuffer (); + this.guid_heap = new GuidHeapBuffer (); + this.user_string_heap = new UserStringHeapBuffer (); + this.blob_heap = new BlobHeapBuffer (); + this.table_heap = new TableHeapBuffer (module, this); + this.pdb_heap = new PdbHeapBuffer (); + + this.document_table = GetTable (Table.Document); + this.method_debug_information_table = GetTable (Table.MethodDebugInformation); + this.local_scope_table = GetTable (Table.LocalScope); + this.local_variable_table = GetTable (Table.LocalVariable); + this.local_constant_table = GetTable (Table.LocalConstant); + this.import_scope_table = GetTable (Table.ImportScope); + this.state_machine_method_table = GetTable (Table.StateMachineMethod); + this.custom_debug_information_table = GetTable (Table.CustomDebugInformation); + + var row_equality_comparer = new RowEqualityComparer (); + + this.document_map = new Dictionary (); + this.import_scope_map = new Dictionary (row_equality_comparer); + } + + public void SetSymbolWriter (ISymbolWriter writer) + { + symbol_writer = writer; + + if (symbol_writer == null && module.HasImage && module.Image.HasDebugTables ()) + symbol_writer = new PortablePdbWriter (this, module); + } + + TextMap CreateTextMap () + { + var map = new TextMap (); + map.AddMap (TextSegment.ImportAddressTable, module.Architecture == TargetArchitecture.I386 ? 8 : 0); + map.AddMap (TextSegment.CLIHeader, 0x48, 8); + return map; + } + + TTable GetTable (Table table) where TTable : MetadataTable, new() + { + return table_heap.GetTable (table); + } + + uint GetStringIndex (string @string) + { + if (string.IsNullOrEmpty (@string)) + return 0; + + return string_heap.GetStringIndex (@string); + } + + uint GetGuidIndex (Guid guid) + { + return guid_heap.GetGuidIndex (guid); + } + + uint GetBlobIndex (ByteBuffer blob) + { + if (blob.length == 0) + return 0; + + return blob_heap.GetBlobIndex (blob); + } + + uint GetBlobIndex (byte [] blob) + { + if (blob.IsNullOrEmpty ()) + return 0; + + return GetBlobIndex (new ByteBuffer (blob)); + } + + public void BuildMetadata () + { + BuildModule (); + + table_heap.string_offsets = string_heap.WriteStrings (); + table_heap.ComputeTableInformations (); + table_heap.WriteTableHeap (); + } + + void BuildModule () + { + var table = GetTable (Table.Module); + table.row.Col1 = GetStringIndex (module.Name); + table.row.Col2 = GetGuidIndex (module.Mvid); + + var assembly = module.Assembly; + + if (module.kind != ModuleKind.NetModule && assembly != null) + BuildAssembly (); + + if (module.HasAssemblyReferences) + AddAssemblyReferences (); + + if (module.HasModuleReferences) + AddModuleReferences (); + + if (module.HasResources) + AddResources (); + + if (module.HasExportedTypes) + AddExportedTypes (); + + BuildTypes (); + + if (module.kind != ModuleKind.NetModule && assembly != null) { + if (assembly.HasCustomAttributes) + AddCustomAttributes (assembly); + + if (assembly.HasSecurityDeclarations) + AddSecurityDeclarations (assembly); + } + + if (module.HasCustomAttributes) + AddCustomAttributes (module); + + if (module.EntryPoint != null) + entry_point = LookupToken (module.EntryPoint); + } + + void BuildAssembly () + { + var assembly = module.Assembly; + var name = assembly.Name; + + var table = GetTable (Table.Assembly); + + table.row = new AssemblyRow ( + name.HashAlgorithm, + (ushort)name.Version.Major, + (ushort)name.Version.Minor, + (ushort)name.Version.Build, + (ushort)name.Version.Revision, + name.Attributes, + GetBlobIndex (name.PublicKey), + GetStringIndex (name.Name), + GetStringIndex (name.Culture)); + + if (assembly.Modules.Count > 1) + BuildModules (); + } + + void BuildModules () + { + var modules = this.module.Assembly.Modules; + var table = GetTable (Table.File); + + for (int i = 0; i < modules.Count; i++) { + var module = modules [i]; + if (module.IsMain) + continue; + +#if NET_CORE + throw new NotSupportedException (); +#else + var parameters = new WriterParameters { + SymbolWriterProvider = symbol_writer_provider, + }; + + var file_name = GetModuleFileName (module.Name); + module.Write (file_name, parameters); + + var hash = CryptoService.ComputeHash (file_name); + + table.AddRow (new FileRow ( + FileAttributes.ContainsMetaData, + GetStringIndex (module.Name), + GetBlobIndex (hash))); +#endif + } + } + +#if !NET_CORE + string GetModuleFileName (string name) + { + if (string.IsNullOrEmpty (name)) + throw new NotSupportedException (); + + var path = Path.GetDirectoryName (fq_name); + return Path.Combine (path, name); + } +#endif + + void AddAssemblyReferences () + { + var references = module.AssemblyReferences; + var table = GetTable (Table.AssemblyRef); + + if (module.IsWindowsMetadata ()) + module.Projections.RemoveVirtualReferences (references); + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + + var key_or_token = reference.PublicKey.IsNullOrEmpty () + ? reference.PublicKeyToken + : reference.PublicKey; + + var version = reference.Version; + + var rid = table.AddRow (new AssemblyRefRow ( + (ushort)version.Major, + (ushort)version.Minor, + (ushort)version.Build, + (ushort)version.Revision, + reference.Attributes, + GetBlobIndex (key_or_token), + GetStringIndex (reference.Name), + GetStringIndex (reference.Culture), + GetBlobIndex (reference.Hash))); + + reference.token = new MetadataToken (TokenType.AssemblyRef, rid); + } + + if (module.IsWindowsMetadata ()) + module.Projections.AddVirtualReferences (references); + } + + void AddModuleReferences () + { + var references = module.ModuleReferences; + var table = GetTable (Table.ModuleRef); + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + + reference.token = new MetadataToken ( + TokenType.ModuleRef, + table.AddRow (GetStringIndex (reference.Name))); + } + } + + void AddResources () + { + var resources = module.Resources; + var table = GetTable (Table.ManifestResource); + + for (int i = 0; i < resources.Count; i++) { + var resource = resources [i]; + + var row = new ManifestResourceRow ( + 0, + resource.Attributes, + GetStringIndex (resource.Name), + 0); + + switch (resource.ResourceType) { + case ResourceType.Embedded: + row.Col1 = AddEmbeddedResource ((EmbeddedResource)resource); + break; + case ResourceType.Linked: + row.Col4 = CodedIndex.Implementation.CompressMetadataToken ( + new MetadataToken ( + TokenType.File, + AddLinkedResource ((LinkedResource)resource))); + break; + case ResourceType.AssemblyLinked: + row.Col4 = CodedIndex.Implementation.CompressMetadataToken ( + ((AssemblyLinkedResource)resource).Assembly.MetadataToken); + break; + default: + throw new NotSupportedException (); + } + + table.AddRow (row); + } + } + + uint AddLinkedResource (LinkedResource resource) + { + var table = GetTable (Table.File); + var hash = resource.Hash; + + if (hash.IsNullOrEmpty ()) + hash = CryptoService.ComputeHash (resource.File); + + return (uint)table.AddRow (new FileRow ( + FileAttributes.ContainsNoMetaData, + GetStringIndex (resource.File), + GetBlobIndex (hash))); + } + + uint AddEmbeddedResource (EmbeddedResource resource) + { + return resources.AddResource (resource.GetResourceData ()); + } + + void AddExportedTypes () + { + var exported_types = module.ExportedTypes; + var table = GetTable (Table.ExportedType); + + for (int i = 0; i < exported_types.Count; i++) { + var exported_type = exported_types [i]; + + var rid = table.AddRow (new ExportedTypeRow ( + exported_type.Attributes, + (uint)exported_type.Identifier, + GetStringIndex (exported_type.Name), + GetStringIndex (exported_type.Namespace), + MakeCodedRID (GetExportedTypeScope (exported_type), CodedIndex.Implementation))); + + exported_type.token = new MetadataToken (TokenType.ExportedType, rid); + } + } + + MetadataToken GetExportedTypeScope (ExportedType exported_type) + { + if (exported_type.DeclaringType != null) + return exported_type.DeclaringType.MetadataToken; + + var scope = exported_type.Scope; + switch (scope.MetadataToken.TokenType) { + case TokenType.AssemblyRef: + return scope.MetadataToken; + case TokenType.ModuleRef: + var file_table = GetTable (Table.File); + for (int i = 0; i < file_table.length; i++) + if (file_table.rows [i].Col2 == GetStringIndex (scope.Name)) + return new MetadataToken (TokenType.File, i + 1); + + break; + } + + throw new NotSupportedException (); + } + + void BuildTypes () + { + if (!module.HasTypes) + return; + + AttachTokens (); + AddTypes (); + AddGenericParameters (); + } + + void AttachTokens () + { + var types = module.Types; + + for (int i = 0; i < types.Count; i++) + AttachTypeToken (types [i]); + } + + void AttachTypeToken (TypeDefinition type) + { + var treatment = WindowsRuntimeProjections.RemoveProjection (type); + + type.token = new MetadataToken (TokenType.TypeDef, type_rid++); + type.fields_range.Start = field_rid; + type.methods_range.Start = method_rid; + + if (type.HasFields) + AttachFieldsToken (type); + + if (type.HasMethods) + AttachMethodsToken (type); + + if (type.HasNestedTypes) + AttachNestedTypesToken (type); + + WindowsRuntimeProjections.ApplyProjection (type, treatment); + } + + void AttachNestedTypesToken (TypeDefinition type) + { + var nested_types = type.NestedTypes; + for (int i = 0; i < nested_types.Count; i++) + AttachTypeToken (nested_types [i]); + } + + void AttachFieldsToken (TypeDefinition type) + { + var fields = type.Fields; + type.fields_range.Length = (uint)fields.Count; + for (int i = 0; i < fields.Count; i++) + fields [i].token = new MetadataToken (TokenType.Field, field_rid++); + } + + void AttachMethodsToken (TypeDefinition type) + { + var methods = type.Methods; + type.methods_range.Length = (uint)methods.Count; + for (int i = 0; i < methods.Count; i++) + methods [i].token = new MetadataToken (TokenType.Method, method_rid++); + } + + MetadataToken GetTypeToken (TypeReference type) + { + if (type == null) + return MetadataToken.Zero; + + if (type.IsDefinition) + return type.token; + + if (type.IsTypeSpecification ()) + return GetTypeSpecToken (type); + + return GetTypeRefToken (type); + } + + MetadataToken GetTypeSpecToken (TypeReference type) + { + var row = GetBlobIndex (GetTypeSpecSignature (type)); + + MetadataToken token; + if (type_spec_map.TryGetValue (row, out token)) + return token; + + return AddTypeSpecification (type, row); + } + + MetadataToken AddTypeSpecification (TypeReference type, uint row) + { + type.token = new MetadataToken (TokenType.TypeSpec, typespec_table.AddRow (row)); + + var token = type.token; + type_spec_map.Add (row, token); + return token; + } + + MetadataToken GetTypeRefToken (TypeReference type) + { + var projection = WindowsRuntimeProjections.RemoveProjection (type); + + var row = CreateTypeRefRow (type); + + MetadataToken token; + if (!type_ref_map.TryGetValue (row, out token)) + token = AddTypeReference (type, row); + + WindowsRuntimeProjections.ApplyProjection (type, projection); + + return token; + } + + TypeRefRow CreateTypeRefRow (TypeReference type) + { + var scope_token = GetScopeToken (type); + + return new TypeRefRow ( + MakeCodedRID (scope_token, CodedIndex.ResolutionScope), + GetStringIndex (type.Name), + GetStringIndex (type.Namespace)); + } + + MetadataToken GetScopeToken (TypeReference type) + { + if (type.IsNested) + return GetTypeRefToken (type.DeclaringType); + + var scope = type.Scope; + + if (scope == null) + return MetadataToken.Zero; + + return scope.MetadataToken; + } + + static CodedRID MakeCodedRID (IMetadataTokenProvider provider, CodedIndex index) + { + return MakeCodedRID (provider.MetadataToken, index); + } + + static CodedRID MakeCodedRID (MetadataToken token, CodedIndex index) + { + return index.CompressMetadataToken (token); + } + + MetadataToken AddTypeReference (TypeReference type, TypeRefRow row) + { + type.token = new MetadataToken (TokenType.TypeRef, type_ref_table.AddRow (row)); + + var token = type.token; + type_ref_map.Add (row, token); + return token; + } + + void AddTypes () + { + var types = module.Types; + + for (int i = 0; i < types.Count; i++) + AddType (types [i]); + } + + void AddType (TypeDefinition type) + { + var treatment = WindowsRuntimeProjections.RemoveProjection (type); + + type_def_table.AddRow (new TypeDefRow ( + type.Attributes, + GetStringIndex (type.Name), + GetStringIndex (type.Namespace), + MakeCodedRID (GetTypeToken (type.BaseType), CodedIndex.TypeDefOrRef), + type.fields_range.Start, + type.methods_range.Start)); + + if (type.HasGenericParameters) + AddGenericParameters (type); + + if (type.HasInterfaces) + AddInterfaces (type); + + if (type.HasLayoutInfo) + AddLayoutInfo (type); + + if (type.HasFields) + AddFields (type); + + if (type.HasMethods) + AddMethods (type); + + if (type.HasProperties) + AddProperties (type); + + if (type.HasEvents) + AddEvents (type); + + if (type.HasCustomAttributes) + AddCustomAttributes (type); + + if (type.HasSecurityDeclarations) + AddSecurityDeclarations (type); + + if (type.HasNestedTypes) + AddNestedTypes (type); + + WindowsRuntimeProjections.ApplyProjection (type, treatment); + } + + void AddGenericParameters (IGenericParameterProvider owner) + { + var parameters = owner.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) + generic_parameters.Add (parameters [i]); + } + + sealed class GenericParameterComparer : IComparer { + + public int Compare (GenericParameter a, GenericParameter b) + { + var a_owner = MakeCodedRID (a.Owner, CodedIndex.TypeOrMethodDef); + var b_owner = MakeCodedRID (b.Owner, CodedIndex.TypeOrMethodDef); + if (a_owner == b_owner) { + var a_pos = a.Position; + var b_pos = b.Position; + return a_pos == b_pos ? 0 : a_pos > b_pos ? 1 : -1; + } + + return a_owner > b_owner ? 1 : -1; + } + } + + void AddGenericParameters () + { + var items = this.generic_parameters.items; + var size = this.generic_parameters.size; + Array.Sort (items, 0, size, new GenericParameterComparer ()); + + var generic_param_table = GetTable (Table.GenericParam); + var generic_param_constraint_table = GetTable (Table.GenericParamConstraint); + + for (int i = 0; i < size; i++) { + var generic_parameter = items [i]; + + var rid = generic_param_table.AddRow (new GenericParamRow ( + (ushort)generic_parameter.Position, + generic_parameter.Attributes, + MakeCodedRID (generic_parameter.Owner, CodedIndex.TypeOrMethodDef), + GetStringIndex (generic_parameter.Name))); + + generic_parameter.token = new MetadataToken (TokenType.GenericParam, rid); + + if (generic_parameter.HasConstraints) + AddConstraints (generic_parameter, generic_param_constraint_table); + + if (generic_parameter.HasCustomAttributes) + AddCustomAttributes (generic_parameter); + } + } + + void AddConstraints (GenericParameter generic_parameter, GenericParamConstraintTable table) + { + var constraints = generic_parameter.Constraints; + + var gp_rid = generic_parameter.token.RID; + + for (int i = 0; i < constraints.Count; i++) { + var constraint = constraints [i]; + + var rid = table.AddRow (new GenericParamConstraintRow ( + gp_rid, + MakeCodedRID (GetTypeToken (constraint.ConstraintType), CodedIndex.TypeDefOrRef))); + + constraint.token = new MetadataToken (TokenType.GenericParamConstraint, rid); + + if (constraint.HasCustomAttributes) + AddCustomAttributes (constraint); + } + } + + void AddInterfaces (TypeDefinition type) + { + var interfaces = type.Interfaces; + var type_rid = type.token.RID; + + for (int i = 0; i < interfaces.Count; i++) { + var iface_impl = interfaces [i]; + + var rid = iface_impl_table.AddRow (new InterfaceImplRow ( + type_rid, + MakeCodedRID (GetTypeToken (iface_impl.InterfaceType), CodedIndex.TypeDefOrRef))); + + iface_impl.token = new MetadataToken (TokenType.InterfaceImpl, rid); + + if (iface_impl.HasCustomAttributes) + AddCustomAttributes (iface_impl); + } + } + + void AddLayoutInfo (TypeDefinition type) + { + var table = GetTable (Table.ClassLayout); + + table.AddRow (new ClassLayoutRow ( + (ushort)type.PackingSize, + (uint)type.ClassSize, + type.token.RID)); + } + + void AddNestedTypes (TypeDefinition type) + { + var nested_types = type.NestedTypes; + var nested_table = GetTable (Table.NestedClass); + + for (int i = 0; i < nested_types.Count; i++) { + var nested = nested_types [i]; + AddType (nested); + nested_table.AddRow (new NestedClassRow (nested.token.RID, type.token.RID)); + } + } + + void AddFields (TypeDefinition type) + { + var fields = type.Fields; + + for (int i = 0; i < fields.Count; i++) + AddField (fields [i]); + } + + void AddField (FieldDefinition field) + { + var projection = WindowsRuntimeProjections.RemoveProjection (field); + + field_table.AddRow (new FieldRow ( + field.Attributes, + GetStringIndex (field.Name), + GetBlobIndex (GetFieldSignature (field)))); + + if (!field.InitialValue.IsNullOrEmpty ()) + AddFieldRVA (field); + + if (field.HasLayoutInfo) + AddFieldLayout (field); + + if (field.HasCustomAttributes) + AddCustomAttributes (field); + + if (field.HasConstant) + AddConstant (field, field.FieldType); + + if (field.HasMarshalInfo) + AddMarshalInfo (field); + + WindowsRuntimeProjections.ApplyProjection (field, projection); + } + + void AddFieldRVA (FieldDefinition field) + { + var table = GetTable (Table.FieldRVA); + table.AddRow (new FieldRVARow ( + data.AddData (field.InitialValue), + field.token.RID)); + } + + void AddFieldLayout (FieldDefinition field) + { + var table = GetTable (Table.FieldLayout); + table.AddRow (new FieldLayoutRow ((uint)field.Offset, field.token.RID)); + } + + void AddMethods (TypeDefinition type) + { + var methods = type.Methods; + + for (int i = 0; i < methods.Count; i++) + AddMethod (methods [i]); + } + + void AddMethod (MethodDefinition method) + { + var projection = WindowsRuntimeProjections.RemoveProjection (method); + + method_table.AddRow (new MethodRow ( + method.HasBody ? code.WriteMethodBody (method) : 0, + method.ImplAttributes, + method.Attributes, + GetStringIndex (method.Name), + GetBlobIndex (GetMethodSignature (method)), + param_rid)); + + AddParameters (method); + + if (method.HasGenericParameters) + AddGenericParameters (method); + + if (method.IsPInvokeImpl) + AddPInvokeInfo (method); + + if (method.HasCustomAttributes) + AddCustomAttributes (method); + + if (method.HasSecurityDeclarations) + AddSecurityDeclarations (method); + + if (method.HasOverrides) + AddOverrides (method); + + WindowsRuntimeProjections.ApplyProjection (method, projection); + } + + void AddParameters (MethodDefinition method) + { + var return_parameter = method.MethodReturnType.parameter; + + if (return_parameter != null && RequiresParameterRow (return_parameter)) + AddParameter (0, return_parameter, param_table); + + if (!method.HasParameters) + return; + + var parameters = method.Parameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + if (!RequiresParameterRow (parameter)) + continue; + + AddParameter ((ushort)(i + 1), parameter, param_table); + } + } + + void AddPInvokeInfo (MethodDefinition method) + { + var pinvoke = method.PInvokeInfo; + if (pinvoke == null) + return; + + var table = GetTable (Table.ImplMap); + table.AddRow (new ImplMapRow ( + pinvoke.Attributes, + MakeCodedRID (method, CodedIndex.MemberForwarded), + GetStringIndex (pinvoke.EntryPoint), + pinvoke.Module.MetadataToken.RID)); + } + + void AddOverrides (MethodDefinition method) + { + var overrides = method.Overrides; + var table = GetTable (Table.MethodImpl); + + for (int i = 0; i < overrides.Count; i++) { + table.AddRow (new MethodImplRow ( + method.DeclaringType.token.RID, + MakeCodedRID (method, CodedIndex.MethodDefOrRef), + MakeCodedRID (LookupToken (overrides [i]), CodedIndex.MethodDefOrRef))); + } + } + + static bool RequiresParameterRow (ParameterDefinition parameter) + { + return !string.IsNullOrEmpty (parameter.Name) + || parameter.Attributes != ParameterAttributes.None + || parameter.HasMarshalInfo + || parameter.HasConstant + || parameter.HasCustomAttributes; + } + + void AddParameter (ushort sequence, ParameterDefinition parameter, ParamTable table) + { + table.AddRow (new ParamRow ( + parameter.Attributes, + sequence, + GetStringIndex (parameter.Name))); + + parameter.token = new MetadataToken (TokenType.Param, param_rid++); + + if (parameter.HasCustomAttributes) + AddCustomAttributes (parameter); + + if (parameter.HasConstant) + AddConstant (parameter, parameter.ParameterType); + + if (parameter.HasMarshalInfo) + AddMarshalInfo (parameter); + } + + void AddMarshalInfo (IMarshalInfoProvider owner) + { + var table = GetTable (Table.FieldMarshal); + + table.AddRow (new FieldMarshalRow ( + MakeCodedRID (owner, CodedIndex.HasFieldMarshal), + GetBlobIndex (GetMarshalInfoSignature (owner)))); + } + + void AddProperties (TypeDefinition type) + { + var properties = type.Properties; + + property_map_table.AddRow (new PropertyMapRow (type.token.RID, property_rid)); + + for (int i = 0; i < properties.Count; i++) + AddProperty (properties [i]); + } + + void AddProperty (PropertyDefinition property) + { + property_table.AddRow (new PropertyRow ( + property.Attributes, + GetStringIndex (property.Name), + GetBlobIndex (GetPropertySignature (property)))); + property.token = new MetadataToken (TokenType.Property, property_rid++); + + var method = property.GetMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Getter, property, method); + + method = property.SetMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Setter, property, method); + + if (property.HasOtherMethods) + AddOtherSemantic (property, property.OtherMethods); + + if (property.HasCustomAttributes) + AddCustomAttributes (property); + + if (property.HasConstant) + AddConstant (property, property.PropertyType); + } + + void AddOtherSemantic (IMetadataTokenProvider owner, Collection others) + { + for (int i = 0; i < others.Count; i++) + AddSemantic (MethodSemanticsAttributes.Other, owner, others [i]); + } + + void AddEvents (TypeDefinition type) + { + var events = type.Events; + + event_map_table.AddRow (new EventMapRow (type.token.RID, event_rid)); + + for (int i = 0; i < events.Count; i++) + AddEvent (events [i]); + } + + void AddEvent (EventDefinition @event) + { + event_table.AddRow (new EventRow ( + @event.Attributes, + GetStringIndex (@event.Name), + MakeCodedRID (GetTypeToken (@event.EventType), CodedIndex.TypeDefOrRef))); + @event.token = new MetadataToken (TokenType.Event, event_rid++); + + var method = @event.AddMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.AddOn, @event, method); + + method = @event.InvokeMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Fire, @event, method); + + method = @event.RemoveMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.RemoveOn, @event, method); + + if (@event.HasOtherMethods) + AddOtherSemantic (@event, @event.OtherMethods); + + if (@event.HasCustomAttributes) + AddCustomAttributes (@event); + } + + void AddSemantic (MethodSemanticsAttributes semantics, IMetadataTokenProvider provider, MethodDefinition method) + { + method.SemanticsAttributes = semantics; + var table = GetTable (Table.MethodSemantics); + + table.AddRow (new MethodSemanticsRow ( + semantics, + method.token.RID, + MakeCodedRID (provider, CodedIndex.HasSemantics))); + } + + void AddConstant (IConstantProvider owner, TypeReference type) + { + var constant = owner.Constant; + var etype = GetConstantType (type, constant); + + constant_table.AddRow (new ConstantRow ( + etype, + MakeCodedRID (owner.MetadataToken, CodedIndex.HasConstant), + GetBlobIndex (GetConstantSignature (etype, constant)))); + } + + static ElementType GetConstantType (TypeReference constant_type, object constant) + { + if (constant == null) + return ElementType.Class; + + var etype = constant_type.etype; + switch (etype) { + case ElementType.None: + var type = constant_type.CheckedResolve (); + if (type.IsEnum) + return GetConstantType (type.GetEnumUnderlyingType (), constant); + + return ElementType.Class; + case ElementType.String: + return ElementType.String; + case ElementType.Object: + return GetConstantType (constant.GetType ()); + case ElementType.Array: + case ElementType.SzArray: + case ElementType.MVar: + case ElementType.Var: + return ElementType.Class; + case ElementType.GenericInst: + var generic_instance = (GenericInstanceType)constant_type; + if (generic_instance.ElementType.IsTypeOf ("System", "Nullable`1")) + return GetConstantType (generic_instance.GenericArguments [0], constant); + + return GetConstantType (((TypeSpecification)constant_type).ElementType, constant); + case ElementType.CModOpt: + case ElementType.CModReqD: + case ElementType.ByRef: + case ElementType.Sentinel: + return GetConstantType (((TypeSpecification)constant_type).ElementType, constant); + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I: + case ElementType.I1: + case ElementType.I2: + case ElementType.I4: + case ElementType.I8: + case ElementType.U: + case ElementType.U1: + case ElementType.U2: + case ElementType.U4: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + return GetConstantType (constant.GetType ()); + default: + return etype; + } + } + + static ElementType GetConstantType (Type type) + { + switch (Type.GetTypeCode (type)) { + case TypeCode.Boolean: + return ElementType.Boolean; + case TypeCode.Byte: + return ElementType.U1; + case TypeCode.SByte: + return ElementType.I1; + case TypeCode.Char: + return ElementType.Char; + case TypeCode.Int16: + return ElementType.I2; + case TypeCode.UInt16: + return ElementType.U2; + case TypeCode.Int32: + return ElementType.I4; + case TypeCode.UInt32: + return ElementType.U4; + case TypeCode.Int64: + return ElementType.I8; + case TypeCode.UInt64: + return ElementType.U8; + case TypeCode.Single: + return ElementType.R4; + case TypeCode.Double: + return ElementType.R8; + case TypeCode.String: + return ElementType.String; + default: + throw new NotSupportedException (type.FullName); + } + } + + void AddCustomAttributes (ICustomAttributeProvider owner) + { + var custom_attributes = owner.CustomAttributes; + + for (int i = 0; i < custom_attributes.Count; i++) { + var attribute = custom_attributes [i]; + + var projection = WindowsRuntimeProjections.RemoveProjection (attribute); + + custom_attribute_table.AddRow (new CustomAttributeRow ( + MakeCodedRID (owner, CodedIndex.HasCustomAttribute), + MakeCodedRID (LookupToken (attribute.Constructor), CodedIndex.CustomAttributeType), + GetBlobIndex (GetCustomAttributeSignature (attribute)))); + + WindowsRuntimeProjections.ApplyProjection (attribute, projection); + } + } + + void AddSecurityDeclarations (ISecurityDeclarationProvider owner) + { + var declarations = owner.SecurityDeclarations; + + for (int i = 0; i < declarations.Count; i++) { + var declaration = declarations [i]; + + declsec_table.AddRow (new DeclSecurityRow ( + declaration.Action, + MakeCodedRID (owner, CodedIndex.HasDeclSecurity), + GetBlobIndex (GetSecurityDeclarationSignature (declaration)))); + } + } + + MetadataToken GetMemberRefToken (MemberReference member) + { + var row = CreateMemberRefRow (member); + + MetadataToken token; + if (!member_ref_map.TryGetValue (row, out token)) + token = AddMemberReference (member, row); + + return token; + } + + MemberRefRow CreateMemberRefRow (MemberReference member) + { + return new MemberRefRow ( + MakeCodedRID (GetTypeToken (member.DeclaringType), CodedIndex.MemberRefParent), + GetStringIndex (member.Name), + GetBlobIndex (GetMemberRefSignature (member))); + } + + MetadataToken AddMemberReference (MemberReference member, MemberRefRow row) + { + member.token = new MetadataToken (TokenType.MemberRef, member_ref_table.AddRow (row)); + + var token = member.token; + member_ref_map.Add (row, token); + return token; + } + + MetadataToken GetMethodSpecToken (MethodSpecification method_spec) + { + var row = CreateMethodSpecRow (method_spec); + + MetadataToken token; + if (method_spec_map.TryGetValue (row, out token)) + return token; + + AddMethodSpecification (method_spec, row); + + return method_spec.token; + } + + void AddMethodSpecification (MethodSpecification method_spec, MethodSpecRow row) + { + method_spec.token = new MetadataToken (TokenType.MethodSpec, method_spec_table.AddRow (row)); + method_spec_map.Add (row, method_spec.token); + } + + MethodSpecRow CreateMethodSpecRow (MethodSpecification method_spec) + { + return new MethodSpecRow ( + MakeCodedRID (LookupToken (method_spec.ElementMethod), CodedIndex.MethodDefOrRef), + GetBlobIndex (GetMethodSpecSignature (method_spec))); + } + + SignatureWriter CreateSignatureWriter () + { + return new SignatureWriter (this); + } + + SignatureWriter GetMethodSpecSignature (MethodSpecification method_spec) + { + if (!method_spec.IsGenericInstance) + throw new NotSupportedException (); + + var generic_instance = (GenericInstanceMethod)method_spec; + + var signature = CreateSignatureWriter (); + signature.WriteByte (0x0a); + + signature.WriteGenericInstanceSignature (generic_instance); + + return signature; + } + + public uint AddStandAloneSignature (uint signature) + { + return (uint)standalone_sig_table.AddRow (signature); + } + + public uint GetLocalVariableBlobIndex (Collection variables) + { + return GetBlobIndex (GetVariablesSignature (variables)); + } + + public uint GetCallSiteBlobIndex (CallSite call_site) + { + return GetBlobIndex (GetMethodSignature (call_site)); + } + + public uint GetConstantTypeBlobIndex (TypeReference constant_type) + { + return GetBlobIndex (GetConstantTypeSignature (constant_type)); + } + + SignatureWriter GetVariablesSignature (Collection variables) + { + var signature = CreateSignatureWriter (); + signature.WriteByte (0x7); + signature.WriteCompressedUInt32 ((uint)variables.Count); + for (int i = 0; i < variables.Count; i++) + signature.WriteTypeSignature (variables [i].VariableType); + return signature; + } + + SignatureWriter GetConstantTypeSignature (TypeReference constant_type) + { + var signature = CreateSignatureWriter (); + signature.WriteByte (0x6); + signature.WriteTypeSignature (constant_type); + return signature; + } + + SignatureWriter GetFieldSignature (FieldReference field) + { + var signature = CreateSignatureWriter (); + signature.WriteByte (0x6); + signature.WriteTypeSignature (field.FieldType); + return signature; + } + + SignatureWriter GetMethodSignature (IMethodSignature method) + { + var signature = CreateSignatureWriter (); + signature.WriteMethodSignature (method); + return signature; + } + + SignatureWriter GetMemberRefSignature (MemberReference member) + { + var field = member as FieldReference; + if (field != null) + return GetFieldSignature (field); + + var method = member as MethodReference; + if (method != null) + return GetMethodSignature (method); + + throw new NotSupportedException (); + } + + SignatureWriter GetPropertySignature (PropertyDefinition property) + { + var signature = CreateSignatureWriter (); + byte calling_convention = 0x8; + if (property.HasThis) + calling_convention |= 0x20; + + uint param_count = 0; + Collection parameters = null; + + if (property.HasParameters) { + parameters = property.Parameters; + param_count = (uint)parameters.Count; + } + + signature.WriteByte (calling_convention); + signature.WriteCompressedUInt32 (param_count); + signature.WriteTypeSignature (property.PropertyType); + + if (param_count == 0) + return signature; + + for (int i = 0; i < param_count; i++) + signature.WriteTypeSignature (parameters [i].ParameterType); + + return signature; + } + + SignatureWriter GetTypeSpecSignature (TypeReference type) + { + var signature = CreateSignatureWriter (); + signature.WriteTypeSignature (type); + return signature; + } + + SignatureWriter GetConstantSignature (ElementType type, object value) + { + var signature = CreateSignatureWriter (); + + switch (type) { + case ElementType.Array: + case ElementType.SzArray: + case ElementType.Class: + case ElementType.Object: + case ElementType.None: + case ElementType.Var: + case ElementType.MVar: + signature.WriteInt32 (0); + break; + case ElementType.String: + signature.WriteConstantString ((string)value); + break; + default: + signature.WriteConstantPrimitive (value); + break; + } + + return signature; + } + + SignatureWriter GetCustomAttributeSignature (CustomAttribute attribute) + { + var signature = CreateSignatureWriter (); + if (!attribute.resolved) { + signature.WriteBytes (attribute.GetBlob ()); + return signature; + } + + signature.WriteUInt16 (0x0001); + + signature.WriteCustomAttributeConstructorArguments (attribute); + + signature.WriteCustomAttributeNamedArguments (attribute); + + return signature; + } + + SignatureWriter GetSecurityDeclarationSignature (SecurityDeclaration declaration) + { + var signature = CreateSignatureWriter (); + + if (!declaration.resolved) + signature.WriteBytes (declaration.GetBlob ()); + else if (module.Runtime < TargetRuntime.Net_2_0) + signature.WriteXmlSecurityDeclaration (declaration); + else + signature.WriteSecurityDeclaration (declaration); + + return signature; + } + + SignatureWriter GetMarshalInfoSignature (IMarshalInfoProvider owner) + { + var signature = CreateSignatureWriter (); + + signature.WriteMarshalInfo (owner.MarshalInfo); + + return signature; + } + + static Exception CreateForeignMemberException (MemberReference member) + { + return new ArgumentException (string.Format ("Member '{0}' is declared in another module and needs to be imported", member)); + } + + public MetadataToken LookupToken (IMetadataTokenProvider provider) + { + if (provider == null) + throw new ArgumentNullException (); + + if (metadata_builder != null) + return metadata_builder.LookupToken (provider); + + var member = provider as MemberReference; + if (member == null || member.Module != module) + throw CreateForeignMemberException (member); + + var token = provider.MetadataToken; + + switch (token.TokenType) { + case TokenType.TypeDef: + case TokenType.Method: + case TokenType.Field: + case TokenType.Event: + case TokenType.Property: + return token; + case TokenType.TypeRef: + case TokenType.TypeSpec: + case TokenType.GenericParam: + return GetTypeToken ((TypeReference)provider); + case TokenType.MethodSpec: + return GetMethodSpecToken ((MethodSpecification)provider); + case TokenType.MemberRef: + return GetMemberRefToken (member); + default: + throw new NotSupportedException (); + } + } + + public void AddMethodDebugInformation (MethodDebugInformation method_info) + { + if (method_info.HasSequencePoints) + AddSequencePoints (method_info); + + if (method_info.Scope != null) + AddLocalScope (method_info, method_info.Scope); + + if (method_info.StateMachineKickOffMethod != null) + AddStateMachineMethod (method_info); + + AddCustomDebugInformations (method_info.Method); + } + + void AddStateMachineMethod (MethodDebugInformation method_info) + { + state_machine_method_table.AddRow (new StateMachineMethodRow (method_info.Method.MetadataToken.RID, method_info.StateMachineKickOffMethod.MetadataToken.RID)); + } + + void AddLocalScope (MethodDebugInformation method_info, ScopeDebugInformation scope) + { + var rid = local_scope_table.AddRow (new LocalScopeRow ( + method_info.Method.MetadataToken.RID, + scope.import != null ? AddImportScope (scope.import) : 0, + local_variable_rid, + local_constant_rid, + (uint)scope.Start.Offset, + (uint)((scope.End.IsEndOfMethod ? method_info.code_size : scope.End.Offset) - scope.Start.Offset))); + + scope.token = new MetadataToken (TokenType.LocalScope, rid); + + AddCustomDebugInformations (scope); + + if (scope.HasVariables) + AddLocalVariables (scope); + + if (scope.HasConstants) + AddLocalConstants (scope); + + for (int i = 0; i < scope.Scopes.Count; i++) + AddLocalScope (method_info, scope.Scopes [i]); + } + + void AddLocalVariables (ScopeDebugInformation scope) + { + for (int i = 0; i < scope.Variables.Count; i++) { + var variable = scope.Variables [i]; + local_variable_table.AddRow (new LocalVariableRow (variable.Attributes, (ushort)variable.Index, GetStringIndex (variable.Name))); + variable.token = new MetadataToken (TokenType.LocalVariable, local_variable_rid); + local_variable_rid++; + + AddCustomDebugInformations (variable); + } + } + + void AddLocalConstants (ScopeDebugInformation scope) + { + for (int i = 0; i < scope.Constants.Count; i++) { + var constant = scope.Constants [i]; + local_constant_table.AddRow (new LocalConstantRow (GetStringIndex (constant.Name), GetBlobIndex (GetConstantSignature (constant)))); + constant.token = new MetadataToken (TokenType.LocalConstant, local_constant_rid); + local_constant_rid++; + } + } + + SignatureWriter GetConstantSignature (ConstantDebugInformation constant) + { + var type = constant.ConstantType; + + var signature = CreateSignatureWriter (); + signature.WriteTypeSignature (type); + + if (type.IsTypeOf ("System", "Decimal")) { + var bits = decimal.GetBits ((decimal)constant.Value); + + var low = (uint)bits [0]; + var mid = (uint)bits [1]; + var high = (uint)bits [2]; + + var scale = (byte)(bits [3] >> 16); + var negative = (bits [3] & 0x80000000) != 0; + + signature.WriteByte ((byte)(scale | (negative ? 0x80 : 0x00))); + signature.WriteUInt32 (low); + signature.WriteUInt32 (mid); + signature.WriteUInt32 (high); + + return signature; + } + + if (type.IsTypeOf ("System", "DateTime")) { + var date = (DateTime)constant.Value; + signature.WriteInt64 (date.Ticks); + return signature; + } + + signature.WriteBytes (GetConstantSignature (type.etype, constant.Value)); + + return signature; + } + + public void AddCustomDebugInformations (ICustomDebugInformationProvider provider) + { + if (!provider.HasCustomDebugInformations) + return; + + var custom_infos = provider.CustomDebugInformations; + + for (int i = 0; i < custom_infos.Count; i++) { + var custom_info = custom_infos [i]; + switch (custom_info.Kind) { + case CustomDebugInformationKind.Binary: + var binary_info = (BinaryCustomDebugInformation)custom_info; + AddCustomDebugInformation (provider, binary_info, GetBlobIndex (binary_info.Data)); + break; + case CustomDebugInformationKind.AsyncMethodBody: + AddAsyncMethodBodyDebugInformation (provider, (AsyncMethodBodyDebugInformation)custom_info); + break; + case CustomDebugInformationKind.StateMachineScope: + AddStateMachineScopeDebugInformation (provider, (StateMachineScopeDebugInformation)custom_info); + break; + case CustomDebugInformationKind.EmbeddedSource: + AddEmbeddedSourceDebugInformation (provider, (EmbeddedSourceDebugInformation)custom_info); + break; + case CustomDebugInformationKind.SourceLink: + AddSourceLinkDebugInformation (provider, (SourceLinkDebugInformation)custom_info); + break; + default: + throw new NotImplementedException (); + } + } + } + + void AddStateMachineScopeDebugInformation (ICustomDebugInformationProvider provider, StateMachineScopeDebugInformation state_machine_scope) + { + var method_info = ((MethodDefinition)provider).DebugInformation; + + var signature = CreateSignatureWriter (); + + var scopes = state_machine_scope.Scopes; + + for (int i = 0; i < scopes.Count; i++) { + var scope = scopes [i]; + signature.WriteUInt32 ((uint)scope.Start.Offset); + + var end_offset = scope.End.IsEndOfMethod + ? method_info.code_size + : scope.End.Offset; + + signature.WriteUInt32 ((uint)(end_offset - scope.Start.Offset)); + } + + AddCustomDebugInformation (provider, state_machine_scope, signature); + } + + void AddAsyncMethodBodyDebugInformation (ICustomDebugInformationProvider provider, AsyncMethodBodyDebugInformation async_method) + { + var signature = CreateSignatureWriter (); + signature.WriteUInt32 ((uint)async_method.catch_handler.Offset + 1); + + if (!async_method.yields.IsNullOrEmpty ()) { + for (int i = 0; i < async_method.yields.Count; i++) { + signature.WriteUInt32 ((uint)async_method.yields [i].Offset); + signature.WriteUInt32 ((uint)async_method.resumes [i].Offset); + signature.WriteCompressedUInt32 (async_method.resume_methods [i].MetadataToken.RID); + } + } + + AddCustomDebugInformation (provider, async_method, signature); + } + + void AddEmbeddedSourceDebugInformation (ICustomDebugInformationProvider provider, EmbeddedSourceDebugInformation embedded_source) + { + var signature = CreateSignatureWriter (); + + if (!embedded_source.resolved) { + signature.WriteBytes (embedded_source.ReadRawEmbeddedSourceDebugInformation ()); + AddCustomDebugInformation (provider, embedded_source, signature); + return; + } + + var content = embedded_source.content ?? Empty.Array; + if (embedded_source.compress) { + signature.WriteInt32 (content.Length); + + var decompressed_stream = new MemoryStream (content); + var content_stream = new MemoryStream (); + + using (var compress_stream = new DeflateStream (content_stream, CompressionMode.Compress, leaveOpen: true)) + decompressed_stream.CopyTo (compress_stream); + + signature.WriteBytes (content_stream.ToArray ()); + } else { + signature.WriteInt32 (0); + signature.WriteBytes (content); + } + + AddCustomDebugInformation (provider, embedded_source, signature); + } + + void AddSourceLinkDebugInformation (ICustomDebugInformationProvider provider, SourceLinkDebugInformation source_link) + { + var signature = CreateSignatureWriter (); + signature.WriteBytes (Encoding.UTF8.GetBytes (source_link.content)); + + AddCustomDebugInformation (provider, source_link, signature); + } + + void AddCustomDebugInformation (ICustomDebugInformationProvider provider, CustomDebugInformation custom_info, SignatureWriter signature) + { + AddCustomDebugInformation (provider, custom_info, GetBlobIndex (signature)); + } + + void AddCustomDebugInformation (ICustomDebugInformationProvider provider, CustomDebugInformation custom_info, uint blob_index) + { + var rid = custom_debug_information_table.AddRow (new CustomDebugInformationRow ( + MakeCodedRID (provider.MetadataToken, CodedIndex.HasCustomDebugInformation), + GetGuidIndex (custom_info.Identifier), + blob_index)); + + custom_info.token = new MetadataToken (TokenType.CustomDebugInformation, rid); + } + + uint AddImportScope (ImportDebugInformation import) + { + uint parent = 0; + if (import.Parent != null) + parent = AddImportScope (import.Parent); + + uint targets_index = 0; + if (import.HasTargets) { + var signature = CreateSignatureWriter (); + + for (int i = 0; i < import.Targets.Count; i++) + AddImportTarget (import.Targets [i], signature); + + targets_index = GetBlobIndex (signature); + } + + var row = new ImportScopeRow (parent, targets_index); + + MetadataToken import_token; + if (import_scope_map.TryGetValue (row, out import_token)) + return import_token.RID; + + import_token = new MetadataToken (TokenType.ImportScope, import_scope_table.AddRow (row)); + import_scope_map.Add (row, import_token); + + return import_token.RID; + } + + void AddImportTarget (ImportTarget target, SignatureWriter signature) + { + signature.WriteCompressedUInt32 ((uint)target.kind); + + switch (target.kind) { + case ImportTargetKind.ImportNamespace: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.@namespace)); + break; + case ImportTargetKind.ImportNamespaceInAssembly: + signature.WriteCompressedUInt32 (target.reference.MetadataToken.RID); + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.@namespace)); + break; + case ImportTargetKind.ImportType: + signature.WriteTypeToken (target.type); + break; + case ImportTargetKind.ImportXmlNamespaceWithAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.@namespace)); + break; + case ImportTargetKind.ImportAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + break; + case ImportTargetKind.DefineAssemblyAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + signature.WriteCompressedUInt32 (target.reference.MetadataToken.RID); + break; + case ImportTargetKind.DefineNamespaceAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.@namespace)); + break; + case ImportTargetKind.DefineNamespaceInAssemblyAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + signature.WriteCompressedUInt32 (target.reference.MetadataToken.RID); + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.@namespace)); + break; + case ImportTargetKind.DefineTypeAlias: + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (target.alias)); + signature.WriteTypeToken (target.type); + break; + } + } + + uint GetUTF8StringBlobIndex (string s) + { + return GetBlobIndex (Encoding.UTF8.GetBytes (s)); + } + + public MetadataToken GetDocumentToken (Document document) + { + MetadataToken token; + if (document_map.TryGetValue (document.Url, out token)) + return token; + + token = new MetadataToken (TokenType.Document, document_table.AddRow ( + new DocumentRow (GetBlobIndex (GetDocumentNameSignature (document)), + GetGuidIndex (document.HashAlgorithm.ToGuid ()), + GetBlobIndex (document.Hash), + GetGuidIndex (document.Language.ToGuid ())))); + + document.token = token; + + AddCustomDebugInformations (document); + + document_map.Add (document.Url, token); + + return token; + } + + SignatureWriter GetDocumentNameSignature (Document document) + { + var name = document.Url; + var signature = CreateSignatureWriter (); + + char separator; + if (!TryGetDocumentNameSeparator (name, out separator)) { + signature.WriteByte (0); + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (name)); + return signature; + } + + signature.WriteByte ((byte)separator); + var parts = name.Split (new [] { separator }); + for (int i = 0; i < parts.Length; i++) { + if (parts [i] == String.Empty) + signature.WriteCompressedUInt32 (0); + else + signature.WriteCompressedUInt32 (GetUTF8StringBlobIndex (parts [i])); + } + + return signature; + } + + static bool TryGetDocumentNameSeparator (string path, out char separator) + { + const char unix = '/'; + const char win = '\\'; + const char zero = (char)0; + + separator = zero; + if (string.IsNullOrEmpty (path)) + return false; + + int unix_count = 0; + int win_count = 0; + + for (int i = 0; i < path.Length; i++) { + if (path [i] == unix) + unix_count++; + else if (path [i] == win) + win_count++; + } + + if (unix_count == 0 && win_count == 0) + return false; + + if (unix_count >= win_count) { + separator = unix; + return true; + } + + separator = win; + return true; + } + + void AddSequencePoints (MethodDebugInformation info) + { + var rid = info.Method.MetadataToken.RID; + + Document document; + if (info.TryGetUniqueDocument (out document)) + method_debug_information_table.rows [rid - 1].Col1 = GetDocumentToken (document).RID; + + var signature = CreateSignatureWriter (); + signature.WriteSequencePoints (info); + + method_debug_information_table.rows [rid - 1].Col2 = GetBlobIndex (signature); + } + + public void ComputeDeterministicMvid () + { + var guid = CryptoService.ComputeGuid (CryptoService.ComputeHash ( + data, + resources, + string_heap, + user_string_heap, + blob_heap, + table_heap, + code)); + + var position = guid_heap.position; + guid_heap.position = 0; + guid_heap.WriteBytes (guid.ToByteArray ()); + guid_heap.position = position; + + module.Mvid = guid; + } + } + + sealed class SignatureWriter : ByteBuffer { + + readonly MetadataBuilder metadata; + + public SignatureWriter (MetadataBuilder metadata) + : base (6) + { + this.metadata = metadata; + } + + public void WriteElementType (ElementType element_type) + { + WriteByte ((byte)element_type); + } + + public void WriteUTF8String (string @string) + { + if (@string == null) { + WriteByte (0xff); + return; + } + + var bytes = Encoding.UTF8.GetBytes (@string); + WriteCompressedUInt32 ((uint)bytes.Length); + WriteBytes (bytes); + } + + public void WriteMethodSignature (IMethodSignature method) + { + byte calling_convention = (byte)method.CallingConvention; + if (method.HasThis) + calling_convention |= 0x20; + if (method.ExplicitThis) + calling_convention |= 0x40; + + var generic_provider = method as IGenericParameterProvider; + var generic_arity = generic_provider != null && generic_provider.HasGenericParameters + ? generic_provider.GenericParameters.Count + : 0; + + if (generic_arity > 0) + calling_convention |= 0x10; + + var param_count = method.HasParameters ? method.Parameters.Count : 0; + + WriteByte (calling_convention); + + if (generic_arity > 0) + WriteCompressedUInt32 ((uint)generic_arity); + + WriteCompressedUInt32 ((uint)param_count); + WriteTypeSignature (method.ReturnType); + + if (param_count == 0) + return; + + var parameters = method.Parameters; + + for (int i = 0; i < param_count; i++) + WriteTypeSignature (parameters [i].ParameterType); + } + + uint MakeTypeDefOrRefCodedRID (TypeReference type) + { + return CodedIndex.TypeDefOrRef.CompressMetadataToken (metadata.LookupToken (type)); + } + + public void WriteTypeToken (TypeReference type) + { + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (type)); + } + + public void WriteTypeSignature (TypeReference type) + { + if (type == null) + throw new ArgumentNullException (); + + var etype = type.etype; + + switch (etype) { + case ElementType.MVar: + case ElementType.Var: { + var generic_parameter = (GenericParameter)type; + + WriteElementType (etype); + var position = generic_parameter.Position; + if (position == -1) + throw new NotSupportedException (); + + WriteCompressedUInt32 ((uint)position); + break; + } + + case ElementType.GenericInst: { + var generic_instance = (GenericInstanceType)type; + WriteElementType (ElementType.GenericInst); + WriteElementType (generic_instance.IsValueType ? ElementType.ValueType : ElementType.Class); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (generic_instance.ElementType)); + + WriteGenericInstanceSignature (generic_instance); + break; + } + + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.Pinned: + case ElementType.Sentinel: { + var type_spec = (TypeSpecification)type; + WriteElementType (etype); + WriteTypeSignature (type_spec.ElementType); + break; + } + + case ElementType.FnPtr: { + var fptr = (FunctionPointerType)type; + WriteElementType (ElementType.FnPtr); + WriteMethodSignature (fptr); + break; + } + + case ElementType.CModOpt: + case ElementType.CModReqD: { + var modifier = (IModifierType)type; + WriteModifierSignature (etype, modifier); + break; + } + + case ElementType.Array: { + var array = (ArrayType)type; + if (!array.IsVector) { + WriteArrayTypeSignature (array); + break; + } + + WriteElementType (ElementType.SzArray); + WriteTypeSignature (array.ElementType); + break; + } + + case ElementType.None: { + WriteElementType (type.IsValueType ? ElementType.ValueType : ElementType.Class); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (type)); + break; + } + + default: + if (!TryWriteElementType (type)) + throw new NotSupportedException (); + + break; + + } + } + + void WriteArrayTypeSignature (ArrayType array) + { + WriteElementType (ElementType.Array); + WriteTypeSignature (array.ElementType); + + var dimensions = array.Dimensions; + var rank = dimensions.Count; + + WriteCompressedUInt32 ((uint)rank); + + var sized = 0; + var lbounds = 0; + + for (int i = 0; i < rank; i++) { + var dimension = dimensions [i]; + + if (dimension.UpperBound.HasValue) { + sized++; + lbounds++; + } else if (dimension.LowerBound.HasValue) + lbounds++; + } + + var sizes = new int [sized]; + var low_bounds = new int [lbounds]; + + for (int i = 0; i < lbounds; i++) { + var dimension = dimensions [i]; + low_bounds [i] = dimension.LowerBound.GetValueOrDefault (); + if (dimension.UpperBound.HasValue) + sizes [i] = dimension.UpperBound.Value - low_bounds [i] + 1; + } + + WriteCompressedUInt32 ((uint)sized); + for (int i = 0; i < sized; i++) + WriteCompressedUInt32 ((uint)sizes [i]); + + WriteCompressedUInt32 ((uint)lbounds); + for (int i = 0; i < lbounds; i++) + WriteCompressedInt32 (low_bounds [i]); + } + + public void WriteGenericInstanceSignature (IGenericInstance instance) + { + var generic_arguments = instance.GenericArguments; + var arity = generic_arguments.Count; + + WriteCompressedUInt32 ((uint)arity); + for (int i = 0; i < arity; i++) + WriteTypeSignature (generic_arguments [i]); + } + + void WriteModifierSignature (ElementType element_type, IModifierType type) + { + WriteElementType (element_type); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (type.ModifierType)); + WriteTypeSignature (type.ElementType); + } + + bool TryWriteElementType (TypeReference type) + { + var element = type.etype; + + if (element == ElementType.None) + return false; + + WriteElementType (element); + return true; + } + + public void WriteConstantString (string value) + { + if (value != null) + WriteBytes (Encoding.Unicode.GetBytes (value)); + else + WriteByte (0xff); + } + + public void WriteConstantPrimitive (object value) + { + WritePrimitiveValue (value); + } + + public void WriteCustomAttributeConstructorArguments (CustomAttribute attribute) + { + if (!attribute.HasConstructorArguments) + return; + + var arguments = attribute.ConstructorArguments; + var parameters = attribute.Constructor.Parameters; + + if (parameters.Count != arguments.Count) + throw new InvalidOperationException (); + + for (int i = 0; i < arguments.Count; i++) + WriteCustomAttributeFixedArgument (parameters [i].ParameterType, arguments [i]); + } + + void WriteCustomAttributeFixedArgument (TypeReference type, CustomAttributeArgument argument) + { + if (type.IsArray) { + WriteCustomAttributeFixedArrayArgument ((ArrayType)type, argument); + return; + } + + WriteCustomAttributeElement (type, argument); + } + + void WriteCustomAttributeFixedArrayArgument (ArrayType type, CustomAttributeArgument argument) + { + var values = argument.Value as CustomAttributeArgument []; + + if (values == null) { + WriteUInt32 (0xffffffff); + return; + } + + WriteInt32 (values.Length); + + if (values.Length == 0) + return; + + var element_type = type.ElementType; + + for (int i = 0; i < values.Length; i++) + WriteCustomAttributeElement (element_type, values [i]); + } + + void WriteCustomAttributeElement (TypeReference type, CustomAttributeArgument argument) + { + if (type.IsArray) { + WriteCustomAttributeFixedArrayArgument ((ArrayType)type, argument); + return; + } + + if (type.etype == ElementType.Object) { + argument = (CustomAttributeArgument)argument.Value; + type = argument.Type; + + WriteCustomAttributeFieldOrPropType (type); + WriteCustomAttributeElement (type, argument); + return; + } + + WriteCustomAttributeValue (type, argument.Value); + } + + void WriteCustomAttributeValue (TypeReference type, object value) + { + var etype = type.etype; + + switch (etype) { + case ElementType.String: + var @string = (string)value; + if (@string == null) + WriteByte (0xff); + else + WriteUTF8String (@string); + break; + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + WriteCustomAttributeTypeValue ((TypeReference)value); + else + WriteCustomAttributeEnumValue (type, value); + break; + default: + WritePrimitiveValue (value); + break; + } + } + + private void WriteCustomAttributeTypeValue (TypeReference value) + { + var typeDefinition = value as TypeDefinition; + + if (typeDefinition != null) { + TypeDefinition outermostDeclaringType = typeDefinition; + while (outermostDeclaringType.DeclaringType != null) + outermostDeclaringType = outermostDeclaringType.DeclaringType; + + // In CLR .winmd files, custom attribute arguments reference unmangled type names (rather than Name) + if (WindowsRuntimeProjections.IsClrImplementationType (outermostDeclaringType)) { + WindowsRuntimeProjections.Project (outermostDeclaringType); + WriteTypeReference (value); + WindowsRuntimeProjections.RemoveProjection (outermostDeclaringType); + return; + } + } + + WriteTypeReference (value); + } + + void WritePrimitiveValue (object value) + { + if (value == null) + throw new ArgumentNullException (); + + switch (Type.GetTypeCode (value.GetType ())) { + case TypeCode.Boolean: + WriteByte ((byte)(((bool)value) ? 1 : 0)); + break; + case TypeCode.Byte: + WriteByte ((byte)value); + break; + case TypeCode.SByte: + WriteSByte ((sbyte)value); + break; + case TypeCode.Int16: + WriteInt16 ((short)value); + break; + case TypeCode.UInt16: + WriteUInt16 ((ushort)value); + break; + case TypeCode.Char: + WriteInt16 ((short)(char)value); + break; + case TypeCode.Int32: + WriteInt32 ((int)value); + break; + case TypeCode.UInt32: + WriteUInt32 ((uint)value); + break; + case TypeCode.Single: + WriteSingle ((float)value); + break; + case TypeCode.Int64: + WriteInt64 ((long)value); + break; + case TypeCode.UInt64: + WriteUInt64 ((ulong)value); + break; + case TypeCode.Double: + WriteDouble ((double)value); + break; + default: + throw new NotSupportedException (value.GetType ().FullName); + } + } + + void WriteCustomAttributeEnumValue (TypeReference enum_type, object value) + { + var type = enum_type.CheckedResolve (); + if (!type.IsEnum) + throw new ArgumentException (); + + WriteCustomAttributeValue (type.GetEnumUnderlyingType (), value); + } + + void WriteCustomAttributeFieldOrPropType (TypeReference type) + { + if (type.IsArray) { + var array = (ArrayType)type; + WriteElementType (ElementType.SzArray); + WriteCustomAttributeFieldOrPropType (array.ElementType); + return; + } + + var etype = type.etype; + + switch (etype) { + case ElementType.Object: + WriteElementType (ElementType.Boxed); + return; + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + WriteElementType (ElementType.Type); + else { + WriteElementType (ElementType.Enum); + WriteTypeReference (type); + } + return; + default: + WriteElementType (etype); + return; + } + } + + public void WriteCustomAttributeNamedArguments (CustomAttribute attribute) + { + var count = GetNamedArgumentCount (attribute); + + WriteUInt16 ((ushort)count); + + if (count == 0) + return; + + WriteICustomAttributeNamedArguments (attribute); + } + + static int GetNamedArgumentCount (ICustomAttribute attribute) + { + int count = 0; + + if (attribute.HasFields) + count += attribute.Fields.Count; + + if (attribute.HasProperties) + count += attribute.Properties.Count; + + return count; + } + + void WriteICustomAttributeNamedArguments (ICustomAttribute attribute) + { + if (attribute.HasFields) + WriteCustomAttributeNamedArguments (0x53, attribute.Fields); + + if (attribute.HasProperties) + WriteCustomAttributeNamedArguments (0x54, attribute.Properties); + } + + void WriteCustomAttributeNamedArguments (byte kind, Collection named_arguments) + { + for (int i = 0; i < named_arguments.Count; i++) + WriteCustomAttributeNamedArgument (kind, named_arguments [i]); + } + + void WriteCustomAttributeNamedArgument (byte kind, CustomAttributeNamedArgument named_argument) + { + var argument = named_argument.Argument; + + WriteByte (kind); + WriteCustomAttributeFieldOrPropType (argument.Type); + WriteUTF8String (named_argument.Name); + WriteCustomAttributeFixedArgument (argument.Type, argument); + } + + void WriteSecurityAttribute (SecurityAttribute attribute) + { + WriteTypeReference (attribute.AttributeType); + + var count = GetNamedArgumentCount (attribute); + + if (count == 0) { + WriteCompressedUInt32 (1); // length + WriteCompressedUInt32 (0); // count + return; + } + + var buffer = new SignatureWriter (metadata); + buffer.WriteCompressedUInt32 ((uint)count); + buffer.WriteICustomAttributeNamedArguments (attribute); + + WriteCompressedUInt32 ((uint)buffer.length); + WriteBytes (buffer); + } + + public void WriteSecurityDeclaration (SecurityDeclaration declaration) + { + WriteByte ((byte)'.'); + + var attributes = declaration.security_attributes; + if (attributes == null) + throw new NotSupportedException (); + + WriteCompressedUInt32 ((uint)attributes.Count); + + for (int i = 0; i < attributes.Count; i++) + WriteSecurityAttribute (attributes [i]); + } + + public void WriteXmlSecurityDeclaration (SecurityDeclaration declaration) + { + var xml = GetXmlSecurityDeclaration (declaration); + if (xml == null) + throw new NotSupportedException (); + + WriteBytes (Encoding.Unicode.GetBytes (xml)); + } + + static string GetXmlSecurityDeclaration (SecurityDeclaration declaration) + { + if (declaration.security_attributes == null || declaration.security_attributes.Count != 1) + return null; + + var attribute = declaration.security_attributes [0]; + + if (!attribute.AttributeType.IsTypeOf ("System.Security.Permissions", "PermissionSetAttribute")) + return null; + + if (attribute.properties == null || attribute.properties.Count != 1) + return null; + + var property = attribute.properties [0]; + if (property.Name != "XML") + return null; + + return (string)property.Argument.Value; + } + + void WriteTypeReference (TypeReference type) + { + WriteUTF8String (TypeParser.ToParseable (type, top_level: false)); + } + + public void WriteMarshalInfo (MarshalInfo marshal_info) + { + WriteNativeType (marshal_info.native); + + switch (marshal_info.native) { + case NativeType.Array: { + var array = (ArrayMarshalInfo)marshal_info; + if (array.element_type != NativeType.None) + WriteNativeType (array.element_type); + if (array.size_parameter_index > -1) + WriteCompressedUInt32 ((uint)array.size_parameter_index); + if (array.size > -1) + WriteCompressedUInt32 ((uint)array.size); + if (array.size_parameter_multiplier > -1) + WriteCompressedUInt32 ((uint)array.size_parameter_multiplier); + return; + } + case NativeType.SafeArray: { + var array = (SafeArrayMarshalInfo)marshal_info; + if (array.element_type != VariantType.None) + WriteVariantType (array.element_type); + return; + } + case NativeType.FixedArray: { + var array = (FixedArrayMarshalInfo)marshal_info; + if (array.size > -1) + WriteCompressedUInt32 ((uint)array.size); + if (array.element_type != NativeType.None) + WriteNativeType (array.element_type); + return; + } + case NativeType.FixedSysString: + var sys_string = (FixedSysStringMarshalInfo)marshal_info; + if (sys_string.size > -1) + WriteCompressedUInt32 ((uint)sys_string.size); + return; + case NativeType.CustomMarshaler: + var marshaler = (CustomMarshalInfo)marshal_info; + WriteUTF8String (marshaler.guid != Guid.Empty ? marshaler.guid.ToString () : string.Empty); + WriteUTF8String (marshaler.unmanaged_type); + WriteTypeReference (marshaler.managed_type); + WriteUTF8String (marshaler.cookie); + return; + } + } + + void WriteNativeType (NativeType native) + { + WriteByte ((byte)native); + } + + void WriteVariantType (VariantType variant) + { + WriteByte ((byte)variant); + } + + public void WriteSequencePoints (MethodDebugInformation info) + { + var start_line = -1; + var start_column = -1; + + WriteCompressedUInt32 (info.local_var_token.RID); + + Document previous_document; + if (!info.TryGetUniqueDocument (out previous_document)) + previous_document = null; + + for (int i = 0; i < info.SequencePoints.Count; i++) { + var sequence_point = info.SequencePoints [i]; + + var document = sequence_point.Document; + if (previous_document != document) { + var document_token = metadata.GetDocumentToken (document); + + if (previous_document != null) + WriteCompressedUInt32 (0); + + WriteCompressedUInt32 (document_token.RID); + previous_document = document; + } + + if (i > 0) + WriteCompressedUInt32 ((uint)(sequence_point.Offset - info.SequencePoints [i - 1].Offset)); + else + WriteCompressedUInt32 ((uint)sequence_point.Offset); + + if (sequence_point.IsHidden) { + WriteInt16 (0); + continue; + } + + var delta_lines = sequence_point.EndLine - sequence_point.StartLine; + var delta_columns = sequence_point.EndColumn - sequence_point.StartColumn; + + WriteCompressedUInt32 ((uint)delta_lines); + + if (delta_lines == 0) + WriteCompressedUInt32 ((uint)delta_columns); + else + WriteCompressedInt32 (delta_columns); + + if (start_line < 0) { + WriteCompressedUInt32 ((uint)sequence_point.StartLine); + WriteCompressedUInt32 ((uint)sequence_point.StartColumn); + } else { + WriteCompressedInt32 (sequence_point.StartLine - start_line); + WriteCompressedInt32 (sequence_point.StartColumn - start_column); + } + + start_line = sequence_point.StartLine; + start_column = sequence_point.StartColumn; + } + } + } + + static partial class Mixin { + + public static bool TryGetUniqueDocument (this MethodDebugInformation info, out Document document) + { + document = info.SequencePoints [0].Document; + + for (int i = 1; i < info.SequencePoints.Count; i++) { + var sequence_point = info.SequencePoints [i]; + if (sequence_point.Document != document) + return false; + } + + return true; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs.meta new file mode 100644 index 0000000..a25718a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/AssemblyWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a88ce645df13da4aa9eca43f013f6ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs new file mode 100644 index 0000000..cb3c16a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs @@ -0,0 +1,406 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace MonoFN.Cecil { + + public delegate AssemblyDefinition AssemblyResolveEventHandler (object sender, AssemblyNameReference reference); + + public sealed class AssemblyResolveEventArgs : EventArgs { + + readonly AssemblyNameReference reference; + + public AssemblyNameReference AssemblyReference { + get { return reference; } + } + + public AssemblyResolveEventArgs (AssemblyNameReference reference) + { + this.reference = reference; + } + } + +#if !NET_CORE + [Serializable] +#endif + public sealed class AssemblyResolutionException : FileNotFoundException { + + readonly AssemblyNameReference reference; + + public AssemblyNameReference AssemblyReference { + get { return reference; } + } + + public AssemblyResolutionException (AssemblyNameReference reference) + : this (reference, null) + { + } + + public AssemblyResolutionException (AssemblyNameReference reference, Exception innerException) + : base (string.Format ("Failed to resolve assembly: '{0}'", reference), innerException) + { + this.reference = reference; + } + +#if !NET_CORE + AssemblyResolutionException ( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base (info, context) + { + } +#endif + } + + public abstract class BaseAssemblyResolver : IAssemblyResolver { + + static readonly bool on_mono = Type.GetType ("MonoFN.Runtime") != null; + + readonly Collection directories; + +#if NET_CORE + // Maps file names of available trusted platform assemblies to their full paths. + // Internal for testing. + internal static readonly Lazy> TrustedPlatformAssemblies = new Lazy> (CreateTrustedPlatformAssemblyMap); +#else + Collection gac_paths; +#endif + + public void AddSearchDirectory (string directory) + { + directories.Add (directory); + } + + public void RemoveSearchDirectory (string directory) + { + directories.Remove (directory); + } + + public string [] GetSearchDirectories () + { + var directories = new string [this.directories.size]; + Array.Copy (this.directories.items, directories, directories.Length); + return directories; + } + + public event AssemblyResolveEventHandler ResolveFailure; + + protected BaseAssemblyResolver () + { + directories = new Collection (2) { ".", "bin" }; + } + + AssemblyDefinition GetAssembly (string file, ReaderParameters parameters) + { + if (parameters.AssemblyResolver == null) + parameters.AssemblyResolver = this; + + return ModuleDefinition.ReadModule (file, parameters).Assembly; + } + + public virtual AssemblyDefinition Resolve (AssemblyNameReference name) + { + return Resolve (name, new ReaderParameters ()); + } + + public virtual AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) + { + Mixin.CheckName (name); + Mixin.CheckParameters (parameters); + + var assembly = SearchDirectory (name, directories, parameters); + if (assembly != null) + return assembly; + + if (name.IsRetargetable) { + // if the reference is retargetable, zero it + name = new AssemblyNameReference (name.Name, Mixin.ZeroVersion) { + PublicKeyToken = Empty.Array, + }; + } + +#if NET_CORE + assembly = SearchTrustedPlatformAssemblies (name, parameters); + if (assembly != null) + return assembly; +#else + var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName); + var framework_dirs = on_mono + ? new [] { framework_dir, Path.Combine (framework_dir, "Facades") } + : new [] { framework_dir }; + + if (IsZero (name.Version)) { + assembly = SearchDirectory (name, framework_dirs, parameters); + if (assembly != null) + return assembly; + } + + if (name.Name == "mscorlib") { + assembly = GetCorlib (name, parameters); + if (assembly != null) + return assembly; + } + + assembly = GetAssemblyInGac (name, parameters); + if (assembly != null) + return assembly; + + assembly = SearchDirectory (name, framework_dirs, parameters); + if (assembly != null) + return assembly; +#endif + if (ResolveFailure != null) { + assembly = ResolveFailure (this, name); + if (assembly != null) + return assembly; + } + + throw new AssemblyResolutionException (name); + } + +#if NET_CORE + AssemblyDefinition SearchTrustedPlatformAssemblies (AssemblyNameReference name, ReaderParameters parameters) + { + if (name.IsWindowsRuntime) + return null; + + if (TrustedPlatformAssemblies.Value.TryGetValue (name.Name, out string path)) + return GetAssembly (path, parameters); + + return null; + } + + static Dictionary CreateTrustedPlatformAssemblyMap () + { + var result = new Dictionary (StringComparer.OrdinalIgnoreCase); + + string paths; + + try { + paths = (string) AppDomain.CurrentDomain.GetData ("TRUSTED_PLATFORM_ASSEMBLIES"); + } catch { + paths = null; + } + + if (paths == null) + return result; + + foreach (var path in paths.Split (Path.PathSeparator)) + if (string.Equals (Path.GetExtension (path), ".dll", StringComparison.OrdinalIgnoreCase)) + result [Path.GetFileNameWithoutExtension (path)] = path; + + return result; + } +#endif + + protected virtual AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable directories, ReaderParameters parameters) + { + var extensions = name.IsWindowsRuntime ? new [] { ".winmd", ".dll" } : new [] { ".exe", ".dll" }; + foreach (var directory in directories) { + foreach (var extension in extensions) { + string file = Path.Combine (directory, name.Name + extension); + if (!File.Exists (file)) + continue; + try { + return GetAssembly (file, parameters); + } + catch (System.BadImageFormatException) { + continue; + } + } + } + + return null; + } + + static bool IsZero (Version version) + { + return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0; + } + +#if !NET_CORE + AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters) + { + var version = reference.Version; + var corlib = typeof (object).Assembly.GetName (); + if (corlib.Version == version || IsZero (version)) + return GetAssembly (typeof (object).Module.FullyQualifiedName, parameters); + + var path = Directory.GetParent ( + Directory.GetParent ( + typeof (object).Module.FullyQualifiedName).FullName + ).FullName; + + if (on_mono) { + if (version.Major == 1) + path = Path.Combine (path, "1.0"); + else if (version.Major == 2) { + if (version.MajorRevision == 5) + path = Path.Combine (path, "2.1"); + else + path = Path.Combine (path, "2.0"); + } else if (version.Major == 4) + path = Path.Combine (path, "4.0"); + else + throw new NotSupportedException ("Version not supported: " + version); + } else { + switch (version.Major) { + case 1: + if (version.MajorRevision == 3300) + path = Path.Combine (path, "v1.0.3705"); + else + path = Path.Combine (path, "v1.1.4322"); + break; + case 2: + path = Path.Combine (path, "v2.0.50727"); + break; + case 4: + path = Path.Combine (path, "v4.0.30319"); + break; + default: + throw new NotSupportedException ("Version not supported: " + version); + } + } + + var file = Path.Combine (path, "mscorlib.dll"); + if (File.Exists (file)) + return GetAssembly (file, parameters); + + if (on_mono && Directory.Exists (path + "-api")) { + file = Path.Combine (path + "-api", "mscorlib.dll"); + if (File.Exists (file)) + return GetAssembly (file, parameters); + } + + return null; + } + + static Collection GetGacPaths () + { + if (on_mono) + return GetDefaultMonoGacPaths (); + + var paths = new Collection (2); + var windir = Environment.GetEnvironmentVariable ("WINDIR"); + if (windir == null) + return paths; + + paths.Add (Path.Combine (windir, "assembly")); + paths.Add (Path.Combine (windir, Path.Combine ("Microsoft.NET", "assembly"))); + return paths; + } + + static Collection GetDefaultMonoGacPaths () + { + var paths = new Collection (1); + var gac = GetCurrentMonoGac (); + if (gac != null) + paths.Add (gac); + + var gac_paths_env = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX"); + if (string.IsNullOrEmpty (gac_paths_env)) + return paths; + + var prefixes = gac_paths_env.Split (Path.PathSeparator); + foreach (var prefix in prefixes) { + if (string.IsNullOrEmpty (prefix)) + continue; + + var gac_path = Path.Combine (Path.Combine (Path.Combine (prefix, "lib"), "mono"), "gac"); + if (Directory.Exists (gac_path) && !paths.Contains (gac)) + paths.Add (gac_path); + } + + return paths; + } + + static string GetCurrentMonoGac () + { + return Path.Combine ( + Directory.GetParent ( + Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName, + "gac"); + } + + AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters) + { + if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0) + return null; + + if (gac_paths == null) + gac_paths = GetGacPaths (); + + if (on_mono) + return GetAssemblyInMonoGac (reference, parameters); + + return GetAssemblyInNetGac (reference, parameters); + } + + AssemblyDefinition GetAssemblyInMonoGac (AssemblyNameReference reference, ReaderParameters parameters) + { + for (int i = 0; i < gac_paths.Count; i++) { + var gac_path = gac_paths [i]; + var file = GetAssemblyFile (reference, string.Empty, gac_path); + if (File.Exists (file)) + return GetAssembly (file, parameters); + } + + return null; + } + + AssemblyDefinition GetAssemblyInNetGac (AssemblyNameReference reference, ReaderParameters parameters) + { + var gacs = new [] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" }; + var prefixes = new [] { string.Empty, "v4.0_" }; + + for (int i = 0; i < gac_paths.Count; i++) { + for (int j = 0; j < gacs.Length; j++) { + var gac = Path.Combine (gac_paths [i], gacs [j]); + var file = GetAssemblyFile (reference, prefixes [i], gac); + if (Directory.Exists (gac) && File.Exists (file)) + return GetAssembly (file, parameters); + } + } + + return null; + } + + static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac) + { + var gac_folder = new StringBuilder () + .Append (prefix) + .Append (reference.Version) + .Append ("__"); + + for (int i = 0; i < reference.PublicKeyToken.Length; i++) + gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2")); + + return Path.Combine ( + Path.Combine ( + Path.Combine (gac, reference.Name), gac_folder.ToString ()), + reference.Name + ".dll"); + } +#endif + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs.meta new file mode 100644 index 0000000..87211a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/BaseAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ab1d53794ef7444c81e276b5a3a5c2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs new file mode 100644 index 0000000..34e8ac7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs @@ -0,0 +1,105 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Text; + +namespace MonoFN.Cecil { + + public sealed class CallSite : IMethodSignature { + + readonly MethodReference signature; + + public bool HasThis { + get { return signature.HasThis; } + set { signature.HasThis = value; } + } + + public bool ExplicitThis { + get { return signature.ExplicitThis; } + set { signature.ExplicitThis = value; } + } + + public MethodCallingConvention CallingConvention { + get { return signature.CallingConvention; } + set { signature.CallingConvention = value; } + } + + public bool HasParameters { + get { return signature.HasParameters; } + } + + public Collection Parameters { + get { return signature.Parameters; } + } + + public TypeReference ReturnType { + get { return signature.MethodReturnType.ReturnType; } + set { signature.MethodReturnType.ReturnType = value; } + } + + public MethodReturnType MethodReturnType { + get { return signature.MethodReturnType; } + } + + public string Name { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public string Namespace { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public ModuleDefinition Module { + get { return ReturnType.Module; } + } + + public IMetadataScope Scope { + get { return signature.ReturnType.Scope; } + } + + public MetadataToken MetadataToken { + get { return signature.token; } + set { signature.token = value; } + } + + public string FullName { + get { + var signature = new StringBuilder (); + signature.Append (ReturnType.FullName); + this.MethodSignatureFullName (signature); + return signature.ToString (); + } + } + + internal CallSite () + { + this.signature = new MethodReference (); + this.signature.token = new MetadataToken (TokenType.Signature, 0); + } + + public CallSite (TypeReference returnType) + : this () + { + if (returnType == null) + throw new ArgumentNullException ("returnType"); + + this.signature.ReturnType = returnType; + } + + public override string ToString () + { + return FullName; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs.meta new file mode 100644 index 0000000..8eac3ae --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CallSite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 087823dce9623d348927f193f95a1807 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs new file mode 100644 index 0000000..54f90e6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs @@ -0,0 +1,4 @@ +static class Consts { + public const string AssemblyName = "MonoFN.Cecil"; + public const string PublicKey = "00240000048000009400000006020000002400005253413100040000010001002b5c9f7f04346c324a3176f8d3ee823bbf2d60efdbc35f86fd9e65ea3e6cd11bcdcba3a353e55133c8ac5c4caaba581b2c6dfff2cc2d0edc43959ddb86b973300a479a82419ef489c3225f1fe429a708507bd515835160e10bc743d20ca33ab9570cfd68d479fcf0bc797a763bec5d1000f0159ef619e709d915975e87beebaf"; +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs.meta new file mode 100644 index 0000000..2491449 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Consts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da413e0e98056364a9512beb26e9aea5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs new file mode 100644 index 0000000..d9bda73 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs @@ -0,0 +1,221 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Diagnostics; +using System.Threading; + +namespace MonoFN.Cecil { + + public struct CustomAttributeArgument { + + readonly TypeReference type; + readonly object value; + + public TypeReference Type { + get { return type; } + } + + public object Value { + get { return value; } + } + + public CustomAttributeArgument (TypeReference type, object value) + { + Mixin.CheckType (type); + this.type = type; + this.value = value; + } + } + + public struct CustomAttributeNamedArgument { + + readonly string name; + readonly CustomAttributeArgument argument; + + public string Name { + get { return name; } + } + + public CustomAttributeArgument Argument { + get { return argument; } + } + + public CustomAttributeNamedArgument (string name, CustomAttributeArgument argument) + { + Mixin.CheckName (name); + this.name = name; + this.argument = argument; + } + } + + public interface ICustomAttribute { + + TypeReference AttributeType { get; } + + bool HasFields { get; } + bool HasProperties { get; } + bool HasConstructorArguments { get; } + Collection Fields { get; } + Collection Properties { get; } + Collection ConstructorArguments { get; } + } + + [DebuggerDisplay ("{AttributeType}")] + public sealed class CustomAttribute : ICustomAttribute { + + internal CustomAttributeValueProjection projection; + readonly internal uint signature; + internal bool resolved; + MethodReference constructor; + byte [] blob; + internal Collection arguments; + internal Collection fields; + internal Collection properties; + + public MethodReference Constructor { + get { return constructor; } + set { constructor = value; } + } + + public TypeReference AttributeType { + get { return constructor.DeclaringType; } + } + + public bool IsResolved { + get { return resolved; } + } + + public bool HasConstructorArguments { + get { + Resolve (); + + return !arguments.IsNullOrEmpty (); + } + } + + public Collection ConstructorArguments { + get { + Resolve (); + + if (arguments == null) + Interlocked.CompareExchange (ref arguments, new Collection (), null); + + return arguments; + } + } + + public bool HasFields { + get { + Resolve (); + + return !fields.IsNullOrEmpty (); + } + } + + public Collection Fields { + get { + Resolve (); + + if (fields == null) + Interlocked.CompareExchange (ref fields, new Collection (), null); + + return fields; + } + } + + public bool HasProperties { + get { + Resolve (); + + return !properties.IsNullOrEmpty (); + } + } + + public Collection Properties { + get { + Resolve (); + + if (properties == null) + Interlocked.CompareExchange (ref properties, new Collection (), null); + + return properties; + } + } + + internal bool HasImage { + get { return constructor != null && constructor.HasImage; } + } + + internal ModuleDefinition Module { + get { return constructor.Module; } + } + + internal CustomAttribute (uint signature, MethodReference constructor) + { + this.signature = signature; + this.constructor = constructor; + this.resolved = false; + } + + public CustomAttribute (MethodReference constructor) + { + this.constructor = constructor; + this.resolved = true; + } + + public CustomAttribute (MethodReference constructor, byte [] blob) + { + this.constructor = constructor; + this.resolved = false; + this.blob = blob; + } + + public byte [] GetBlob () + { + if (blob != null) + return blob; + + if (!HasImage) + throw new NotSupportedException (); + + return Module.Read (ref blob, this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature)); + } + + void Resolve () + { + if (resolved || !HasImage) + return; + + lock (Module.SyncRoot) { + if (resolved) + return; + + Module.Read (this, (attribute, reader) => { + try { + reader.ReadCustomAttributeSignature (attribute); + resolved = true; + } + catch (ResolutionException) { + if (arguments != null) + arguments.Clear (); + if (fields != null) + fields.Clear (); + if (properties != null) + properties.Clear (); + + resolved = false; + } + }); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs.meta new file mode 100644 index 0000000..d60edbe --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/CustomAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91db4bc8250b4b949bf262a196c9c0c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs new file mode 100644 index 0000000..6bbcf96 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs @@ -0,0 +1,61 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; + +namespace MonoFN.Cecil { + + public class DefaultAssemblyResolver : BaseAssemblyResolver { + + readonly IDictionary cache; + + public DefaultAssemblyResolver () + { + cache = new Dictionary (StringComparer.Ordinal); + } + + public override AssemblyDefinition Resolve (AssemblyNameReference name) + { + Mixin.CheckName (name); + + AssemblyDefinition assembly; + if (cache.TryGetValue (name.FullName, out assembly)) + return assembly; + + assembly = base.Resolve (name); + cache [name.FullName] = assembly; + + return assembly; + } + + protected void RegisterAssembly (AssemblyDefinition assembly) + { + if (assembly == null) + throw new ArgumentNullException ("assembly"); + + var name = assembly.Name.FullName; + if (cache.ContainsKey (name)) + return; + + cache [name] = assembly; + } + + protected override void Dispose (bool disposing) + { + foreach (var assembly in cache.Values) + assembly.Dispose (); + + cache.Clear (); + + base.Dispose (disposing); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs.meta new file mode 100644 index 0000000..75e60fb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/DefaultAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5390b4f18cb83c046baaaa937fec06a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs new file mode 100644 index 0000000..693283e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs @@ -0,0 +1,98 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.IO; + +namespace MonoFN.Cecil { + + public sealed class EmbeddedResource : Resource { + + readonly MetadataReader reader; + + uint? offset; + byte [] data; + Stream stream; + + public override ResourceType ResourceType { + get { return ResourceType.Embedded; } + } + + public EmbeddedResource (string name, ManifestResourceAttributes attributes, byte [] data) : + base (name, attributes) + { + this.data = data; + } + + public EmbeddedResource (string name, ManifestResourceAttributes attributes, Stream stream) : + base (name, attributes) + { + this.stream = stream; + } + + internal EmbeddedResource (string name, ManifestResourceAttributes attributes, uint offset, MetadataReader reader) + : base (name, attributes) + { + this.offset = offset; + this.reader = reader; + } + + public Stream GetResourceStream () + { + if (stream != null) + return stream; + + if (data != null) + return new MemoryStream (data); + + if (offset.HasValue) + return new MemoryStream (reader.GetManagedResource (offset.Value)); + + throw new InvalidOperationException (); + } + + public byte [] GetResourceData () + { + if (stream != null) + return ReadStream (stream); + + if (data != null) + return data; + + if (offset.HasValue) + return reader.GetManagedResource (offset.Value); + + throw new InvalidOperationException (); + } + + static byte [] ReadStream (Stream stream) + { + int read; + + if (stream.CanSeek) { + var length = (int)stream.Length; + var data = new byte [length]; + int offset = 0; + + while ((read = stream.Read (data, offset, length - offset)) > 0) + offset += read; + + return data; + } + + var buffer = new byte [1024 * 8]; + var memory = new MemoryStream (); + while ((read = stream.Read (buffer, 0, buffer.Length)) > 0) + memory.Write (buffer, 0, read); + + return memory.ToArray (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs.meta new file mode 100644 index 0000000..d7d8b36 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EmbeddedResource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5874acd8fee1b4499a3249dd4648428 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs new file mode 100644 index 0000000..7be266a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs @@ -0,0 +1,21 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum EventAttributes : ushort { + None = 0x0000, + SpecialName = 0x0200, // Event is special + RTSpecialName = 0x0400 // CLI provides 'special' behavior, depending upon the name of the event + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs.meta new file mode 100644 index 0000000..11259a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20c18be3d45bbf84d82732fd16751df3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs new file mode 100644 index 0000000..28776b5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs @@ -0,0 +1,156 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class EventDefinition : EventReference, IMemberDefinition { + + ushort attributes; + + Collection custom_attributes; + + internal MethodDefinition add_method; + internal MethodDefinition invoke_method; + internal MethodDefinition remove_method; + internal Collection other_methods; + + public EventAttributes Attributes { + get { return (EventAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public MethodDefinition AddMethod { + get { + if (add_method != null) + return add_method; + + InitializeMethods (); + return add_method; + } + set { add_method = value; } + } + + public MethodDefinition InvokeMethod { + get { + if (invoke_method != null) + return invoke_method; + + InitializeMethods (); + return invoke_method; + } + set { invoke_method = value; } + } + + public MethodDefinition RemoveMethod { + get { + if (remove_method != null) + return remove_method; + + InitializeMethods (); + return remove_method; + } + set { remove_method = value; } + } + + public bool HasOtherMethods { + get { + if (other_methods != null) + return other_methods.Count > 0; + + InitializeMethods (); + return !other_methods.IsNullOrEmpty (); + } + } + + public Collection OtherMethods { + get { + if (other_methods != null) + return other_methods; + + InitializeMethods (); + + if (other_methods == null) + Interlocked.CompareExchange (ref other_methods, new Collection (), null); + + return other_methods; + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + #region EventAttributes + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort)EventAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort)EventAttributes.SpecialName, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort)EventAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort)EventAttributes.RTSpecialName, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition)base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public override bool IsDefinition { + get { return true; } + } + + public EventDefinition (string name, EventAttributes attributes, TypeReference eventType) + : base (name, eventType) + { + this.attributes = (ushort)attributes; + this.token = new MetadataToken (TokenType.Event); + } + + void InitializeMethods () + { + var module = this.Module; + if (module == null) + return; + + lock (module.SyncRoot) { + if (add_method != null + || invoke_method != null + || remove_method != null) + return; + + if (!module.HasImage ()) + return; + + module.Read (this, (@event, reader) => reader.ReadMethods (@event)); + } + } + + public override EventDefinition Resolve () + { + return this; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs.meta new file mode 100644 index 0000000..c8daf6b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b201911ff1f925438edbe5b91275268 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs new file mode 100644 index 0000000..d188a37 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs @@ -0,0 +1,40 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public abstract class EventReference : MemberReference { + + TypeReference event_type; + + public TypeReference EventType { + get { return event_type; } + set { event_type = value; } + } + + public override string FullName { + get { return event_type.FullName + " " + MemberFullName (); } + } + + protected EventReference (string name, TypeReference eventType) + : base (name) + { + Mixin.CheckType (eventType, Mixin.Argument.eventType); + event_type = eventType; + } + + protected override IMemberDefinition ResolveDefinition () + { + return this.Resolve (); + } + + public new abstract EventDefinition Resolve (); + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs.meta new file mode 100644 index 0000000..80e4e71 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/EventReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94d9b58b6c4033343b975f6730127514 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs new file mode 100644 index 0000000..68b4410 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs @@ -0,0 +1,238 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public sealed class ExportedType : IMetadataTokenProvider { + + string @namespace; + string name; + uint attributes; + IMetadataScope scope; + ModuleDefinition module; + int identifier; + ExportedType declaring_type; + internal MetadataToken token; + + public string Namespace { + get { return @namespace; } + set { @namespace = value; } + } + + public string Name { + get { return name; } + set { name = value; } + } + + public TypeAttributes Attributes { + get { return (TypeAttributes)attributes; } + set { attributes = (uint)value; } + } + + public IMetadataScope Scope { + get { + if (declaring_type != null) + return declaring_type.Scope; + + return scope; + } + set { + if (declaring_type != null) { + declaring_type.Scope = value; + return; + } + + scope = value; + } + } + + public ExportedType DeclaringType { + get { return declaring_type; } + set { declaring_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + public int Identifier { + get { return identifier; } + set { identifier = value; } + } + + #region TypeAttributes + + public bool IsNotPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NotPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NotPublic, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.Public, value); } + } + + public bool IsNestedPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPublic, value); } + } + + public bool IsNestedPrivate { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPrivate); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPrivate, value); } + } + + public bool IsNestedFamily { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamily); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamily, value); } + } + + public bool IsNestedAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedAssembly); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedAssembly, value); } + } + + public bool IsNestedFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamANDAssem, value); } + } + + public bool IsNestedFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamORAssem, value); } + } + + public bool IsAutoLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.AutoLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.AutoLayout, value); } + } + + public bool IsSequentialLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.SequentialLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.SequentialLayout, value); } + } + + public bool IsExplicitLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.ExplicitLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.ExplicitLayout, value); } + } + + public bool IsClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Class); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Class, value); } + } + + public bool IsInterface { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Interface); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Interface, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((uint)TypeAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Abstract, value); } + } + + public bool IsSealed { + get { return attributes.GetAttributes ((uint)TypeAttributes.Sealed); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Sealed, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((uint)TypeAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.SpecialName, value); } + } + + public bool IsImport { + get { return attributes.GetAttributes ((uint)TypeAttributes.Import); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Import, value); } + } + + public bool IsSerializable { + get { return attributes.GetAttributes ((uint)TypeAttributes.Serializable); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Serializable, value); } + } + + public bool IsAnsiClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AnsiClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AnsiClass, value); } + } + + public bool IsUnicodeClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.UnicodeClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.UnicodeClass, value); } + } + + public bool IsAutoClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AutoClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AutoClass, value); } + } + + public bool IsBeforeFieldInit { + get { return attributes.GetAttributes ((uint)TypeAttributes.BeforeFieldInit); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.BeforeFieldInit, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((uint)TypeAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((uint)TypeAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.HasSecurity, value); } + } + + #endregion + + public bool IsForwarder { + get { return attributes.GetAttributes ((uint)TypeAttributes.Forwarder); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Forwarder, value); } + } + + public string FullName { + get { + var fullname = string.IsNullOrEmpty (@namespace) + ? name + : @namespace + '.' + name; + + if (declaring_type != null) + return declaring_type.FullName + "/" + fullname; + + return fullname; + } + } + + public ExportedType (string @namespace, string name, ModuleDefinition module, IMetadataScope scope) + { + this.@namespace = @namespace; + this.name = name; + this.scope = scope; + this.module = module; + } + + public override string ToString () + { + return FullName; + } + + public TypeDefinition Resolve () + { + return module.Resolve (CreateReference ()); + } + + internal TypeReference CreateReference () + { + return new TypeReference (@namespace, name, module, scope) { + DeclaringType = declaring_type != null ? declaring_type.CreateReference () : null, + }; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs.meta new file mode 100644 index 0000000..27b33ff --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ExportedType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7fa6f0bdd43c0d44a63cd789a765eeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs new file mode 100644 index 0000000..e4afd2c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs @@ -0,0 +1,41 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum FieldAttributes : ushort { + FieldAccessMask = 0x0007, + CompilerControlled = 0x0000, // Member not referenceable + Private = 0x0001, // Accessible only by the parent type + FamANDAssem = 0x0002, // Accessible by sub-types only in this assembly + Assembly = 0x0003, // Accessible by anyone in the Assembly + Family = 0x0004, // Accessible only by type and sub-types + FamORAssem = 0x0005, // Accessible by sub-types anywhere, plus anyone in the assembly + Public = 0x0006, // Accessible by anyone who has visibility to this scope field contract attributes + + Static = 0x0010, // Defined on type, else per instance + InitOnly = 0x0020, // Field may only be initialized, not written after init + Literal = 0x0040, // Value is compile time constant + NotSerialized = 0x0080, // Field does not have to be serialized when type is remoted + SpecialName = 0x0200, // Field is special + + // Interop Attributes + PInvokeImpl = 0x2000, // Implementation is forwarded through PInvoke + + // Additional flags + RTSpecialName = 0x0400, // CLI provides 'special' behavior, depending upon the name of the field + HasFieldMarshal = 0x1000, // Field has marshalling information + HasDefault = 0x8000, // Field has default + HasFieldRVA = 0x0100 // Field has RVA + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs.meta new file mode 100644 index 0000000..767a61d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e9187082e8fc1446a8c2aa12d8f3fa4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs new file mode 100644 index 0000000..73cdbc9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs @@ -0,0 +1,281 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil { + + public sealed class FieldDefinition : FieldReference, IMemberDefinition, IConstantProvider, IMarshalInfoProvider { + + ushort attributes; + Collection custom_attributes; + + int offset = Mixin.NotResolvedMarker; + + internal int rva = Mixin.NotResolvedMarker; + byte [] initial_value; + + object constant = Mixin.NotResolved; + + MarshalInfo marshal_info; + + void ResolveLayout () + { + if (offset != Mixin.NotResolvedMarker) + return; + + if (!HasImage) { + offset = Mixin.NoDataMarker; + return; + } + + lock (Module.SyncRoot) { + if (offset != Mixin.NotResolvedMarker) + return; + offset = Module.Read (this, (field, reader) => reader.ReadFieldLayout (field)); + } + } + + public bool HasLayoutInfo { + get { + if (offset >= 0) + return true; + + ResolveLayout (); + + return offset >= 0; + } + } + + public int Offset { + get { + if (offset >= 0) + return offset; + + ResolveLayout (); + + return offset >= 0 ? offset : -1; + } + set { offset = value; } + } + + internal FieldDefinitionProjection WindowsRuntimeProjection { + get { return (FieldDefinitionProjection)projection; } + set { projection = value; } + } + + void ResolveRVA () + { + if (rva != Mixin.NotResolvedMarker) + return; + + if (!HasImage) + return; + + lock (Module.SyncRoot) { + if (rva != Mixin.NotResolvedMarker) + return; + rva = Module.Read (this, (field, reader) => reader.ReadFieldRVA (field)); + } + } + + public int RVA { + get { + if (rva > 0) + return rva; + + ResolveRVA (); + + return rva > 0 ? rva : 0; + } + } + + public byte [] InitialValue { + get { + if (initial_value != null) + return initial_value; + + ResolveRVA (); + + if (initial_value == null) + initial_value = Empty.Array; + + return initial_value; + } + set { + initial_value = value; + HasFieldRVA = !initial_value.IsNullOrEmpty (); + rva = 0; + } + } + + public FieldAttributes Attributes { + get { return (FieldAttributes)attributes; } + set { + if (IsWindowsRuntimeProjection && (ushort)value != attributes) + throw new InvalidOperationException (); + + attributes = (ushort)value; + } + } + + public bool HasConstant { + get { + this.ResolveConstant (ref constant, Module); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + public bool HasMarshalInfo { + get { + if (marshal_info != null) + return true; + + return this.GetHasMarshalInfo (Module); + } + } + + public MarshalInfo MarshalInfo { + get { return marshal_info ?? (this.GetMarshalInfo (ref marshal_info, Module)); } + set { marshal_info = value; } + } + + #region FieldAttributes + + public bool IsCompilerControlled { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.CompilerControlled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.CompilerControlled, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Private, value); } + } + + public bool IsFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.FamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.FamANDAssem, value); } + } + + public bool IsAssembly { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Assembly); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Assembly, value); } + } + + public bool IsFamily { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Family); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Family, value); } + } + + public bool IsFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.FamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.FamORAssem, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((ushort)FieldAttributes.FieldAccessMask, (ushort)FieldAttributes.Public, value); } + } + + public bool IsStatic { + get { return attributes.GetAttributes ((ushort)FieldAttributes.Static); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.Static, value); } + } + + public bool IsInitOnly { + get { return attributes.GetAttributes ((ushort)FieldAttributes.InitOnly); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.InitOnly, value); } + } + + public bool IsLiteral { + get { return attributes.GetAttributes ((ushort)FieldAttributes.Literal); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.Literal, value); } + } + + public bool IsNotSerialized { + get { return attributes.GetAttributes ((ushort)FieldAttributes.NotSerialized); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.NotSerialized, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort)FieldAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.SpecialName, value); } + } + + public bool IsPInvokeImpl { + get { return attributes.GetAttributes ((ushort)FieldAttributes.PInvokeImpl); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.PInvokeImpl, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort)FieldAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.RTSpecialName, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort)FieldAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.HasDefault, value); } + } + + public bool HasFieldRVA { + get { return attributes.GetAttributes ((ushort)FieldAttributes.HasFieldRVA); } + set { attributes = attributes.SetAttributes ((ushort)FieldAttributes.HasFieldRVA, value); } + } + + #endregion + + public override bool IsDefinition { + get { return true; } + } + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition)base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public FieldDefinition (string name, FieldAttributes attributes, TypeReference fieldType) + : base (name, fieldType) + { + this.attributes = (ushort)attributes; + } + + public override FieldDefinition Resolve () + { + return this; + } + } + + static partial class Mixin { + + public const int NotResolvedMarker = -2; + public const int NoDataMarker = -1; + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs.meta new file mode 100644 index 0000000..99dac2a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00dcb95135f39ec4c923f7923bcc93ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs new file mode 100644 index 0000000..1e9d3e3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs @@ -0,0 +1,68 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public class FieldReference : MemberReference { + + TypeReference field_type; + + public TypeReference FieldType { + get { return field_type; } + set { field_type = value; } + } + + public override string FullName { + get { return field_type.FullName + " " + MemberFullName (); } + } + + public override bool ContainsGenericParameter { + get { return field_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + internal FieldReference () + { + this.token = new MetadataToken (TokenType.MemberRef); + } + + public FieldReference (string name, TypeReference fieldType) + : base (name) + { + Mixin.CheckType (fieldType, Mixin.Argument.fieldType); + + this.field_type = fieldType; + this.token = new MetadataToken (TokenType.MemberRef); + } + + public FieldReference (string name, TypeReference fieldType, TypeReference declaringType) + : this (name, fieldType) + { + Mixin.CheckType (declaringType, Mixin.Argument.declaringType); + + this.DeclaringType = declaringType; + } + + protected override IMemberDefinition ResolveDefinition () + { + return this.Resolve (); + } + + public new virtual FieldDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs.meta new file mode 100644 index 0000000..6f1c541 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FieldReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 990be2becde06b4468f79bd17646a47a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs new file mode 100644 index 0000000..32715d5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs @@ -0,0 +1,17 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + enum FileAttributes : uint { + ContainsMetaData = 0x0000, // This is not a resource file + ContainsNoMetaData = 0x0001, // This is a resource file or other non-metadata-containing file + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs.meta new file mode 100644 index 0000000..58c3fe0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FileAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56e662d580c0894489669cc8058a2783 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs new file mode 100644 index 0000000..8558c54 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs @@ -0,0 +1,111 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Text; +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class FunctionPointerType : TypeSpecification, IMethodSignature { + + readonly MethodReference function; + + public bool HasThis { + get { return function.HasThis; } + set { function.HasThis = value; } + } + + public bool ExplicitThis { + get { return function.ExplicitThis; } + set { function.ExplicitThis = value; } + } + + public MethodCallingConvention CallingConvention { + get { return function.CallingConvention; } + set { function.CallingConvention = value; } + } + + public bool HasParameters { + get { return function.HasParameters; } + } + + public Collection Parameters { + get { return function.Parameters; } + } + + public TypeReference ReturnType { + get { return function.MethodReturnType.ReturnType; } + set { function.MethodReturnType.ReturnType = value; } + } + + public MethodReturnType MethodReturnType { + get { return function.MethodReturnType; } + } + + public override string Name { + get { return function.Name; } + set { throw new InvalidOperationException (); } + } + + public override string Namespace { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public override ModuleDefinition Module { + get { return ReturnType.Module; } + } + + public override IMetadataScope Scope { + get { return function.ReturnType.Scope; } + set { throw new InvalidOperationException (); } + } + + public override bool IsFunctionPointer { + get { return true; } + } + + public override bool ContainsGenericParameter { + get { return function.ContainsGenericParameter; } + } + + public override string FullName { + get { + var signature = new StringBuilder (); + signature.Append (function.Name); + signature.Append (" "); + signature.Append (function.ReturnType.FullName); + signature.Append (" *"); + this.MethodSignatureFullName (signature); + return signature.ToString (); + } + } + + public FunctionPointerType () + : base (null) + { + this.function = new MethodReference (); + this.function.Name = "method"; + this.etype = MD.ElementType.FnPtr; + } + + public override TypeDefinition Resolve () + { + return null; + } + + public override TypeReference GetElementType () + { + return this; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs.meta new file mode 100644 index 0000000..a576fd7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/FunctionPointerType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91d84cd146416f945acbfce1b1dbcacb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs new file mode 100644 index 0000000..64737a9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs @@ -0,0 +1,77 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Text; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class GenericInstanceMethod : MethodSpecification, IGenericInstance, IGenericContext { + + Collection arguments; + + public bool HasGenericArguments { + get { return !arguments.IsNullOrEmpty (); } + } + + public Collection GenericArguments { + get { + if (arguments == null) + Interlocked.CompareExchange (ref arguments, new Collection (), null); + + return arguments; + } + } + + public override bool IsGenericInstance { + get { return true; } + } + + IGenericParameterProvider IGenericContext.Method { + get { return ElementMethod; } + } + + IGenericParameterProvider IGenericContext.Type { + get { return ElementMethod.DeclaringType; } + } + + public override bool ContainsGenericParameter { + get { return this.ContainsGenericParameter () || base.ContainsGenericParameter; } + } + + public override string FullName { + get { + var signature = new StringBuilder (); + var method = this.ElementMethod; + signature.Append (method.ReturnType.FullName) + .Append (" ") + .Append (method.DeclaringType.FullName) + .Append ("::") + .Append (method.Name); + this.GenericInstanceFullName (signature); + this.MethodSignatureFullName (signature); + return signature.ToString (); + + } + } + + public GenericInstanceMethod (MethodReference method) + : base (method) + { + } + + internal GenericInstanceMethod (MethodReference method, int arity) + : this (method) + { + this.arguments = new Collection (arity); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs.meta new file mode 100644 index 0000000..cee2434 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceMethod.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd61b82dc3c653d42a1fc0f4e4c003f8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs new file mode 100644 index 0000000..4f40314 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs @@ -0,0 +1,75 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Text; +using System.Threading; +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class GenericInstanceType : TypeSpecification, IGenericInstance, IGenericContext { + + Collection arguments; + + public bool HasGenericArguments { + get { return !arguments.IsNullOrEmpty (); } + } + + public Collection GenericArguments { + get { + if (arguments == null) + Interlocked.CompareExchange (ref arguments, new Collection (), null); + + return arguments; + } + } + + public override TypeReference DeclaringType { + get { return ElementType.DeclaringType; } + set { throw new NotSupportedException (); } + } + + public override string FullName { + get { + var name = new StringBuilder (); + name.Append (base.FullName); + this.GenericInstanceFullName (name); + return name.ToString (); + } + } + + public override bool IsGenericInstance { + get { return true; } + } + + public override bool ContainsGenericParameter { + get { return this.ContainsGenericParameter () || base.ContainsGenericParameter; } + } + + IGenericParameterProvider IGenericContext.Type { + get { return ElementType; } + } + + public GenericInstanceType (TypeReference type) + : base (type) + { + base.IsValueType = type.IsValueType; + this.etype = MD.ElementType.GenericInst; + } + + internal GenericInstanceType (TypeReference type, int arity) + : this (type) + { + this.arguments = new Collection (arity); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs.meta new file mode 100644 index 0000000..3d8278d --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericInstanceType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 536e7e359f0fa6c449a352476e8af197 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs new file mode 100644 index 0000000..6b7ada6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs @@ -0,0 +1,360 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class GenericParameter : TypeReference, ICustomAttributeProvider { + + internal int position; + internal GenericParameterType type; + internal IGenericParameterProvider owner; + + ushort attributes; + GenericParameterConstraintCollection constraints; + Collection custom_attributes; + + public GenericParameterAttributes Attributes { + get { return (GenericParameterAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public int Position { + get { return position; } + } + + public GenericParameterType Type { + get { return type; } + } + + public IGenericParameterProvider Owner { + get { return owner; } + } + + public bool HasConstraints { + get { + if (constraints != null) + return constraints.Count > 0; + + return HasImage && Module.Read (this, (generic_parameter, reader) => reader.HasGenericConstraints (generic_parameter)); + } + } + + public Collection Constraints { + get { + if (constraints != null) + return constraints; + + if (HasImage) + return Module.Read (ref constraints, this, (generic_parameter, reader) => reader.ReadGenericConstraints (generic_parameter)); + + Interlocked.CompareExchange (ref constraints, new GenericParameterConstraintCollection (this), null); + return constraints; + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + public override IMetadataScope Scope { + get { + if (owner == null) + return null; + + return owner.GenericParameterType == GenericParameterType.Method + ? ((MethodReference)owner).DeclaringType.Scope + : ((TypeReference)owner).Scope; + } + set { throw new InvalidOperationException (); } + } + + public override TypeReference DeclaringType { + get { return owner as TypeReference; } + set { throw new InvalidOperationException (); } + } + + public MethodReference DeclaringMethod { + get { return owner as MethodReference; } + } + + public override ModuleDefinition Module { + get { return module ?? owner.Module; } + } + + public override string Name { + get { + if (!string.IsNullOrEmpty (base.Name)) + return base.Name; + + return base.Name = (type == GenericParameterType.Method ? "!!" : "!") + position; + } + } + + public override string Namespace { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public override string FullName { + get { return Name; } + } + + public override bool IsGenericParameter { + get { return true; } + } + + public override bool ContainsGenericParameter { + get { return true; } + } + + public override MetadataType MetadataType { + get { return (MetadataType)etype; } + } + + #region GenericParameterAttributes + + public bool IsNonVariant { + get { return attributes.GetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.NonVariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.NonVariant, value); } + } + + public bool IsCovariant { + get { return attributes.GetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.Covariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.Covariant, value); } + } + + public bool IsContravariant { + get { return attributes.GetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.Contravariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort)GenericParameterAttributes.VarianceMask, (ushort)GenericParameterAttributes.Contravariant, value); } + } + + public bool HasReferenceTypeConstraint { + get { return attributes.GetAttributes ((ushort)GenericParameterAttributes.ReferenceTypeConstraint); } + set { attributes = attributes.SetAttributes ((ushort)GenericParameterAttributes.ReferenceTypeConstraint, value); } + } + + public bool HasNotNullableValueTypeConstraint { + get { return attributes.GetAttributes ((ushort)GenericParameterAttributes.NotNullableValueTypeConstraint); } + set { attributes = attributes.SetAttributes ((ushort)GenericParameterAttributes.NotNullableValueTypeConstraint, value); } + } + + public bool HasDefaultConstructorConstraint { + get { return attributes.GetAttributes ((ushort)GenericParameterAttributes.DefaultConstructorConstraint); } + set { attributes = attributes.SetAttributes ((ushort)GenericParameterAttributes.DefaultConstructorConstraint, value); } + } + + #endregion + + public GenericParameter (IGenericParameterProvider owner) + : this (string.Empty, owner) + { + } + + public GenericParameter (string name, IGenericParameterProvider owner) + : base (string.Empty, name) + { + if (owner == null) + throw new ArgumentNullException (); + + this.position = -1; + this.owner = owner; + this.type = owner.GenericParameterType; + this.etype = ConvertGenericParameterType (this.type); + this.token = new MetadataToken (TokenType.GenericParam); + + } + + internal GenericParameter (int position, GenericParameterType type, ModuleDefinition module) + : base (string.Empty, string.Empty) + { + Mixin.CheckModule (module); + + this.position = position; + this.type = type; + this.etype = ConvertGenericParameterType (type); + this.module = module; + this.token = new MetadataToken (TokenType.GenericParam); + } + + static ElementType ConvertGenericParameterType (GenericParameterType type) + { + switch (type) { + case GenericParameterType.Type: + return ElementType.Var; + case GenericParameterType.Method: + return ElementType.MVar; + } + + throw new ArgumentOutOfRangeException (); + } + + public override TypeDefinition Resolve () + { + return null; + } + } + + sealed class GenericParameterCollection : Collection { + + readonly IGenericParameterProvider owner; + + internal GenericParameterCollection (IGenericParameterProvider owner) + { + this.owner = owner; + } + + internal GenericParameterCollection (IGenericParameterProvider owner, int capacity) + : base (capacity) + { + this.owner = owner; + } + + protected override void OnAdd (GenericParameter item, int index) + { + UpdateGenericParameter (item, index); + } + + protected override void OnInsert (GenericParameter item, int index) + { + UpdateGenericParameter (item, index); + + for (int i = index; i < size; i++) + items [i].position = i + 1; + } + + protected override void OnSet (GenericParameter item, int index) + { + UpdateGenericParameter (item, index); + } + + void UpdateGenericParameter (GenericParameter item, int index) + { + item.owner = owner; + item.position = index; + item.type = owner.GenericParameterType; + } + + protected override void OnRemove (GenericParameter item, int index) + { + item.owner = null; + item.position = -1; + item.type = GenericParameterType.Type; + + for (int i = index + 1; i < size; i++) + items [i].position = i - 1; + } + } + + public sealed class GenericParameterConstraint : ICustomAttributeProvider { + + internal GenericParameter generic_parameter; + internal MetadataToken token; + + TypeReference constraint_type; + Collection custom_attributes; + + public TypeReference ConstraintType { + get { return constraint_type; } + set { constraint_type = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + if (generic_parameter == null) + return false; + + return this.GetHasCustomAttributes (generic_parameter.Module); + } + } + + public Collection CustomAttributes { + get { + if (generic_parameter == null) { + if (custom_attributes == null) + Interlocked.CompareExchange (ref custom_attributes, new Collection (), null); + return custom_attributes; + } + + return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, generic_parameter.Module)); + } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal GenericParameterConstraint (TypeReference constraintType, MetadataToken token) + { + this.constraint_type = constraintType; + this.token = token; + } + + public GenericParameterConstraint (TypeReference constraintType) + { + Mixin.CheckType (constraintType, Mixin.Argument.constraintType); + + this.constraint_type = constraintType; + this.token = new MetadataToken (TokenType.GenericParamConstraint); + } + } + + class GenericParameterConstraintCollection : Collection { + readonly GenericParameter generic_parameter; + + internal GenericParameterConstraintCollection (GenericParameter genericParameter) + { + this.generic_parameter = genericParameter; + } + + internal GenericParameterConstraintCollection (GenericParameter genericParameter, int length) + : base (length) + { + this.generic_parameter = genericParameter; + } + + protected override void OnAdd (GenericParameterConstraint item, int index) + { + item.generic_parameter = generic_parameter; + } + + protected override void OnInsert (GenericParameterConstraint item, int index) + { + item.generic_parameter = generic_parameter; + } + + protected override void OnSet (GenericParameterConstraint item, int index) + { + item.generic_parameter = generic_parameter; + } + + protected override void OnRemove (GenericParameterConstraint item, int index) + { + item.generic_parameter = null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs.meta new file mode 100644 index 0000000..73db53b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a20d39eab5fe7884c8cdf55fde143904 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs new file mode 100644 index 0000000..a5ae0fc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs @@ -0,0 +1,27 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum GenericParameterAttributes : ushort { + VarianceMask = 0x0003, + NonVariant = 0x0000, + Covariant = 0x0001, + Contravariant = 0x0002, + + SpecialConstraintMask = 0x001c, + ReferenceTypeConstraint = 0x0004, + NotNullableValueTypeConstraint = 0x0008, + DefaultConstructorConstraint = 0x0010 + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs.meta new file mode 100644 index 0000000..b4e1bf9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 406369465fc07a643b3923d53fb1e941 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs new file mode 100644 index 0000000..b3677e6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs @@ -0,0 +1,175 @@ +using MonoFN.Cecil.Cil; +using System; + +namespace MonoFN.Cecil { + internal sealed class GenericParameterResolver { + internal static TypeReference ResolveReturnTypeIfNeeded (MethodReference methodReference) + { + if (methodReference.DeclaringType.IsArray && methodReference.Name == "Get") + return methodReference.ReturnType; + + var genericInstanceMethod = methodReference as GenericInstanceMethod; + var declaringGenericInstanceType = methodReference.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return methodReference.ReturnType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, methodReference.ReturnType); + } + + internal static TypeReference ResolveFieldTypeIfNeeded (FieldReference fieldReference) + { + return ResolveIfNeeded (null, fieldReference.DeclaringType as GenericInstanceType, fieldReference.FieldType); + } + + internal static TypeReference ResolveParameterTypeIfNeeded (MethodReference method, ParameterReference parameter) + { + var genericInstanceMethod = method as GenericInstanceMethod; + var declaringGenericInstanceType = method.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return parameter.ParameterType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, parameter.ParameterType); + } + + internal static TypeReference ResolveVariableTypeIfNeeded (MethodReference method, VariableReference variable) + { + var genericInstanceMethod = method as GenericInstanceMethod; + var declaringGenericInstanceType = method.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return variable.VariableType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, variable.VariableType); + } + + private static TypeReference ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance declaringGenericInstanceType, TypeReference parameterType) + { + var byRefType = parameterType as ByReferenceType; + if (byRefType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, byRefType); + + var arrayType = parameterType as ArrayType; + if (arrayType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, arrayType); + + var genericInstanceType = parameterType as GenericInstanceType; + if (genericInstanceType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, genericInstanceType); + + var genericParameter = parameterType as GenericParameter; + if (genericParameter != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, genericParameter); + + var requiredModifierType = parameterType as RequiredModifierType; + if (requiredModifierType != null && ContainsGenericParameters (requiredModifierType)) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, requiredModifierType.ElementType); + + if (ContainsGenericParameters (parameterType)) + throw new Exception ("Unexpected generic parameter."); + + return parameterType; + } + + private static TypeReference ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, GenericParameter genericParameterElement) + { + return (genericParameterElement.MetadataType == MetadataType.MVar) + ? (genericInstanceMethod != null ? genericInstanceMethod.GenericArguments [genericParameterElement.Position] : genericParameterElement) + : genericInstanceType.GenericArguments [genericParameterElement.Position]; + } + + private static ArrayType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, ArrayType arrayType) + { + return new ArrayType (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, arrayType.ElementType), arrayType.Rank); + } + + private static ByReferenceType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, ByReferenceType byReferenceType) + { + return new ByReferenceType (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, byReferenceType.ElementType)); + } + + private static GenericInstanceType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, GenericInstanceType genericInstanceType1) + { + if (!ContainsGenericParameters (genericInstanceType1)) + return genericInstanceType1; + + var newGenericInstance = new GenericInstanceType (genericInstanceType1.ElementType); + + foreach (var genericArgument in genericInstanceType1.GenericArguments) { + if (!genericArgument.IsGenericParameter) { + newGenericInstance.GenericArguments.Add (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, genericArgument)); + continue; + } + + var genParam = (GenericParameter)genericArgument; + + switch (genParam.Type) { + case GenericParameterType.Type: { + if (genericInstanceType == null) + throw new NotSupportedException (); + + newGenericInstance.GenericArguments.Add (genericInstanceType.GenericArguments [genParam.Position]); + } + break; + + case GenericParameterType.Method: { + if (genericInstanceMethod == null) + newGenericInstance.GenericArguments.Add (genParam); + else + newGenericInstance.GenericArguments.Add (genericInstanceMethod.GenericArguments [genParam.Position]); + } + break; + } + } + + return newGenericInstance; + } + + private static bool ContainsGenericParameters (TypeReference typeReference) + { + var genericParameter = typeReference as GenericParameter; + if (genericParameter != null) + return true; + + var arrayType = typeReference as ArrayType; + if (arrayType != null) + return ContainsGenericParameters (arrayType.ElementType); + + var pointerType = typeReference as PointerType; + if (pointerType != null) + return ContainsGenericParameters (pointerType.ElementType); + + var byRefType = typeReference as ByReferenceType; + if (byRefType != null) + return ContainsGenericParameters (byRefType.ElementType); + + var sentinelType = typeReference as SentinelType; + if (sentinelType != null) + return ContainsGenericParameters (sentinelType.ElementType); + + var pinnedType = typeReference as PinnedType; + if (pinnedType != null) + return ContainsGenericParameters (pinnedType.ElementType); + + var requiredModifierType = typeReference as RequiredModifierType; + if (requiredModifierType != null) + return ContainsGenericParameters (requiredModifierType.ElementType); + + var genericInstance = typeReference as GenericInstanceType; + if (genericInstance != null) { + foreach (var genericArgument in genericInstance.GenericArguments) { + if (ContainsGenericParameters (genericArgument)) + return true; + } + + return false; + } + + if (typeReference is TypeSpecification) + throw new NotSupportedException (); + + return false; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs.meta new file mode 100644 index 0000000..c982dd5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/GenericParameterResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4151464170fe40440a031e1f4f2ecf53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs new file mode 100644 index 0000000..3631258 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs @@ -0,0 +1,44 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public interface IConstantProvider : IMetadataTokenProvider { + + bool HasConstant { get; set; } + object Constant { get; set; } + } + + static partial class Mixin { + + internal static object NoValue = new object (); + internal static object NotResolved = new object (); + + public static void ResolveConstant ( + this IConstantProvider self, + ref object constant, + ModuleDefinition module) + { + if (module == null) { + constant = Mixin.NoValue; + return; + } + + lock (module.SyncRoot) { + if (constant != Mixin.NotResolved) + return; + if (module.HasImage ()) + constant = module.Read (self, (provider, reader) => reader.ReadConstant (provider)); + else + constant = Mixin.NoValue; + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs.meta new file mode 100644 index 0000000..8f377d7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IConstantProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58315b928b9e49540b9d1591523c92c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs new file mode 100644 index 0000000..39b8f01 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs @@ -0,0 +1,44 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + public interface ICustomAttributeProvider : IMetadataTokenProvider { + + Collection CustomAttributes { get; } + + bool HasCustomAttributes { get; } + } + + static partial class Mixin { + + public static bool GetHasCustomAttributes ( + this ICustomAttributeProvider self, + ModuleDefinition module) + { + return module.HasImage () && module.Read (self, (provider, reader) => reader.HasCustomAttributes (provider)); + } + + public static Collection GetCustomAttributes ( + this ICustomAttributeProvider self, + ref Collection variable, + ModuleDefinition module) + { + if (module.HasImage ()) + return module.Read (ref variable, self, (provider, reader) => reader.ReadCustomAttributes (provider)); + + Interlocked.CompareExchange (ref variable, new Collection (), null); + return variable; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs.meta new file mode 100644 index 0000000..e61f1f9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ICustomAttributeProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1585603aa3fe4f1409c42694378a557c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs new file mode 100644 index 0000000..ecee2cc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs @@ -0,0 +1,47 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Text; + +namespace MonoFN.Cecil { + + public interface IGenericInstance : IMetadataTokenProvider { + + bool HasGenericArguments { get; } + Collection GenericArguments { get; } + } + + static partial class Mixin { + + public static bool ContainsGenericParameter (this IGenericInstance self) + { + var arguments = self.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + if (arguments [i].ContainsGenericParameter) + return true; + + return false; + } + + public static void GenericInstanceFullName (this IGenericInstance self, StringBuilder builder) + { + builder.Append ("<"); + var arguments = self.GenericArguments; + for (int i = 0; i < arguments.Count; i++) { + if (i > 0) + builder.Append (","); + builder.Append (arguments [i].FullName); + } + builder.Append (">"); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs.meta new file mode 100644 index 0000000..3907d65 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22b3a8ddd25a989449e5e9ffc632bc00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs new file mode 100644 index 0000000..da27ad3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs @@ -0,0 +1,58 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + public interface IGenericParameterProvider : IMetadataTokenProvider { + + bool HasGenericParameters { get; } + bool IsDefinition { get; } + ModuleDefinition Module { get; } + Collection GenericParameters { get; } + GenericParameterType GenericParameterType { get; } + } + + public enum GenericParameterType { + Type, + Method + } + + interface IGenericContext { + + bool IsDefinition { get; } + IGenericParameterProvider Type { get; } + IGenericParameterProvider Method { get; } + } + + static partial class Mixin { + + public static bool GetHasGenericParameters ( + this IGenericParameterProvider self, + ModuleDefinition module) + { + return module.HasImage () && module.Read (self, (provider, reader) => reader.HasGenericParameters (provider)); + } + + public static Collection GetGenericParameters ( + this IGenericParameterProvider self, + ref Collection collection, + ModuleDefinition module) + { + if (module.HasImage ()) + return module.Read (ref collection, self, (provider, reader) => reader.ReadGenericParameters (provider)); + + Interlocked.CompareExchange (ref collection, new GenericParameterCollection (self), null); + return collection; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs.meta new file mode 100644 index 0000000..d11d967 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IGenericParameterProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c81842a9d1ff34f4b94b047da954469f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs new file mode 100644 index 0000000..75faa1a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs @@ -0,0 +1,38 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public interface IMarshalInfoProvider : IMetadataTokenProvider { + + bool HasMarshalInfo { get; } + MarshalInfo MarshalInfo { get; set; } + } + + static partial class Mixin { + + public static bool GetHasMarshalInfo ( + this IMarshalInfoProvider self, + ModuleDefinition module) + { + return module.HasImage () && module.Read (self, (provider, reader) => reader.HasMarshalInfo (provider)); + } + + public static MarshalInfo GetMarshalInfo ( + this IMarshalInfoProvider self, + ref MarshalInfo variable, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (ref variable, self, (provider, reader) => reader.ReadMarshalInfo (provider)) + : null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs.meta new file mode 100644 index 0000000..8ce8f0c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMarshalInfoProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a73829f4e35521e4892ef4e0cce2e4f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs new file mode 100644 index 0000000..743e8d4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs @@ -0,0 +1,82 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public interface IMemberDefinition : ICustomAttributeProvider { + + string Name { get; set; } + string FullName { get; } + + bool IsSpecialName { get; set; } + bool IsRuntimeSpecialName { get; set; } + + TypeDefinition DeclaringType { get; set; } + } + + static partial class Mixin { + + public static bool GetAttributes (this uint self, uint attributes) + { + return (self & attributes) != 0; + } + + public static uint SetAttributes (this uint self, uint attributes, bool value) + { + if (value) + return self | attributes; + + return self & ~attributes; + } + + public static bool GetMaskedAttributes (this uint self, uint mask, uint attributes) + { + return (self & mask) == attributes; + } + + public static uint SetMaskedAttributes (this uint self, uint mask, uint attributes, bool value) + { + if (value) { + self &= ~mask; + return self | attributes; + } + + return self & ~(mask & attributes); + } + + public static bool GetAttributes (this ushort self, ushort attributes) + { + return (self & attributes) != 0; + } + + public static ushort SetAttributes (this ushort self, ushort attributes, bool value) + { + if (value) + return (ushort)(self | attributes); + + return (ushort)(self & ~attributes); + } + + public static bool GetMaskedAttributes (this ushort self, ushort mask, uint attributes) + { + return (self & mask) == attributes; + } + + public static ushort SetMaskedAttributes (this ushort self, ushort mask, uint attributes, bool value) + { + if (value) { + self = (ushort)(self & ~mask); + return (ushort)(self | attributes); + } + + return (ushort)(self & ~(mask & attributes)); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs.meta new file mode 100644 index 0000000..b78f8dc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMemberDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 482577ba8693d3f438504e54d6edb971 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs new file mode 100644 index 0000000..7604a9e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs @@ -0,0 +1,23 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum MetadataScopeType { + AssemblyNameReference, + ModuleReference, + ModuleDefinition, + } + + public interface IMetadataScope : IMetadataTokenProvider { + MetadataScopeType MetadataScopeType { get; } + string Name { get; set; } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs.meta new file mode 100644 index 0000000..0b8b2bc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataScope.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da1ce103d170a414c8c8c6849a8856a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs new file mode 100644 index 0000000..a82c759 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs @@ -0,0 +1,17 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public interface IMetadataTokenProvider { + + MetadataToken MetadataToken { get; set; } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs.meta new file mode 100644 index 0000000..eb83452 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMetadataTokenProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c01133d3a99e95542b153987746696d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs new file mode 100644 index 0000000..57be39c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs @@ -0,0 +1,56 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Text; + +namespace MonoFN.Cecil { + + public interface IMethodSignature : IMetadataTokenProvider { + + bool HasThis { get; set; } + bool ExplicitThis { get; set; } + MethodCallingConvention CallingConvention { get; set; } + + bool HasParameters { get; } + Collection Parameters { get; } + TypeReference ReturnType { get; set; } + MethodReturnType MethodReturnType { get; } + } + + static partial class Mixin { + + public static bool HasImplicitThis (this IMethodSignature self) + { + return self.HasThis && !self.ExplicitThis; + } + + public static void MethodSignatureFullName (this IMethodSignature self, StringBuilder builder) + { + builder.Append ("("); + + if (self.HasParameters) { + var parameters = self.Parameters; + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + if (i > 0) + builder.Append (","); + + if (parameter.ParameterType.IsSentinel) + builder.Append ("...,"); + + builder.Append (parameter.ParameterType.FullName); + } + } + + builder.Append (")"); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs.meta new file mode 100644 index 0000000..2f3a715 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/IMethodSignature.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fdcc55987f0a4f4b93358d994704a98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs new file mode 100644 index 0000000..7770c5b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs @@ -0,0 +1,816 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using SR = System.Reflection; + +namespace MonoFN.Cecil { + + public interface IMetadataImporterProvider { + IMetadataImporter GetMetadataImporter (ModuleDefinition module); + } + + public interface IMetadataImporter { + AssemblyNameReference ImportReference (AssemblyNameReference reference); + TypeReference ImportReference (TypeReference type, IGenericParameterProvider context); + FieldReference ImportReference (FieldReference field, IGenericParameterProvider context); + MethodReference ImportReference (MethodReference method, IGenericParameterProvider context); + } + + public interface IReflectionImporterProvider { + IReflectionImporter GetReflectionImporter (ModuleDefinition module); + } + + public interface IReflectionImporter { + AssemblyNameReference ImportReference (SR.AssemblyName reference); + TypeReference ImportReference (Type type, IGenericParameterProvider context); + FieldReference ImportReference (SR.FieldInfo field, IGenericParameterProvider context); + MethodReference ImportReference (SR.MethodBase method, IGenericParameterProvider context); + } + + struct ImportGenericContext { + + Collection stack; + + public bool IsEmpty { get { return stack == null; } } + + public ImportGenericContext (IGenericParameterProvider provider) + { + if (provider == null) + throw new ArgumentNullException ("provider"); + + stack = null; + + Push (provider); + } + + public void Push (IGenericParameterProvider provider) + { + if (stack == null) + stack = new Collection (1) { provider }; + else + stack.Add (provider); + } + + public void Pop () + { + stack.RemoveAt (stack.Count - 1); + } + + public TypeReference MethodParameter (string method, int position) + { + for (int i = stack.Count - 1; i >= 0; i--) { + var candidate = stack [i] as MethodReference; + if (candidate == null) + continue; + + if (method != NormalizeMethodName (candidate)) + continue; + + return candidate.GenericParameters [position]; + } + + throw new InvalidOperationException (); + } + + public string NormalizeMethodName (MethodReference method) + { + return method.DeclaringType.GetElementType ().FullName + "." + method.Name; + } + + public TypeReference TypeParameter (string type, int position) + { + for (int i = stack.Count - 1; i >= 0; i--) { + var candidate = GenericTypeFor (stack [i]); + + if (candidate.FullName != type) + continue; + + return candidate.GenericParameters [position]; + } + + throw new InvalidOperationException (); + } + + static TypeReference GenericTypeFor (IGenericParameterProvider context) + { + var type = context as TypeReference; + if (type != null) + return type.GetElementType (); + + var method = context as MethodReference; + if (method != null) + return method.DeclaringType.GetElementType (); + + throw new InvalidOperationException (); + } + + public static ImportGenericContext For (IGenericParameterProvider context) + { + return context != null ? new ImportGenericContext (context) : default (ImportGenericContext); + } + } + + public class DefaultReflectionImporter : IReflectionImporter { + + readonly protected ModuleDefinition module; + + public DefaultReflectionImporter (ModuleDefinition module) + { + Mixin.CheckModule (module); + + this.module = module; + } + + enum ImportGenericKind { + Definition, + Open, + } + + static readonly Dictionary type_etype_mapping = new Dictionary (18) { + { typeof (void), ElementType.Void }, + { typeof (bool), ElementType.Boolean }, + { typeof (char), ElementType.Char }, + { typeof (sbyte), ElementType.I1 }, + { typeof (byte), ElementType.U1 }, + { typeof (short), ElementType.I2 }, + { typeof (ushort), ElementType.U2 }, + { typeof (int), ElementType.I4 }, + { typeof (uint), ElementType.U4 }, + { typeof (long), ElementType.I8 }, + { typeof (ulong), ElementType.U8 }, + { typeof (float), ElementType.R4 }, + { typeof (double), ElementType.R8 }, + { typeof (string), ElementType.String }, + { typeof (TypedReference), ElementType.TypedByRef }, + { typeof (IntPtr), ElementType.I }, + { typeof (UIntPtr), ElementType.U }, + { typeof (object), ElementType.Object }, + }; + + TypeReference ImportType (Type type, ImportGenericContext context) + { + return ImportType (type, context, ImportGenericKind.Open); + } + + TypeReference ImportType (Type type, ImportGenericContext context, ImportGenericKind import_kind) + { + if (IsTypeSpecification (type) || ImportOpenGenericType (type, import_kind)) + return ImportTypeSpecification (type, context); + + var reference = new TypeReference ( + string.Empty, + type.Name, + module, + ImportScope (type), + type.IsValueType); + + reference.etype = ImportElementType (type); + + if (IsNestedType (type)) + reference.DeclaringType = ImportType (type.DeclaringType, context, import_kind); + else + reference.Namespace = type.Namespace ?? string.Empty; + + if (type.IsGenericType) + ImportGenericParameters (reference, type.GetGenericArguments ()); + + return reference; + } + + protected virtual IMetadataScope ImportScope (Type type) + { + return ImportScope (type.Assembly); + } + + static bool ImportOpenGenericType (Type type, ImportGenericKind import_kind) + { + return type.IsGenericType && type.IsGenericTypeDefinition && import_kind == ImportGenericKind.Open; + } + + static bool ImportOpenGenericMethod (SR.MethodBase method, ImportGenericKind import_kind) + { + return method.IsGenericMethod && method.IsGenericMethodDefinition && import_kind == ImportGenericKind.Open; + } + + static bool IsNestedType (Type type) + { + return type.IsNested; + } + + TypeReference ImportTypeSpecification (Type type, ImportGenericContext context) + { + if (type.IsByRef) + return new ByReferenceType (ImportType (type.GetElementType (), context)); + + if (type.IsPointer) + return new PointerType (ImportType (type.GetElementType (), context)); + + if (type.IsArray) + return new ArrayType (ImportType (type.GetElementType (), context), type.GetArrayRank ()); + + if (type.IsGenericType) + return ImportGenericInstance (type, context); + + if (type.IsGenericParameter) + return ImportGenericParameter (type, context); + + throw new NotSupportedException (type.FullName); + } + + static TypeReference ImportGenericParameter (Type type, ImportGenericContext context) + { + if (context.IsEmpty) + throw new InvalidOperationException (); + + if (type.DeclaringMethod != null) + return context.MethodParameter (NormalizeMethodName (type.DeclaringMethod), type.GenericParameterPosition); + + if (type.DeclaringType != null) + return context.TypeParameter (NormalizeTypeFullName (type.DeclaringType), type.GenericParameterPosition); + + throw new InvalidOperationException (); + } + + static string NormalizeMethodName (SR.MethodBase method) + { + return NormalizeTypeFullName (method.DeclaringType) + "." + method.Name; + } + + static string NormalizeTypeFullName (Type type) + { + if (IsNestedType (type)) + return NormalizeTypeFullName (type.DeclaringType) + "/" + type.Name; + + return type.FullName; + } + + TypeReference ImportGenericInstance (Type type, ImportGenericContext context) + { + var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition); + var arguments = type.GetGenericArguments (); + var instance = new GenericInstanceType (element_type, arguments.Length); + var instance_arguments = instance.GenericArguments; + + context.Push (element_type); + try { + for (int i = 0; i < arguments.Length; i++) + instance_arguments.Add (ImportType (arguments [i], context)); + + return instance; + } + finally { + context.Pop (); + } + } + + static bool IsTypeSpecification (Type type) + { + return type.HasElementType + || IsGenericInstance (type) + || type.IsGenericParameter; + } + + static bool IsGenericInstance (Type type) + { + return type.IsGenericType && !type.IsGenericTypeDefinition; + } + + static ElementType ImportElementType (Type type) + { + ElementType etype; + if (!type_etype_mapping.TryGetValue (type, out etype)) + return ElementType.None; + + return etype; + } + + protected AssemblyNameReference ImportScope (SR.Assembly assembly) + { + return ImportReference (assembly.GetName ()); + } + + public virtual AssemblyNameReference ImportReference (SR.AssemblyName name) + { + Mixin.CheckName (name); + + AssemblyNameReference reference; + if (TryGetAssemblyNameReference (name, out reference)) + return reference; + + reference = new AssemblyNameReference (name.Name, name.Version) { + PublicKeyToken = name.GetPublicKeyToken (), + Culture = name.CultureInfo.Name, + HashAlgorithm = (AssemblyHashAlgorithm)name.HashAlgorithm, + }; + + module.AssemblyReferences.Add (reference); + + return reference; + } + + bool TryGetAssemblyNameReference (SR.AssemblyName name, out AssemblyNameReference assembly_reference) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (name.FullName != reference.FullName) // TODO compare field by field + continue; + + assembly_reference = reference; + return true; + } + + assembly_reference = null; + return false; + } + + FieldReference ImportField (SR.FieldInfo field, ImportGenericContext context) + { + var declaring_type = ImportType (field.DeclaringType, context); + + if (IsGenericInstance (field.DeclaringType)) + field = ResolveFieldDefinition (field); + + context.Push (declaring_type); + try { + return new FieldReference { + Name = field.Name, + DeclaringType = declaring_type, + FieldType = ImportType (field.FieldType, context), + }; + } + finally { + context.Pop (); + } + } + + static SR.FieldInfo ResolveFieldDefinition (SR.FieldInfo field) + { + return field.Module.ResolveField (field.MetadataToken); + } + + static SR.MethodBase ResolveMethodDefinition (SR.MethodBase method) + { + return method.Module.ResolveMethod (method.MetadataToken); + } + + MethodReference ImportMethod (SR.MethodBase method, ImportGenericContext context, ImportGenericKind import_kind) + { + if (IsMethodSpecification (method) || ImportOpenGenericMethod (method, import_kind)) + return ImportMethodSpecification (method, context); + + var declaring_type = ImportType (method.DeclaringType, context); + + if (IsGenericInstance (method.DeclaringType)) + method = ResolveMethodDefinition (method); + + var reference = new MethodReference { + Name = method.Name, + HasThis = HasCallingConvention (method, SR.CallingConventions.HasThis), + ExplicitThis = HasCallingConvention (method, SR.CallingConventions.ExplicitThis), + DeclaringType = ImportType (method.DeclaringType, context, ImportGenericKind.Definition), + }; + + if (HasCallingConvention (method, SR.CallingConventions.VarArgs)) + reference.CallingConvention &= MethodCallingConvention.VarArg; + + if (method.IsGenericMethod) + ImportGenericParameters (reference, method.GetGenericArguments ()); + + context.Push (reference); + try { + var method_info = method as SR.MethodInfo; + reference.ReturnType = method_info != null + ? ImportType (method_info.ReturnType, context) + : ImportType (typeof (void), default (ImportGenericContext)); + + var parameters = method.GetParameters (); + var reference_parameters = reference.Parameters; + + for (int i = 0; i < parameters.Length; i++) + reference_parameters.Add ( + new ParameterDefinition (ImportType (parameters [i].ParameterType, context))); + + reference.DeclaringType = declaring_type; + + return reference; + } + finally { + context.Pop (); + } + } + + static void ImportGenericParameters (IGenericParameterProvider provider, Type [] arguments) + { + var provider_parameters = provider.GenericParameters; + + for (int i = 0; i < arguments.Length; i++) + provider_parameters.Add (new GenericParameter (arguments [i].Name, provider)); + } + + static bool IsMethodSpecification (SR.MethodBase method) + { + return method.IsGenericMethod && !method.IsGenericMethodDefinition; + } + + MethodReference ImportMethodSpecification (SR.MethodBase method, ImportGenericContext context) + { + var method_info = method as SR.MethodInfo; + if (method_info == null) + throw new InvalidOperationException (); + + var element_method = ImportMethod (method_info.GetGenericMethodDefinition (), context, ImportGenericKind.Definition); + var instance = new GenericInstanceMethod (element_method); + var arguments = method.GetGenericArguments (); + var instance_arguments = instance.GenericArguments; + + context.Push (element_method); + try { + for (int i = 0; i < arguments.Length; i++) + instance_arguments.Add (ImportType (arguments [i], context)); + + return instance; + } + finally { + context.Pop (); + } + } + + static bool HasCallingConvention (SR.MethodBase method, SR.CallingConventions conventions) + { + return (method.CallingConvention & conventions) != 0; + } + + public virtual TypeReference ImportReference (Type type, IGenericParameterProvider context) + { + Mixin.CheckType (type); + return ImportType ( + type, + ImportGenericContext.For (context), + context != null ? ImportGenericKind.Open : ImportGenericKind.Definition); + } + + public virtual FieldReference ImportReference (SR.FieldInfo field, IGenericParameterProvider context) + { + Mixin.CheckField (field); + return ImportField (field, ImportGenericContext.For (context)); + } + + public virtual MethodReference ImportReference (SR.MethodBase method, IGenericParameterProvider context) + { + Mixin.CheckMethod (method); + return ImportMethod (method, + ImportGenericContext.For (context), + context != null ? ImportGenericKind.Open : ImportGenericKind.Definition); + } + } + + public class DefaultMetadataImporter : IMetadataImporter { + + readonly protected ModuleDefinition module; + + public DefaultMetadataImporter (ModuleDefinition module) + { + Mixin.CheckModule (module); + + this.module = module; + } + + TypeReference ImportType (TypeReference type, ImportGenericContext context) + { + if (type.IsTypeSpecification ()) + return ImportTypeSpecification (type, context); + + var reference = new TypeReference ( + type.Namespace, + type.Name, + module, + ImportScope (type), + type.IsValueType); + + MetadataSystem.TryProcessPrimitiveTypeReference (reference); + + if (type.IsNested) + reference.DeclaringType = ImportType (type.DeclaringType, context); + + if (type.HasGenericParameters) + ImportGenericParameters (reference, type); + + return reference; + } + + protected virtual IMetadataScope ImportScope (TypeReference type) + { + return ImportScope (type.Scope); + } + + protected IMetadataScope ImportScope (IMetadataScope scope) + { + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + return ImportReference ((AssemblyNameReference)scope); + case MetadataScopeType.ModuleDefinition: + if (scope == module) return scope; + return ImportReference (((ModuleDefinition)scope).Assembly.Name); + case MetadataScopeType.ModuleReference: + throw new NotImplementedException (); + } + + throw new NotSupportedException (); + } + + public virtual AssemblyNameReference ImportReference (AssemblyNameReference name) + { + Mixin.CheckName (name); + + AssemblyNameReference reference; + if (module.TryGetAssemblyNameReference (name, out reference)) + return reference; + + reference = new AssemblyNameReference (name.Name, name.Version) { + Culture = name.Culture, + HashAlgorithm = name.HashAlgorithm, + IsRetargetable = name.IsRetargetable, + IsWindowsRuntime = name.IsWindowsRuntime, + }; + + var pk_token = !name.PublicKeyToken.IsNullOrEmpty () + ? new byte [name.PublicKeyToken.Length] + : Empty.Array; + + if (pk_token.Length > 0) + Buffer.BlockCopy (name.PublicKeyToken, 0, pk_token, 0, pk_token.Length); + + reference.PublicKeyToken = pk_token; + + module.AssemblyReferences.Add (reference); + + return reference; + } + + static void ImportGenericParameters (IGenericParameterProvider imported, IGenericParameterProvider original) + { + var parameters = original.GenericParameters; + var imported_parameters = imported.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) + imported_parameters.Add (new GenericParameter (parameters [i].Name, imported)); + } + + TypeReference ImportTypeSpecification (TypeReference type, ImportGenericContext context) + { + switch (type.etype) { + case ElementType.SzArray: + var vector = (ArrayType)type; + return new ArrayType (ImportType (vector.ElementType, context)); + case ElementType.Ptr: + var pointer = (PointerType)type; + return new PointerType (ImportType (pointer.ElementType, context)); + case ElementType.ByRef: + var byref = (ByReferenceType)type; + return new ByReferenceType (ImportType (byref.ElementType, context)); + case ElementType.Pinned: + var pinned = (PinnedType)type; + return new PinnedType (ImportType (pinned.ElementType, context)); + case ElementType.Sentinel: + var sentinel = (SentinelType)type; + return new SentinelType (ImportType (sentinel.ElementType, context)); + case ElementType.FnPtr: + var fnptr = (FunctionPointerType)type; + var imported_fnptr = new FunctionPointerType () { + HasThis = fnptr.HasThis, + ExplicitThis = fnptr.ExplicitThis, + CallingConvention = fnptr.CallingConvention, + ReturnType = ImportType (fnptr.ReturnType, context), + }; + + if (!fnptr.HasParameters) + return imported_fnptr; + + for (int i = 0; i < fnptr.Parameters.Count; i++) + imported_fnptr.Parameters.Add (new ParameterDefinition ( + ImportType (fnptr.Parameters [i].ParameterType, context))); + + return imported_fnptr; + case ElementType.CModOpt: + var modopt = (OptionalModifierType)type; + return new OptionalModifierType ( + ImportType (modopt.ModifierType, context), + ImportType (modopt.ElementType, context)); + case ElementType.CModReqD: + var modreq = (RequiredModifierType)type; + return new RequiredModifierType ( + ImportType (modreq.ModifierType, context), + ImportType (modreq.ElementType, context)); + case ElementType.Array: + var array = (ArrayType)type; + var imported_array = new ArrayType (ImportType (array.ElementType, context)); + if (array.IsVector) + return imported_array; + + var dimensions = array.Dimensions; + var imported_dimensions = imported_array.Dimensions; + + imported_dimensions.Clear (); + + for (int i = 0; i < dimensions.Count; i++) { + var dimension = dimensions [i]; + + imported_dimensions.Add (new ArrayDimension (dimension.LowerBound, dimension.UpperBound)); + } + + return imported_array; + case ElementType.GenericInst: + var instance = (GenericInstanceType)type; + var element_type = ImportType (instance.ElementType, context); + var arguments = instance.GenericArguments; + var imported_instance = new GenericInstanceType (element_type, arguments.Count); + var imported_arguments = imported_instance.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + imported_arguments.Add (ImportType (arguments [i], context)); + + return imported_instance; + case ElementType.Var: + var var_parameter = (GenericParameter)type; + if (var_parameter.DeclaringType == null) + throw new InvalidOperationException (); + return context.TypeParameter (var_parameter.DeclaringType.FullName, var_parameter.Position); + case ElementType.MVar: + var mvar_parameter = (GenericParameter)type; + if (mvar_parameter.DeclaringMethod == null) + throw new InvalidOperationException (); + return context.MethodParameter (context.NormalizeMethodName (mvar_parameter.DeclaringMethod), mvar_parameter.Position); + } + + throw new NotSupportedException (type.etype.ToString ()); + } + + FieldReference ImportField (FieldReference field, ImportGenericContext context) + { + var declaring_type = ImportType (field.DeclaringType, context); + + context.Push (declaring_type); + try { + return new FieldReference { + Name = field.Name, + DeclaringType = declaring_type, + FieldType = ImportType (field.FieldType, context), + }; + } + finally { + context.Pop (); + } + } + + MethodReference ImportMethod (MethodReference method, ImportGenericContext context) + { + if (method.IsGenericInstance) + return ImportMethodSpecification (method, context); + + var declaring_type = ImportType (method.DeclaringType, context); + + var reference = new MethodReference { + Name = method.Name, + HasThis = method.HasThis, + ExplicitThis = method.ExplicitThis, + DeclaringType = declaring_type, + CallingConvention = method.CallingConvention, + }; + + if (method.HasGenericParameters) + ImportGenericParameters (reference, method); + + context.Push (reference); + try { + reference.ReturnType = ImportType (method.ReturnType, context); + + if (!method.HasParameters) + return reference; + + var parameters = method.Parameters; + var reference_parameters = reference.parameters = new ParameterDefinitionCollection (reference, parameters.Count); + for (int i = 0; i < parameters.Count; i++) + reference_parameters.Add ( + new ParameterDefinition (ImportType (parameters [i].ParameterType, context))); + + return reference; + } + finally { + context.Pop (); + } + } + + MethodSpecification ImportMethodSpecification (MethodReference method, ImportGenericContext context) + { + if (!method.IsGenericInstance) + throw new NotSupportedException (); + + var instance = (GenericInstanceMethod)method; + var element_method = ImportMethod (instance.ElementMethod, context); + var imported_instance = new GenericInstanceMethod (element_method); + + var arguments = instance.GenericArguments; + var imported_arguments = imported_instance.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + imported_arguments.Add (ImportType (arguments [i], context)); + + return imported_instance; + } + + public virtual TypeReference ImportReference (TypeReference type, IGenericParameterProvider context) + { + Mixin.CheckType (type); + return ImportType (type, ImportGenericContext.For (context)); + } + + public virtual FieldReference ImportReference (FieldReference field, IGenericParameterProvider context) + { + Mixin.CheckField (field); + return ImportField (field, ImportGenericContext.For (context)); + } + + public virtual MethodReference ImportReference (MethodReference method, IGenericParameterProvider context) + { + Mixin.CheckMethod (method); + return ImportMethod (method, ImportGenericContext.For (context)); + } + } + + static partial class Mixin { + + public static void CheckModule (ModuleDefinition module) + { + if (module == null) + throw new ArgumentNullException (Argument.module.ToString ()); + } + + public static bool TryGetAssemblyNameReference (this ModuleDefinition module, AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (!Equals (name_reference, reference)) + continue; + + assembly_reference = reference; + return true; + } + + assembly_reference = null; + return false; + } + + static bool Equals (byte [] a, byte [] b) + { + if (ReferenceEquals (a, b)) + return true; + if (a == null) + return false; + if (a.Length != b.Length) + return false; + for (int i = 0; i < a.Length; i++) + if (a [i] != b [i]) + return false; + return true; + } + + static bool Equals (T a, T b) where T : class, IEquatable + { + if (ReferenceEquals (a, b)) + return true; + if (a == null) + return false; + return a.Equals (b); + } + + static bool Equals (AssemblyNameReference a, AssemblyNameReference b) + { + if (ReferenceEquals (a, b)) + return true; + if (a.Name != b.Name) + return false; + if (!Equals (a.Version, b.Version)) + return false; + if (a.Culture != b.Culture) + return false; + if (!Equals (a.PublicKeyToken, b.PublicKeyToken)) + return false; + return true; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs.meta new file mode 100644 index 0000000..f898f90 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Import.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa57d261f1a90c746abaef3d59b4c655 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs new file mode 100644 index 0000000..392ffdb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs @@ -0,0 +1,42 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public sealed class LinkedResource : Resource { + + internal byte [] hash; + string file; + + public byte [] Hash { + get { return hash; } + } + + public string File { + get { return file; } + set { file = value; } + } + + public override ResourceType ResourceType { + get { return ResourceType.Linked; } + } + + public LinkedResource (string name, ManifestResourceAttributes flags) + : base (name, flags) + { + } + + public LinkedResource (string name, ManifestResourceAttributes flags, string file) + : base (name, flags) + { + this.file = file; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs.meta new file mode 100644 index 0000000..531db4c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/LinkedResource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18c45c1a0891fdc40a07d309b564ec6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs new file mode 100644 index 0000000..693004c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs @@ -0,0 +1,21 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum ManifestResourceAttributes : uint { + VisibilityMask = 0x0007, + Public = 0x0001, // The resource is exported from the Assembly + Private = 0x0002 // The resource is private to the Assembly + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs.meta new file mode 100644 index 0000000..a88aad4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ManifestResourceAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 136b98b695702f048857ea31d91193fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs new file mode 100644 index 0000000..e93d1ef --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs @@ -0,0 +1,153 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public class MarshalInfo { + + internal NativeType native; + + public NativeType NativeType { + get { return native; } + set { native = value; } + } + + public MarshalInfo (NativeType native) + { + this.native = native; + } + } + + public sealed class ArrayMarshalInfo : MarshalInfo { + + internal NativeType element_type; + internal int size_parameter_index; + internal int size; + internal int size_parameter_multiplier; + + public NativeType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public int SizeParameterIndex { + get { return size_parameter_index; } + set { size_parameter_index = value; } + } + + public int Size { + get { return size; } + set { size = value; } + } + + public int SizeParameterMultiplier { + get { return size_parameter_multiplier; } + set { size_parameter_multiplier = value; } + } + + public ArrayMarshalInfo () + : base (NativeType.Array) + { + element_type = NativeType.None; + size_parameter_index = -1; + size = -1; + size_parameter_multiplier = -1; + } + } + + public sealed class CustomMarshalInfo : MarshalInfo { + + internal Guid guid; + internal string unmanaged_type; + internal TypeReference managed_type; + internal string cookie; + + public Guid Guid { + get { return guid; } + set { guid = value; } + } + + public string UnmanagedType { + get { return unmanaged_type; } + set { unmanaged_type = value; } + } + + public TypeReference ManagedType { + get { return managed_type; } + set { managed_type = value; } + } + + public string Cookie { + get { return cookie; } + set { cookie = value; } + } + + public CustomMarshalInfo () + : base (NativeType.CustomMarshaler) + { + } + } + + public sealed class SafeArrayMarshalInfo : MarshalInfo { + + internal VariantType element_type; + + public VariantType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public SafeArrayMarshalInfo () + : base (NativeType.SafeArray) + { + element_type = VariantType.None; + } + } + + public sealed class FixedArrayMarshalInfo : MarshalInfo { + + internal NativeType element_type; + internal int size; + + public NativeType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public int Size { + get { return size; } + set { size = value; } + } + + public FixedArrayMarshalInfo () + : base (NativeType.FixedArray) + { + element_type = NativeType.None; + } + } + + public sealed class FixedSysStringMarshalInfo : MarshalInfo { + + internal int size; + + public int Size { + get { return size; } + set { size = value; } + } + + public FixedSysStringMarshalInfo () + : base (NativeType.FixedSysString) + { + size = -1; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs.meta new file mode 100644 index 0000000..1a110e3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MarshalInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 081d03dc18ced1648ae4d9f2eefd3370 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs new file mode 100644 index 0000000..172d349 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs @@ -0,0 +1,73 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil { + + sealed class MemberDefinitionCollection : Collection where T : IMemberDefinition { + + TypeDefinition container; + + internal MemberDefinitionCollection (TypeDefinition container) + { + this.container = container; + } + + internal MemberDefinitionCollection (TypeDefinition container, int capacity) + : base (capacity) + { + this.container = container; + } + + protected override void OnAdd (T item, int index) + { + Attach (item); + } + + protected sealed override void OnSet (T item, int index) + { + Attach (item); + } + + protected sealed override void OnInsert (T item, int index) + { + Attach (item); + } + + protected sealed override void OnRemove (T item, int index) + { + Detach (item); + } + + protected sealed override void OnClear () + { + foreach (var definition in this) + Detach (definition); + } + + void Attach (T element) + { + if (element.DeclaringType == container) + return; + + if (element.DeclaringType != null) + throw new ArgumentException ("Member already attached"); + + element.DeclaringType = this.container; + } + + static void Detach (T element) + { + element.DeclaringType = null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs.meta new file mode 100644 index 0000000..6684de2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberDefinitionCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e5caa999f42a585459c62b7b65eefdd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs new file mode 100644 index 0000000..4f75843 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs @@ -0,0 +1,102 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public abstract class MemberReference : IMetadataTokenProvider { + + string name; + TypeReference declaring_type; + + internal MetadataToken token; + internal object projection; + + public virtual string Name { + get { return name; } + set { + if (IsWindowsRuntimeProjection && value != name) + throw new InvalidOperationException (); + + name = value; + } + } + + public abstract string FullName { + get; + } + + public virtual TypeReference DeclaringType { + get { return declaring_type; } + set { declaring_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + public bool IsWindowsRuntimeProjection { + get { return projection != null; } + } + + internal bool HasImage { + get { + var module = Module; + if (module == null) + return false; + + return module.HasImage; + } + } + + public virtual ModuleDefinition Module { + get { return declaring_type != null ? declaring_type.Module : null; } + } + + public virtual bool IsDefinition { + get { return false; } + } + + public virtual bool ContainsGenericParameter { + get { return declaring_type != null && declaring_type.ContainsGenericParameter; } + } + + internal MemberReference () + { + } + + internal MemberReference (string name) + { + this.name = name ?? string.Empty; + } + + internal string MemberFullName () + { + if (declaring_type == null) + return name; + + return declaring_type.FullName + "::" + name; + } + + public IMemberDefinition Resolve () + { + return ResolveDefinition (); + } + + protected abstract IMemberDefinition ResolveDefinition (); + + public override string ToString () + { + return FullName; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs.meta new file mode 100644 index 0000000..c3d8f54 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MemberReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2dcf551ad731c204fa148ec1ee0ce881 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs new file mode 100644 index 0000000..ce212e4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs @@ -0,0 +1,391 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil { + + public interface IAssemblyResolver : IDisposable { + AssemblyDefinition Resolve (AssemblyNameReference name); + AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters); + } + + public interface IMetadataResolver { + TypeDefinition Resolve (TypeReference type); + FieldDefinition Resolve (FieldReference field); + MethodDefinition Resolve (MethodReference method); + } + +#if !NET_CORE + [Serializable] +#endif + public sealed class ResolutionException : Exception { + + readonly MemberReference member; + + public MemberReference Member { + get { return member; } + } + + public IMetadataScope Scope { + get { + var type = member as TypeReference; + if (type != null) + return type.Scope; + + var declaring_type = member.DeclaringType; + if (declaring_type != null) + return declaring_type.Scope; + + throw new NotSupportedException (); + } + } + + public ResolutionException (MemberReference member) + : base ("Failed to resolve " + member.FullName) + { + if (member == null) + throw new ArgumentNullException ("member"); + + this.member = member; + } + + public ResolutionException (MemberReference member, Exception innerException) + : base ("Failed to resolve " + member.FullName, innerException) + { + if (member == null) + throw new ArgumentNullException ("member"); + + this.member = member; + } + +#if !NET_CORE + ResolutionException ( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base (info, context) + { + } +#endif + } + + public class MetadataResolver : IMetadataResolver { + + readonly IAssemblyResolver assembly_resolver; + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + } + + public MetadataResolver (IAssemblyResolver assemblyResolver) + { + if (assemblyResolver == null) + throw new ArgumentNullException ("assemblyResolver"); + + assembly_resolver = assemblyResolver; + } + + public virtual TypeDefinition Resolve (TypeReference type) + { + Mixin.CheckType (type); + + type = type.GetElementType (); + + var scope = type.Scope; + + if (scope == null) + return null; + + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + var assembly = assembly_resolver.Resolve ((AssemblyNameReference)scope); + if (assembly == null) + return null; + + return GetType (assembly.MainModule, type); + case MetadataScopeType.ModuleDefinition: + return GetType ((ModuleDefinition)scope, type); + case MetadataScopeType.ModuleReference: + if (type.Module.Assembly == null) + return null; + + var modules = type.Module.Assembly.Modules; + var module_ref = (ModuleReference)scope; + for (int i = 0; i < modules.Count; i++) { + var netmodule = modules [i]; + if (netmodule.Name == module_ref.Name) + return GetType (netmodule, type); + } + break; + } + + throw new NotSupportedException (); + } + + static TypeDefinition GetType (ModuleDefinition module, TypeReference reference) + { + var type = GetTypeDefinition (module, reference); + if (type != null) + return type; + + if (!module.HasExportedTypes) + return null; + + var exported_types = module.ExportedTypes; + + for (int i = 0; i < exported_types.Count; i++) { + var exported_type = exported_types [i]; + if (exported_type.Name != reference.Name) + continue; + + if (exported_type.Namespace != reference.Namespace) + continue; + + return exported_type.Resolve (); + } + + return null; + } + + static TypeDefinition GetTypeDefinition (ModuleDefinition module, TypeReference type) + { + if (!type.IsNested) + return module.GetType (type.Namespace, type.Name); + + var declaring_type = type.DeclaringType.Resolve (); + if (declaring_type == null) + return null; + + return declaring_type.GetNestedType (type.TypeFullName ()); + } + + public virtual FieldDefinition Resolve (FieldReference field) + { + Mixin.CheckField (field); + + var type = Resolve (field.DeclaringType); + if (type == null) + return null; + + if (!type.HasFields) + return null; + + return GetField (type, field); + } + + FieldDefinition GetField (TypeDefinition type, FieldReference reference) + { + while (type != null) { + var field = GetField (type.Fields, reference); + if (field != null) + return field; + + if (type.BaseType == null) + return null; + + type = Resolve (type.BaseType); + } + + return null; + } + + static FieldDefinition GetField (Collection fields, FieldReference reference) + { + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + + if (field.Name != reference.Name) + continue; + + if (!AreSame (field.FieldType, reference.FieldType)) + continue; + + return field; + } + + return null; + } + + public virtual MethodDefinition Resolve (MethodReference method) + { + Mixin.CheckMethod (method); + + var type = Resolve (method.DeclaringType); + if (type == null) + return null; + + method = method.GetElementMethod (); + + if (!type.HasMethods) + return null; + + return GetMethod (type, method); + } + + MethodDefinition GetMethod (TypeDefinition type, MethodReference reference) + { + while (type != null) { + var method = GetMethod (type.Methods, reference); + if (method != null) + return method; + + if (type.BaseType == null) + return null; + + type = Resolve (type.BaseType); + } + + return null; + } + + public static MethodDefinition GetMethod (Collection methods, MethodReference reference) + { + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + + if (method.Name != reference.Name) + continue; + + if (method.HasGenericParameters != reference.HasGenericParameters) + continue; + + if (method.HasGenericParameters && method.GenericParameters.Count != reference.GenericParameters.Count) + continue; + + if (!AreSame (method.ReturnType, reference.ReturnType)) + continue; + + if (method.IsVarArg () != reference.IsVarArg ()) + continue; + + if (method.IsVarArg () && IsVarArgCallTo (method, reference)) + return method; + + if (method.HasParameters != reference.HasParameters) + continue; + + if (!method.HasParameters && !reference.HasParameters) + return method; + + if (!AreSame (method.Parameters, reference.Parameters)) + continue; + + return method; + } + + return null; + } + + static bool AreSame (Collection a, Collection b) + { + var count = a.Count; + + if (count != b.Count) + return false; + + if (count == 0) + return true; + + for (int i = 0; i < count; i++) + if (!AreSame (a [i].ParameterType, b [i].ParameterType)) + return false; + + return true; + } + + static bool IsVarArgCallTo (MethodDefinition method, MethodReference reference) + { + if (method.Parameters.Count >= reference.Parameters.Count) + return false; + + if (reference.GetSentinelPosition () != method.Parameters.Count) + return false; + + for (int i = 0; i < method.Parameters.Count; i++) + if (!AreSame (method.Parameters [i].ParameterType, reference.Parameters [i].ParameterType)) + return false; + + return true; + } + + static bool AreSame (TypeSpecification a, TypeSpecification b) + { + if (!AreSame (a.ElementType, b.ElementType)) + return false; + + if (a.IsGenericInstance) + return AreSame ((GenericInstanceType)a, (GenericInstanceType)b); + + if (a.IsRequiredModifier || a.IsOptionalModifier) + return AreSame ((IModifierType)a, (IModifierType)b); + + if (a.IsArray) + return AreSame ((ArrayType)a, (ArrayType)b); + + return true; + } + + static bool AreSame (ArrayType a, ArrayType b) + { + if (a.Rank != b.Rank) + return false; + + // TODO: dimensions + + return true; + } + + static bool AreSame (IModifierType a, IModifierType b) + { + return AreSame (a.ModifierType, b.ModifierType); + } + + static bool AreSame (GenericInstanceType a, GenericInstanceType b) + { + if (a.GenericArguments.Count != b.GenericArguments.Count) + return false; + + for (int i = 0; i < a.GenericArguments.Count; i++) + if (!AreSame (a.GenericArguments [i], b.GenericArguments [i])) + return false; + + return true; + } + + static bool AreSame (GenericParameter a, GenericParameter b) + { + return a.Position == b.Position; + } + + static bool AreSame (TypeReference a, TypeReference b) + { + if (ReferenceEquals (a, b)) + return true; + + if (a == null || b == null) + return false; + + if (a.etype != b.etype) + return false; + + if (a.IsGenericParameter) + return AreSame ((GenericParameter)a, (GenericParameter)b); + + if (a.IsTypeSpecification ()) + return AreSame ((TypeSpecification)a, (TypeSpecification)b); + + if (a.Name != b.Name || a.Namespace != b.Namespace) + return false; + + return AreSame (a.DeclaringType, b.DeclaringType); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs.meta new file mode 100644 index 0000000..9a42f6b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdd2c926d773ffd4692e2d042135fd2b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs new file mode 100644 index 0000000..00ef319 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs @@ -0,0 +1,431 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + struct Range { + public uint Start; + public uint Length; + + public Range (uint index, uint length) + { + this.Start = index; + this.Length = length; + } + } + + sealed class MetadataSystem { + + internal AssemblyNameReference [] AssemblyReferences; + internal ModuleReference [] ModuleReferences; + + internal TypeDefinition [] Types; + internal TypeReference [] TypeReferences; + + internal FieldDefinition [] Fields; + internal MethodDefinition [] Methods; + internal MemberReference [] MemberReferences; + + internal Dictionary> NestedTypes; + internal Dictionary ReverseNestedTypes; + internal Dictionary>> Interfaces; + internal Dictionary> ClassLayouts; + internal Dictionary FieldLayouts; + internal Dictionary FieldRVAs; + internal Dictionary FieldMarshals; + internal Dictionary> Constants; + internal Dictionary> Overrides; + internal Dictionary CustomAttributes; + internal Dictionary SecurityDeclarations; + internal Dictionary Events; + internal Dictionary Properties; + internal Dictionary> Semantics; + internal Dictionary> PInvokes; + internal Dictionary GenericParameters; + internal Dictionary>> GenericConstraints; + + internal Document [] Documents; + internal Dictionary>> LocalScopes; + internal ImportDebugInformation [] ImportScopes; + internal Dictionary StateMachineMethods; + internal Dictionary []> CustomDebugInformations; + + static Dictionary> primitive_value_types; + + static void InitializePrimitives () + { + var types = new Dictionary> (18, StringComparer.Ordinal) { + { "Void", new Row (ElementType.Void, false) }, + { "Boolean", new Row (ElementType.Boolean, true) }, + { "Char", new Row (ElementType.Char, true) }, + { "SByte", new Row (ElementType.I1, true) }, + { "Byte", new Row (ElementType.U1, true) }, + { "Int16", new Row (ElementType.I2, true) }, + { "UInt16", new Row (ElementType.U2, true) }, + { "Int32", new Row (ElementType.I4, true) }, + { "UInt32", new Row (ElementType.U4, true) }, + { "Int64", new Row (ElementType.I8, true) }, + { "UInt64", new Row (ElementType.U8, true) }, + { "Single", new Row (ElementType.R4, true) }, + { "Double", new Row (ElementType.R8, true) }, + { "String", new Row (ElementType.String, false) }, + { "TypedReference", new Row (ElementType.TypedByRef, false) }, + { "IntPtr", new Row (ElementType.I, true) }, + { "UIntPtr", new Row (ElementType.U, true) }, + { "Object", new Row (ElementType.Object, false) }, + }; + + Interlocked.CompareExchange (ref primitive_value_types, types, null); + } + + public static void TryProcessPrimitiveTypeReference (TypeReference type) + { + if (type.Namespace != "System") + return; + + var scope = type.scope; + if (scope == null || scope.MetadataScopeType != MetadataScopeType.AssemblyNameReference) + return; + + Row primitive_data; + if (!TryGetPrimitiveData (type, out primitive_data)) + return; + + type.etype = primitive_data.Col1; + type.IsValueType = primitive_data.Col2; + } + + public static bool TryGetPrimitiveElementType (TypeDefinition type, out ElementType etype) + { + etype = ElementType.None; + + if (type.Namespace != "System") + return false; + + Row primitive_data; + if (TryGetPrimitiveData (type, out primitive_data)) { + etype = primitive_data.Col1; + return true; + } + + return false; + } + + static bool TryGetPrimitiveData (TypeReference type, out Row primitive_data) + { + if (primitive_value_types == null) + InitializePrimitives (); + + return primitive_value_types.TryGetValue (type.Name, out primitive_data); + } + + public void Clear () + { + if (NestedTypes != null) NestedTypes = new Dictionary> (capacity: 0); + if (ReverseNestedTypes != null) ReverseNestedTypes = new Dictionary (capacity: 0); + if (Interfaces != null) Interfaces = new Dictionary>> (capacity: 0); + if (ClassLayouts != null) ClassLayouts = new Dictionary> (capacity: 0); + if (FieldLayouts != null) FieldLayouts = new Dictionary (capacity: 0); + if (FieldRVAs != null) FieldRVAs = new Dictionary (capacity: 0); + if (FieldMarshals != null) FieldMarshals = new Dictionary (capacity: 0); + if (Constants != null) Constants = new Dictionary> (capacity: 0); + if (Overrides != null) Overrides = new Dictionary> (capacity: 0); + if (CustomAttributes != null) CustomAttributes = new Dictionary (capacity: 0); + if (SecurityDeclarations != null) SecurityDeclarations = new Dictionary (capacity: 0); + if (Events != null) Events = new Dictionary (capacity: 0); + if (Properties != null) Properties = new Dictionary (capacity: 0); + if (Semantics != null) Semantics = new Dictionary> (capacity: 0); + if (PInvokes != null) PInvokes = new Dictionary> (capacity: 0); + if (GenericParameters != null) GenericParameters = new Dictionary (capacity: 0); + if (GenericConstraints != null) GenericConstraints = new Dictionary>> (capacity: 0); + + Documents = Empty.Array; + ImportScopes = Empty.Array; + if (LocalScopes != null) LocalScopes = new Dictionary>> (capacity: 0); + if (StateMachineMethods != null) StateMachineMethods = new Dictionary (capacity: 0); + } + + public AssemblyNameReference GetAssemblyNameReference (uint rid) + { + if (rid < 1 || rid > AssemblyReferences.Length) + return null; + + return AssemblyReferences [rid - 1]; + } + + public TypeDefinition GetTypeDefinition (uint rid) + { + if (rid < 1 || rid > Types.Length) + return null; + + return Types [rid - 1]; + } + + public void AddTypeDefinition (TypeDefinition type) + { + Types [type.token.RID - 1] = type; + } + + public TypeReference GetTypeReference (uint rid) + { + if (rid < 1 || rid > TypeReferences.Length) + return null; + + return TypeReferences [rid - 1]; + } + + public void AddTypeReference (TypeReference type) + { + TypeReferences [type.token.RID - 1] = type; + } + + public FieldDefinition GetFieldDefinition (uint rid) + { + if (rid < 1 || rid > Fields.Length) + return null; + + return Fields [rid - 1]; + } + + public void AddFieldDefinition (FieldDefinition field) + { + Fields [field.token.RID - 1] = field; + } + + public MethodDefinition GetMethodDefinition (uint rid) + { + if (rid < 1 || rid > Methods.Length) + return null; + + return Methods [rid - 1]; + } + + public void AddMethodDefinition (MethodDefinition method) + { + Methods [method.token.RID - 1] = method; + } + + public MemberReference GetMemberReference (uint rid) + { + if (rid < 1 || rid > MemberReferences.Length) + return null; + + return MemberReferences [rid - 1]; + } + + public void AddMemberReference (MemberReference member) + { + MemberReferences [member.token.RID - 1] = member; + } + + public bool TryGetNestedTypeMapping (TypeDefinition type, out Collection mapping) + { + return NestedTypes.TryGetValue (type.token.RID, out mapping); + } + + public void SetNestedTypeMapping (uint type_rid, Collection mapping) + { + NestedTypes [type_rid] = mapping; + } + + public void RemoveNestedTypeMapping (TypeDefinition type) + { + NestedTypes.Remove (type.token.RID); + } + + public bool TryGetReverseNestedTypeMapping (TypeDefinition type, out uint declaring) + { + return ReverseNestedTypes.TryGetValue (type.token.RID, out declaring); + } + + public void SetReverseNestedTypeMapping (uint nested, uint declaring) + { + ReverseNestedTypes [nested] = declaring; + } + + public void RemoveReverseNestedTypeMapping (TypeDefinition type) + { + ReverseNestedTypes.Remove (type.token.RID); + } + + public bool TryGetInterfaceMapping (TypeDefinition type, out Collection> mapping) + { + return Interfaces.TryGetValue (type.token.RID, out mapping); + } + + public void SetInterfaceMapping (uint type_rid, Collection> mapping) + { + Interfaces [type_rid] = mapping; + } + + public void RemoveInterfaceMapping (TypeDefinition type) + { + Interfaces.Remove (type.token.RID); + } + + public void AddPropertiesRange (uint type_rid, Range range) + { + Properties.Add (type_rid, range); + } + + public bool TryGetPropertiesRange (TypeDefinition type, out Range range) + { + return Properties.TryGetValue (type.token.RID, out range); + } + + public void RemovePropertiesRange (TypeDefinition type) + { + Properties.Remove (type.token.RID); + } + + public void AddEventsRange (uint type_rid, Range range) + { + Events.Add (type_rid, range); + } + + public bool TryGetEventsRange (TypeDefinition type, out Range range) + { + return Events.TryGetValue (type.token.RID, out range); + } + + public void RemoveEventsRange (TypeDefinition type) + { + Events.Remove (type.token.RID); + } + + public bool TryGetGenericParameterRanges (IGenericParameterProvider owner, out Range [] ranges) + { + return GenericParameters.TryGetValue (owner.MetadataToken, out ranges); + } + + public void RemoveGenericParameterRange (IGenericParameterProvider owner) + { + GenericParameters.Remove (owner.MetadataToken); + } + + public bool TryGetCustomAttributeRanges (ICustomAttributeProvider owner, out Range [] ranges) + { + return CustomAttributes.TryGetValue (owner.MetadataToken, out ranges); + } + + public void RemoveCustomAttributeRange (ICustomAttributeProvider owner) + { + CustomAttributes.Remove (owner.MetadataToken); + } + + public bool TryGetSecurityDeclarationRanges (ISecurityDeclarationProvider owner, out Range [] ranges) + { + return SecurityDeclarations.TryGetValue (owner.MetadataToken, out ranges); + } + + public void RemoveSecurityDeclarationRange (ISecurityDeclarationProvider owner) + { + SecurityDeclarations.Remove (owner.MetadataToken); + } + + public bool TryGetGenericConstraintMapping (GenericParameter generic_parameter, out Collection> mapping) + { + return GenericConstraints.TryGetValue (generic_parameter.token.RID, out mapping); + } + + public void SetGenericConstraintMapping (uint gp_rid, Collection> mapping) + { + GenericConstraints [gp_rid] = mapping; + } + + public void RemoveGenericConstraintMapping (GenericParameter generic_parameter) + { + GenericConstraints.Remove (generic_parameter.token.RID); + } + + public bool TryGetOverrideMapping (MethodDefinition method, out Collection mapping) + { + return Overrides.TryGetValue (method.token.RID, out mapping); + } + + public void SetOverrideMapping (uint rid, Collection mapping) + { + Overrides [rid] = mapping; + } + + public void RemoveOverrideMapping (MethodDefinition method) + { + Overrides.Remove (method.token.RID); + } + + public Document GetDocument (uint rid) + { + if (rid < 1 || rid > Documents.Length) + return null; + + return Documents [rid - 1]; + } + + public bool TryGetLocalScopes (MethodDefinition method, out Collection> scopes) + { + return LocalScopes.TryGetValue (method.MetadataToken.RID, out scopes); + } + + public void SetLocalScopes (uint method_rid, Collection> records) + { + LocalScopes [method_rid] = records; + } + + public ImportDebugInformation GetImportScope (uint rid) + { + if (rid < 1 || rid > ImportScopes.Length) + return null; + + return ImportScopes [rid - 1]; + } + + public bool TryGetStateMachineKickOffMethod (MethodDefinition method, out uint rid) + { + return StateMachineMethods.TryGetValue (method.MetadataToken.RID, out rid); + } + + public TypeDefinition GetFieldDeclaringType (uint field_rid) + { + return BinaryRangeSearch (Types, field_rid, true); + } + + public TypeDefinition GetMethodDeclaringType (uint method_rid) + { + return BinaryRangeSearch (Types, method_rid, false); + } + + static TypeDefinition BinaryRangeSearch (TypeDefinition [] types, uint rid, bool field) + { + int min = 0; + int max = types.Length - 1; + while (min <= max) { + int mid = min + ((max - min) / 2); + var type = types [mid]; + var range = field ? type.fields_range : type.methods_range; + + if (rid < range.Start) + max = mid - 1; + else if (rid >= range.Start + range.Length) + min = mid + 1; + else + return type; + } + + return null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs.meta new file mode 100644 index 0000000..46912ce --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MetadataSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ea39c5122499d14fbca126d3ed39890 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs new file mode 100644 index 0000000..043e77a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs @@ -0,0 +1,48 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum MethodAttributes : ushort { + MemberAccessMask = 0x0007, + CompilerControlled = 0x0000, // Member not referenceable + Private = 0x0001, // Accessible only by the parent type + FamANDAssem = 0x0002, // Accessible by sub-types only in this Assembly + Assembly = 0x0003, // Accessibly by anyone in the Assembly + Family = 0x0004, // Accessible only by type and sub-types + FamORAssem = 0x0005, // Accessibly by sub-types anywhere, plus anyone in assembly + Public = 0x0006, // Accessibly by anyone who has visibility to this scope + + Static = 0x0010, // Defined on type, else per instance + Final = 0x0020, // Method may not be overridden + Virtual = 0x0040, // Method is virtual + HideBySig = 0x0080, // Method hides by name+sig, else just by name + + VtableLayoutMask = 0x0100, // Use this mask to retrieve vtable attributes + ReuseSlot = 0x0000, // Method reuses existing slot in vtable + NewSlot = 0x0100, // Method always gets a new slot in the vtable + + CheckAccessOnOverride = 0x0200, // Method can only be overriden if also accessible + Abstract = 0x0400, // Method does not provide an implementation + SpecialName = 0x0800, // Method is special + + // Interop Attributes + PInvokeImpl = 0x2000, // Implementation is forwarded through PInvoke + UnmanagedExport = 0x0008, // Reserved: shall be zero for conforming implementations + + // Additional flags + RTSpecialName = 0x1000, // CLI provides 'special' behavior, depending upon the name of the method + HasSecurity = 0x4000, // Method has security associate with it + RequireSecObject = 0x8000 // Method calls another method containing security code + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs.meta new file mode 100644 index 0000000..6060bf0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84996fdfc826be145836c454e3781c51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs new file mode 100644 index 0000000..2c219ba --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs @@ -0,0 +1,22 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum MethodCallingConvention : byte { + Default = 0x0, + C = 0x1, + StdCall = 0x2, + ThisCall = 0x3, + FastCall = 0x4, + VarArg = 0x5, + Generic = 0x10, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs.meta new file mode 100644 index 0000000..0897aab --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodCallingConvention.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d279830051a3cf4a9a8198756171875 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs new file mode 100644 index 0000000..164c0fb --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs @@ -0,0 +1,558 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Collections.Generic; +using System; +using System.Threading; +using RVA = System.UInt32; + +namespace MonoFN.Cecil { + + public sealed class MethodDefinition : MethodReference, IMemberDefinition, ISecurityDeclarationProvider, ICustomDebugInformationProvider { + + ushort attributes; + ushort impl_attributes; + internal volatile bool sem_attrs_ready; + internal MethodSemanticsAttributes sem_attrs; + Collection custom_attributes; + Collection security_declarations; + + internal RVA rva; + internal PInvokeInfo pinvoke; + Collection overrides; + + internal MethodBody body; + internal MethodDebugInformation debug_info; + internal Collection custom_infos; + + public override string Name { + get { return base.Name; } + set { + if (IsWindowsRuntimeProjection && value != base.Name) + throw new InvalidOperationException (); + + base.Name = value; + } + } + + public MethodAttributes Attributes { + get { return (MethodAttributes)attributes; } + set { + if (IsWindowsRuntimeProjection && (ushort)value != attributes) + throw new InvalidOperationException (); + + attributes = (ushort)value; + } + } + + public MethodImplAttributes ImplAttributes { + get { return (MethodImplAttributes)impl_attributes; } + set { + if (IsWindowsRuntimeProjection && (ushort)value != impl_attributes) + throw new InvalidOperationException (); + + impl_attributes = (ushort)value; + } + } + + public MethodSemanticsAttributes SemanticsAttributes { + get { + if (sem_attrs_ready) + return sem_attrs; + + if (HasImage) { + ReadSemantics (); + return sem_attrs; + } + + sem_attrs = MethodSemanticsAttributes.None; + sem_attrs_ready = true; + return sem_attrs; + } + set { sem_attrs = value; } + } + + internal MethodDefinitionProjection WindowsRuntimeProjection { + get { return (MethodDefinitionProjection)projection; } + set { projection = value; } + } + + internal void ReadSemantics () + { + if (sem_attrs_ready) + return; + + var module = this.Module; + if (module == null) + return; + + if (!module.HasImage) + return; + + lock (module.SyncRoot) { + if (sem_attrs_ready) + return; + + module.Read (this, (method, reader) => reader.ReadAllSemantics (method)); + } + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (Module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + public int RVA { + get { return (int)rva; } + } + + public bool HasBody { + get { + return (attributes & (ushort)MethodAttributes.Abstract) == 0 && + (attributes & (ushort)MethodAttributes.PInvokeImpl) == 0 && + (impl_attributes & (ushort)MethodImplAttributes.InternalCall) == 0 && + (impl_attributes & (ushort)MethodImplAttributes.Native) == 0 && + (impl_attributes & (ushort)MethodImplAttributes.Unmanaged) == 0 && + (impl_attributes & (ushort)MethodImplAttributes.Runtime) == 0; + } + } + + public MethodBody Body { + get { + var local = this.body; + if (local != null) + return local; + + if (!HasBody) + return null; + + if (HasImage && rva != 0) + return Module.Read (ref body, this, (method, reader) => reader.ReadMethodBody (method)); + + Interlocked.CompareExchange (ref body, new MethodBody (this), null); + + return body; + } + set { + var module = this.Module; + if (module == null) { + body = value; + return; + } + + // we reset Body to null in ILSpy to save memory; so we need that operation to be thread-safe + lock (module.SyncRoot) { + body = value; + if (value == null) + this.debug_info = null; + } + } + } + + public MethodDebugInformation DebugInformation { + get { + Mixin.Read (Body); + + if (debug_info == null) { + Interlocked.CompareExchange (ref debug_info, new MethodDebugInformation (this), null); + } + + return debug_info; + } + set { + debug_info = value; + } + } + + public bool HasPInvokeInfo { + get { + if (pinvoke != null) + return true; + + return IsPInvokeImpl; + } + } + + public PInvokeInfo PInvokeInfo { + get { + if (pinvoke != null) + return pinvoke; + + if (HasImage && IsPInvokeImpl) + return Module.Read (ref pinvoke, this, (method, reader) => reader.ReadPInvokeInfo (method)); + + return null; + } + set { + IsPInvokeImpl = true; + pinvoke = value; + } + } + + public bool HasOverrides { + get { + if (overrides != null) + return overrides.Count > 0; + + return HasImage && Module.Read (this, (method, reader) => reader.HasOverrides (method)); + } + } + + public Collection Overrides { + get { + if (overrides != null) + return overrides; + + if (HasImage) + return Module.Read (ref overrides, this, (method, reader) => reader.ReadOverrides (method)); + + Interlocked.CompareExchange (ref overrides, new Collection (), null); + + return overrides; + } + } + + public override bool HasGenericParameters { + get { + if (generic_parameters != null) + return generic_parameters.Count > 0; + + return this.GetHasGenericParameters (Module); + } + } + + public override Collection GenericParameters { + get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); } + } + + public bool HasCustomDebugInformations { + get { + Mixin.Read (Body); + + return !custom_infos.IsNullOrEmpty (); + } + } + + public Collection CustomDebugInformations { + get { + Mixin.Read (Body); + + if (custom_infos == null) + Interlocked.CompareExchange (ref custom_infos, new Collection (), null); + + return custom_infos; + } + } + + #region MethodAttributes + + public bool IsCompilerControlled { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.CompilerControlled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.CompilerControlled, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Private, value); } + } + + public bool IsFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.FamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.FamANDAssem, value); } + } + + public bool IsAssembly { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Assembly); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Assembly, value); } + } + + public bool IsFamily { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Family); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Family, value); } + } + + public bool IsFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.FamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.FamORAssem, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.MemberAccessMask, (ushort)MethodAttributes.Public, value); } + } + + public bool IsStatic { + get { return attributes.GetAttributes ((ushort)MethodAttributes.Static); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.Static, value); } + } + + public bool IsFinal { + get { return attributes.GetAttributes ((ushort)MethodAttributes.Final); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.Final, value); } + } + + public bool IsVirtual { + get { return attributes.GetAttributes ((ushort)MethodAttributes.Virtual); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.Virtual, value); } + } + + public bool IsHideBySig { + get { return attributes.GetAttributes ((ushort)MethodAttributes.HideBySig); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.HideBySig, value); } + } + + public bool IsReuseSlot { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.VtableLayoutMask, (ushort)MethodAttributes.ReuseSlot); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.VtableLayoutMask, (ushort)MethodAttributes.ReuseSlot, value); } + } + + public bool IsNewSlot { + get { return attributes.GetMaskedAttributes ((ushort)MethodAttributes.VtableLayoutMask, (ushort)MethodAttributes.NewSlot); } + set { attributes = attributes.SetMaskedAttributes ((ushort)MethodAttributes.VtableLayoutMask, (ushort)MethodAttributes.NewSlot, value); } + } + + public bool IsCheckAccessOnOverride { + get { return attributes.GetAttributes ((ushort)MethodAttributes.CheckAccessOnOverride); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.CheckAccessOnOverride, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((ushort)MethodAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.Abstract, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort)MethodAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.SpecialName, value); } + } + + public bool IsPInvokeImpl { + get { return attributes.GetAttributes ((ushort)MethodAttributes.PInvokeImpl); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.PInvokeImpl, value); } + } + + public bool IsUnmanagedExport { + get { return attributes.GetAttributes ((ushort)MethodAttributes.UnmanagedExport); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.UnmanagedExport, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort)MethodAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((ushort)MethodAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((ushort)MethodAttributes.HasSecurity, value); } + } + + #endregion + + #region MethodImplAttributes + + public bool IsIL { + get { return impl_attributes.GetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.IL); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.IL, value); } + } + + public bool IsNative { + get { return impl_attributes.GetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.Native); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.Native, value); } + } + + public bool IsRuntime { + get { return impl_attributes.GetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.Runtime); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort)MethodImplAttributes.CodeTypeMask, (ushort)MethodImplAttributes.Runtime, value); } + } + + public bool IsUnmanaged { + get { return impl_attributes.GetMaskedAttributes ((ushort)MethodImplAttributes.ManagedMask, (ushort)MethodImplAttributes.Unmanaged); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort)MethodImplAttributes.ManagedMask, (ushort)MethodImplAttributes.Unmanaged, value); } + } + + public bool IsManaged { + get { return impl_attributes.GetMaskedAttributes ((ushort)MethodImplAttributes.ManagedMask, (ushort)MethodImplAttributes.Managed); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort)MethodImplAttributes.ManagedMask, (ushort)MethodImplAttributes.Managed, value); } + } + + public bool IsForwardRef { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.ForwardRef); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.ForwardRef, value); } + } + + public bool IsPreserveSig { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.PreserveSig); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.PreserveSig, value); } + } + + public bool IsInternalCall { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.InternalCall); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.InternalCall, value); } + } + + public bool IsSynchronized { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.Synchronized); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.Synchronized, value); } + } + + public bool NoInlining { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.NoInlining); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.NoInlining, value); } + } + + public bool NoOptimization { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.NoOptimization); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.NoOptimization, value); } + } + + public bool AggressiveInlining { + get { return impl_attributes.GetAttributes ((ushort)MethodImplAttributes.AggressiveInlining); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort)MethodImplAttributes.AggressiveInlining, value); } + } + + #endregion + + #region MethodSemanticsAttributes + + public bool IsSetter { + get { return this.GetSemantics (MethodSemanticsAttributes.Setter); } + set { this.SetSemantics (MethodSemanticsAttributes.Setter, value); } + } + + public bool IsGetter { + get { return this.GetSemantics (MethodSemanticsAttributes.Getter); } + set { this.SetSemantics (MethodSemanticsAttributes.Getter, value); } + } + + public bool IsOther { + get { return this.GetSemantics (MethodSemanticsAttributes.Other); } + set { this.SetSemantics (MethodSemanticsAttributes.Other, value); } + } + + public bool IsAddOn { + get { return this.GetSemantics (MethodSemanticsAttributes.AddOn); } + set { this.SetSemantics (MethodSemanticsAttributes.AddOn, value); } + } + + public bool IsRemoveOn { + get { return this.GetSemantics (MethodSemanticsAttributes.RemoveOn); } + set { this.SetSemantics (MethodSemanticsAttributes.RemoveOn, value); } + } + + public bool IsFire { + get { return this.GetSemantics (MethodSemanticsAttributes.Fire); } + set { this.SetSemantics (MethodSemanticsAttributes.Fire, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition)base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public bool IsConstructor { + get { + return this.IsRuntimeSpecialName + && this.IsSpecialName + && (this.Name == ".cctor" || this.Name == ".ctor"); + } + } + + public override bool IsDefinition { + get { return true; } + } + + internal MethodDefinition () + { + this.token = new MetadataToken (TokenType.Method); + } + + public MethodDefinition (string name, MethodAttributes attributes, TypeReference returnType) + : base (name, returnType) + { + this.attributes = (ushort)attributes; + this.HasThis = !this.IsStatic; + this.token = new MetadataToken (TokenType.Method); + } + + public override MethodDefinition Resolve () + { + return this; + } + } + + static partial class Mixin { + + public static ParameterDefinition GetParameter (this MethodBody self, int index) + { + var method = self.method; + + if (method.HasThis) { + if (index == 0) + return self.ThisParameter; + + index--; + } + + var parameters = method.Parameters; + + if (index < 0 || index >= parameters.size) + return null; + + return parameters [index]; + } + + public static VariableDefinition GetVariable (this MethodBody self, int index) + { + var variables = self.Variables; + + if (index < 0 || index >= variables.size) + return null; + + return variables [index]; + } + + public static bool GetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics) + { + return (self.SemanticsAttributes & semantics) != 0; + } + + public static void SetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics, bool value) + { + if (value) + self.SemanticsAttributes |= semantics; + else + self.SemanticsAttributes &= ~semantics; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs.meta new file mode 100644 index 0000000..9fbc7fd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51ade7e624f84ae4abb8dc28a51b3082 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs new file mode 100644 index 0000000..722d5c5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs @@ -0,0 +1,36 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum MethodImplAttributes : ushort { + CodeTypeMask = 0x0003, + IL = 0x0000, // Method impl is CIL + Native = 0x0001, // Method impl is native + OPTIL = 0x0002, // Reserved: shall be zero in conforming implementations + Runtime = 0x0003, // Method impl is provided by the runtime + + ManagedMask = 0x0004, // Flags specifying whether the code is managed or unmanaged + Unmanaged = 0x0004, // Method impl is unmanaged, otherwise managed + Managed = 0x0000, // Method impl is managed + + // Implementation info and interop + ForwardRef = 0x0010, // Indicates method is defined; used primarily in merge scenarios + PreserveSig = 0x0080, // Reserved: conforming implementations may ignore + InternalCall = 0x1000, // Reserved: shall be zero in conforming implementations + Synchronized = 0x0020, // Method is single threaded through the body + NoOptimization = 0x0040, // Method is not optimized by the JIT. + NoInlining = 0x0008, // Method may not be inlined + AggressiveInlining = 0x0100, // Method should be inlined, if possible. + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs.meta new file mode 100644 index 0000000..bc1d0fc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodImplAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbe7f8d150d8c6b48abd24ac7718c9f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs new file mode 100644 index 0000000..6280983 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs @@ -0,0 +1,202 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Text; +using System.Threading; + +namespace MonoFN.Cecil { + + public class MethodReference : MemberReference, IMethodSignature, IGenericParameterProvider, IGenericContext { + + internal ParameterDefinitionCollection parameters; + MethodReturnType return_type; + + bool has_this; + bool explicit_this; + MethodCallingConvention calling_convention; + internal Collection generic_parameters; + + public virtual bool HasThis { + get { return has_this; } + set { has_this = value; } + } + + public virtual bool ExplicitThis { + get { return explicit_this; } + set { explicit_this = value; } + } + + public virtual MethodCallingConvention CallingConvention { + get { return calling_convention; } + set { calling_convention = value; } + } + + public virtual bool HasParameters { + get { return !parameters.IsNullOrEmpty (); } + } + + public virtual Collection Parameters { + get { + if (parameters == null) + Interlocked.CompareExchange (ref parameters, new ParameterDefinitionCollection (this), null); + + return parameters; + } + } + + IGenericParameterProvider IGenericContext.Type { + get { + var declaring_type = this.DeclaringType; + var instance = declaring_type as GenericInstanceType; + if (instance != null) + return instance.ElementType; + + return declaring_type; + } + } + + IGenericParameterProvider IGenericContext.Method { + get { return this; } + } + + GenericParameterType IGenericParameterProvider.GenericParameterType { + get { return GenericParameterType.Method; } + } + + public virtual bool HasGenericParameters { + get { return !generic_parameters.IsNullOrEmpty (); } + } + + public virtual Collection GenericParameters { + get { + if (generic_parameters == null) + Interlocked.CompareExchange (ref generic_parameters, new GenericParameterCollection (this), null); + + return generic_parameters; + } + } + + public TypeReference ReturnType { + get { + var return_type = MethodReturnType; + return return_type != null ? return_type.ReturnType : null; + } + set { + var return_type = MethodReturnType; + if (return_type != null) + return_type.ReturnType = value; + } + } + + public virtual MethodReturnType MethodReturnType { + get { return return_type; } + set { return_type = value; } + } + + public override string FullName { + get { + var builder = new StringBuilder (); + builder.Append (ReturnType.FullName) + .Append (" ") + .Append (MemberFullName ()); + this.MethodSignatureFullName (builder); + return builder.ToString (); + } + } + + public virtual bool IsGenericInstance { + get { return false; } + } + + public override bool ContainsGenericParameter { + get { + if (this.ReturnType.ContainsGenericParameter || base.ContainsGenericParameter) + return true; + + if (!HasParameters) + return false; + + var parameters = this.Parameters; + + for (int i = 0; i < parameters.Count; i++) + if (parameters [i].ParameterType.ContainsGenericParameter) + return true; + + return false; + } + } + + internal MethodReference () + { + this.return_type = new MethodReturnType (this); + this.token = new MetadataToken (TokenType.MemberRef); + } + + public MethodReference (string name, TypeReference returnType) + : base (name) + { + Mixin.CheckType (returnType, Mixin.Argument.returnType); + + this.return_type = new MethodReturnType (this); + this.return_type.ReturnType = returnType; + this.token = new MetadataToken (TokenType.MemberRef); + } + + public MethodReference (string name, TypeReference returnType, TypeReference declaringType) + : this (name, returnType) + { + Mixin.CheckType (declaringType, Mixin.Argument.declaringType); + + this.DeclaringType = declaringType; + } + + public virtual MethodReference GetElementMethod () + { + return this; + } + + protected override IMemberDefinition ResolveDefinition () + { + return this.Resolve (); + } + + public new virtual MethodDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } + + static partial class Mixin { + + public static bool IsVarArg (this IMethodSignature self) + { + return self.CallingConvention == MethodCallingConvention.VarArg; + } + + public static int GetSentinelPosition (this IMethodSignature self) + { + if (!self.HasParameters) + return -1; + + var parameters = self.Parameters; + for (int i = 0; i < parameters.Count; i++) + if (parameters [i].ParameterType.IsSentinel) + return i; + + return -1; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs.meta new file mode 100644 index 0000000..2f0eb25 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e894eb84c10b07f42bf952d556a35c1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs new file mode 100644 index 0000000..e8df3fd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; + +namespace MonoFN.Cecil { + internal sealed class MethodReferenceComparer : EqualityComparer { + // Initialized lazily for each thread + [ThreadStatic] + static List xComparisonStack = null; + + [ThreadStatic] + static List yComparisonStack = null; + + public override bool Equals (MethodReference x, MethodReference y) + { + return AreEqual (x, y); + } + + public override int GetHashCode (MethodReference obj) + { + return GetHashCodeFor (obj); + } + + public static bool AreEqual (MethodReference x, MethodReference y) + { + if (ReferenceEquals (x, y)) + return true; + + if (x.HasThis != y.HasThis) + return false; + + if (x.HasParameters != y.HasParameters) + return false; + + if (x.HasGenericParameters != y.HasGenericParameters) + return false; + + if (x.Parameters.Count != y.Parameters.Count) + return false; + + if (x.Name != y.Name) + return false; + + if (!TypeReferenceEqualityComparer.AreEqual (x.DeclaringType, y.DeclaringType)) + return false; + + var xGeneric = x as GenericInstanceMethod; + var yGeneric = y as GenericInstanceMethod; + if (xGeneric != null || yGeneric != null) { + if (xGeneric == null || yGeneric == null) + return false; + + if (xGeneric.GenericArguments.Count != yGeneric.GenericArguments.Count) + return false; + + for (int i = 0; i < xGeneric.GenericArguments.Count; i++) + if (!TypeReferenceEqualityComparer.AreEqual (xGeneric.GenericArguments [i], yGeneric.GenericArguments [i])) + return false; + } + + var xResolved = x.Resolve (); + var yResolved = y.Resolve (); + + if (xResolved != yResolved) + return false; + + if (xResolved == null) { + // We couldn't resolve either method. In order for them to be equal, their parameter types _must_ match. But wait, there's a twist! + // There exists a situation where we might get into a recursive state: parameter type comparison might lead to comparing the same + // methods again if the parameter types are generic parameters whose owners are these methods. We guard against these by using a + // thread static list of all our comparisons carried out in the stack so far, and if we're in progress of comparing them already, + // we'll just say that they match. + + if (xComparisonStack == null) + xComparisonStack = new List (); + + if (yComparisonStack == null) + yComparisonStack = new List (); + + for (int i = 0; i < xComparisonStack.Count; i++) { + if (xComparisonStack [i] == x && yComparisonStack [i] == y) + return true; + } + + xComparisonStack.Add (x); + + try { + yComparisonStack.Add (y); + + try { + for (int i = 0; i < x.Parameters.Count; i++) { + if (!TypeReferenceEqualityComparer.AreEqual (x.Parameters [i].ParameterType, y.Parameters [i].ParameterType)) + return false; + } + } + finally { + yComparisonStack.RemoveAt (yComparisonStack.Count - 1); + } + } + finally { + xComparisonStack.RemoveAt (xComparisonStack.Count - 1); + } + } + + return true; + } + + public static bool AreSignaturesEqual (MethodReference x, MethodReference y, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (x.HasThis != y.HasThis) + return false; + + if (x.Parameters.Count != y.Parameters.Count) + return false; + + if (x.GenericParameters.Count != y.GenericParameters.Count) + return false; + + for (var i = 0; i < x.Parameters.Count; i++) + if (!TypeReferenceEqualityComparer.AreEqual (x.Parameters [i].ParameterType, y.Parameters [i].ParameterType, comparisonMode)) + return false; + + if (!TypeReferenceEqualityComparer.AreEqual (x.ReturnType, y.ReturnType, comparisonMode)) + return false; + + return true; + } + + public static int GetHashCodeFor (MethodReference obj) + { + // a very good prime number + const int hashCodeMultiplier = 486187739; + + var genericInstanceMethod = obj as GenericInstanceMethod; + if (genericInstanceMethod != null) { + var hashCode = GetHashCodeFor (genericInstanceMethod.ElementMethod); + for (var i = 0; i < genericInstanceMethod.GenericArguments.Count; i++) + hashCode = hashCode * hashCodeMultiplier + TypeReferenceEqualityComparer.GetHashCodeFor (genericInstanceMethod.GenericArguments [i]); + return hashCode; + } + + return TypeReferenceEqualityComparer.GetHashCodeFor (obj.DeclaringType) * hashCodeMultiplier + obj.Name.GetHashCode (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs.meta new file mode 100644 index 0000000..901496a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReferenceComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e61a3569af766524884d80a918529ab8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs new file mode 100644 index 0000000..c833565 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs @@ -0,0 +1,97 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class MethodReturnType : IConstantProvider, ICustomAttributeProvider, IMarshalInfoProvider { + + internal IMethodSignature method; + internal ParameterDefinition parameter; + TypeReference return_type; + + public IMethodSignature Method { + get { return method; } + } + + public TypeReference ReturnType { + get { return return_type; } + set { return_type = value; } + } + + internal ParameterDefinition Parameter { + get { + if (parameter == null) + Interlocked.CompareExchange (ref parameter, new ParameterDefinition (return_type, method), null); + + return parameter; + } + } + + public MetadataToken MetadataToken { + get { return Parameter.MetadataToken; } + set { Parameter.MetadataToken = value; } + } + + public ParameterAttributes Attributes { + get { return Parameter.Attributes; } + set { Parameter.Attributes = value; } + } + + public string Name { + get { return Parameter.Name; } + set { Parameter.Name = value; } + } + + public bool HasCustomAttributes { + get { return parameter != null && parameter.HasCustomAttributes; } + } + + public Collection CustomAttributes { + get { return Parameter.CustomAttributes; } + } + + public bool HasDefault { + get { return parameter != null && parameter.HasDefault; } + set { Parameter.HasDefault = value; } + } + + public bool HasConstant { + get { return parameter != null && parameter.HasConstant; } + set { Parameter.HasConstant = value; } + } + + public object Constant { + get { return Parameter.Constant; } + set { Parameter.Constant = value; } + } + + public bool HasFieldMarshal { + get { return parameter != null && parameter.HasFieldMarshal; } + set { Parameter.HasFieldMarshal = value; } + } + + public bool HasMarshalInfo { + get { return parameter != null && parameter.HasMarshalInfo; } + } + + public MarshalInfo MarshalInfo { + get { return Parameter.MarshalInfo; } + set { Parameter.MarshalInfo = value; } + } + + public MethodReturnType (IMethodSignature method) + { + this.method = method; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs.meta new file mode 100644 index 0000000..1cab923 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodReturnType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51d33467d0e0c6f46a788d5da23d7b23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs new file mode 100644 index 0000000..10b9ef9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs @@ -0,0 +1,25 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum MethodSemanticsAttributes : ushort { + None = 0x0000, + Setter = 0x0001, // Setter for property + Getter = 0x0002, // Getter for property + Other = 0x0004, // Other method for property or event + AddOn = 0x0008, // AddOn method for event + RemoveOn = 0x0010, // RemoveOn method for event + Fire = 0x0020 // Fire method for event + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs.meta new file mode 100644 index 0000000..7e68665 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSemanticsAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6ed7cb61b1647749854923d7f4f2c4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs new file mode 100644 index 0000000..b4bc4ed --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs @@ -0,0 +1,83 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil { + + public abstract class MethodSpecification : MethodReference { + + readonly MethodReference method; + + public MethodReference ElementMethod { + get { return method; } + } + + public override string Name { + get { return method.Name; } + set { throw new InvalidOperationException (); } + } + + public override MethodCallingConvention CallingConvention { + get { return method.CallingConvention; } + set { throw new InvalidOperationException (); } + } + + public override bool HasThis { + get { return method.HasThis; } + set { throw new InvalidOperationException (); } + } + + public override bool ExplicitThis { + get { return method.ExplicitThis; } + set { throw new InvalidOperationException (); } + } + + public override MethodReturnType MethodReturnType { + get { return method.MethodReturnType; } + set { throw new InvalidOperationException (); } + } + + public override TypeReference DeclaringType { + get { return method.DeclaringType; } + set { throw new InvalidOperationException (); } + } + + public override ModuleDefinition Module { + get { return method.Module; } + } + + public override bool HasParameters { + get { return method.HasParameters; } + } + + public override Collection Parameters { + get { return method.Parameters; } + } + + public override bool ContainsGenericParameter { + get { return method.ContainsGenericParameter; } + } + + internal MethodSpecification (MethodReference method) + { + Mixin.CheckMethod (method); + + this.method = method; + this.token = new MetadataToken (TokenType.MethodSpec); + } + + public sealed override MethodReference GetElementMethod () + { + return method.GetElementMethod (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs.meta new file mode 100644 index 0000000..0ab0565 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/MethodSpecification.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aab27df5116b6ef46ac37993c843e4f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs new file mode 100644 index 0000000..13367cd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs @@ -0,0 +1,112 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public interface IModifierType { + TypeReference ModifierType { get; } + TypeReference ElementType { get; } + } + + public sealed class OptionalModifierType : TypeSpecification, IModifierType { + + TypeReference modifier_type; + + public TypeReference ModifierType { + get { return modifier_type; } + set { modifier_type = value; } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { return " modopt(" + modifier_type + ")"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsOptionalModifier { + get { return true; } + } + + public override bool ContainsGenericParameter { + get { return modifier_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + public OptionalModifierType (TypeReference modifierType, TypeReference type) + : base (type) + { + if (modifierType == null) + throw new ArgumentNullException (Mixin.Argument.modifierType.ToString ()); + Mixin.CheckType (type); + this.modifier_type = modifierType; + this.etype = MD.ElementType.CModOpt; + } + } + + public sealed class RequiredModifierType : TypeSpecification, IModifierType { + + TypeReference modifier_type; + + public TypeReference ModifierType { + get { return modifier_type; } + set { modifier_type = value; } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { return " modreq(" + modifier_type + ")"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsRequiredModifier { + get { return true; } + } + + public override bool ContainsGenericParameter { + get { return modifier_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + public RequiredModifierType (TypeReference modifierType, TypeReference type) + : base (type) + { + if (modifierType == null) + throw new ArgumentNullException (Mixin.Argument.modifierType.ToString ()); + Mixin.CheckType (type); + this.modifier_type = modifierType; + this.etype = MD.ElementType.CModReqD; + } + + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs.meta new file mode 100644 index 0000000..7678d47 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Modifiers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fc5ce450d74933428a568f51cb49c16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs new file mode 100644 index 0000000..9af60a5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs @@ -0,0 +1,1353 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Cecil.Metadata; +using MonoFN.Cecil.PE; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using SR = System.Reflection; + +namespace MonoFN.Cecil { + + public enum ReadingMode { + Immediate = 1, + Deferred = 2, + } + + public sealed class ReaderParameters { + + ReadingMode reading_mode; + internal IAssemblyResolver assembly_resolver; + internal IMetadataResolver metadata_resolver; + internal IMetadataImporterProvider metadata_importer_provider; + internal IReflectionImporterProvider reflection_importer_provider; + Stream symbol_stream; + ISymbolReaderProvider symbol_reader_provider; + bool read_symbols; + bool throw_symbols_mismatch; + bool projections; + bool in_memory; + bool read_write; + + public ReadingMode ReadingMode { + get { return reading_mode; } + set { reading_mode = value; } + } + + public bool InMemory { + get { return in_memory; } + set { in_memory = value; } + } + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + set { assembly_resolver = value; } + } + + public IMetadataResolver MetadataResolver { + get { return metadata_resolver; } + set { metadata_resolver = value; } + } + + public IMetadataImporterProvider MetadataImporterProvider { + get { return metadata_importer_provider; } + set { metadata_importer_provider = value; } + } + + public IReflectionImporterProvider ReflectionImporterProvider { + get { return reflection_importer_provider; } + set { reflection_importer_provider = value; } + } + + public Stream SymbolStream { + get { return symbol_stream; } + set { symbol_stream = value; } + } + + public ISymbolReaderProvider SymbolReaderProvider { + get { return symbol_reader_provider; } + set { symbol_reader_provider = value; } + } + + public bool ReadSymbols { + get { return read_symbols; } + set { read_symbols = value; } + } + + public bool ThrowIfSymbolsAreNotMatching { + get { return throw_symbols_mismatch; } + set { throw_symbols_mismatch = value; } + } + + public bool ReadWrite { + get { return read_write; } + set { read_write = value; } + } + + public bool ApplyWindowsRuntimeProjections { + get { return projections; } + set { projections = value; } + } + + public ReaderParameters () + : this (ReadingMode.Deferred) + { + } + + public ReaderParameters (ReadingMode readingMode) + { + this.reading_mode = readingMode; + this.throw_symbols_mismatch = true; + } + } + + public sealed class ModuleParameters { + + ModuleKind kind; + TargetRuntime runtime; + uint? timestamp; + TargetArchitecture architecture; + IAssemblyResolver assembly_resolver; + IMetadataResolver metadata_resolver; + IMetadataImporterProvider metadata_importer_provider; + IReflectionImporterProvider reflection_importer_provider; + + public ModuleKind Kind { + get { return kind; } + set { kind = value; } + } + + public TargetRuntime Runtime { + get { return runtime; } + set { runtime = value; } + } + + public uint? Timestamp { + get { return timestamp; } + set { timestamp = value; } + } + + public TargetArchitecture Architecture { + get { return architecture; } + set { architecture = value; } + } + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + set { assembly_resolver = value; } + } + + public IMetadataResolver MetadataResolver { + get { return metadata_resolver; } + set { metadata_resolver = value; } + } + + public IMetadataImporterProvider MetadataImporterProvider { + get { return metadata_importer_provider; } + set { metadata_importer_provider = value; } + } + + public IReflectionImporterProvider ReflectionImporterProvider { + get { return reflection_importer_provider; } + set { reflection_importer_provider = value; } + } + + public ModuleParameters () + { + this.kind = ModuleKind.Dll; + this.Runtime = GetCurrentRuntime (); + this.architecture = TargetArchitecture.I386; + } + + static TargetRuntime GetCurrentRuntime () + { + return typeof (object).Assembly.ImageRuntimeVersion.ParseRuntime (); + } + } + + public sealed class WriterParameters { + + uint? timestamp; + Stream symbol_stream; + ISymbolWriterProvider symbol_writer_provider; + bool write_symbols; + byte [] key_blob; + string key_container; + SR.StrongNameKeyPair key_pair; + + public uint? Timestamp { + get { return timestamp; } + set { timestamp = value; } + } + + public Stream SymbolStream { + get { return symbol_stream; } + set { symbol_stream = value; } + } + + public ISymbolWriterProvider SymbolWriterProvider { + get { return symbol_writer_provider; } + set { symbol_writer_provider = value; } + } + + public bool WriteSymbols { + get { return write_symbols; } + set { write_symbols = value; } + } + + public bool HasStrongNameKey { + get { return key_pair != null || key_blob != null || key_container != null; } + } + + public byte [] StrongNameKeyBlob { + get { return key_blob; } + set { key_blob = value; } + } + + public string StrongNameKeyContainer { + get { return key_container; } + set { key_container = value; } + } + + public SR.StrongNameKeyPair StrongNameKeyPair { + get { return key_pair; } + set { key_pair = value; } + } + + public bool DeterministicMvid { get; set; } + } + + public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider, ICustomDebugInformationProvider, IDisposable { + + internal Image Image; + internal MetadataSystem MetadataSystem; + internal ReadingMode ReadingMode; + internal ISymbolReaderProvider SymbolReaderProvider; + + internal ISymbolReader symbol_reader; + internal Disposable assembly_resolver; + internal IMetadataResolver metadata_resolver; + internal TypeSystem type_system; + internal readonly MetadataReader reader; + readonly string file_name; + + internal string runtime_version; + internal ModuleKind kind; + WindowsRuntimeProjections projections; + MetadataKind metadata_kind; + TargetRuntime runtime; + TargetArchitecture architecture; + ModuleAttributes attributes; + ModuleCharacteristics characteristics; + Guid mvid; + + internal ushort linker_version = 8; + internal ushort subsystem_major = 4; + internal ushort subsystem_minor = 0; + internal uint timestamp; + + internal AssemblyDefinition assembly; + MethodDefinition entry_point; + bool entry_point_set; + + internal IReflectionImporter reflection_importer; + internal IMetadataImporter metadata_importer; + + Collection custom_attributes; + Collection references; + Collection modules; + Collection resources; + Collection exported_types; + TypeDefinitionCollection types; + + internal Collection custom_infos; + + internal MetadataBuilder metadata_builder; + + public bool IsMain { + get { return kind != ModuleKind.NetModule; } + } + + public ModuleKind Kind { + get { return kind; } + set { kind = value; } + } + + public MetadataKind MetadataKind { + get { return metadata_kind; } + set { metadata_kind = value; } + } + + internal WindowsRuntimeProjections Projections { + get { + if (projections == null) + Interlocked.CompareExchange (ref projections, new WindowsRuntimeProjections (this), null); + + return projections; + } + } + + public TargetRuntime Runtime { + get { return runtime; } + set { + runtime = value; + runtime_version = runtime.RuntimeVersionString (); + } + } + + public string RuntimeVersion { + get { return runtime_version; } + set { + runtime_version = value; + runtime = runtime_version.ParseRuntime (); + } + } + + public TargetArchitecture Architecture { + get { return architecture; } + set { architecture = value; } + } + + public ModuleAttributes Attributes { + get { return attributes; } + set { attributes = value; } + } + + public ModuleCharacteristics Characteristics { + get { return characteristics; } + set { characteristics = value; } + } + + [Obsolete ("Use FileName")] + public string FullyQualifiedName { + get { return file_name; } + } + + public string FileName { + get { return file_name; } + } + + public Guid Mvid { + get { return mvid; } + set { mvid = value; } + } + + internal bool HasImage { + get { return Image != null; } + } + + public bool HasSymbols { + get { return symbol_reader != null; } + } + + public ISymbolReader SymbolReader { + get { return symbol_reader; } + } + + public override MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.ModuleDefinition; } + } + + public AssemblyDefinition Assembly { + get { return assembly; } + } + + internal IReflectionImporter ReflectionImporter { + get { + if (reflection_importer == null) + Interlocked.CompareExchange (ref reflection_importer, new DefaultReflectionImporter (this), null); + + return reflection_importer; + } + } + + internal IMetadataImporter MetadataImporter { + get { + if (metadata_importer == null) + Interlocked.CompareExchange (ref metadata_importer, new DefaultMetadataImporter (this), null); + + return metadata_importer; + } + } + + public IAssemblyResolver AssemblyResolver { + get { + if (assembly_resolver.value == null) { + lock (module_lock) { + assembly_resolver = Disposable.Owned (new DefaultAssemblyResolver () as IAssemblyResolver); + } + } + + return assembly_resolver.value; + } + } + + public IMetadataResolver MetadataResolver { + get { + if (metadata_resolver == null) + Interlocked.CompareExchange (ref metadata_resolver, new MetadataResolver (this.AssemblyResolver), null); + + return metadata_resolver; + } + } + + public TypeSystem TypeSystem { + get { + if (type_system == null) + Interlocked.CompareExchange (ref type_system, TypeSystem.CreateTypeSystem (this), null); + + return type_system; + } + } + + public bool HasAssemblyReferences { + get { + if (references != null) + return references.Count > 0; + + return HasImage && Image.HasTable (Table.AssemblyRef); + } + } + + public Collection AssemblyReferences { + get { + if (references != null) + return references; + + if (HasImage) + return Read (ref references, this, (_, reader) => reader.ReadAssemblyReferences ()); + + Interlocked.CompareExchange (ref references, new Collection (), null); + return references; + } + } + + public bool HasModuleReferences { + get { + if (modules != null) + return modules.Count > 0; + + return HasImage && Image.HasTable (Table.ModuleRef); + } + } + + public Collection ModuleReferences { + get { + if (modules != null) + return modules; + + if (HasImage) + return Read (ref modules, this, (_, reader) => reader.ReadModuleReferences ()); + + Interlocked.CompareExchange (ref modules, new Collection (), null); + return modules; + } + } + + public bool HasResources { + get { + if (resources != null) + return resources.Count > 0; + + if (HasImage) + return Image.HasTable (Table.ManifestResource) || Read (this, (_, reader) => reader.HasFileResource ()); + + return false; + } + } + + public Collection Resources { + get { + if (resources != null) + return resources; + + if (HasImage) + return Read (ref resources, this, (_, reader) => reader.ReadResources ()); + + Interlocked.CompareExchange (ref resources, new Collection (), null); + return resources; + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (this); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, this)); } + } + + public bool HasTypes { + get { + if (types != null) + return types.Count > 0; + + return HasImage && Image.HasTable (Table.TypeDef); + } + } + + public Collection Types { + get { + if (types != null) + return types; + + if (HasImage) + return Read (ref types, this, (_, reader) => reader.ReadTypes ()); + + Interlocked.CompareExchange (ref types, new TypeDefinitionCollection (this), null); + return types; + } + } + + public bool HasExportedTypes { + get { + if (exported_types != null) + return exported_types.Count > 0; + + return HasImage && Image.HasTable (Table.ExportedType); + } + } + + public Collection ExportedTypes { + get { + if (exported_types != null) + return exported_types; + + if (HasImage) + return Read (ref exported_types, this, (_, reader) => reader.ReadExportedTypes ()); + + Interlocked.CompareExchange (ref exported_types, new Collection (), null); + return exported_types; + } + } + + public MethodDefinition EntryPoint { + get { + if (entry_point_set) + return entry_point; + + if (HasImage) + Read (ref entry_point, this, (_, reader) => reader.ReadEntryPoint ()); + else + entry_point = null; + + entry_point_set = true; + return entry_point; + } + set { + entry_point = value; + entry_point_set = true; + } + } + + public bool HasCustomDebugInformations { + get { + return custom_infos != null && custom_infos.Count > 0; + } + } + + public Collection CustomDebugInformations { + get { + if (custom_infos == null) + Interlocked.CompareExchange (ref custom_infos, new Collection (), null); + + return custom_infos; + } + } + + internal ModuleDefinition () + { + this.MetadataSystem = new MetadataSystem (); + this.token = new MetadataToken (TokenType.Module, 1); + } + + internal ModuleDefinition (Image image) + : this () + { + this.Image = image; + this.kind = image.Kind; + this.RuntimeVersion = image.RuntimeVersion; + this.architecture = image.Architecture; + this.attributes = image.Attributes; + this.characteristics = image.DllCharacteristics; + this.linker_version = image.LinkerVersion; + this.subsystem_major = image.SubSystemMajor; + this.subsystem_minor = image.SubSystemMinor; + this.file_name = image.FileName; + this.timestamp = image.Timestamp; + + this.reader = new MetadataReader (this); + } + + public void Dispose () + { + if (Image != null) + Image.Dispose (); + + if (symbol_reader != null) + symbol_reader.Dispose (); + + if (assembly_resolver.value != null) + assembly_resolver.Dispose (); + } + + public bool HasTypeReference (string fullName) + { + return HasTypeReference (string.Empty, fullName); + } + + public bool HasTypeReference (string scope, string fullName) + { + Mixin.CheckFullName (fullName); + + if (!HasImage) + return false; + + return GetTypeReference (scope, fullName) != null; + } + + public bool TryGetTypeReference (string fullName, out TypeReference type) + { + return TryGetTypeReference (string.Empty, fullName, out type); + } + + public bool TryGetTypeReference (string scope, string fullName, out TypeReference type) + { + Mixin.CheckFullName (fullName); + + if (!HasImage) { + type = null; + return false; + } + + return (type = GetTypeReference (scope, fullName)) != null; + } + + TypeReference GetTypeReference (string scope, string fullname) + { + return Read (new Row (scope, fullname), (row, reader) => reader.GetTypeReference (row.Col1, row.Col2)); + } + + public IEnumerable GetTypeReferences () + { + if (!HasImage) + return Empty.Array; + + return Read (this, (_, reader) => reader.GetTypeReferences ()); + } + + public IEnumerable GetMemberReferences () + { + if (!HasImage) + return Empty.Array; + + return Read (this, (_, reader) => reader.GetMemberReferences ()); + } + + public IEnumerable GetCustomAttributes () + { + if (!HasImage) + return Empty.Array; + + return Read (this, (_, reader) => reader.GetCustomAttributes ()); + } + + public TypeReference GetType (string fullName, bool runtimeName) + { + return runtimeName + ? TypeParser.ParseType (this, fullName, typeDefinitionOnly: true) + : GetType (fullName); + } + + public TypeDefinition GetType (string fullName) + { + Mixin.CheckFullName (fullName); + + var position = fullName.IndexOf ('/'); + if (position > 0) + return GetNestedType (fullName); + + return ((TypeDefinitionCollection)this.Types).GetType (fullName); + } + + public TypeDefinition GetType (string @namespace, string name) + { + Mixin.CheckName (name); + + return ((TypeDefinitionCollection)this.Types).GetType (@namespace ?? string.Empty, name); + } + + public IEnumerable GetTypes () + { + return GetTypes (Types); + } + + static IEnumerable GetTypes (Collection types) + { + for (int i = 0; i < types.Count; i++) { + var type = types [i]; + + yield return type; + + if (!type.HasNestedTypes) + continue; + + foreach (var nested in GetTypes (type.NestedTypes)) + yield return nested; + } + } + + TypeDefinition GetNestedType (string fullname) + { + var names = fullname.Split ('/'); + var type = GetType (names [0]); + + if (type == null) + return null; + + for (int i = 1; i < names.Length; i++) { + var nested_type = type.GetNestedType (names [i]); + if (nested_type == null) + return null; + + type = nested_type; + } + + return type; + } + + internal FieldDefinition Resolve (FieldReference field) + { + return MetadataResolver.Resolve (field); + } + + internal MethodDefinition Resolve (MethodReference method) + { + return MetadataResolver.Resolve (method); + } + + internal TypeDefinition Resolve (TypeReference type) + { + return MetadataResolver.Resolve (type); + } + + static void CheckContext (IGenericParameterProvider context, ModuleDefinition module) + { + if (context == null) + return; + + if (context.Module != module) + throw new ArgumentException (); + } + + [Obsolete ("Use ImportReference", error: false)] + public TypeReference Import (Type type) + { + return ImportReference (type, null); + } + + public TypeReference ImportReference (Type type) + { + return ImportReference (type, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public TypeReference Import (Type type, IGenericParameterProvider context) + { + return ImportReference (type, context); + } + + public TypeReference ImportReference (Type type, IGenericParameterProvider context) + { + Mixin.CheckType (type); + CheckContext (context, this); + + return ReflectionImporter.ImportReference (type, context); + } + + [Obsolete ("Use ImportReference", error: false)] + public FieldReference Import (SR.FieldInfo field) + { + return ImportReference (field, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public FieldReference Import (SR.FieldInfo field, IGenericParameterProvider context) + { + return ImportReference (field, context); + } + + public FieldReference ImportReference (SR.FieldInfo field) + { + return ImportReference (field, null); + } + + public FieldReference ImportReference (SR.FieldInfo field, IGenericParameterProvider context) + { + Mixin.CheckField (field); + CheckContext (context, this); + + return ReflectionImporter.ImportReference (field, context); + } + + [Obsolete ("Use ImportReference", error: false)] + public MethodReference Import (SR.MethodBase method) + { + return ImportReference (method, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public MethodReference Import (SR.MethodBase method, IGenericParameterProvider context) + { + return ImportReference (method, context); + } + + public MethodReference ImportReference (SR.MethodBase method) + { + return ImportReference (method, null); + } + + public MethodReference ImportReference (SR.MethodBase method, IGenericParameterProvider context) + { + Mixin.CheckMethod (method); + CheckContext (context, this); + + return ReflectionImporter.ImportReference (method, context); + } + + [Obsolete ("Use ImportReference", error: false)] + public TypeReference Import (TypeReference type) + { + return ImportReference (type, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public TypeReference Import (TypeReference type, IGenericParameterProvider context) + { + return ImportReference (type, context); + } + + public TypeReference ImportReference (TypeReference type) + { + return ImportReference (type, null); + } + + public TypeReference ImportReference (TypeReference type, IGenericParameterProvider context) + { + Mixin.CheckType (type); + + if (type.Module == this) + return type; + + CheckContext (context, this); + + return MetadataImporter.ImportReference (type, context); + } + + [Obsolete ("Use ImportReference", error: false)] + public FieldReference Import (FieldReference field) + { + return ImportReference (field, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public FieldReference Import (FieldReference field, IGenericParameterProvider context) + { + return ImportReference (field, context); + } + + public FieldReference ImportReference (FieldReference field) + { + return ImportReference (field, null); + } + + public FieldReference ImportReference (FieldReference field, IGenericParameterProvider context) + { + Mixin.CheckField (field); + + if (field.Module == this) + return field; + + CheckContext (context, this); + + return MetadataImporter.ImportReference (field, context); + } + + [Obsolete ("Use ImportReference", error: false)] + public MethodReference Import (MethodReference method) + { + return ImportReference (method, null); + } + + [Obsolete ("Use ImportReference", error: false)] + public MethodReference Import (MethodReference method, IGenericParameterProvider context) + { + return ImportReference (method, context); + } + + public MethodReference ImportReference (MethodReference method) + { + return ImportReference (method, null); + } + + public MethodReference ImportReference (MethodReference method, IGenericParameterProvider context) + { + Mixin.CheckMethod (method); + + if (method.Module == this) + return method; + + CheckContext (context, this); + + return MetadataImporter.ImportReference (method, context); + } + + public IMetadataTokenProvider LookupToken (int token) + { + return LookupToken (new MetadataToken ((uint)token)); + } + + public IMetadataTokenProvider LookupToken (MetadataToken token) + { + return Read (token, (t, reader) => reader.LookupToken (t)); + } + + public void ImmediateRead () + { + if (!HasImage) + return; + ReadingMode = ReadingMode.Immediate; + var moduleReader = new ImmediateModuleReader (Image); + moduleReader.ReadModule (this, resolve_attributes: true); + } + + readonly object module_lock = new object (); + + internal object SyncRoot { + get { return module_lock; } + } + + internal void Read (TItem item, Action read) + { + lock (module_lock) { + var position = reader.position; + var context = reader.context; + + read (item, reader); + + reader.position = position; + reader.context = context; + } + } + + internal TRet Read (TItem item, Func read) + { + lock (module_lock) { + var position = reader.position; + var context = reader.context; + + var ret = read (item, reader); + + reader.position = position; + reader.context = context; + + return ret; + } + } + + internal TRet Read (ref TRet variable, TItem item, Func read) where TRet : class + { + lock (module_lock) { + if (variable != null) + return variable; + + var position = reader.position; + var context = reader.context; + + var ret = read (item, reader); + + reader.position = position; + reader.context = context; + + return variable = ret; + } + } + + public bool HasDebugHeader { + get { return Image != null && Image.DebugHeader != null; } + } + + public ImageDebugHeader GetDebugHeader () + { + return Image.DebugHeader ?? new ImageDebugHeader (); + } + + public static ModuleDefinition CreateModule (string name, ModuleKind kind) + { + return CreateModule (name, new ModuleParameters { Kind = kind }); + } + + public static ModuleDefinition CreateModule (string name, ModuleParameters parameters) + { + Mixin.CheckName (name); + Mixin.CheckParameters (parameters); + + var module = new ModuleDefinition { + Name = name, + kind = parameters.Kind, + timestamp = parameters.Timestamp ?? Mixin.GetTimestamp (), + Runtime = parameters.Runtime, + architecture = parameters.Architecture, + mvid = Guid.NewGuid (), + Attributes = ModuleAttributes.ILOnly, + Characteristics = (ModuleCharacteristics)0x8540, + }; + + if (parameters.AssemblyResolver != null) + module.assembly_resolver = Disposable.NotOwned (parameters.AssemblyResolver); + + if (parameters.MetadataResolver != null) + module.metadata_resolver = parameters.MetadataResolver; + + if (parameters.MetadataImporterProvider != null) + module.metadata_importer = parameters.MetadataImporterProvider.GetMetadataImporter (module); + + if (parameters.ReflectionImporterProvider != null) + module.reflection_importer = parameters.ReflectionImporterProvider.GetReflectionImporter (module); + + if (parameters.Kind != ModuleKind.NetModule) { + var assembly = new AssemblyDefinition (); + module.assembly = assembly; + module.assembly.Name = CreateAssemblyName (name); + assembly.main_module = module; + } + + module.Types.Add (new TypeDefinition (string.Empty, "", TypeAttributes.NotPublic)); + + return module; + } + + static AssemblyNameDefinition CreateAssemblyName (string name) + { + if (name.EndsWith (".dll") || name.EndsWith (".exe")) + name = name.Substring (0, name.Length - 4); + + return new AssemblyNameDefinition (name, Mixin.ZeroVersion); + } + + public void ReadSymbols () + { + if (string.IsNullOrEmpty (file_name)) + throw new InvalidOperationException (); + + var provider = new DefaultSymbolReaderProvider (throwIfNoSymbol: true); + ReadSymbols (provider.GetSymbolReader (this, file_name), throwIfSymbolsAreNotMaching: true); + } + + public void ReadSymbols (ISymbolReader reader) + { + ReadSymbols (reader, throwIfSymbolsAreNotMaching: true); + } + + public void ReadSymbols (ISymbolReader reader, bool throwIfSymbolsAreNotMaching) + { + if (reader == null) + throw new ArgumentNullException ("reader"); + + symbol_reader = reader; + + if (!symbol_reader.ProcessDebugHeader (GetDebugHeader ())) { + symbol_reader = null; + + if (throwIfSymbolsAreNotMaching) + throw new SymbolsNotMatchingException ("Symbols were found but are not matching the assembly"); + + return; + } + + if (HasImage && ReadingMode == ReadingMode.Immediate) { + var immediate_reader = new ImmediateModuleReader (Image); + immediate_reader.ReadSymbols (this); + } + } + + public static ModuleDefinition ReadModule (string fileName) + { + return ReadModule (fileName, new ReaderParameters (ReadingMode.Deferred)); + } + + public static ModuleDefinition ReadModule (string fileName, ReaderParameters parameters) + { + var stream = GetFileStream (fileName, FileMode.Open, parameters.ReadWrite ? FileAccess.ReadWrite : FileAccess.Read, FileShare.Read); + + if (parameters.InMemory) { + var memory = new MemoryStream (stream.CanSeek ? (int)stream.Length : 0); + using (stream) + stream.CopyTo (memory); + + memory.Position = 0; + stream = memory; + } + + try { + return ReadModule (Disposable.Owned (stream), fileName, parameters); + } + catch (Exception) { + stream.Dispose (); + throw; + } + } + + static Stream GetFileStream (string fileName, FileMode mode, FileAccess access, FileShare share) + { + Mixin.CheckFileName (fileName); + + return new FileStream (fileName, mode, access, share); + } + + public static ModuleDefinition ReadModule (Stream stream) + { + return ReadModule (stream, new ReaderParameters (ReadingMode.Deferred)); + } + + public static ModuleDefinition ReadModule (Stream stream, ReaderParameters parameters) + { + Mixin.CheckStream (stream); + Mixin.CheckReadSeek (stream); + + return ReadModule (Disposable.NotOwned (stream), stream.GetFileName (), parameters); + } + + static ModuleDefinition ReadModule (Disposable stream, string fileName, ReaderParameters parameters) + { + Mixin.CheckParameters (parameters); + + return ModuleReader.CreateModule ( + ImageReader.ReadImage (stream, fileName), + parameters); + } + + public void Write (string fileName) + { + Write (fileName, new WriterParameters ()); + } + + public void Write (string fileName, WriterParameters parameters) + { + Mixin.CheckParameters (parameters); + var file = GetFileStream (fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read); + ModuleWriter.WriteModule (this, Disposable.Owned (file), parameters); + } + + public void Write () + { + Write (new WriterParameters ()); + } + + public void Write (WriterParameters parameters) + { + if (!HasImage) + throw new InvalidOperationException (); + + Write (Image.Stream.value, parameters); + } + + public void Write (Stream stream) + { + Write (stream, new WriterParameters ()); + } + + public void Write (Stream stream, WriterParameters parameters) + { + Mixin.CheckStream (stream); + Mixin.CheckWriteSeek (stream); + Mixin.CheckParameters (parameters); + + ModuleWriter.WriteModule (this, Disposable.NotOwned (stream), parameters); + } + } + + static partial class Mixin { + + public enum Argument { + name, + fileName, + fullName, + stream, + type, + method, + field, + parameters, + module, + modifierType, + eventType, + fieldType, + declaringType, + returnType, + propertyType, + interfaceType, + constraintType, + } + + public static void CheckName (object name) + { + if (name == null) + throw new ArgumentNullException (Argument.name.ToString ()); + } + + public static void CheckName (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentNullOrEmptyException (Argument.name.ToString ()); + } + + public static void CheckFileName (string fileName) + { + if (string.IsNullOrEmpty (fileName)) + throw new ArgumentNullOrEmptyException (Argument.fileName.ToString ()); + } + + public static void CheckFullName (string fullName) + { + if (string.IsNullOrEmpty (fullName)) + throw new ArgumentNullOrEmptyException (Argument.fullName.ToString ()); + } + + public static void CheckStream (object stream) + { + if (stream == null) + throw new ArgumentNullException (Argument.stream.ToString ()); + } + + public static void CheckWriteSeek (Stream stream) + { + if (!stream.CanWrite || !stream.CanSeek) + throw new ArgumentException ("Stream must be writable and seekable."); + } + + public static void CheckReadSeek (Stream stream) + { + if (!stream.CanRead || !stream.CanSeek) + throw new ArgumentException ("Stream must be readable and seekable."); + } + + public static void CheckType (object type) + { + if (type == null) + throw new ArgumentNullException (Argument.type.ToString ()); + } + + public static void CheckType (object type, Argument argument) + { + if (type == null) + throw new ArgumentNullException (argument.ToString ()); + } + + public static void CheckField (object field) + { + if (field == null) + throw new ArgumentNullException (Argument.field.ToString ()); + } + + public static void CheckMethod (object method) + { + if (method == null) + throw new ArgumentNullException (Argument.method.ToString ()); + } + + public static void CheckParameters (object parameters) + { + if (parameters == null) + throw new ArgumentNullException (Argument.parameters.ToString ()); + } + + public static uint GetTimestamp () + { + return (uint)DateTime.UtcNow.Subtract (new DateTime (1970, 1, 1)).TotalSeconds; + } + + public static bool HasImage (this ModuleDefinition self) + { + return self != null && self.HasImage; + } + + public static string GetFileName (this Stream self) + { + var file_stream = self as FileStream; + if (file_stream == null) + return string.Empty; + + return Path.GetFullPath (file_stream.Name); + } + + public static TargetRuntime ParseRuntime (this string self) + { + if (string.IsNullOrEmpty (self)) + return TargetRuntime.Net_4_0; + + switch (self [1]) { + case '1': + return self [3] == '0' + ? TargetRuntime.Net_1_0 + : TargetRuntime.Net_1_1; + case '2': + return TargetRuntime.Net_2_0; + case '4': + default: + return TargetRuntime.Net_4_0; + } + } + + public static string RuntimeVersionString (this TargetRuntime runtime) + { + switch (runtime) { + case TargetRuntime.Net_1_0: + return "v1.0.3705"; + case TargetRuntime.Net_1_1: + return "v1.1.4322"; + case TargetRuntime.Net_2_0: + return "v2.0.50727"; + case TargetRuntime.Net_4_0: + default: + return "v4.0.30319"; + } + } + + public static bool IsWindowsMetadata (this ModuleDefinition module) + { + return module.MetadataKind != MetadataKind.Ecma335; + } + + public static byte [] ReadAll (this Stream self) + { + int read; + var memory = new MemoryStream ((int)self.Length); + var buffer = new byte [1024]; + + while ((read = self.Read (buffer, 0, buffer.Length)) != 0) + memory.Write (buffer, 0, read); + + return memory.ToArray (); + } + + public static void Read (object o) + { + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs.meta new file mode 100644 index 0000000..d34c5c1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be36668e876daba419d4cf3aa5e8cac9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs new file mode 100644 index 0000000..429fa8f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs @@ -0,0 +1,55 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public enum ModuleKind { + Dll, + Console, + Windows, + NetModule, + } + + public enum MetadataKind { + Ecma335, + WindowsMetadata, + ManagedWindowsMetadata, + } + + public enum TargetArchitecture { + I386 = 0x014c, + AMD64 = 0x8664, + IA64 = 0x0200, + ARM = 0x01c0, + ARMv7 = 0x01c4, + ARM64 = 0xaa64, + } + + [Flags] + public enum ModuleAttributes { + ILOnly = 1, + Required32Bit = 2, + ILLibrary = 4, + StrongNameSigned = 8, + Preferred32Bit = 0x00020000, + } + + [Flags] + public enum ModuleCharacteristics { + HighEntropyVA = 0x0020, + DynamicBase = 0x0040, + NoSEH = 0x0400, + NXCompat = 0x0100, + AppContainer = 0x1000, + TerminalServerAware = 0x8000, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs.meta new file mode 100644 index 0000000..110cc83 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleKind.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b85d54df2658b6d4bab3d27002f45a01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs new file mode 100644 index 0000000..eb22872 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs @@ -0,0 +1,49 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public class ModuleReference : IMetadataScope { + + string name; + + internal MetadataToken token; + + public string Name { + get { return name; } + set { name = value; } + } + + public virtual MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.ModuleReference; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal ModuleReference () + { + this.token = new MetadataToken (TokenType.ModuleRef); + } + + public ModuleReference (string name) + : this () + { + this.name = name; + } + + public override string ToString () + { + return name; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs.meta new file mode 100644 index 0000000..3510c8c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ModuleReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b28049ba3ae6394dbe9f227aaf9c88e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs new file mode 100644 index 0000000..b2ed6d2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs @@ -0,0 +1,55 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum NativeType { + None = 0x66, + + Boolean = 0x02, + I1 = 0x03, + U1 = 0x04, + I2 = 0x05, + U2 = 0x06, + I4 = 0x07, + U4 = 0x08, + I8 = 0x09, + U8 = 0x0a, + R4 = 0x0b, + R8 = 0x0c, + LPStr = 0x14, + Int = 0x1f, + UInt = 0x20, + Func = 0x26, + Array = 0x2a, + + // Msft specific + Currency = 0x0f, + BStr = 0x13, + LPWStr = 0x15, + LPTStr = 0x16, + FixedSysString = 0x17, + IUnknown = 0x19, + IDispatch = 0x1a, + Struct = 0x1b, + IntF = 0x1c, + SafeArray = 0x1d, + FixedArray = 0x1e, + ByValStr = 0x22, + ANSIBStr = 0x23, + TBStr = 0x24, + VariantBool = 0x25, + ASAny = 0x28, + LPStruct = 0x2b, + CustomMarshaler = 0x2c, + Error = 0x2d, + Max = 0x50 + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs.meta new file mode 100644 index 0000000..a6dd298 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/NativeType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb32c8b42f4f314448ff4b2c7eae0533 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs new file mode 100644 index 0000000..d99aca4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs @@ -0,0 +1,44 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum PInvokeAttributes : ushort { + NoMangle = 0x0001, // PInvoke is to use the member name as specified + + // Character set + CharSetMask = 0x0006, + CharSetNotSpec = 0x0000, + CharSetAnsi = 0x0002, + CharSetUnicode = 0x0004, + CharSetAuto = 0x0006, + + SupportsLastError = 0x0040, // Information about target function. Not relevant for fields + + // Calling convetion + CallConvMask = 0x0700, + CallConvWinapi = 0x0100, + CallConvCdecl = 0x0200, + CallConvStdCall = 0x0300, + CallConvThiscall = 0x0400, + CallConvFastcall = 0x0500, + + BestFitMask = 0x0030, + BestFitEnabled = 0x0010, + BestFitDisabled = 0x0020, + + ThrowOnUnmappableCharMask = 0x3000, + ThrowOnUnmappableCharEnabled = 0x1000, + ThrowOnUnmappableCharDisabled = 0x2000, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs.meta new file mode 100644 index 0000000..e1bed46 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf3019a5e2270654abca972684f5c2f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs new file mode 100644 index 0000000..079c6bc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs @@ -0,0 +1,120 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public sealed class PInvokeInfo { + + ushort attributes; + string entry_point; + ModuleReference module; + + public PInvokeAttributes Attributes { + get { return (PInvokeAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public string EntryPoint { + get { return entry_point; } + set { entry_point = value; } + } + + public ModuleReference Module { + get { return module; } + set { module = value; } + } + + #region PInvokeAttributes + + public bool IsNoMangle { + get { return attributes.GetAttributes ((ushort)PInvokeAttributes.NoMangle); } + set { attributes = attributes.SetAttributes ((ushort)PInvokeAttributes.NoMangle, value); } + } + + public bool IsCharSetNotSpec { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetNotSpec); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetNotSpec, value); } + } + + public bool IsCharSetAnsi { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetAnsi); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetAnsi, value); } + } + + public bool IsCharSetUnicode { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetUnicode); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetUnicode, value); } + } + + public bool IsCharSetAuto { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetAuto); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CharSetMask, (ushort)PInvokeAttributes.CharSetAuto, value); } + } + + public bool SupportsLastError { + get { return attributes.GetAttributes ((ushort)PInvokeAttributes.SupportsLastError); } + set { attributes = attributes.SetAttributes ((ushort)PInvokeAttributes.SupportsLastError, value); } + } + + public bool IsCallConvWinapi { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvWinapi); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvWinapi, value); } + } + + public bool IsCallConvCdecl { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvCdecl); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvCdecl, value); } + } + + public bool IsCallConvStdCall { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvStdCall); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvStdCall, value); } + } + + public bool IsCallConvThiscall { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvThiscall); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvThiscall, value); } + } + + public bool IsCallConvFastcall { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvFastcall); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.CallConvMask, (ushort)PInvokeAttributes.CallConvFastcall, value); } + } + + public bool IsBestFitEnabled { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.BestFitMask, (ushort)PInvokeAttributes.BestFitEnabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.BestFitMask, (ushort)PInvokeAttributes.BestFitEnabled, value); } + } + + public bool IsBestFitDisabled { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.BestFitMask, (ushort)PInvokeAttributes.BestFitDisabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.BestFitMask, (ushort)PInvokeAttributes.BestFitDisabled, value); } + } + + public bool IsThrowOnUnmappableCharEnabled { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort)PInvokeAttributes.ThrowOnUnmappableCharEnabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort)PInvokeAttributes.ThrowOnUnmappableCharEnabled, value); } + } + + public bool IsThrowOnUnmappableCharDisabled { + get { return attributes.GetMaskedAttributes ((ushort)PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort)PInvokeAttributes.ThrowOnUnmappableCharDisabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort)PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort)PInvokeAttributes.ThrowOnUnmappableCharDisabled, value); } + } + + #endregion + + public PInvokeInfo (PInvokeAttributes attributes, string entryPoint, ModuleReference module) + { + this.attributes = (ushort)attributes; + this.entry_point = entryPoint; + this.module = module; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs.meta new file mode 100644 index 0000000..4c27d4b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PInvokeInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56eb336b3d1ea2b4094fbb5586a11d49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs new file mode 100644 index 0000000..387e1dc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs @@ -0,0 +1,27 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum ParameterAttributes : ushort { + None = 0x0000, + In = 0x0001, // Param is [In] + Out = 0x0002, // Param is [Out] + Lcid = 0x0004, + Retval = 0x0008, + Optional = 0x0010, // Param is optional + HasDefault = 0x1000, // Param has default value + HasFieldMarshal = 0x2000, // Param has field marshal + Unused = 0xcfe0 // Reserved: shall be zero in a conforming implementation + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs.meta new file mode 100644 index 0000000..487cc73 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc153e8db6e9d1b4ca432cd66ecfe423 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs new file mode 100644 index 0000000..cd4905a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs @@ -0,0 +1,146 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; + +namespace MonoFN.Cecil { + + public sealed class ParameterDefinition : ParameterReference, ICustomAttributeProvider, IConstantProvider, IMarshalInfoProvider { + + ushort attributes; + + internal IMethodSignature method; + + object constant = Mixin.NotResolved; + Collection custom_attributes; + MarshalInfo marshal_info; + + public ParameterAttributes Attributes { + get { return (ParameterAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public IMethodSignature Method { + get { return method; } + } + + public int Sequence { + get { + if (method == null) + return -1; + + return method.HasImplicitThis () ? index + 1 : index; + } + } + + public bool HasConstant { + get { + this.ResolveConstant (ref constant, parameter_type.Module); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (parameter_type.Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, parameter_type.Module)); } + } + + public bool HasMarshalInfo { + get { + if (marshal_info != null) + return true; + + return this.GetHasMarshalInfo (parameter_type.Module); + } + } + + public MarshalInfo MarshalInfo { + get { return marshal_info ?? (this.GetMarshalInfo (ref marshal_info, parameter_type.Module)); } + set { marshal_info = value; } + } + + #region ParameterAttributes + + public bool IsIn { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.In); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.In, value); } + } + + public bool IsOut { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.Out); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.Out, value); } + } + + public bool IsLcid { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.Lcid); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.Lcid, value); } + } + + public bool IsReturnValue { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.Retval); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.Retval, value); } + } + + public bool IsOptional { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.Optional); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.Optional, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.HasDefault, value); } + } + + public bool HasFieldMarshal { + get { return attributes.GetAttributes ((ushort)ParameterAttributes.HasFieldMarshal); } + set { attributes = attributes.SetAttributes ((ushort)ParameterAttributes.HasFieldMarshal, value); } + } + + #endregion + + internal ParameterDefinition (TypeReference parameterType, IMethodSignature method) + : this (string.Empty, ParameterAttributes.None, parameterType) + { + this.method = method; + } + + public ParameterDefinition (TypeReference parameterType) + : this (string.Empty, ParameterAttributes.None, parameterType) + { + } + + public ParameterDefinition (string name, ParameterAttributes attributes, TypeReference parameterType) + : base (name, parameterType) + { + this.attributes = (ushort)attributes; + this.token = new MetadataToken (TokenType.Param); + } + + public override ParameterDefinition Resolve () + { + return this; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs.meta new file mode 100644 index 0000000..06cef24 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6759139d8b53974087e609a88da6072 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs new file mode 100644 index 0000000..26eaec0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs @@ -0,0 +1,60 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; + +namespace MonoFN.Cecil { + + sealed class ParameterDefinitionCollection : Collection { + + readonly IMethodSignature method; + + internal ParameterDefinitionCollection (IMethodSignature method) + { + this.method = method; + } + + internal ParameterDefinitionCollection (IMethodSignature method, int capacity) + : base (capacity) + { + this.method = method; + } + + protected override void OnAdd (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + } + + protected override void OnInsert (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + + for (int i = index; i < size; i++) + items [i].index = i + 1; + } + + protected override void OnSet (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + } + + protected override void OnRemove (ParameterDefinition item, int index) + { + item.method = null; + item.index = -1; + + for (int i = index + 1; i < size; i++) + items [i].index = i - 1; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs.meta new file mode 100644 index 0000000..1e96811 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterDefinitionCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01e788194a3a3604784e347ac41ec6b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs new file mode 100644 index 0000000..b84fe3f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs @@ -0,0 +1,57 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public abstract class ParameterReference : IMetadataTokenProvider { + + string name; + internal int index = -1; + protected TypeReference parameter_type; + internal MetadataToken token; + + public string Name { + get { return name; } + set { name = value; } + } + + public int Index { + get { return index; } + } + + public TypeReference ParameterType { + get { return parameter_type; } + set { parameter_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal ParameterReference (string name, TypeReference parameterType) + { + if (parameterType == null) + throw new ArgumentNullException ("parameterType"); + + this.name = name ?? string.Empty; + this.parameter_type = parameterType; + } + + public override string ToString () + { + return name; + } + + public abstract ParameterDefinition Resolve (); + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs.meta new file mode 100644 index 0000000..69166ca --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ParameterReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0643ce0ca6e47bf4e92518aed8a3a955 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs new file mode 100644 index 0000000..dc83596 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs @@ -0,0 +1,35 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class PinnedType : TypeSpecification { + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsPinned { + get { return true; } + } + + public PinnedType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Pinned; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs.meta new file mode 100644 index 0000000..325921b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PinnedType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6840e25b64ef0924d84724d5587cfa68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs new file mode 100644 index 0000000..5c27093 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs @@ -0,0 +1,43 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class PointerType : TypeSpecification { + + public override string Name { + get { return base.Name + "*"; } + } + + public override string FullName { + get { return base.FullName + "*"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsPointer { + get { return true; } + } + + public PointerType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Ptr; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs.meta new file mode 100644 index 0000000..665c696 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PointerType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b6a1c540eedbb04082628ad5dd10583 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs new file mode 100644 index 0000000..1f32a51 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs @@ -0,0 +1,23 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum PropertyAttributes : ushort { + None = 0x0000, + SpecialName = 0x0200, // Property is special + RTSpecialName = 0x0400, // Runtime(metadata internal APIs) should check name encoding + HasDefault = 0x1000, // Property has default + Unused = 0xe9ff // Reserved: shall be zero in a conforming implementation + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs.meta new file mode 100644 index 0000000..6a0dbc7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 163bf99004c8e294f8b4113c29cae987 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs new file mode 100644 index 0000000..3268ffd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs @@ -0,0 +1,245 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System.Text; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class PropertyDefinition : PropertyReference, IMemberDefinition, IConstantProvider { + + bool? has_this; + ushort attributes; + + Collection custom_attributes; + + internal MethodDefinition get_method; + internal MethodDefinition set_method; + internal Collection other_methods; + + object constant = Mixin.NotResolved; + + public PropertyAttributes Attributes { + get { return (PropertyAttributes)attributes; } + set { attributes = (ushort)value; } + } + + public bool HasThis { + get { + if (has_this.HasValue) + return has_this.Value; + + if (GetMethod != null) + return get_method.HasThis; + + if (SetMethod != null) + return set_method.HasThis; + + return false; + } + set { has_this = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + public MethodDefinition GetMethod { + get { + if (get_method != null) + return get_method; + + InitializeMethods (); + return get_method; + } + set { get_method = value; } + } + + public MethodDefinition SetMethod { + get { + if (set_method != null) + return set_method; + + InitializeMethods (); + return set_method; + } + set { set_method = value; } + } + + public bool HasOtherMethods { + get { + if (other_methods != null) + return other_methods.Count > 0; + + InitializeMethods (); + return !other_methods.IsNullOrEmpty (); + } + } + + public Collection OtherMethods { + get { + if (other_methods != null) + return other_methods; + + InitializeMethods (); + + if (other_methods != null) + return other_methods; + + Interlocked.CompareExchange (ref other_methods, new Collection (), null); + return other_methods; + } + } + + public bool HasParameters { + get { + InitializeMethods (); + + if (get_method != null) + return get_method.HasParameters; + + if (set_method != null) + return set_method.HasParameters && set_method.Parameters.Count > 1; + + return false; + } + } + + public override Collection Parameters { + get { + InitializeMethods (); + + if (get_method != null) + return MirrorParameters (get_method, 0); + + if (set_method != null) + return MirrorParameters (set_method, 1); + + return new Collection (); + } + } + + static Collection MirrorParameters (MethodDefinition method, int bound) + { + var parameters = new Collection (); + if (!method.HasParameters) + return parameters; + + var original_parameters = method.Parameters; + var end = original_parameters.Count - bound; + + for (int i = 0; i < end; i++) + parameters.Add (original_parameters [i]); + + return parameters; + } + + public bool HasConstant { + get { + this.ResolveConstant (ref constant, Module); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + #region PropertyAttributes + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort)PropertyAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort)PropertyAttributes.SpecialName, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort)PropertyAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort)PropertyAttributes.RTSpecialName, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort)PropertyAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort)PropertyAttributes.HasDefault, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition)base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public override bool IsDefinition { + get { return true; } + } + + public override string FullName { + get { + var builder = new StringBuilder (); + builder.Append (PropertyType.ToString ()); + builder.Append (' '); + builder.Append (MemberFullName ()); + builder.Append ('('); + if (HasParameters) { + var parameters = Parameters; + for (int i = 0; i < parameters.Count; i++) { + if (i > 0) + builder.Append (','); + builder.Append (parameters [i].ParameterType.FullName); + } + } + builder.Append (')'); + return builder.ToString (); + } + } + + public PropertyDefinition (string name, PropertyAttributes attributes, TypeReference propertyType) + : base (name, propertyType) + { + this.attributes = (ushort)attributes; + this.token = new MetadataToken (TokenType.Property); + } + + void InitializeMethods () + { + var module = this.Module; + if (module == null) + return; + + lock (module.SyncRoot) { + if (get_method != null || set_method != null) + return; + + if (!module.HasImage ()) + return; + + module.Read (this, (property, reader) => reader.ReadMethods (property)); + } + } + + public override PropertyDefinition Resolve () + { + return this; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs.meta new file mode 100644 index 0000000..a372850 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c1878ca62c0e6f4595238eb6a87edfd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs new file mode 100644 index 0000000..d3f7a4c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs @@ -0,0 +1,43 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; + +namespace MonoFN.Cecil { + + public abstract class PropertyReference : MemberReference { + + TypeReference property_type; + + public TypeReference PropertyType { + get { return property_type; } + set { property_type = value; } + } + + public abstract Collection Parameters { + get; + } + + internal PropertyReference (string name, TypeReference propertyType) + : base (name) + { + Mixin.CheckType (propertyType, Mixin.Argument.propertyType); + + property_type = propertyType; + } + + protected override IMemberDefinition ResolveDefinition () + { + return this.Resolve (); + } + + public new abstract PropertyDefinition Resolve (); + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs.meta new file mode 100644 index 0000000..a218f3c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/PropertyReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a30c5751a554ce649bf88a597e4075e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs new file mode 100644 index 0000000..e2703a4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs @@ -0,0 +1,43 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class ByReferenceType : TypeSpecification { + + public override string Name { + get { return base.Name + "&"; } + } + + public override string FullName { + get { return base.FullName + "&"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsByReference { + get { return true; } + } + + public ByReferenceType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.ByRef; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs.meta new file mode 100644 index 0000000..de5a90f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/ReferenceType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32a78d7552e92774cbf44ddd46fb7aa4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs new file mode 100644 index 0000000..92c007f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs @@ -0,0 +1,58 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum ResourceType { + Linked, + Embedded, + AssemblyLinked, + } + + public abstract class Resource { + + string name; + uint attributes; + + public string Name { + get { return name; } + set { name = value; } + } + + public ManifestResourceAttributes Attributes { + get { return (ManifestResourceAttributes)attributes; } + set { attributes = (uint)value; } + } + + public abstract ResourceType ResourceType { + get; + } + + #region ManifestResourceAttributes + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint)ManifestResourceAttributes.VisibilityMask, (uint)ManifestResourceAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint)ManifestResourceAttributes.VisibilityMask, (uint)ManifestResourceAttributes.Public, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((uint)ManifestResourceAttributes.VisibilityMask, (uint)ManifestResourceAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((uint)ManifestResourceAttributes.VisibilityMask, (uint)ManifestResourceAttributes.Private, value); } + } + + #endregion + + internal Resource (string name, ManifestResourceAttributes attributes) + { + this.name = name; + this.attributes = (uint)attributes; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs.meta new file mode 100644 index 0000000..c4c82c9 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Resource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8b738634202e694ebec627727698b83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs new file mode 100644 index 0000000..c3e27b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs @@ -0,0 +1,201 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Diagnostics; +using System.Threading; + +namespace MonoFN.Cecil { + + public enum SecurityAction : ushort { + Request = 1, + Demand = 2, + Assert = 3, + Deny = 4, + PermitOnly = 5, + LinkDemand = 6, + InheritDemand = 7, + RequestMinimum = 8, + RequestOptional = 9, + RequestRefuse = 10, + PreJitGrant = 11, + PreJitDeny = 12, + NonCasDemand = 13, + NonCasLinkDemand = 14, + NonCasInheritance = 15 + } + + public interface ISecurityDeclarationProvider : IMetadataTokenProvider { + + bool HasSecurityDeclarations { get; } + Collection SecurityDeclarations { get; } + } + + [DebuggerDisplay ("{AttributeType}")] + public sealed class SecurityAttribute : ICustomAttribute { + + TypeReference attribute_type; + + internal Collection fields; + internal Collection properties; + + public TypeReference AttributeType { + get { return attribute_type; } + set { attribute_type = value; } + } + + public bool HasFields { + get { return !fields.IsNullOrEmpty (); } + } + + public Collection Fields { + get { + if (fields == null) + Interlocked.CompareExchange (ref fields, new Collection (), null); + + return fields; + } + } + + public bool HasProperties { + get { return !properties.IsNullOrEmpty (); } + } + + public Collection Properties { + get { + if (properties == null) + Interlocked.CompareExchange (ref properties, new Collection (), null); + + return properties; + } + } + + public SecurityAttribute (TypeReference attributeType) + { + this.attribute_type = attributeType; + } + + bool ICustomAttribute.HasConstructorArguments { + get { return false; } + } + + Collection ICustomAttribute.ConstructorArguments { + get { throw new NotSupportedException (); } + } + } + + public sealed class SecurityDeclaration { + + readonly internal uint signature; + byte [] blob; + readonly ModuleDefinition module; + + internal bool resolved; + SecurityAction action; + internal Collection security_attributes; + + public SecurityAction Action { + get { return action; } + set { action = value; } + } + + public bool HasSecurityAttributes { + get { + Resolve (); + + return !security_attributes.IsNullOrEmpty (); + } + } + + public Collection SecurityAttributes { + get { + Resolve (); + + if (security_attributes == null) + Interlocked.CompareExchange (ref security_attributes, new Collection (), null); + + return security_attributes; + } + } + + internal bool HasImage { + get { return module != null && module.HasImage; } + } + + internal SecurityDeclaration (SecurityAction action, uint signature, ModuleDefinition module) + { + this.action = action; + this.signature = signature; + this.module = module; + } + + public SecurityDeclaration (SecurityAction action) + { + this.action = action; + this.resolved = true; + } + + public SecurityDeclaration (SecurityAction action, byte [] blob) + { + this.action = action; + this.resolved = false; + this.blob = blob; + } + + public byte [] GetBlob () + { + if (blob != null) + return blob; + + if (!HasImage || signature == 0) + throw new NotSupportedException (); + + return module.Read (ref blob, this, (declaration, reader) => reader.ReadSecurityDeclarationBlob (declaration.signature)); + } + + void Resolve () + { + if (resolved || !HasImage) + return; + + lock (module.SyncRoot) { + + if (resolved) + return; + + module.Read (this, (declaration, reader) => reader.ReadSecurityDeclarationSignature (declaration)); + resolved = true; + } + } + } + + static partial class Mixin { + + public static bool GetHasSecurityDeclarations ( + this ISecurityDeclarationProvider self, + ModuleDefinition module) + { + return module.HasImage () && module.Read (self, (provider, reader) => reader.HasSecurityDeclarations (provider)); + } + + public static Collection GetSecurityDeclarations ( + this ISecurityDeclarationProvider self, + ref Collection variable, + ModuleDefinition module) + { + if (module.HasImage) + return module.Read (ref variable, self, (provider, reader) => reader.ReadSecurityDeclarations (provider)); + + Interlocked.CompareExchange (ref variable, new Collection (), null); + return variable; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs.meta new file mode 100644 index 0000000..67a6b92 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SecurityDeclaration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a39c3df615f71b409a5aa3d102fb35e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs new file mode 100644 index 0000000..24e3840 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs @@ -0,0 +1,35 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +using MD = MonoFN.Cecil.Metadata; + +namespace MonoFN.Cecil { + + public sealed class SentinelType : TypeSpecification { + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsSentinel { + get { return true; } + } + + public SentinelType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Sentinel; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs.meta new file mode 100644 index 0000000..f025abf --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/SentinelType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31522df8b7c72c1499a3fb951e73a69a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs new file mode 100644 index 0000000..d2c48f3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs @@ -0,0 +1,19 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum TargetRuntime { + Net_1_0, + Net_1_1, + Net_2_0, + Net_4_0, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs.meta new file mode 100644 index 0000000..9192b08 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TargetRuntime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64ac90055dca01347b6ed93dff5e4284 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs new file mode 100644 index 0000000..4b65d6a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs @@ -0,0 +1,61 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + enum TypeDefinitionTreatment { + None = 0x0, + + KindMask = 0xf, + NormalType = 0x1, + NormalAttribute = 0x2, + UnmangleWindowsRuntimeName = 0x3, + PrefixWindowsRuntimeName = 0x4, + RedirectToClrType = 0x5, + RedirectToClrAttribute = 0x6, + RedirectImplementedMethods = 0x7, + + Abstract = 0x10, + Internal = 0x20, + } + + enum TypeReferenceTreatment { + None = 0x0, + SystemDelegate = 0x1, + SystemAttribute = 0x2, + UseProjectionInfo = 0x3, + } + + [Flags] + enum MethodDefinitionTreatment { + None = 0x0, + Abstract = 0x2, + Private = 0x4, + Public = 0x8, + Runtime = 0x10, + InternalCall = 0x20, + } + + enum FieldDefinitionTreatment { + None = 0x0, + Public = 0x1, + } + + enum CustomAttributeValueTreatment { + None = 0x0, + AllowSingle = 0x1, + AllowMultiple = 0x2, + VersionAttribute = 0x3, + DeprecatedAttribute = 0x4, + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs.meta new file mode 100644 index 0000000..d9698b7 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/Treatments.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2bba6ea16ba63147b7bff91a65ad5fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs new file mode 100644 index 0000000..dae187b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs @@ -0,0 +1,63 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + [Flags] + public enum TypeAttributes : uint { + // Visibility attributes + VisibilityMask = 0x00000007, // Use this mask to retrieve visibility information + NotPublic = 0x00000000, // Class has no public scope + Public = 0x00000001, // Class has public scope + NestedPublic = 0x00000002, // Class is nested with public visibility + NestedPrivate = 0x00000003, // Class is nested with private visibility + NestedFamily = 0x00000004, // Class is nested with family visibility + NestedAssembly = 0x00000005, // Class is nested with assembly visibility + NestedFamANDAssem = 0x00000006, // Class is nested with family and assembly visibility + NestedFamORAssem = 0x00000007, // Class is nested with family or assembly visibility + + // Class layout attributes + LayoutMask = 0x00000018, // Use this mask to retrieve class layout information + AutoLayout = 0x00000000, // Class fields are auto-laid out + SequentialLayout = 0x00000008, // Class fields are laid out sequentially + ExplicitLayout = 0x00000010, // Layout is supplied explicitly + + // Class semantics attributes + ClassSemanticMask = 0x00000020, // Use this mask to retrieve class semantics information + Class = 0x00000000, // Type is a class + Interface = 0x00000020, // Type is an interface + + // Special semantics in addition to class semantics + Abstract = 0x00000080, // Class is abstract + Sealed = 0x00000100, // Class cannot be extended + SpecialName = 0x00000400, // Class name is special + + // Implementation attributes + Import = 0x00001000, // Class/Interface is imported + Serializable = 0x00002000, // Class is serializable + WindowsRuntime = 0x00004000, // Windows Runtime type + + // String formatting attributes + StringFormatMask = 0x00030000, // Use this mask to retrieve string information for native interop + AnsiClass = 0x00000000, // LPSTR is interpreted as ANSI + UnicodeClass = 0x00010000, // LPSTR is interpreted as Unicode + AutoClass = 0x00020000, // LPSTR is interpreted automatically + + // Class initialization attributes + BeforeFieldInit = 0x00100000, // Initialize the class before first static field access + + // Additional flags + RTSpecialName = 0x00000800, // CLI provides 'special' behavior, depending upon the name of the Type + HasSecurity = 0x00040000, // Type has security associate with it + Forwarder = 0x00200000, // Exported type is a type forwarder + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs.meta new file mode 100644 index 0000000..eb01e16 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a634580522059d74bb5ad1f997af1284 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs new file mode 100644 index 0000000..b61e8aa --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs @@ -0,0 +1,11 @@ +namespace MonoFN.Cecil { + internal enum TypeComparisonMode { + Exact, + SignatureOnly, + + /// + /// Types can be in different assemblies, as long as the module, assembly, and type names match they will be considered equal + /// + SignatureOnlyLoose + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs.meta new file mode 100644 index 0000000..235e452 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeComparisonMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3777ff31cb318a8488a68226f53f7381 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs new file mode 100644 index 0000000..6562ecc --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs @@ -0,0 +1,618 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Threading; + +namespace MonoFN.Cecil { + + public sealed class TypeDefinition : TypeReference, IMemberDefinition, ISecurityDeclarationProvider { + + uint attributes; + TypeReference base_type; + internal Range fields_range; + internal Range methods_range; + + short packing_size = Mixin.NotResolvedMarker; + int class_size = Mixin.NotResolvedMarker; + + InterfaceImplementationCollection interfaces; + Collection nested_types; + Collection methods; + Collection fields; + Collection events; + Collection properties; + Collection custom_attributes; + Collection security_declarations; + + public TypeAttributes Attributes { + get { return (TypeAttributes)attributes; } + set { + if (IsWindowsRuntimeProjection && (ushort)value != attributes) + throw new InvalidOperationException (); + + attributes = (uint)value; + } + } + + public TypeReference BaseType { + get { return base_type; } + set { base_type = value; } + } + + public override string Name { + get { return base.Name; } + set { + if (IsWindowsRuntimeProjection && value != base.Name) + throw new InvalidOperationException (); + + base.Name = value; + } + } + + void ResolveLayout () + { + if (!HasImage) { + packing_size = Mixin.NoDataMarker; + class_size = Mixin.NoDataMarker; + return; + } + + lock (Module.SyncRoot) { + if (packing_size != Mixin.NotResolvedMarker || class_size != Mixin.NotResolvedMarker) + return; + + var row = Module.Read (this, (type, reader) => reader.ReadTypeLayout (type)); + + packing_size = row.Col1; + class_size = row.Col2; + } + } + + public bool HasLayoutInfo { + get { + if (packing_size >= 0 || class_size >= 0) + return true; + + ResolveLayout (); + + return packing_size >= 0 || class_size >= 0; + } + } + + public short PackingSize { + get { + if (packing_size >= 0) + return packing_size; + + ResolveLayout (); + + return packing_size >= 0 ? packing_size : (short)-1; + } + set { packing_size = value; } + } + + public int ClassSize { + get { + if (class_size >= 0) + return class_size; + + ResolveLayout (); + + return class_size >= 0 ? class_size : -1; + } + set { class_size = value; } + } + + public bool HasInterfaces { + get { + if (interfaces != null) + return interfaces.Count > 0; + + return HasImage && Module.Read (this, (type, reader) => reader.HasInterfaces (type)); + } + } + + public Collection Interfaces { + get { + if (interfaces != null) + return interfaces; + + if (HasImage) + return Module.Read (ref interfaces, this, (type, reader) => reader.ReadInterfaces (type)); + + Interlocked.CompareExchange (ref interfaces, new InterfaceImplementationCollection (this), null); + return interfaces; + } + } + + public bool HasNestedTypes { + get { + if (nested_types != null) + return nested_types.Count > 0; + + return HasImage && Module.Read (this, (type, reader) => reader.HasNestedTypes (type)); + } + } + + public Collection NestedTypes { + get { + if (nested_types != null) + return nested_types; + + if (HasImage) + return Module.Read (ref nested_types, this, (type, reader) => reader.ReadNestedTypes (type)); + + Interlocked.CompareExchange (ref nested_types, new MemberDefinitionCollection (this), null); + return nested_types; + } + } + + public bool HasMethods { + get { + if (methods != null) + return methods.Count > 0; + + return HasImage && methods_range.Length > 0; + } + } + + public Collection Methods { + get { + if (methods != null) + return methods; + + if (HasImage) + return Module.Read (ref methods, this, (type, reader) => reader.ReadMethods (type)); + + Interlocked.CompareExchange (ref methods, new MemberDefinitionCollection (this), null); + return methods; + } + } + + public bool HasFields { + get { + if (fields != null) + return fields.Count > 0; + + return HasImage && fields_range.Length > 0; + } + } + + public Collection Fields { + get { + if (fields != null) + return fields; + + if (HasImage) + return Module.Read (ref fields, this, (type, reader) => reader.ReadFields (type)); + + Interlocked.CompareExchange (ref fields, new MemberDefinitionCollection (this), null); + return fields; + } + } + + public bool HasEvents { + get { + if (events != null) + return events.Count > 0; + + return HasImage && Module.Read (this, (type, reader) => reader.HasEvents (type)); + } + } + + public Collection Events { + get { + if (events != null) + return events; + + if (HasImage) + return Module.Read (ref events, this, (type, reader) => reader.ReadEvents (type)); + + Interlocked.CompareExchange (ref events, new MemberDefinitionCollection (this), null); + return events; + } + } + + public bool HasProperties { + get { + if (properties != null) + return properties.Count > 0; + + return HasImage && Module.Read (this, (type, reader) => reader.HasProperties (type)); + } + } + + public Collection Properties { + get { + if (properties != null) + return properties; + + if (HasImage) + return Module.Read (ref properties, this, (type, reader) => reader.ReadProperties (type)); + + Interlocked.CompareExchange (ref properties, new MemberDefinitionCollection (this), null); + return properties; + } + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (Module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } + } + + public override bool HasGenericParameters { + get { + if (generic_parameters != null) + return generic_parameters.Count > 0; + + return this.GetHasGenericParameters (Module); + } + } + + public override Collection GenericParameters { + get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); } + } + + #region TypeAttributes + + public bool IsNotPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NotPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NotPublic, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.Public, value); } + } + + public bool IsNestedPublic { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPublic, value); } + } + + public bool IsNestedPrivate { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPrivate); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedPrivate, value); } + } + + public bool IsNestedFamily { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamily); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamily, value); } + } + + public bool IsNestedAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedAssembly); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedAssembly, value); } + } + + public bool IsNestedFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamANDAssem, value); } + } + + public bool IsNestedFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.VisibilityMask, (uint)TypeAttributes.NestedFamORAssem, value); } + } + + public bool IsAutoLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.AutoLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.AutoLayout, value); } + } + + public bool IsSequentialLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.SequentialLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.SequentialLayout, value); } + } + + public bool IsExplicitLayout { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.ExplicitLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.LayoutMask, (uint)TypeAttributes.ExplicitLayout, value); } + } + + public bool IsClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Class); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Class, value); } + } + + public bool IsInterface { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Interface); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.ClassSemanticMask, (uint)TypeAttributes.Interface, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((uint)TypeAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Abstract, value); } + } + + public bool IsSealed { + get { return attributes.GetAttributes ((uint)TypeAttributes.Sealed); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Sealed, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((uint)TypeAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.SpecialName, value); } + } + + public bool IsImport { + get { return attributes.GetAttributes ((uint)TypeAttributes.Import); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Import, value); } + } + + public bool IsSerializable { + get { return attributes.GetAttributes ((uint)TypeAttributes.Serializable); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.Serializable, value); } + } + + public bool IsWindowsRuntime { + get { return attributes.GetAttributes ((uint)TypeAttributes.WindowsRuntime); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.WindowsRuntime, value); } + } + + public bool IsAnsiClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AnsiClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AnsiClass, value); } + } + + public bool IsUnicodeClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.UnicodeClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.UnicodeClass, value); } + } + + public bool IsAutoClass { + get { return attributes.GetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AutoClass); } + set { attributes = attributes.SetMaskedAttributes ((uint)TypeAttributes.StringFormatMask, (uint)TypeAttributes.AutoClass, value); } + } + + public bool IsBeforeFieldInit { + get { return attributes.GetAttributes ((uint)TypeAttributes.BeforeFieldInit); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.BeforeFieldInit, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((uint)TypeAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((uint)TypeAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((uint)TypeAttributes.HasSecurity, value); } + } + + #endregion + + public bool IsEnum { + get { return base_type != null && base_type.IsTypeOf ("System", "Enum"); } + } + + public override bool IsValueType { + get { + if (base_type == null) + return false; + + return base_type.IsTypeOf ("System", "Enum") || (base_type.IsTypeOf ("System", "ValueType") && !this.IsTypeOf ("System", "Enum")); + } + set { + throw new NotSupportedException (); + } + } + + public override bool IsPrimitive { + get { + ElementType primitive_etype; + return MetadataSystem.TryGetPrimitiveElementType (this, out primitive_etype) && primitive_etype.IsPrimitive (); + } + } + + public override MetadataType MetadataType { + get { + ElementType primitive_etype; + if (MetadataSystem.TryGetPrimitiveElementType (this, out primitive_etype)) + return (MetadataType)primitive_etype; + + return base.MetadataType; + } + } + + public override bool IsDefinition { + get { return true; } + } + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition)base.DeclaringType; } + set { base.DeclaringType = value; } + } + + internal new TypeDefinitionProjection WindowsRuntimeProjection { + get { return (TypeDefinitionProjection)projection; } + set { projection = value; } + } + + public TypeDefinition (string @namespace, string name, TypeAttributes attributes) + : base (@namespace, name) + { + this.attributes = (uint)attributes; + this.token = new MetadataToken (TokenType.TypeDef); + } + + public TypeDefinition (string @namespace, string name, TypeAttributes attributes, TypeReference baseType) : + this (@namespace, name, attributes) + { + this.BaseType = baseType; + } + + protected override void ClearFullName () + { + base.ClearFullName (); + + if (!HasNestedTypes) + return; + + var nested_types = this.NestedTypes; + + for (int i = 0; i < nested_types.Count; i++) + nested_types [i].ClearFullName (); + } + + public override TypeDefinition Resolve () + { + return this; + } + } + + public sealed class InterfaceImplementation : ICustomAttributeProvider { + internal TypeDefinition type; + internal MetadataToken token; + + TypeReference interface_type; + Collection custom_attributes; + + public TypeReference InterfaceType { + get { return interface_type; } + set { interface_type = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + if (type == null) + return false; + + return this.GetHasCustomAttributes (type.Module); + } + } + + public Collection CustomAttributes { + get { + if (type == null) { + if (custom_attributes == null) + Interlocked.CompareExchange (ref custom_attributes, new Collection (), null); + return custom_attributes; + } + + return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, type.Module)); + } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal InterfaceImplementation (TypeReference interfaceType, MetadataToken token) + { + this.interface_type = interfaceType; + this.token = token; + } + + public InterfaceImplementation (TypeReference interfaceType) + { + Mixin.CheckType (interfaceType, Mixin.Argument.interfaceType); + + this.interface_type = interfaceType; + this.token = new MetadataToken (TokenType.InterfaceImpl); + } + } + + class InterfaceImplementationCollection : Collection { + readonly TypeDefinition type; + + internal InterfaceImplementationCollection (TypeDefinition type) + { + this.type = type; + } + + internal InterfaceImplementationCollection (TypeDefinition type, int length) + : base (length) + { + this.type = type; + } + + protected override void OnAdd (InterfaceImplementation item, int index) + { + item.type = type; + } + + protected override void OnInsert (InterfaceImplementation item, int index) + { + item.type = type; + } + + protected override void OnSet (InterfaceImplementation item, int index) + { + item.type = type; + } + + protected override void OnRemove (InterfaceImplementation item, int index) + { + item.type = null; + } + } + + static partial class Mixin { + + public static TypeReference GetEnumUnderlyingType (this TypeDefinition self) + { + var fields = self.Fields; + + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + if (!field.IsStatic) + return field.FieldType; + } + + throw new ArgumentException (); + } + + public static TypeDefinition GetNestedType (this TypeDefinition self, string fullname) + { + if (!self.HasNestedTypes) + return null; + + var nested_types = self.NestedTypes; + + for (int i = 0; i < nested_types.Count; i++) { + var nested_type = nested_types [i]; + + if (nested_type.TypeFullName () == fullname) + return nested_type; + } + + return null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs.meta new file mode 100644 index 0000000..c55bd55 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4616a4ea6dc219f419ae9ba98109f98c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs new file mode 100644 index 0000000..aa07389 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs @@ -0,0 +1,98 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; + +namespace MonoFN.Cecil { + + using Slot = Row; + + sealed class TypeDefinitionCollection : Collection { + + readonly ModuleDefinition container; + readonly Dictionary name_cache; + + internal TypeDefinitionCollection (ModuleDefinition container) + { + this.container = container; + this.name_cache = new Dictionary (new RowEqualityComparer ()); + } + + internal TypeDefinitionCollection (ModuleDefinition container, int capacity) + : base (capacity) + { + this.container = container; + this.name_cache = new Dictionary (capacity, new RowEqualityComparer ()); + } + + protected override void OnAdd (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnSet (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnInsert (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnRemove (TypeDefinition item, int index) + { + Detach (item); + } + + protected override void OnClear () + { + foreach (var type in this) + Detach (type); + } + + void Attach (TypeDefinition type) + { + if (type.Module != null && type.Module != container) + throw new ArgumentException ("Type already attached"); + + type.module = container; + type.scope = container; + name_cache [new Slot (type.Namespace, type.Name)] = type; + } + + void Detach (TypeDefinition type) + { + type.module = null; + type.scope = null; + name_cache.Remove (new Slot (type.Namespace, type.Name)); + } + + public TypeDefinition GetType (string fullname) + { + string @namespace, name; + TypeParser.SplitFullName (fullname, out @namespace, out name); + + return GetType (@namespace, name); + } + + public TypeDefinition GetType (string @namespace, string name) + { + TypeDefinition type; + if (name_cache.TryGetValue (new Slot (@namespace, name), out type)) + return type; + + return null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs.meta new file mode 100644 index 0000000..e800734 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeDefinitionCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4440ec34ba0da7b4aac0fc4c009035aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs new file mode 100644 index 0000000..c533b98 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs @@ -0,0 +1,531 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using System; +using System.Text; + +namespace MonoFN.Cecil { + + class TypeParser { + + class Type { + public const int Ptr = -1; + public const int ByRef = -2; + public const int SzArray = -3; + + public string type_fullname; + public string [] nested_names; + public int arity; + public int [] specs; + public Type [] generic_arguments; + public string assembly; + } + + readonly string fullname; + readonly int length; + + int position; + + TypeParser (string fullname) + { + this.fullname = fullname; + this.length = fullname.Length; + } + + Type ParseType (bool fq_name) + { + var type = new Type (); + type.type_fullname = ParsePart (); + + type.nested_names = ParseNestedNames (); + + if (TryGetArity (type)) + type.generic_arguments = ParseGenericArguments (type.arity); + + type.specs = ParseSpecs (); + + if (fq_name) + type.assembly = ParseAssemblyName (); + + return type; + } + + static bool TryGetArity (Type type) + { + int arity = 0; + + TryAddArity (type.type_fullname, ref arity); + + var nested_names = type.nested_names; + if (!nested_names.IsNullOrEmpty ()) { + for (int i = 0; i < nested_names.Length; i++) + TryAddArity (nested_names [i], ref arity); + } + + type.arity = arity; + return arity > 0; + } + + static bool TryGetArity (string name, out int arity) + { + arity = 0; + var index = name.LastIndexOf ('`'); + if (index == -1) + return false; + + return ParseInt32 (name.Substring (index + 1), out arity); + } + + static bool ParseInt32 (string value, out int result) + { + return int.TryParse (value, out result); + } + + static void TryAddArity (string name, ref int arity) + { + int type_arity; + if (!TryGetArity (name, out type_arity)) + return; + + arity += type_arity; + } + + string ParsePart () + { + var part = new StringBuilder (); + while (position < length && !IsDelimiter (fullname [position])) { + if (fullname [position] == '\\') + position++; + + part.Append (fullname [position++]); + } + + return part.ToString (); + } + + static bool IsDelimiter (char chr) + { + return "+,[]*&".IndexOf (chr) != -1; + } + + void TryParseWhiteSpace () + { + while (position < length && Char.IsWhiteSpace (fullname [position])) + position++; + } + + string [] ParseNestedNames () + { + string [] nested_names = null; + while (TryParse ('+')) + Add (ref nested_names, ParsePart ()); + + return nested_names; + } + + bool TryParse (char chr) + { + if (position < length && fullname [position] == chr) { + position++; + return true; + } + + return false; + } + + static void Add (ref T [] array, T item) + { + array = array.Add (item); + } + + int [] ParseSpecs () + { + int [] specs = null; + + while (position < length) { + switch (fullname [position]) { + case '*': + position++; + Add (ref specs, Type.Ptr); + break; + case '&': + position++; + Add (ref specs, Type.ByRef); + break; + case '[': + position++; + switch (fullname [position]) { + case ']': + position++; + Add (ref specs, Type.SzArray); + break; + case '*': + position++; + Add (ref specs, 1); + break; + default: + var rank = 1; + while (TryParse (',')) + rank++; + + Add (ref specs, rank); + + TryParse (']'); + break; + } + break; + default: + return specs; + } + } + + return specs; + } + + Type [] ParseGenericArguments (int arity) + { + Type [] generic_arguments = null; + + if (position == length || fullname [position] != '[') + return generic_arguments; + + TryParse ('['); + + for (int i = 0; i < arity; i++) { + var fq_argument = TryParse ('['); + Add (ref generic_arguments, ParseType (fq_argument)); + if (fq_argument) + TryParse (']'); + + TryParse (','); + TryParseWhiteSpace (); + } + + TryParse (']'); + + return generic_arguments; + } + + string ParseAssemblyName () + { + if (!TryParse (',')) + return string.Empty; + + TryParseWhiteSpace (); + + var start = position; + while (position < length) { + var chr = fullname [position]; + if (chr == '[' || chr == ']') + break; + + position++; + } + + return fullname.Substring (start, position - start); + } + + public static TypeReference ParseType (ModuleDefinition module, string fullname, bool typeDefinitionOnly = false) + { + if (string.IsNullOrEmpty (fullname)) + return null; + + var parser = new TypeParser (fullname); + return GetTypeReference (module, parser.ParseType (true), typeDefinitionOnly); + } + + static TypeReference GetTypeReference (ModuleDefinition module, Type type_info, bool type_def_only) + { + TypeReference type; + if (!TryGetDefinition (module, type_info, out type)) { + if (type_def_only) + return null; + + type = CreateReference (type_info, module, GetMetadataScope (module, type_info)); + } + + return CreateSpecs (type, type_info); + } + + static TypeReference CreateSpecs (TypeReference type, Type type_info) + { + type = TryCreateGenericInstanceType (type, type_info); + + var specs = type_info.specs; + if (specs.IsNullOrEmpty ()) + return type; + + for (int i = 0; i < specs.Length; i++) { + switch (specs [i]) { + case Type.Ptr: + type = new PointerType (type); + break; + case Type.ByRef: + type = new ByReferenceType (type); + break; + case Type.SzArray: + type = new ArrayType (type); + break; + default: + var array = new ArrayType (type); + array.Dimensions.Clear (); + + for (int j = 0; j < specs [i]; j++) + array.Dimensions.Add (new ArrayDimension ()); + + type = array; + break; + } + } + + return type; + } + + static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info) + { + var generic_arguments = type_info.generic_arguments; + if (generic_arguments.IsNullOrEmpty ()) + return type; + + var instance = new GenericInstanceType (type, generic_arguments.Length); + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < generic_arguments.Length; i++) + instance_arguments.Add (GetTypeReference (type.Module, generic_arguments [i], false)); + + return instance; + } + + public static void SplitFullName (string fullname, out string @namespace, out string name) + { + var last_dot = fullname.LastIndexOf ('.'); + + if (last_dot == -1) { + @namespace = string.Empty; + name = fullname; + } else { + @namespace = fullname.Substring (0, last_dot); + name = fullname.Substring (last_dot + 1); + } + } + + static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope) + { + string @namespace, name; + SplitFullName (type_info.type_fullname, out @namespace, out name); + + var type = new TypeReference (@namespace, name, module, scope); + MetadataSystem.TryProcessPrimitiveTypeReference (type); + + AdjustGenericParameters (type); + + var nested_names = type_info.nested_names; + if (nested_names.IsNullOrEmpty ()) + return type; + + for (int i = 0; i < nested_names.Length; i++) { + type = new TypeReference (string.Empty, nested_names [i], module, null) { + DeclaringType = type, + }; + + AdjustGenericParameters (type); + } + + return type; + } + + static void AdjustGenericParameters (TypeReference type) + { + int arity; + if (!TryGetArity (type.Name, out arity)) + return; + + for (int i = 0; i < arity; i++) + type.GenericParameters.Add (new GenericParameter (type)); + } + + static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info) + { + if (string.IsNullOrEmpty (type_info.assembly)) + return module.TypeSystem.CoreLibrary; + + AssemblyNameReference match; + var reference = AssemblyNameReference.Parse (type_info.assembly); + + return module.TryGetAssemblyNameReference (reference, out match) + ? match + : reference; + } + + static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type) + { + type = null; + if (!TryCurrentModule (module, type_info)) + return false; + + var typedef = module.GetType (type_info.type_fullname); + if (typedef == null) + return false; + + var nested_names = type_info.nested_names; + if (!nested_names.IsNullOrEmpty ()) { + for (int i = 0; i < nested_names.Length; i++) { + var nested_type = typedef.GetNestedType (nested_names [i]); + if (nested_type == null) + return false; + + typedef = nested_type; + } + } + + type = typedef; + return true; + } + + static bool TryCurrentModule (ModuleDefinition module, Type type_info) + { + if (string.IsNullOrEmpty (type_info.assembly)) + return true; + + if (module.assembly != null && module.assembly.Name.FullName == type_info.assembly) + return true; + + return false; + } + + public static string ToParseable (TypeReference type, bool top_level = true) + { + if (type == null) + return null; + + var name = new StringBuilder (); + AppendType (type, name, true, top_level); + return name.ToString (); + } + + static void AppendNamePart (string part, StringBuilder name) + { + foreach (var c in part) { + if (IsDelimiter (c)) + name.Append ('\\'); + + name.Append (c); + } + } + + static void AppendType (TypeReference type, StringBuilder name, bool fq_name, bool top_level) + { + var element_type = type.GetElementType (); + + var declaring_type = element_type.DeclaringType; + if (declaring_type != null) { + AppendType (declaring_type, name, false, top_level); + name.Append ('+'); + } + + var @namespace = type.Namespace; + if (!string.IsNullOrEmpty (@namespace)) { + AppendNamePart (@namespace, name); + name.Append ('.'); + } + + AppendNamePart (element_type.Name, name); + + if (!fq_name) + return; + + if (type.IsTypeSpecification ()) + AppendTypeSpecification ((TypeSpecification)type, name); + + if (RequiresFullyQualifiedName (type, top_level)) { + name.Append (", "); + name.Append (GetScopeFullName (type)); + } + } + + static string GetScopeFullName (TypeReference type) + { + var scope = type.Scope; + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + return ((AssemblyNameReference)scope).FullName; + case MetadataScopeType.ModuleDefinition: + return ((ModuleDefinition)scope).Assembly.Name.FullName; + } + + throw new ArgumentException (); + } + + static void AppendTypeSpecification (TypeSpecification type, StringBuilder name) + { + if (type.ElementType.IsTypeSpecification ()) + AppendTypeSpecification ((TypeSpecification)type.ElementType, name); + + switch (type.etype) { + case ElementType.Ptr: + name.Append ('*'); + break; + case ElementType.ByRef: + name.Append ('&'); + break; + case ElementType.SzArray: + case ElementType.Array: + var array = (ArrayType)type; + if (array.IsVector) { + name.Append ("[]"); + } else { + name.Append ('['); + for (int i = 1; i < array.Rank; i++) + name.Append (','); + name.Append (']'); + } + break; + case ElementType.GenericInst: + var instance = (GenericInstanceType)type; + var arguments = instance.GenericArguments; + + name.Append ('['); + + for (int i = 0; i < arguments.Count; i++) { + if (i > 0) + name.Append (','); + + var argument = arguments [i]; + var requires_fqname = argument.Scope != argument.Module; + + if (requires_fqname) + name.Append ('['); + + AppendType (argument, name, true, false); + + if (requires_fqname) + name.Append (']'); + } + + name.Append (']'); + break; + default: + return; + } + } + + static bool RequiresFullyQualifiedName (TypeReference type, bool top_level) + { + if (type.Scope == type.Module) + return false; + + if (type.Scope.Name == "mscorlib" && top_level) + return false; + + return true; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs.meta new file mode 100644 index 0000000..0cc685b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14cea45910a5fc94ca89429bd0587148 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs new file mode 100644 index 0000000..993daf5 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs @@ -0,0 +1,352 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using MonoFN.Collections.Generic; +using System; +using System.Threading; + +namespace MonoFN.Cecil { + + public enum MetadataType : byte { + Void = ElementType.Void, + Boolean = ElementType.Boolean, + Char = ElementType.Char, + SByte = ElementType.I1, + Byte = ElementType.U1, + Int16 = ElementType.I2, + UInt16 = ElementType.U2, + Int32 = ElementType.I4, + UInt32 = ElementType.U4, + Int64 = ElementType.I8, + UInt64 = ElementType.U8, + Single = ElementType.R4, + Double = ElementType.R8, + String = ElementType.String, + Pointer = ElementType.Ptr, + ByReference = ElementType.ByRef, + ValueType = ElementType.ValueType, + Class = ElementType.Class, + Var = ElementType.Var, + Array = ElementType.Array, + GenericInstance = ElementType.GenericInst, + TypedByReference = ElementType.TypedByRef, + IntPtr = ElementType.I, + UIntPtr = ElementType.U, + FunctionPointer = ElementType.FnPtr, + Object = ElementType.Object, + MVar = ElementType.MVar, + RequiredModifier = ElementType.CModReqD, + OptionalModifier = ElementType.CModOpt, + Sentinel = ElementType.Sentinel, + Pinned = ElementType.Pinned, + } + + public class TypeReference : MemberReference, IGenericParameterProvider, IGenericContext { + + string @namespace; + bool value_type; + internal IMetadataScope scope; + internal ModuleDefinition module; + + internal ElementType etype = ElementType.None; + + string fullname; + + protected Collection generic_parameters; + + public override string Name { + get { return base.Name; } + set { + if (IsWindowsRuntimeProjection && value != base.Name) + throw new InvalidOperationException ("Projected type reference name can't be changed."); + base.Name = value; + ClearFullName (); + } + } + + public virtual string Namespace { + get { return @namespace; } + set { + if (IsWindowsRuntimeProjection && value != @namespace) + throw new InvalidOperationException ("Projected type reference namespace can't be changed."); + @namespace = value; + ClearFullName (); + } + } + + public virtual bool IsValueType { + get { return value_type; } + set { value_type = value; } + } + + public override ModuleDefinition Module { + get { + if (module != null) + return module; + + var declaring_type = this.DeclaringType; + if (declaring_type != null) + return declaring_type.Module; + + return null; + } + } + + internal TypeReferenceProjection WindowsRuntimeProjection { + get { return (TypeReferenceProjection)projection; } + set { projection = value; } + } + + IGenericParameterProvider IGenericContext.Type { + get { return this; } + } + + IGenericParameterProvider IGenericContext.Method { + get { return null; } + } + + GenericParameterType IGenericParameterProvider.GenericParameterType { + get { return GenericParameterType.Type; } + } + + public virtual bool HasGenericParameters { + get { return !generic_parameters.IsNullOrEmpty (); } + } + + public virtual Collection GenericParameters { + get { + if (generic_parameters == null) + Interlocked.CompareExchange (ref generic_parameters, new GenericParameterCollection (this), null); + + return generic_parameters; + } + } + + public virtual IMetadataScope Scope { + get { + var declaring_type = this.DeclaringType; + if (declaring_type != null) + return declaring_type.Scope; + + return scope; + } + set { + var declaring_type = this.DeclaringType; + if (declaring_type != null) { + if (IsWindowsRuntimeProjection && value != declaring_type.Scope) + throw new InvalidOperationException ("Projected type scope can't be changed."); + declaring_type.Scope = value; + return; + } + + if (IsWindowsRuntimeProjection && value != scope) + throw new InvalidOperationException ("Projected type scope can't be changed."); + scope = value; + } + } + + public bool IsNested { + get { return this.DeclaringType != null; } + } + + public override TypeReference DeclaringType { + get { return base.DeclaringType; } + set { + if (IsWindowsRuntimeProjection && value != base.DeclaringType) + throw new InvalidOperationException ("Projected type declaring type can't be changed."); + base.DeclaringType = value; + ClearFullName (); + } + } + + public override string FullName { + get { + if (fullname != null) + return fullname; + + var new_fullname = this.TypeFullName (); + + if (IsNested) + new_fullname = DeclaringType.FullName + "/" + new_fullname; + Interlocked.CompareExchange (ref fullname, new_fullname, null); + return fullname; + } + } + + public virtual bool IsByReference { + get { return false; } + } + + public virtual bool IsPointer { + get { return false; } + } + + public virtual bool IsSentinel { + get { return false; } + } + + public virtual bool IsArray { + get { return false; } + } + + public virtual bool IsGenericParameter { + get { return false; } + } + + public virtual bool IsGenericInstance { + get { return false; } + } + + public virtual bool IsRequiredModifier { + get { return false; } + } + + public virtual bool IsOptionalModifier { + get { return false; } + } + + public virtual bool IsPinned { + get { return false; } + } + + public virtual bool IsFunctionPointer { + get { return false; } + } + + public virtual bool IsPrimitive { + get { return etype.IsPrimitive (); } + } + + public virtual MetadataType MetadataType { + get { + switch (etype) { + case ElementType.None: + return IsValueType ? MetadataType.ValueType : MetadataType.Class; + default: + return (MetadataType)etype; + } + } + } + + protected TypeReference (string @namespace, string name) + : base (name) + { + this.@namespace = @namespace ?? string.Empty; + this.token = new MetadataToken (TokenType.TypeRef, 0); + } + + public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope) + : this (@namespace, name) + { + this.module = module; + this.scope = scope; + } + + public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope, bool valueType) : + this (@namespace, name, module, scope) + { + value_type = valueType; + } + + protected virtual void ClearFullName () + { + this.fullname = null; + } + + public virtual TypeReference GetElementType () + { + return this; + } + + protected override IMemberDefinition ResolveDefinition () + { + return this.Resolve (); + } + + public new virtual TypeDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } + + static partial class Mixin { + + public static bool IsPrimitive (this ElementType self) + { + switch (self) { + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I: + case ElementType.U: + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + case ElementType.I8: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + return true; + default: + return false; + } + } + + public static string TypeFullName (this TypeReference self) + { + return string.IsNullOrEmpty (self.Namespace) + ? self.Name + : self.Namespace + '.' + self.Name; + } + + public static bool IsTypeOf (this TypeReference self, string @namespace, string name) + { + return self.Name == name + && self.Namespace == @namespace; + } + + public static bool IsTypeSpecification (this TypeReference type) + { + switch (type.etype) { + case ElementType.Array: + case ElementType.ByRef: + case ElementType.CModOpt: + case ElementType.CModReqD: + case ElementType.FnPtr: + case ElementType.GenericInst: + case ElementType.MVar: + case ElementType.Pinned: + case ElementType.Ptr: + case ElementType.SzArray: + case ElementType.Sentinel: + case ElementType.Var: + return true; + } + + return false; + } + + public static TypeDefinition CheckedResolve (this TypeReference self) + { + var type = self.Resolve (); + if (type == null) + throw new ResolutionException (self); + + return type; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs.meta new file mode 100644 index 0000000..6133f4f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be8b0c2aa3d8d534a90ff392789fac67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs new file mode 100644 index 0000000..a399fba --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; + +namespace MonoFN.Cecil { + internal sealed class TypeReferenceEqualityComparer : EqualityComparer { + public override bool Equals (TypeReference x, TypeReference y) + { + return AreEqual (x, y); + } + + public override int GetHashCode (TypeReference obj) + { + return GetHashCodeFor (obj); + } + + public static bool AreEqual (TypeReference a, TypeReference b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + if (a == null || b == null) + return false; + + var aMetadataType = a.MetadataType; + var bMetadataType = b.MetadataType; + + if (aMetadataType == MetadataType.GenericInstance || bMetadataType == MetadataType.GenericInstance) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericInstanceType)a, (GenericInstanceType)b, comparisonMode); + } + + if (aMetadataType == MetadataType.Array || bMetadataType == MetadataType.Array) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (ArrayType)a; + var b1 = (ArrayType)b; + if (a1.Rank != b1.Rank) + return false; + + return AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Var || bMetadataType == MetadataType.Var) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericParameter)a, (GenericParameter)b, comparisonMode); + } + + if (aMetadataType == MetadataType.MVar || bMetadataType == MetadataType.MVar) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericParameter)a, (GenericParameter)b, comparisonMode); + } + + if (aMetadataType == MetadataType.ByReference || bMetadataType == MetadataType.ByReference) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((ByReferenceType)a).ElementType, ((ByReferenceType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Pointer || bMetadataType == MetadataType.Pointer) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((PointerType)a).ElementType, ((PointerType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.RequiredModifier || bMetadataType == MetadataType.RequiredModifier) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (RequiredModifierType)a; + var b1 = (RequiredModifierType)b; + + return AreEqual (a1.ModifierType, b1.ModifierType, comparisonMode) && AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.OptionalModifier || bMetadataType == MetadataType.OptionalModifier) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (OptionalModifierType)a; + var b1 = (OptionalModifierType)b; + + return AreEqual (a1.ModifierType, b1.ModifierType, comparisonMode) && AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Pinned || bMetadataType == MetadataType.Pinned) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((PinnedType)a).ElementType, ((PinnedType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Sentinel || bMetadataType == MetadataType.Sentinel) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((SentinelType)a).ElementType, ((SentinelType)b).ElementType, comparisonMode); + } + + if (!a.Name.Equals (b.Name) || !a.Namespace.Equals (b.Namespace)) + return false; + + var xDefinition = a.Resolve (); + var yDefinition = b.Resolve (); + + // For loose signature the types could be in different assemblies, as long as the type names match we will consider them equal + if (comparisonMode == TypeComparisonMode.SignatureOnlyLoose) { + if (xDefinition.Module.Name != yDefinition.Module.Name) + return false; + + if (xDefinition.Module.Assembly.Name.Name != yDefinition.Module.Assembly.Name.Name) + return false; + + return xDefinition.FullName == yDefinition.FullName; + } + + return xDefinition == yDefinition; + } + + static bool AreEqual (GenericParameter a, GenericParameter b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + if (a.Position != b.Position) + return false; + + if (a.Type != b.Type) + return false; + + var aOwnerType = a.Owner as TypeReference; + if (aOwnerType != null && AreEqual (aOwnerType, b.Owner as TypeReference, comparisonMode)) + return true; + + var aOwnerMethod = a.Owner as MethodReference; + if (aOwnerMethod != null && comparisonMode != TypeComparisonMode.SignatureOnlyLoose && MethodReferenceComparer.AreEqual (aOwnerMethod, b.Owner as MethodReference)) + return true; + + return comparisonMode == TypeComparisonMode.SignatureOnly || comparisonMode == TypeComparisonMode.SignatureOnlyLoose; + } + + static bool AreEqual (GenericInstanceType a, GenericInstanceType b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + var aGenericArgumentsCount = a.GenericArguments.Count; + if (aGenericArgumentsCount != b.GenericArguments.Count) + return false; + + if (!AreEqual (a.ElementType, b.ElementType, comparisonMode)) + return false; + + for (int i = 0; i < aGenericArgumentsCount; i++) + if (!AreEqual (a.GenericArguments [i], b.GenericArguments [i], comparisonMode)) + return false; + + return true; + } + + public static int GetHashCodeFor (TypeReference obj) + { + // a very good prime number + const int hashCodeMultiplier = 486187739; + // prime numbers + const int genericInstanceTypeMultiplier = 31; + const int byReferenceMultiplier = 37; + const int pointerMultiplier = 41; + const int requiredModifierMultiplier = 43; + const int optionalModifierMultiplier = 47; + const int pinnedMultiplier = 53; + const int sentinelMultiplier = 59; + + var metadataType = obj.MetadataType; + + if (metadataType == MetadataType.GenericInstance) { + var genericInstanceType = (GenericInstanceType)obj; + var hashCode = GetHashCodeFor (genericInstanceType.ElementType) * hashCodeMultiplier + genericInstanceTypeMultiplier; + for (var i = 0; i < genericInstanceType.GenericArguments.Count; i++) + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (genericInstanceType.GenericArguments [i]); + return hashCode; + } + + if (metadataType == MetadataType.Array) { + var arrayType = (ArrayType)obj; + return GetHashCodeFor (arrayType.ElementType) * hashCodeMultiplier + arrayType.Rank.GetHashCode (); + } + + if (metadataType == MetadataType.Var || metadataType == MetadataType.MVar) { + var genericParameter = (GenericParameter)obj; + var hashCode = genericParameter.Position.GetHashCode () * hashCodeMultiplier + ((int)metadataType).GetHashCode (); + + var ownerTypeReference = genericParameter.Owner as TypeReference; + if (ownerTypeReference != null) + return hashCode * hashCodeMultiplier + GetHashCodeFor (ownerTypeReference); + + var ownerMethodReference = genericParameter.Owner as MethodReference; + if (ownerMethodReference != null) + return hashCode * hashCodeMultiplier + MethodReferenceComparer.GetHashCodeFor (ownerMethodReference); + + throw new InvalidOperationException ("Generic parameter encountered with invalid owner"); + } + + if (metadataType == MetadataType.ByReference) { + var byReferenceType = (ByReferenceType)obj; + return GetHashCodeFor (byReferenceType.ElementType) * hashCodeMultiplier * byReferenceMultiplier; + } + + if (metadataType == MetadataType.Pointer) { + var pointerType = (PointerType)obj; + return GetHashCodeFor (pointerType.ElementType) * hashCodeMultiplier * pointerMultiplier; + } + + if (metadataType == MetadataType.RequiredModifier) { + var requiredModifierType = (RequiredModifierType)obj; + var hashCode = GetHashCodeFor (requiredModifierType.ElementType) * requiredModifierMultiplier; + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (requiredModifierType.ModifierType); + return hashCode; + } + + if (metadataType == MetadataType.OptionalModifier) { + var optionalModifierType = (OptionalModifierType)obj; + var hashCode = GetHashCodeFor (optionalModifierType.ElementType) * optionalModifierMultiplier; + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (optionalModifierType.ModifierType); + return hashCode; + } + + if (metadataType == MetadataType.Pinned) { + var pinnedType = (PinnedType)obj; + return GetHashCodeFor (pinnedType.ElementType) * hashCodeMultiplier * pinnedMultiplier; + } + + if (metadataType == MetadataType.Sentinel) { + var sentinelType = (SentinelType)obj; + return GetHashCodeFor (sentinelType.ElementType) * hashCodeMultiplier * sentinelMultiplier; + } + + if (metadataType == MetadataType.FunctionPointer) { + throw new NotImplementedException ("We currently don't handle function pointer types."); + } + + return obj.Namespace.GetHashCode () * hashCodeMultiplier + obj.FullName.GetHashCode (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs.meta new file mode 100644 index 0000000..e8ce2b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeReferenceEqualityComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e048a822386ae34ab1124eaf29e1d84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs new file mode 100644 index 0000000..69b8507 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs @@ -0,0 +1,220 @@ +using MonoFN.Cecil.Cil; +using System; + +namespace MonoFN.Cecil { + internal sealed class TypeResolver { + private readonly IGenericInstance _typeDefinitionContext; + private readonly IGenericInstance _methodDefinitionContext; + + public static TypeResolver For (TypeReference typeReference) + { + return typeReference.IsGenericInstance ? new TypeResolver ((GenericInstanceType)typeReference) : new TypeResolver (); + } + + public static TypeResolver For (TypeReference typeReference, MethodReference methodReference) + { + return new TypeResolver (typeReference as GenericInstanceType, methodReference as GenericInstanceMethod); + } + + public TypeResolver () + { + + } + + public TypeResolver (GenericInstanceType typeDefinitionContext) + { + _typeDefinitionContext = typeDefinitionContext; + } + + public TypeResolver (GenericInstanceMethod methodDefinitionContext) + { + _methodDefinitionContext = methodDefinitionContext; + } + + public TypeResolver (GenericInstanceType typeDefinitionContext, GenericInstanceMethod methodDefinitionContext) + { + _typeDefinitionContext = typeDefinitionContext; + _methodDefinitionContext = methodDefinitionContext; + } + + public MethodReference Resolve (MethodReference method) + { + var methodReference = method; + if (IsDummy ()) + return methodReference; + + var declaringType = Resolve (method.DeclaringType); + + var genericInstanceMethod = method as GenericInstanceMethod; + if (genericInstanceMethod != null) { + methodReference = new MethodReference (method.Name, method.ReturnType, declaringType); + + foreach (var p in method.Parameters) + methodReference.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, p.ParameterType)); + + foreach (var gp in genericInstanceMethod.ElementMethod.GenericParameters) + methodReference.GenericParameters.Add (new GenericParameter (gp.Name, methodReference)); + + methodReference.HasThis = method.HasThis; + + var m = new GenericInstanceMethod (methodReference); + foreach (var ga in genericInstanceMethod.GenericArguments) { + m.GenericArguments.Add (Resolve (ga)); + } + + methodReference = m; + } else { + methodReference = new MethodReference (method.Name, method.ReturnType, declaringType); + + foreach (var gp in method.GenericParameters) + methodReference.GenericParameters.Add (new GenericParameter (gp.Name, methodReference)); + + foreach (var p in method.Parameters) + methodReference.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, p.ParameterType)); + + methodReference.HasThis = method.HasThis; + } + + + return methodReference; + } + + public FieldReference Resolve (FieldReference field) + { + var declaringType = Resolve (field.DeclaringType); + + if (declaringType == field.DeclaringType) + return field; + + return new FieldReference (field.Name, field.FieldType, declaringType); + } + + public TypeReference ResolveReturnType (MethodReference method) + { + return Resolve (GenericParameterResolver.ResolveReturnTypeIfNeeded (method)); + } + + public TypeReference ResolveParameterType (MethodReference method, ParameterReference parameter) + { + return Resolve (GenericParameterResolver.ResolveParameterTypeIfNeeded (method, parameter)); + } + + public TypeReference ResolveVariableType (MethodReference method, VariableReference variable) + { + return Resolve (GenericParameterResolver.ResolveVariableTypeIfNeeded (method, variable)); + } + + public TypeReference ResolveFieldType (FieldReference field) + { + return Resolve (GenericParameterResolver.ResolveFieldTypeIfNeeded (field)); + } + + public TypeReference Resolve (TypeReference typeReference) + { + return Resolve (typeReference, true); + } + + public TypeReference Resolve (TypeReference typeReference, bool includeTypeDefinitions) + { + if (IsDummy ()) + return typeReference; + + if (_typeDefinitionContext != null && _typeDefinitionContext.GenericArguments.Contains (typeReference)) + return typeReference; + if (_methodDefinitionContext != null && _methodDefinitionContext.GenericArguments.Contains (typeReference)) + return typeReference; + + var genericParameter = typeReference as GenericParameter; + if (genericParameter != null) { + if (_typeDefinitionContext != null && _typeDefinitionContext.GenericArguments.Contains (genericParameter)) + return genericParameter; + if (_methodDefinitionContext != null && _methodDefinitionContext.GenericArguments.Contains (genericParameter)) + return genericParameter; + return ResolveGenericParameter (genericParameter); + } + + var arrayType = typeReference as ArrayType; + if (arrayType != null) + return new ArrayType (Resolve (arrayType.ElementType), arrayType.Rank); + + var pointerType = typeReference as PointerType; + if (pointerType != null) + return new PointerType (Resolve (pointerType.ElementType)); + + var byReferenceType = typeReference as ByReferenceType; + if (byReferenceType != null) + return new ByReferenceType (Resolve (byReferenceType.ElementType)); + + var pinnedType = typeReference as PinnedType; + if (pinnedType != null) + return new PinnedType (Resolve (pinnedType.ElementType)); + + var genericInstanceType = typeReference as GenericInstanceType; + if (genericInstanceType != null) { + var newGenericInstanceType = new GenericInstanceType (genericInstanceType.ElementType); + foreach (var genericArgument in genericInstanceType.GenericArguments) + newGenericInstanceType.GenericArguments.Add (Resolve (genericArgument)); + return newGenericInstanceType; + } + + var requiredModType = typeReference as RequiredModifierType; + if (requiredModType != null) + return Resolve (requiredModType.ElementType, includeTypeDefinitions); + + + if (includeTypeDefinitions) { + var typeDefinition = typeReference as TypeDefinition; + if (typeDefinition != null && typeDefinition.HasGenericParameters) { + var newGenericInstanceType = new GenericInstanceType (typeDefinition); + foreach (var gp in typeDefinition.GenericParameters) + newGenericInstanceType.GenericArguments.Add (Resolve (gp)); + return newGenericInstanceType; + } + } + + if (typeReference is TypeSpecification) + throw new NotSupportedException (string.Format ("The type {0} cannot be resolved correctly.", typeReference.FullName)); + + return typeReference; + } + + internal TypeResolver Nested (GenericInstanceMethod genericInstanceMethod) + { + return new TypeResolver (_typeDefinitionContext as GenericInstanceType, genericInstanceMethod); + } + + private TypeReference ResolveGenericParameter (GenericParameter genericParameter) + { + if (genericParameter.Owner == null) + return HandleOwnerlessInvalidILCode (genericParameter); + + var memberReference = genericParameter.Owner as MemberReference; + if (memberReference == null) + throw new NotSupportedException (); + + return genericParameter.Type == GenericParameterType.Type + ? _typeDefinitionContext.GenericArguments [genericParameter.Position] + : (_methodDefinitionContext != null ? _methodDefinitionContext.GenericArguments [genericParameter.Position] : genericParameter); + } + + private TypeReference HandleOwnerlessInvalidILCode (GenericParameter genericParameter) + { + // NOTE: If owner is null and we have a method parameter, then we'll assume that the method parameter + // is actually a type parameter, and we'll use the type parameter from the corresponding position. I think + // this assumption is valid, but if you're visiting this code then I might have been proven wrong. + if (genericParameter.Type == GenericParameterType.Method && (_typeDefinitionContext != null && genericParameter.Position < _typeDefinitionContext.GenericArguments.Count)) + return _typeDefinitionContext.GenericArguments [genericParameter.Position]; + + // NOTE: Owner cannot be null, but sometimes the Mono compiler generates invalid IL and we + // end up in this situation. + // When we do, we assume that the runtime doesn't care about the resolved type of the GenericParameter, + // thus we return a reference to System.Object. + return genericParameter.Module.TypeSystem.Object; + } + + private bool IsDummy () + { + return _typeDefinitionContext == null && _methodDefinitionContext == null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs.meta new file mode 100644 index 0000000..9b42c4c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94140ae852ea8954489f238f1e59f865 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs new file mode 100644 index 0000000..4be061f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs @@ -0,0 +1,66 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil { + + public abstract class TypeSpecification : TypeReference { + + readonly TypeReference element_type; + + public TypeReference ElementType { + get { return element_type; } + } + + public override string Name { + get { return element_type.Name; } + set { throw new InvalidOperationException (); } + } + + public override string Namespace { + get { return element_type.Namespace; } + set { throw new InvalidOperationException (); } + } + + public override IMetadataScope Scope { + get { return element_type.Scope; } + set { throw new InvalidOperationException (); } + } + + public override ModuleDefinition Module { + get { return element_type.Module; } + } + + public override string FullName { + get { return element_type.FullName; } + } + + public override bool ContainsGenericParameter { + get { return element_type.ContainsGenericParameter; } + } + + public override MetadataType MetadataType { + get { return (MetadataType)etype; } + } + + internal TypeSpecification (TypeReference type) + : base (null, null) + { + this.element_type = type; + this.token = new MetadataToken (TokenType.TypeSpec); + } + + public override TypeReference GetElementType () + { + return element_type.GetElementType (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs.meta new file mode 100644 index 0000000..2d6b903 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSpecification.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c1d979e44d835a4dbcdefa35a45a07a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs new file mode 100644 index 0000000..686156c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs @@ -0,0 +1,330 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Metadata; +using System; + +namespace MonoFN.Cecil { + + public abstract class TypeSystem { + + sealed class CoreTypeSystem : TypeSystem { + + public CoreTypeSystem (ModuleDefinition module) + : base (module) + { + } + + internal override TypeReference LookupType (string @namespace, string name) + { + var type = LookupTypeDefinition (@namespace, name) ?? LookupTypeForwarded (@namespace, name); + if (type != null) + return type; + + throw new NotSupportedException (); + } + + TypeReference LookupTypeDefinition (string @namespace, string name) + { + var metadata = module.MetadataSystem; + if (metadata.Types == null) + Initialize (module.Types); + + return module.Read (new Row (@namespace, name), (row, reader) => { + var types = reader.metadata.Types; + + for (int i = 0; i < types.Length; i++) { + if (types [i] == null) + types [i] = reader.GetTypeDefinition ((uint)i + 1); + + var type = types [i]; + + if (type.Name == row.Col2 && type.Namespace == row.Col1) + return type; + } + + return null; + }); + } + + TypeReference LookupTypeForwarded (string @namespace, string name) + { + if (!module.HasExportedTypes) + return null; + + var exported_types = module.ExportedTypes; + for (int i = 0; i < exported_types.Count; i++) { + var exported_type = exported_types [i]; + + if (exported_type.Name == name && exported_type.Namespace == @namespace) + return exported_type.CreateReference (); + } + + return null; + } + + static void Initialize (object obj) + { + } + } + + sealed class CommonTypeSystem : TypeSystem { + + AssemblyNameReference core_library; + + public CommonTypeSystem (ModuleDefinition module) + : base (module) + { + } + + internal override TypeReference LookupType (string @namespace, string name) + { + return CreateTypeReference (@namespace, name); + } + + public AssemblyNameReference GetCoreLibraryReference () + { + if (core_library != null) + return core_library; + + if (module.TryGetCoreLibraryReference (out core_library)) + return core_library; + + core_library = new AssemblyNameReference { + Name = Mixin.mscorlib, + Version = GetCorlibVersion (), + PublicKeyToken = new byte [] { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }, + }; + + module.AssemblyReferences.Add (core_library); + + return core_library; + } + + Version GetCorlibVersion () + { + switch (module.Runtime) { + case TargetRuntime.Net_1_0: + case TargetRuntime.Net_1_1: + return new Version (1, 0, 0, 0); + case TargetRuntime.Net_2_0: + return new Version (2, 0, 0, 0); + case TargetRuntime.Net_4_0: + return new Version (4, 0, 0, 0); + default: + throw new NotSupportedException (); + } + } + + TypeReference CreateTypeReference (string @namespace, string name) + { + return new TypeReference (@namespace, name, module, GetCoreLibraryReference ()); + } + } + + readonly ModuleDefinition module; + + TypeReference type_object; + TypeReference type_void; + TypeReference type_bool; + TypeReference type_char; + TypeReference type_sbyte; + TypeReference type_byte; + TypeReference type_int16; + TypeReference type_uint16; + TypeReference type_int32; + TypeReference type_uint32; + TypeReference type_int64; + TypeReference type_uint64; + TypeReference type_single; + TypeReference type_double; + TypeReference type_intptr; + TypeReference type_uintptr; + TypeReference type_string; + TypeReference type_typedref; + + TypeSystem (ModuleDefinition module) + { + this.module = module; + } + + internal static TypeSystem CreateTypeSystem (ModuleDefinition module) + { + if (module.IsCoreLibrary ()) + return new CoreTypeSystem (module); + + return new CommonTypeSystem (module); + } + + internal abstract TypeReference LookupType (string @namespace, string name); + + TypeReference LookupSystemType (ref TypeReference reference, string name, ElementType element_type) + { + lock (module.SyncRoot) { + if (reference != null) + return reference; + var type = LookupType ("System", name); + type.etype = element_type; + return reference = type; + } + } + + TypeReference LookupSystemValueType (ref TypeReference typeRef, string name, ElementType element_type) + { + lock (module.SyncRoot) { + if (typeRef != null) + return typeRef; + var type = LookupType ("System", name); + type.etype = element_type; + type.KnownValueType (); + return typeRef = type; + } + } + + [Obsolete ("Use CoreLibrary")] + public IMetadataScope Corlib { + get { return CoreLibrary; } + } + + public IMetadataScope CoreLibrary { + get { + var common = this as CommonTypeSystem; + if (common == null) + return module; + + return common.GetCoreLibraryReference (); + } + } + + public TypeReference Object { + get { return type_object ?? (LookupSystemType (ref type_object, "Object", ElementType.Object)); } + } + + public TypeReference Void { + get { return type_void ?? (LookupSystemType (ref type_void, "Void", ElementType.Void)); } + } + + public TypeReference Boolean { + get { return type_bool ?? (LookupSystemValueType (ref type_bool, "Boolean", ElementType.Boolean)); } + } + + public TypeReference Char { + get { return type_char ?? (LookupSystemValueType (ref type_char, "Char", ElementType.Char)); } + } + + public TypeReference SByte { + get { return type_sbyte ?? (LookupSystemValueType (ref type_sbyte, "SByte", ElementType.I1)); } + } + + public TypeReference Byte { + get { return type_byte ?? (LookupSystemValueType (ref type_byte, "Byte", ElementType.U1)); } + } + + public TypeReference Int16 { + get { return type_int16 ?? (LookupSystemValueType (ref type_int16, "Int16", ElementType.I2)); } + } + + public TypeReference UInt16 { + get { return type_uint16 ?? (LookupSystemValueType (ref type_uint16, "UInt16", ElementType.U2)); } + } + + public TypeReference Int32 { + get { return type_int32 ?? (LookupSystemValueType (ref type_int32, "Int32", ElementType.I4)); } + } + + public TypeReference UInt32 { + get { return type_uint32 ?? (LookupSystemValueType (ref type_uint32, "UInt32", ElementType.U4)); } + } + + public TypeReference Int64 { + get { return type_int64 ?? (LookupSystemValueType (ref type_int64, "Int64", ElementType.I8)); } + } + + public TypeReference UInt64 { + get { return type_uint64 ?? (LookupSystemValueType (ref type_uint64, "UInt64", ElementType.U8)); } + } + + public TypeReference Single { + get { return type_single ?? (LookupSystemValueType (ref type_single, "Single", ElementType.R4)); } + } + + public TypeReference Double { + get { return type_double ?? (LookupSystemValueType (ref type_double, "Double", ElementType.R8)); } + } + + public TypeReference IntPtr { + get { return type_intptr ?? (LookupSystemValueType (ref type_intptr, "IntPtr", ElementType.I)); } + } + + public TypeReference UIntPtr { + get { return type_uintptr ?? (LookupSystemValueType (ref type_uintptr, "UIntPtr", ElementType.U)); } + } + + public TypeReference String { + get { return type_string ?? (LookupSystemType (ref type_string, "String", ElementType.String)); } + } + + public TypeReference TypedReference { + get { return type_typedref ?? (LookupSystemValueType (ref type_typedref, "TypedReference", ElementType.TypedByRef)); } + } + } + + static partial class Mixin { + + public const string mscorlib = "mscorlib"; + public const string system_runtime = "System.Runtime"; + public const string system_private_corelib = "System.Private.CoreLib"; + public const string netstandard = "netstandard"; + + public static bool TryGetCoreLibraryReference (this ModuleDefinition module, out AssemblyNameReference reference) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + reference = references [i]; + if (IsCoreLibrary (reference)) + return true; + } + + reference = null; + return false; + + } + + public static bool IsCoreLibrary (this ModuleDefinition module) + { + if (module.Assembly == null) + return false; + + if (!IsCoreLibrary (module.Assembly.Name)) + return false; + + if (module.HasImage && module.Read (module, (m, reader) => reader.image.GetTableLength (Table.AssemblyRef) > 0)) + return false; + + return true; + } + + public static void KnownValueType (this TypeReference type) + { + if (!type.IsDefinition) + type.IsValueType = true; + } + + static bool IsCoreLibrary (AssemblyNameReference reference) + { + var name = reference.Name; + return name == mscorlib + || name == system_runtime + || name == system_private_corelib + || name == netstandard; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs.meta new file mode 100644 index 0000000..20fec27 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/TypeSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68c81a3fab6a4ee4dbfc5e83e365d1c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs new file mode 100644 index 0000000..9f5ed54 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs @@ -0,0 +1,37 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +namespace MonoFN.Cecil { + + public enum VariantType { + None = 0, + I2 = 2, + I4 = 3, + R4 = 4, + R8 = 5, + CY = 6, + Date = 7, + BStr = 8, + Dispatch = 9, + Error = 10, + Bool = 11, + Variant = 12, + Unknown = 13, + Decimal = 14, + I1 = 16, + UI1 = 17, + UI2 = 18, + UI4 = 19, + I8 = 20, + UI8 = 21, + Int = 22, + UInt = 23 + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs.meta new file mode 100644 index 0000000..5bc5518 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/VariantType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b01b9a572a6975b4c806b3269b858cb1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs new file mode 100644 index 0000000..d505b28 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs @@ -0,0 +1,959 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace MonoFN.Cecil { + + sealed class TypeDefinitionProjection { + + public readonly TypeAttributes Attributes; + public readonly string Name; + public readonly TypeDefinitionTreatment Treatment; + public readonly Collection RedirectedMethods; + public readonly Collection> RedirectedInterfaces; + + public TypeDefinitionProjection (TypeDefinition type, TypeDefinitionTreatment treatment, Collection redirectedMethods, Collection> redirectedInterfaces) + { + Attributes = type.Attributes; + Name = type.Name; + Treatment = treatment; + RedirectedMethods = redirectedMethods; + RedirectedInterfaces = redirectedInterfaces; + } + } + + sealed class TypeReferenceProjection { + + public readonly string Name; + public readonly string Namespace; + public readonly IMetadataScope Scope; + public readonly TypeReferenceTreatment Treatment; + + public TypeReferenceProjection (TypeReference type, TypeReferenceTreatment treatment) + { + Name = type.Name; + Namespace = type.Namespace; + Scope = type.Scope; + Treatment = treatment; + } + } + + sealed class MethodDefinitionProjection { + + public readonly MethodAttributes Attributes; + public readonly MethodImplAttributes ImplAttributes; + public readonly string Name; + public readonly MethodDefinitionTreatment Treatment; + + public MethodDefinitionProjection (MethodDefinition method, MethodDefinitionTreatment treatment) + { + Attributes = method.Attributes; + ImplAttributes = method.ImplAttributes; + Name = method.Name; + Treatment = treatment; + } + } + + sealed class FieldDefinitionProjection { + + public readonly FieldAttributes Attributes; + public readonly FieldDefinitionTreatment Treatment; + + public FieldDefinitionProjection (FieldDefinition field, FieldDefinitionTreatment treatment) + { + Attributes = field.Attributes; + Treatment = treatment; + } + } + + sealed class CustomAttributeValueProjection { + + public readonly AttributeTargets Targets; + public readonly CustomAttributeValueTreatment Treatment; + + public CustomAttributeValueProjection (AttributeTargets targets, CustomAttributeValueTreatment treatment) + { + Targets = targets; + Treatment = treatment; + } + } + + sealed class WindowsRuntimeProjections { + + struct ProjectionInfo { + + public readonly string WinRTNamespace; + public readonly string ClrNamespace; + public readonly string ClrName; + public readonly string ClrAssembly; + public readonly bool Attribute; + + public ProjectionInfo (string winrt_namespace, string clr_namespace, string clr_name, string clr_assembly, bool attribute = false) + { + WinRTNamespace = winrt_namespace; + ClrNamespace = clr_namespace; + ClrName = clr_name; + ClrAssembly = clr_assembly; + Attribute = attribute; + } + } + + static readonly Version version = new Version (4, 0, 0, 0); + + static readonly byte [] contract_pk_token = { + 0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A + }; + + static readonly byte [] contract_pk = { + 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x07, 0xD1, 0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D, + 0xE9, 0xE8, 0xFD, 0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E, + 0xB2, 0x3B, 0xE7, 0x9A, 0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90, + 0x0B, 0x72, 0x3C, 0xF9, 0x80, 0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F, + 0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA, 0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1, + 0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB, 0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D, + 0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5, 0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D, + 0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D, 0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93 + }; + + static Dictionary projections; + + static Dictionary Projections { + get { + if (projections != null) + return projections; + + + var new_projections = new Dictionary { + { "AttributeTargets", new ProjectionInfo ("Windows.Foundation.Metadata", "System", "AttributeTargets", "System.Runtime") }, + { "AttributeUsageAttribute", new ProjectionInfo ("Windows.Foundation.Metadata", "System", "AttributeUsageAttribute", "System.Runtime", attribute: true) }, + { "Color", new ProjectionInfo ("Windows.UI", "Windows.UI", "Color", "System.Runtime.WindowsRuntime") }, + { "CornerRadius", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "CornerRadius", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "DateTime", new ProjectionInfo ("Windows.Foundation", "System", "DateTimeOffset", "System.Runtime") }, + { "Duration", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "Duration", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "DurationType", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "DurationType", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "EventHandler`1", new ProjectionInfo ("Windows.Foundation", "System", "EventHandler`1", "System.Runtime") }, + { "EventRegistrationToken", new ProjectionInfo ("Windows.Foundation", "System.Runtime.InteropServices.WindowsRuntime", "EventRegistrationToken", "System.Runtime.InteropServices.WindowsRuntime") }, + { "GeneratorPosition", new ProjectionInfo ("Windows.UI.Xaml.Controls.Primitives", "Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "GridLength", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "GridLength", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "GridUnitType", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "GridUnitType", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "HResult", new ProjectionInfo ("Windows.Foundation", "System", "Exception", "System.Runtime") }, + { "IBindableIterable", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections", "IEnumerable", "System.Runtime") }, + { "IBindableVector", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections", "IList", "System.Runtime") }, + { "IClosable", new ProjectionInfo ("Windows.Foundation", "System", "IDisposable", "System.Runtime") }, + { "ICommand", new ProjectionInfo ("Windows.UI.Xaml.Input", "System.Windows.Input", "ICommand", "System.ObjectModel") }, + { "IIterable`1", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IEnumerable`1", "System.Runtime") }, + { "IKeyValuePair`2", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "KeyValuePair`2", "System.Runtime") }, + { "IMapView`2", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IReadOnlyDictionary`2", "System.Runtime") }, + { "IMap`2", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IDictionary`2", "System.Runtime") }, + { "INotifyCollectionChanged", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections.Specialized", "INotifyCollectionChanged", "System.ObjectModel") }, + { "INotifyPropertyChanged", new ProjectionInfo ("Windows.UI.Xaml.Data", "System.ComponentModel", "INotifyPropertyChanged", "System.ObjectModel") }, + { "IReference`1", new ProjectionInfo ("Windows.Foundation", "System", "Nullable`1", "System.Runtime") }, + { "IVectorView`1", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IReadOnlyList`1", "System.Runtime") }, + { "IVector`1", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IList`1", "System.Runtime") }, + { "KeyTime", new ProjectionInfo ("Windows.UI.Xaml.Media.Animation", "Windows.UI.Xaml.Media.Animation", "KeyTime", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "Matrix", new ProjectionInfo ("Windows.UI.Xaml.Media", "Windows.UI.Xaml.Media", "Matrix", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "Matrix3D", new ProjectionInfo ("Windows.UI.Xaml.Media.Media3D", "Windows.UI.Xaml.Media.Media3D", "Matrix3D", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "Matrix3x2", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Matrix3x2", "System.Numerics.Vectors") }, + { "Matrix4x4", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Matrix4x4", "System.Numerics.Vectors") }, + { "NotifyCollectionChangedAction", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections.Specialized", "NotifyCollectionChangedAction", "System.ObjectModel") }, + { "NotifyCollectionChangedEventArgs", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections.Specialized", "NotifyCollectionChangedEventArgs", "System.ObjectModel") }, + { "NotifyCollectionChangedEventHandler", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections.Specialized", "NotifyCollectionChangedEventHandler", "System.ObjectModel") }, + { "Plane", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Plane", "System.Numerics.Vectors") }, + { "Point", new ProjectionInfo ("Windows.Foundation", "Windows.Foundation", "Point", "System.Runtime.WindowsRuntime") }, + { "PropertyChangedEventArgs", new ProjectionInfo ("Windows.UI.Xaml.Data", "System.ComponentModel", "PropertyChangedEventArgs", "System.ObjectModel") }, + { "PropertyChangedEventHandler", new ProjectionInfo ("Windows.UI.Xaml.Data", "System.ComponentModel", "PropertyChangedEventHandler", "System.ObjectModel") }, + { "Quaternion", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Quaternion", "System.Numerics.Vectors") }, + { "Rect", new ProjectionInfo ("Windows.Foundation", "Windows.Foundation", "Rect", "System.Runtime.WindowsRuntime") }, + { "RepeatBehavior", new ProjectionInfo ("Windows.UI.Xaml.Media.Animation", "Windows.UI.Xaml.Media.Animation", "RepeatBehavior", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "RepeatBehaviorType", new ProjectionInfo ("Windows.UI.Xaml.Media.Animation", "Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "Size", new ProjectionInfo ("Windows.Foundation", "Windows.Foundation", "Size", "System.Runtime.WindowsRuntime") }, + { "Thickness", new ProjectionInfo ("Windows.UI.Xaml", "Windows.UI.Xaml", "Thickness", "System.Runtime.WindowsRuntime.UI.Xaml") }, + { "TimeSpan", new ProjectionInfo ("Windows.Foundation", "System", "TimeSpan", "System.Runtime") }, + { "TypeName", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System", "Type", "System.Runtime") }, + { "Uri", new ProjectionInfo ("Windows.Foundation", "System", "Uri", "System.Runtime") }, + { "Vector2", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Vector2", "System.Numerics.Vectors") }, + { "Vector3", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Vector3", "System.Numerics.Vectors") }, + { "Vector4", new ProjectionInfo ("Windows.Foundation.Numerics", "System.Numerics", "Vector4", "System.Numerics.Vectors") }, + }; + + Interlocked.CompareExchange (ref projections, new_projections, null); + return projections; + } + } + + readonly ModuleDefinition module; + Version corlib_version = new Version (255, 255, 255, 255); + AssemblyNameReference [] virtual_references; + + AssemblyNameReference [] VirtualReferences { + get { + if (virtual_references == null) { + // force module to read its assembly references. that will in turn initialize virtual_references + Mixin.Read (module.AssemblyReferences); + } + + return virtual_references; + } + } + + public WindowsRuntimeProjections (ModuleDefinition module) + { + this.module = module; + } + + public static void Project (TypeDefinition type) + { + var treatment = TypeDefinitionTreatment.None; + var metadata_kind = type.Module.MetadataKind; + Collection redirectedMethods = null; + Collection> redirectedInterfaces = null; + + if (type.IsWindowsRuntime) { + if (metadata_kind == MetadataKind.WindowsMetadata) { + treatment = GetWellKnownTypeDefinitionTreatment (type); + if (treatment != TypeDefinitionTreatment.None) { + ApplyProjection (type, new TypeDefinitionProjection (type, treatment, redirectedMethods, redirectedInterfaces)); + return; + } + + var base_type = type.BaseType; + if (base_type != null && IsAttribute (base_type)) { + treatment = TypeDefinitionTreatment.NormalAttribute; + } else { + treatment = GenerateRedirectionInformation (type, out redirectedMethods, out redirectedInterfaces); + } + } else if (metadata_kind == MetadataKind.ManagedWindowsMetadata && NeedsWindowsRuntimePrefix (type)) + treatment = TypeDefinitionTreatment.PrefixWindowsRuntimeName; + + if (treatment == TypeDefinitionTreatment.PrefixWindowsRuntimeName || treatment == TypeDefinitionTreatment.NormalType) + if (!type.IsInterface && HasAttribute (type, "Windows.UI.Xaml", "TreatAsAbstractComposableClassAttribute")) + treatment |= TypeDefinitionTreatment.Abstract; + } else if (metadata_kind == MetadataKind.ManagedWindowsMetadata && IsClrImplementationType (type)) + treatment = TypeDefinitionTreatment.UnmangleWindowsRuntimeName; + + if (treatment != TypeDefinitionTreatment.None) + ApplyProjection (type, new TypeDefinitionProjection (type, treatment, redirectedMethods, redirectedInterfaces)); + } + + static TypeDefinitionTreatment GetWellKnownTypeDefinitionTreatment (TypeDefinition type) + { + ProjectionInfo info; + if (!Projections.TryGetValue (type.Name, out info)) + return TypeDefinitionTreatment.None; + + var treatment = info.Attribute ? TypeDefinitionTreatment.RedirectToClrAttribute : TypeDefinitionTreatment.RedirectToClrType; + + if (type.Namespace == info.ClrNamespace) + return treatment; + + if (type.Namespace == info.WinRTNamespace) + return treatment | TypeDefinitionTreatment.Internal; + + return TypeDefinitionTreatment.None; + } + + private static TypeDefinitionTreatment GenerateRedirectionInformation (TypeDefinition type, out Collection redirectedMethods, out Collection> redirectedInterfaces) + { + bool implementsProjectedInterface = false; + redirectedMethods = null; + redirectedInterfaces = null; + + foreach (var implementedInterface in type.Interfaces) { + if (IsRedirectedType (implementedInterface.InterfaceType)) { + implementsProjectedInterface = true; + break; + } + } + + if (!implementsProjectedInterface) + return TypeDefinitionTreatment.NormalType; + + var allImplementedInterfaces = new HashSet (new TypeReferenceEqualityComparer ()); + redirectedMethods = new Collection (); + redirectedInterfaces = new Collection> (); + + foreach (var @interface in type.Interfaces) { + var interfaceType = @interface.InterfaceType; + + if (IsRedirectedType (interfaceType)) { + allImplementedInterfaces.Add (interfaceType); + CollectImplementedInterfaces (interfaceType, allImplementedInterfaces); + } + } + + foreach (var implementedInterface in type.Interfaces) { + var interfaceType = implementedInterface.InterfaceType; + if (IsRedirectedType (implementedInterface.InterfaceType)) { + var etype = interfaceType.GetElementType (); + var unprojectedType = new TypeReference (etype.Namespace, etype.Name, etype.Module, etype.Scope) { + DeclaringType = etype.DeclaringType, + projection = etype.projection + }; + + RemoveProjection (unprojectedType); + + var genericInstanceType = interfaceType as GenericInstanceType; + if (genericInstanceType != null) { + var genericUnprojectedType = new GenericInstanceType (unprojectedType); + foreach (var genericArgument in genericInstanceType.GenericArguments) + genericUnprojectedType.GenericArguments.Add (genericArgument); + + unprojectedType = genericUnprojectedType; + } + + var unprojectedInterface = new InterfaceImplementation (unprojectedType); + redirectedInterfaces.Add (new KeyValuePair (implementedInterface, unprojectedInterface)); + } + } + + // Interfaces don't inherit methods of the interfaces they implement + if (!type.IsInterface) { + foreach (var implementedInterface in allImplementedInterfaces) { + RedirectInterfaceMethods (implementedInterface, redirectedMethods); + } + } + + return TypeDefinitionTreatment.RedirectImplementedMethods; + } + + private static void CollectImplementedInterfaces (TypeReference type, HashSet results) + { + var typeResolver = TypeResolver.For (type); + var typeDef = type.Resolve (); + + foreach (var implementedInterface in typeDef.Interfaces) { + var interfaceType = typeResolver.Resolve (implementedInterface.InterfaceType); + results.Add (interfaceType); + CollectImplementedInterfaces (interfaceType, results); + } + } + + private static void RedirectInterfaceMethods (TypeReference interfaceType, Collection redirectedMethods) + { + var typeResolver = TypeResolver.For (interfaceType); + var typeDef = interfaceType.Resolve (); + + foreach (var method in typeDef.Methods) { + var redirectedMethod = new MethodDefinition (method.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, typeResolver.Resolve (method.ReturnType)); + redirectedMethod.ImplAttributes = MethodImplAttributes.Runtime; + + foreach (var parameter in method.Parameters) { + redirectedMethod.Parameters.Add (new ParameterDefinition (parameter.Name, parameter.Attributes, typeResolver.Resolve (parameter.ParameterType))); + } + + redirectedMethod.Overrides.Add (typeResolver.Resolve (method)); + redirectedMethods.Add (redirectedMethod); + } + } + + private static bool IsRedirectedType (TypeReference type) + { + var typeRefProjection = type.GetElementType ().projection as TypeReferenceProjection; + return typeRefProjection != null && typeRefProjection.Treatment == TypeReferenceTreatment.UseProjectionInfo; + } + + static bool NeedsWindowsRuntimePrefix (TypeDefinition type) + { + if ((type.Attributes & (TypeAttributes.VisibilityMask | TypeAttributes.Interface)) != TypeAttributes.Public) + return false; + + var base_type = type.BaseType; + if (base_type == null || base_type.MetadataToken.TokenType != TokenType.TypeRef) + return false; + + if (base_type.Namespace == "System") + switch (base_type.Name) { + case "Attribute": + case "MulticastDelegate": + case "ValueType": + return false; + } + + return true; + } + + public static bool IsClrImplementationType (TypeDefinition type) + { + if ((type.Attributes & (TypeAttributes.VisibilityMask | TypeAttributes.SpecialName)) != TypeAttributes.SpecialName) + return false; + return type.Name.StartsWith (""); + } + + public static void ApplyProjection (TypeDefinition type, TypeDefinitionProjection projection) + { + if (projection == null) + return; + + var treatment = projection.Treatment; + + switch (treatment & TypeDefinitionTreatment.KindMask) { + case TypeDefinitionTreatment.NormalType: + type.Attributes |= TypeAttributes.WindowsRuntime | TypeAttributes.Import; + break; + + case TypeDefinitionTreatment.NormalAttribute: + type.Attributes |= TypeAttributes.WindowsRuntime | TypeAttributes.Sealed; + break; + + case TypeDefinitionTreatment.UnmangleWindowsRuntimeName: + type.Attributes = type.Attributes & ~TypeAttributes.SpecialName | TypeAttributes.Public; + type.Name = type.Name.Substring ("".Length); + break; + + case TypeDefinitionTreatment.PrefixWindowsRuntimeName: + type.Attributes = type.Attributes & ~TypeAttributes.Public | TypeAttributes.Import; + type.Name = "" + type.Name; + break; + + case TypeDefinitionTreatment.RedirectToClrType: + type.Attributes = type.Attributes & ~TypeAttributes.Public | TypeAttributes.Import; + break; + + case TypeDefinitionTreatment.RedirectToClrAttribute: + type.Attributes = type.Attributes & ~TypeAttributes.Public; + break; + + case TypeDefinitionTreatment.RedirectImplementedMethods: { + type.Attributes |= TypeAttributes.WindowsRuntime | TypeAttributes.Import; + + foreach (var redirectedInterfacePair in projection.RedirectedInterfaces) { + type.Interfaces.Add (redirectedInterfacePair.Value); + + foreach (var customAttribute in redirectedInterfacePair.Key.CustomAttributes) + redirectedInterfacePair.Value.CustomAttributes.Add (customAttribute); + + redirectedInterfacePair.Key.CustomAttributes.Clear (); + + foreach (var method in type.Methods) { + foreach (var @override in method.Overrides) { + if (TypeReferenceEqualityComparer.AreEqual (@override.DeclaringType, redirectedInterfacePair.Key.InterfaceType)) { + @override.DeclaringType = redirectedInterfacePair.Value.InterfaceType; + } + } + } + } + + foreach (var method in projection.RedirectedMethods) { + type.Methods.Add (method); + } + } + break; + } + + if ((treatment & TypeDefinitionTreatment.Abstract) != 0) + type.Attributes |= TypeAttributes.Abstract; + + if ((treatment & TypeDefinitionTreatment.Internal) != 0) + type.Attributes &= ~TypeAttributes.Public; + + type.WindowsRuntimeProjection = projection; + } + + public static TypeDefinitionProjection RemoveProjection (TypeDefinition type) + { + if (!type.IsWindowsRuntimeProjection) + return null; + + var projection = type.WindowsRuntimeProjection; + type.WindowsRuntimeProjection = null; + + type.Attributes = projection.Attributes; + type.Name = projection.Name; + + if (projection.Treatment == TypeDefinitionTreatment.RedirectImplementedMethods) { + foreach (var method in projection.RedirectedMethods) { + type.Methods.Remove (method); + } + + foreach (var redirectedInterfacePair in projection.RedirectedInterfaces) { + foreach (var method in type.Methods) { + foreach (var @override in method.Overrides) { + if (TypeReferenceEqualityComparer.AreEqual (@override.DeclaringType, redirectedInterfacePair.Value.InterfaceType)) { + @override.DeclaringType = redirectedInterfacePair.Key.InterfaceType; + } + } + } + + foreach (var customAttribute in redirectedInterfacePair.Value.CustomAttributes) + redirectedInterfacePair.Key.CustomAttributes.Add (customAttribute); + + redirectedInterfacePair.Value.CustomAttributes.Clear (); + type.Interfaces.Remove (redirectedInterfacePair.Value); + } + } + + return projection; + } + + public static void Project (TypeReference type) + { + TypeReferenceTreatment treatment; + + ProjectionInfo info; + if (Projections.TryGetValue (type.Name, out info) && info.WinRTNamespace == type.Namespace) + treatment = TypeReferenceTreatment.UseProjectionInfo; + else + treatment = GetSpecialTypeReferenceTreatment (type); + + if (treatment != TypeReferenceTreatment.None) + ApplyProjection (type, new TypeReferenceProjection (type, treatment)); + } + + static TypeReferenceTreatment GetSpecialTypeReferenceTreatment (TypeReference type) + { + if (type.Namespace == "System") { + if (type.Name == "MulticastDelegate") + return TypeReferenceTreatment.SystemDelegate; + if (type.Name == "Attribute") + return TypeReferenceTreatment.SystemAttribute; + } + + return TypeReferenceTreatment.None; + } + + static bool IsAttribute (TypeReference type) + { + if (type.MetadataToken.TokenType != TokenType.TypeRef) + return false; + return type.Name == "Attribute" && type.Namespace == "System"; + } + + static bool IsEnum (TypeReference type) + { + if (type.MetadataToken.TokenType != TokenType.TypeRef) + return false; + return type.Name == "Enum" && type.Namespace == "System"; + } + + public static void ApplyProjection (TypeReference type, TypeReferenceProjection projection) + { + if (projection == null) + return; + + switch (projection.Treatment) { + case TypeReferenceTreatment.SystemDelegate: + case TypeReferenceTreatment.SystemAttribute: + type.Scope = type.Module.Projections.GetAssemblyReference ("System.Runtime"); + break; + + case TypeReferenceTreatment.UseProjectionInfo: + var info = Projections [type.Name]; + type.Name = info.ClrName; + type.Namespace = info.ClrNamespace; + type.Scope = type.Module.Projections.GetAssemblyReference (info.ClrAssembly); + break; + } + + type.WindowsRuntimeProjection = projection; + } + + public static TypeReferenceProjection RemoveProjection (TypeReference type) + { + if (!type.IsWindowsRuntimeProjection) + return null; + + var projection = type.WindowsRuntimeProjection; + type.WindowsRuntimeProjection = null; + + type.Name = projection.Name; + type.Namespace = projection.Namespace; + type.Scope = projection.Scope; + + return projection; + } + + public static void Project (MethodDefinition method) + { + var treatment = MethodDefinitionTreatment.None; + var other = false; + var declaring_type = method.DeclaringType; + + if (declaring_type.IsWindowsRuntime) { + if (IsClrImplementationType (declaring_type)) + treatment = MethodDefinitionTreatment.None; + else if (declaring_type.IsNested) + treatment = MethodDefinitionTreatment.None; + else if (declaring_type.IsInterface) + treatment = MethodDefinitionTreatment.Runtime | MethodDefinitionTreatment.InternalCall; + else if (declaring_type.Module.MetadataKind == MetadataKind.ManagedWindowsMetadata && !method.IsPublic) + treatment = MethodDefinitionTreatment.None; + else { + other = true; + + var base_type = declaring_type.BaseType; + if (base_type != null && base_type.MetadataToken.TokenType == TokenType.TypeRef) { + switch (GetSpecialTypeReferenceTreatment (base_type)) { + case TypeReferenceTreatment.SystemDelegate: + treatment = MethodDefinitionTreatment.Runtime | MethodDefinitionTreatment.Public; + other = false; + break; + + case TypeReferenceTreatment.SystemAttribute: + treatment = MethodDefinitionTreatment.Runtime | MethodDefinitionTreatment.InternalCall; + other = false; + break; + } + } + } + } + + if (other) { + var seen_redirected = false; + var seen_non_redirected = false; + + foreach (var @override in method.Overrides) { + if (@override.MetadataToken.TokenType == TokenType.MemberRef && ImplementsRedirectedInterface (@override)) { + seen_redirected = true; + } else { + seen_non_redirected = true; + } + } + + if (seen_redirected && !seen_non_redirected) { + treatment = MethodDefinitionTreatment.Runtime | MethodDefinitionTreatment.InternalCall | MethodDefinitionTreatment.Private; + other = false; + } + } + + if (other) + treatment |= GetMethodDefinitionTreatmentFromCustomAttributes (method); + + if (treatment != MethodDefinitionTreatment.None) + ApplyProjection (method, new MethodDefinitionProjection (method, treatment)); + } + + static MethodDefinitionTreatment GetMethodDefinitionTreatmentFromCustomAttributes (MethodDefinition method) + { + var treatment = MethodDefinitionTreatment.None; + + foreach (var attribute in method.CustomAttributes) { + var type = attribute.AttributeType; + if (type.Namespace != "Windows.UI.Xaml") + continue; + if (type.Name == "TreatAsPublicMethodAttribute") + treatment |= MethodDefinitionTreatment.Public; + else if (type.Name == "TreatAsAbstractMethodAttribute") + treatment |= MethodDefinitionTreatment.Abstract; + } + + return treatment; + } + + public static void ApplyProjection (MethodDefinition method, MethodDefinitionProjection projection) + { + if (projection == null) + return; + + var treatment = projection.Treatment; + + if ((treatment & MethodDefinitionTreatment.Abstract) != 0) + method.Attributes |= MethodAttributes.Abstract; + + if ((treatment & MethodDefinitionTreatment.Private) != 0) + method.Attributes = (method.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Private; + + if ((treatment & MethodDefinitionTreatment.Public) != 0) + method.Attributes = (method.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public; + + if ((treatment & MethodDefinitionTreatment.Runtime) != 0) + method.ImplAttributes |= MethodImplAttributes.Runtime; + + if ((treatment & MethodDefinitionTreatment.InternalCall) != 0) + method.ImplAttributes |= MethodImplAttributes.InternalCall; + + method.WindowsRuntimeProjection = projection; + } + + public static MethodDefinitionProjection RemoveProjection (MethodDefinition method) + { + if (!method.IsWindowsRuntimeProjection) + return null; + + var projection = method.WindowsRuntimeProjection; + method.WindowsRuntimeProjection = null; + + method.Attributes = projection.Attributes; + method.ImplAttributes = projection.ImplAttributes; + method.Name = projection.Name; + + return projection; + } + + public static void Project (FieldDefinition field) + { + var treatment = FieldDefinitionTreatment.None; + var declaring_type = field.DeclaringType; + + if (declaring_type.Module.MetadataKind == MetadataKind.WindowsMetadata && field.IsRuntimeSpecialName && field.Name == "value__") { + var base_type = declaring_type.BaseType; + if (base_type != null && IsEnum (base_type)) + treatment = FieldDefinitionTreatment.Public; + } + + if (treatment != FieldDefinitionTreatment.None) + ApplyProjection (field, new FieldDefinitionProjection (field, treatment)); + } + + public static void ApplyProjection (FieldDefinition field, FieldDefinitionProjection projection) + { + if (projection == null) + return; + + if (projection.Treatment == FieldDefinitionTreatment.Public) + field.Attributes = (field.Attributes & ~FieldAttributes.FieldAccessMask) | FieldAttributes.Public; + + field.WindowsRuntimeProjection = projection; + } + + public static FieldDefinitionProjection RemoveProjection (FieldDefinition field) + { + if (!field.IsWindowsRuntimeProjection) + return null; + + var projection = field.WindowsRuntimeProjection; + field.WindowsRuntimeProjection = null; + + field.Attributes = projection.Attributes; + + return projection; + } + + static bool ImplementsRedirectedInterface (MemberReference member) + { + var declaring_type = member.DeclaringType; + TypeReference type; + switch (declaring_type.MetadataToken.TokenType) { + case TokenType.TypeRef: + type = declaring_type; + break; + + case TokenType.TypeSpec: + if (!declaring_type.IsGenericInstance) + return false; + + type = ((TypeSpecification)declaring_type).ElementType; + if (type.MetadataType != MetadataType.Class || type.MetadataToken.TokenType != TokenType.TypeRef) + return false; + + break; + + default: + return false; + } + + var projection = RemoveProjection (type); + + var found = false; + + ProjectionInfo info; + if (Projections.TryGetValue (type.Name, out info) && type.Namespace == info.WinRTNamespace) { + found = true; + } + + ApplyProjection (type, projection); + + return found; + } + + + public void AddVirtualReferences (Collection references) + { + var corlib = GetCoreLibrary (references); + corlib_version = corlib.Version; + corlib.Version = version; + + if (virtual_references == null) { + var winrt_references = GetAssemblyReferences (corlib); + Interlocked.CompareExchange (ref virtual_references, winrt_references, null); + } + + foreach (var reference in virtual_references) + references.Add (reference); + } + + public void RemoveVirtualReferences (Collection references) + { + var corlib = GetCoreLibrary (references); + corlib.Version = corlib_version; + + foreach (var reference in VirtualReferences) + references.Remove (reference); + } + + static AssemblyNameReference [] GetAssemblyReferences (AssemblyNameReference corlib) + { + var system_runtime = new AssemblyNameReference ("System.Runtime", version); + var system_runtime_interopservices_windowsruntime = new AssemblyNameReference ("System.Runtime.InteropServices.WindowsRuntime", version); + var system_objectmodel = new AssemblyNameReference ("System.ObjectModel", version); + var system_runtime_windowsruntime = new AssemblyNameReference ("System.Runtime.WindowsRuntime", version); + var system_runtime_windowsruntime_ui_xaml = new AssemblyNameReference ("System.Runtime.WindowsRuntime.UI.Xaml", version); + var system_numerics_vectors = new AssemblyNameReference ("System.Numerics.Vectors", version); + + if (corlib.HasPublicKey) { + system_runtime_windowsruntime.PublicKey = + system_runtime_windowsruntime_ui_xaml.PublicKey = corlib.PublicKey; + + system_runtime.PublicKey = + system_runtime_interopservices_windowsruntime.PublicKey = + system_objectmodel.PublicKey = + system_numerics_vectors.PublicKey = contract_pk; + } else { + system_runtime_windowsruntime.PublicKeyToken = + system_runtime_windowsruntime_ui_xaml.PublicKeyToken = corlib.PublicKeyToken; + + system_runtime.PublicKeyToken = + system_runtime_interopservices_windowsruntime.PublicKeyToken = + system_objectmodel.PublicKeyToken = + system_numerics_vectors.PublicKeyToken = contract_pk_token; + } + + return new [] { + system_runtime, + system_runtime_interopservices_windowsruntime, + system_objectmodel, + system_runtime_windowsruntime, + system_runtime_windowsruntime_ui_xaml, + system_numerics_vectors, + }; + } + + static AssemblyNameReference GetCoreLibrary (Collection references) + { + foreach (var reference in references) + if (reference.Name == "mscorlib") + return reference; + + throw new BadImageFormatException ("Missing mscorlib reference in AssemblyRef table."); + } + + AssemblyNameReference GetAssemblyReference (string name) + { + foreach (var assembly in VirtualReferences) + if (assembly.Name == name) + return assembly; + + throw new Exception (); + } + + public static void Project (ICustomAttributeProvider owner, CustomAttribute attribute) + { + if (!IsWindowsAttributeUsageAttribute (owner, attribute)) + return; + + var treatment = CustomAttributeValueTreatment.None; + var type = (TypeDefinition)owner; + + if (type.Namespace == "Windows.Foundation.Metadata") { + if (type.Name == "VersionAttribute") + treatment = CustomAttributeValueTreatment.VersionAttribute; + else if (type.Name == "DeprecatedAttribute") + treatment = CustomAttributeValueTreatment.DeprecatedAttribute; + } + + if (treatment == CustomAttributeValueTreatment.None) { + var multiple = HasAttribute (type, "Windows.Foundation.Metadata", "AllowMultipleAttribute"); + treatment = multiple ? CustomAttributeValueTreatment.AllowMultiple : CustomAttributeValueTreatment.AllowSingle; + } + + if (treatment != CustomAttributeValueTreatment.None) { + var attribute_targets = (AttributeTargets)attribute.ConstructorArguments [0].Value; + ApplyProjection (attribute, new CustomAttributeValueProjection (attribute_targets, treatment)); + } + } + + static bool IsWindowsAttributeUsageAttribute (ICustomAttributeProvider owner, CustomAttribute attribute) + { + if (owner.MetadataToken.TokenType != TokenType.TypeDef) + return false; + + var constructor = attribute.Constructor; + + if (constructor.MetadataToken.TokenType != TokenType.MemberRef) + return false; + + var declaring_type = constructor.DeclaringType; + + if (declaring_type.MetadataToken.TokenType != TokenType.TypeRef) + return false; + + // declaring type is already projected + return declaring_type.Name == "AttributeUsageAttribute" && declaring_type.Namespace == /*"Windows.Foundation.Metadata"*/"System"; + } + + static bool HasAttribute (TypeDefinition type, string @namespace, string name) + { + foreach (var attribute in type.CustomAttributes) { + var attribute_type = attribute.AttributeType; + if (attribute_type.Name == name && attribute_type.Namespace == @namespace) + return true; + } + return false; + } + + public static void ApplyProjection (CustomAttribute attribute, CustomAttributeValueProjection projection) + { + if (projection == null) + return; + + bool version_or_deprecated; + bool multiple; + + switch (projection.Treatment) { + case CustomAttributeValueTreatment.AllowSingle: + version_or_deprecated = false; + multiple = false; + break; + + case CustomAttributeValueTreatment.AllowMultiple: + version_or_deprecated = false; + multiple = true; + break; + + case CustomAttributeValueTreatment.VersionAttribute: + case CustomAttributeValueTreatment.DeprecatedAttribute: + version_or_deprecated = true; + multiple = true; + break; + + default: + throw new ArgumentException (); + } + + var attribute_targets = (AttributeTargets)attribute.ConstructorArguments [0].Value; + if (version_or_deprecated) + attribute_targets |= AttributeTargets.Constructor | AttributeTargets.Property; + attribute.ConstructorArguments [0] = new CustomAttributeArgument (attribute.ConstructorArguments [0].Type, attribute_targets); + + attribute.Properties.Add (new CustomAttributeNamedArgument ("AllowMultiple", new CustomAttributeArgument (attribute.Module.TypeSystem.Boolean, multiple))); + + attribute.projection = projection; + } + + public static CustomAttributeValueProjection RemoveProjection (CustomAttribute attribute) + { + if (attribute.projection == null) + return null; + + var projection = attribute.projection; + attribute.projection = null; + + attribute.ConstructorArguments [0] = new CustomAttributeArgument (attribute.ConstructorArguments [0].Type, projection.Targets); + attribute.Properties.Clear (); + + return projection; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs.meta new file mode 100644 index 0000000..c747763 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil/WindowsRuntimeProjections.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4816f370ee0b9f64ca793643ba5481ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic.meta new file mode 100644 index 0000000..7ec9f6e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc4bc1e600836e94f9bbc5bd8c7cc47a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs new file mode 100644 index 0000000..0c5caf2 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs @@ -0,0 +1,427 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace MonoFN.Collections.Generic { + + public class Collection : IList, IList { + + internal T [] items; + internal int size; + int version; + + public int Count { + get { return size; } + } + + public T this [int index] { + get { + if (index >= size) + throw new ArgumentOutOfRangeException (); + + return items [index]; + } + set { + CheckIndex (index); + if (index == size) + throw new ArgumentOutOfRangeException (); + + OnSet (value, index); + + items [index] = value; + } + } + + public int Capacity { + get { return items.Length; } + set { + if (value < 0 || value < size) + throw new ArgumentOutOfRangeException (); + + Resize (value); + } + } + + bool ICollection.IsReadOnly { + get { return false; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + bool IList.IsReadOnly { + get { return false; } + } + + object IList.this [int index] { + get { return this [index]; } + set { + CheckIndex (index); + + try { + this [index] = (T)value; + return; + } + catch (InvalidCastException) { + } + catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + } + + int ICollection.Count { + get { return Count; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + public Collection () + { + items = Empty.Array; + } + + public Collection (int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException (); + + items = capacity == 0 + ? Empty.Array + : new T [capacity]; + } + + public Collection (ICollection items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + this.items = new T [items.Count]; + items.CopyTo (this.items, 0); + this.size = this.items.Length; + } + + public void Add (T item) + { + if (size == items.Length) + Grow (1); + + OnAdd (item, size); + + items [size++] = item; + version++; + } + + public bool Contains (T item) + { + return IndexOf (item) != -1; + } + + public int IndexOf (T item) + { + return Array.IndexOf (items, item, 0, size); + } + + public void Insert (int index, T item) + { + CheckIndex (index); + if (size == items.Length) + Grow (1); + + OnInsert (item, index); + + Shift (index, 1); + items [index] = item; + version++; + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= size) + throw new ArgumentOutOfRangeException (); + + var item = items [index]; + + OnRemove (item, index); + + Shift (index, -1); + version++; + } + + public bool Remove (T item) + { + var index = IndexOf (item); + if (index == -1) + return false; + + OnRemove (item, index); + + Shift (index, -1); + version++; + + return true; + } + + public void Clear () + { + OnClear (); + + Array.Clear (items, 0, size); + size = 0; + version++; + } + + public void CopyTo (T [] array, int arrayIndex) + { + Array.Copy (items, 0, array, arrayIndex, size); + } + + public T [] ToArray () + { + var array = new T [size]; + Array.Copy (items, 0, array, 0, size); + return array; + } + + void CheckIndex (int index) + { + if (index < 0 || index > size) + throw new ArgumentOutOfRangeException (); + } + + void Shift (int start, int delta) + { + if (delta < 0) + start -= delta; + + if (start < size) + Array.Copy (items, start, items, start + delta, size - start); + + size += delta; + + if (delta < 0) + Array.Clear (items, size, -delta); + } + + protected virtual void OnAdd (T item, int index) + { + } + + protected virtual void OnInsert (T item, int index) + { + } + + protected virtual void OnSet (T item, int index) + { + } + + protected virtual void OnRemove (T item, int index) + { + } + + protected virtual void OnClear () + { + } + + internal virtual void Grow (int desired) + { + int new_size = size + desired; + if (new_size <= items.Length) + return; + + const int default_capacity = 4; + + new_size = System.Math.Max ( + System.Math.Max (items.Length * 2, default_capacity), + new_size); + + Resize (new_size); + } + + protected void Resize (int new_size) + { + if (new_size == size) + return; + if (new_size < size) + throw new ArgumentOutOfRangeException (); + + items = items.Resize (new_size); + } + + int IList.Add (object value) + { + try { + Add ((T)value); + return size - 1; + } + catch (InvalidCastException) { + } + catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + + void IList.Clear () + { + Clear (); + } + + bool IList.Contains (object value) + { + return ((IList)this).IndexOf (value) > -1; + } + + int IList.IndexOf (object value) + { + try { + return IndexOf ((T)value); + } + catch (InvalidCastException) { + } + catch (NullReferenceException) { + } + + return -1; + } + + void IList.Insert (int index, object value) + { + CheckIndex (index); + + try { + Insert (index, (T)value); + return; + } + catch (InvalidCastException) { + } + catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + + void IList.Remove (object value) + { + try { + Remove ((T)value); + } + catch (InvalidCastException) { + } + catch (NullReferenceException) { + } + } + + void IList.RemoveAt (int index) + { + RemoveAt (index); + } + + void ICollection.CopyTo (Array array, int index) + { + Array.Copy (items, 0, array, index, size); + } + + public Enumerator GetEnumerator () + { + return new Enumerator (this); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new Enumerator (this); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new Enumerator (this); + } + + public struct Enumerator : IEnumerator, IDisposable { + + Collection collection; + T current; + + int next; + readonly int version; + + public T Current { + get { return current; } + } + + object IEnumerator.Current { + get { + CheckState (); + + if (next <= 0) + throw new InvalidOperationException (); + + return current; + } + } + + internal Enumerator (Collection collection) + : this () + { + this.collection = collection; + this.version = collection.version; + } + + public bool MoveNext () + { + CheckState (); + + if (next < 0) + return false; + + if (next < collection.size) { + current = collection.items [next++]; + return true; + } + + next = -1; + return false; + } + + public void Reset () + { + CheckState (); + + next = 0; + } + + void CheckState () + { + if (collection == null) + throw new ObjectDisposedException (GetType ().FullName); + + if (version != collection.version) + throw new InvalidOperationException (); + } + + public void Dispose () + { + collection = null; + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs.meta new file mode 100644 index 0000000..01bd872 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/Collection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1f0d8a176addda42a579d710c12a7ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs new file mode 100644 index 0000000..736f1c0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs @@ -0,0 +1,101 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace MonoFN.Collections.Generic { + + public sealed class ReadOnlyCollection : Collection, ICollection, IList { + + static ReadOnlyCollection empty; + + public static ReadOnlyCollection Empty { + get { + if (empty != null) + return empty; + + Interlocked.CompareExchange (ref empty, new ReadOnlyCollection (), null); + return empty; + } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + bool IList.IsReadOnly { + get { return true; } + } + + ReadOnlyCollection () + { + } + + public ReadOnlyCollection (T [] array) + { + if (array == null) + throw new ArgumentNullException (); + + Initialize (array, array.Length); + } + + public ReadOnlyCollection (Collection collection) + { + if (collection == null) + throw new ArgumentNullException (); + + Initialize (collection.items, collection.size); + } + + void Initialize (T [] items, int size) + { + this.items = new T [size]; + Array.Copy (items, 0, this.items, 0, size); + this.size = size; + } + + internal override void Grow (int desired) + { + throw new InvalidOperationException (); + } + + protected override void OnAdd (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnClear () + { + throw new InvalidOperationException (); + } + + protected override void OnInsert (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnRemove (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnSet (T item, int index) + { + throw new InvalidOperationException (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs.meta new file mode 100644 index 0000000..a89c654 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Collections.Generic/ReadOnlyCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d94cb0938831f1349b60e63292a04b67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography.meta new file mode 100644 index 0000000..65c6957 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83669b0a87b783648b0d69a7b37e00ab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs new file mode 100644 index 0000000..c6eacee --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs @@ -0,0 +1,290 @@ +// +// CryptoConvert.cs - Crypto Convertion Routines +// +// Author: +// Sebastien Pouliot +// +// (C) 2003 Motus Technologies Inc. (http://www.motus.com) +// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Security.Cryptography; + +namespace MonoFN.Security.Cryptography { + + static class CryptoConvert { + + static private int ToInt32LE (byte [] bytes, int offset) + { + return (bytes [offset + 3] << 24) | (bytes [offset + 2] << 16) | (bytes [offset + 1] << 8) | bytes [offset]; + } + + static private uint ToUInt32LE (byte [] bytes, int offset) + { + return (uint)((bytes [offset + 3] << 24) | (bytes [offset + 2] << 16) | (bytes [offset + 1] << 8) | bytes [offset]); + } + + static private byte [] GetBytesLE (int val) + { + return new byte [] { + (byte) (val & 0xff), + (byte) ((val >> 8) & 0xff), + (byte) ((val >> 16) & 0xff), + (byte) ((val >> 24) & 0xff) + }; + } + + static private byte [] Trim (byte [] array) + { + for (int i = 0; i < array.Length; i++) { + if (array [i] != 0x00) { + byte [] result = new byte [array.Length - i]; + Buffer.BlockCopy (array, i, result, 0, result.Length); + return result; + } + } + return null; + } + + static RSA FromCapiPrivateKeyBlob (byte [] blob, int offset) + { + RSAParameters rsap = new RSAParameters (); + try { + if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07) + (blob [offset + 1] != 0x02) || // Version (0x02) + (blob [offset + 2] != 0x00) || // Reserved (word) + (blob [offset + 3] != 0x00) || + (ToUInt32LE (blob, offset + 8) != 0x32415352)) // DWORD magic = RSA2 + throw new CryptographicException ("Invalid blob header"); + + // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + // int algId = ToInt32LE (blob, offset+4); + + // DWORD bitlen + int bitLen = ToInt32LE (blob, offset + 12); + + // DWORD public exponent + byte [] exp = new byte [4]; + Buffer.BlockCopy (blob, offset + 16, exp, 0, 4); + Array.Reverse (exp); + rsap.Exponent = Trim (exp); + + int pos = offset + 20; + // BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = (bitLen >> 3); + rsap.Modulus = new byte [byteLen]; + Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse (rsap.Modulus); + pos += byteLen; + + // BYTE prime1[rsapubkey.bitlen/16]; + int byteHalfLen = (byteLen >> 1); + rsap.P = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen); + Array.Reverse (rsap.P); + pos += byteHalfLen; + + // BYTE prime2[rsapubkey.bitlen/16]; + rsap.Q = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen); + Array.Reverse (rsap.Q); + pos += byteHalfLen; + + // BYTE exponent1[rsapubkey.bitlen/16]; + rsap.DP = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen); + Array.Reverse (rsap.DP); + pos += byteHalfLen; + + // BYTE exponent2[rsapubkey.bitlen/16]; + rsap.DQ = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen); + Array.Reverse (rsap.DQ); + pos += byteHalfLen; + + // BYTE coefficient[rsapubkey.bitlen/16]; + rsap.InverseQ = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen); + Array.Reverse (rsap.InverseQ); + pos += byteHalfLen; + + // ok, this is hackish but CryptoAPI support it so... + // note: only works because CRT is used by default + // http://bugzilla.ximian.com/show_bug.cgi?id=57941 + rsap.D = new byte [byteLen]; // must be allocated + if (pos + byteLen + offset <= blob.Length) { + // BYTE privateExponent[rsapubkey.bitlen/8]; + Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen); + Array.Reverse (rsap.D); + } + } + catch (Exception e) { + throw new CryptographicException ("Invalid blob.", e); + } + + RSA rsa = null; + try { + rsa = RSA.Create (); + rsa.ImportParameters (rsap); + } + catch (CryptographicException) { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + bool throws = false; + try { + CspParameters csp = new CspParameters (); + csp.Flags = CspProviderFlags.UseMachineKeyStore; + rsa = new RSACryptoServiceProvider (csp); + rsa.ImportParameters (rsap); + } + catch { + throws = true; + } + + if (throws) { + // rethrow original, not the latter, exception if this fails + throw; + } + } + return rsa; + } + + static RSA FromCapiPublicKeyBlob (byte [] blob, int offset) + { + try { + if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06) + (blob [offset + 1] != 0x02) || // Version (0x02) + (blob [offset + 2] != 0x00) || // Reserved (word) + (blob [offset + 3] != 0x00) || + (ToUInt32LE (blob, offset + 8) != 0x31415352)) // DWORD magic = RSA1 + throw new CryptographicException ("Invalid blob header"); + + // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + // int algId = ToInt32LE (blob, offset+4); + + // DWORD bitlen + int bitLen = ToInt32LE (blob, offset + 12); + + // DWORD public exponent + RSAParameters rsap = new RSAParameters (); + rsap.Exponent = new byte [3]; + rsap.Exponent [0] = blob [offset + 18]; + rsap.Exponent [1] = blob [offset + 17]; + rsap.Exponent [2] = blob [offset + 16]; + + int pos = offset + 20; + // BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = (bitLen >> 3); + rsap.Modulus = new byte [byteLen]; + Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse (rsap.Modulus); + + RSA rsa = null; + try { + rsa = RSA.Create (); + rsa.ImportParameters (rsap); + } + catch (CryptographicException) { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + CspParameters csp = new CspParameters (); + csp.Flags = CspProviderFlags.UseMachineKeyStore; + rsa = new RSACryptoServiceProvider (csp); + rsa.ImportParameters (rsap); + } + return rsa; + } + catch (Exception e) { + throw new CryptographicException ("Invalid blob.", e); + } + } + + // PRIVATEKEYBLOB + // PUBLICKEYBLOB + static public RSA FromCapiKeyBlob (byte [] blob) + { + return FromCapiKeyBlob (blob, 0); + } + + static public RSA FromCapiKeyBlob (byte [] blob, int offset) + { + if (blob == null) + throw new ArgumentNullException ("blob"); + if (offset >= blob.Length) + throw new ArgumentException ("blob is too small."); + + switch (blob [offset]) { + case 0x00: + // this could be a public key inside an header + // like "sn -e" would produce + if (blob [offset + 12] == 0x06) { + return FromCapiPublicKeyBlob (blob, offset + 12); + } + break; + case 0x06: + return FromCapiPublicKeyBlob (blob, offset); + case 0x07: + return FromCapiPrivateKeyBlob (blob, offset); + } + throw new CryptographicException ("Unknown blob format."); + } + + static public byte [] ToCapiPublicKeyBlob (RSA rsa) + { + RSAParameters p = rsa.ExportParameters (false); + int keyLength = p.Modulus.Length; // in bytes + byte [] blob = new byte [20 + keyLength]; + + blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06) + blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) + // [2], [3] // RESERVED - Always 0 + blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN) + blob [8] = 0x52; // Magic - RSA1 (ASCII in hex) + blob [9] = 0x53; + blob [10] = 0x41; + blob [11] = 0x31; + + byte [] bitlen = GetBytesLE (keyLength << 3); + blob [12] = bitlen [0]; // bitlen + blob [13] = bitlen [1]; + blob [14] = bitlen [2]; + blob [15] = bitlen [3]; + + // public exponent (DWORD) + int pos = 16; + int n = p.Exponent.Length; + while (n > 0) + blob [pos++] = p.Exponent [--n]; + // modulus + pos = 20; + byte [] part = p.Modulus; + int len = part.Length; + Array.Reverse (part, 0, len); + Buffer.BlockCopy (part, 0, blob, pos, len); + pos += len; + return blob; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs.meta new file mode 100644 index 0000000..ba086fa --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoConvert.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40b945bb6ba518c4b8ce54b5e54a06b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs new file mode 100644 index 0000000..5582b17 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs @@ -0,0 +1,202 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.PE; +using MonoFN.Security.Cryptography; +using System; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Security.Cryptography; + +namespace MonoFN.Cecil { + + // Most of this code has been adapted + // from Jeroen Frijters' fantastic work + // in IKVM.Reflection.Emit. Thanks! + + static class CryptoService { + + public static byte [] GetPublicKey (WriterParameters parameters) + { + using (var rsa = parameters.CreateRSA ()) { + var cspBlob = CryptoConvert.ToCapiPublicKeyBlob (rsa); + var publicKey = new byte [12 + cspBlob.Length]; + Buffer.BlockCopy (cspBlob, 0, publicKey, 12, cspBlob.Length); + // The first 12 bytes are documented at: + // http://msdn.microsoft.com/library/en-us/cprefadd/html/grfungethashfromfile.asp + // ALG_ID - Signature + publicKey [1] = 36; + // ALG_ID - Hash + publicKey [4] = 4; + publicKey [5] = 128; + // Length of Public Key (in bytes) + publicKey [8] = (byte)(cspBlob.Length >> 0); + publicKey [9] = (byte)(cspBlob.Length >> 8); + publicKey [10] = (byte)(cspBlob.Length >> 16); + publicKey [11] = (byte)(cspBlob.Length >> 24); + return publicKey; + } + } + + public static void StrongName (Stream stream, ImageWriter writer, WriterParameters parameters) + { + int strong_name_pointer; + + var strong_name = CreateStrongName (parameters, HashStream (stream, writer, out strong_name_pointer)); + PatchStrongName (stream, strong_name_pointer, strong_name); + } + + static void PatchStrongName (Stream stream, int strong_name_pointer, byte [] strong_name) + { + stream.Seek (strong_name_pointer, SeekOrigin.Begin); + stream.Write (strong_name, 0, strong_name.Length); + } + + static byte [] CreateStrongName (WriterParameters parameters, byte [] hash) + { + const string hash_algo = "SHA1"; + + using (var rsa = parameters.CreateRSA ()) { + var formatter = new RSAPKCS1SignatureFormatter (rsa); + formatter.SetHashAlgorithm (hash_algo); + + byte [] signature = formatter.CreateSignature (hash); + Array.Reverse (signature); + + return signature; + } + } + + static byte [] HashStream (Stream stream, ImageWriter writer, out int strong_name_pointer) + { + const int buffer_size = 8192; + + var text = writer.text; + var header_size = (int)writer.GetHeaderSize (); + var text_section_pointer = (int)text.PointerToRawData; + var strong_name_directory = writer.GetStrongNameSignatureDirectory (); + + if (strong_name_directory.Size == 0) + throw new InvalidOperationException (); + + strong_name_pointer = (int)(text_section_pointer + + (strong_name_directory.VirtualAddress - text.VirtualAddress)); + var strong_name_length = (int)strong_name_directory.Size; + + var sha1 = new SHA1Managed (); + var buffer = new byte [buffer_size]; + using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) { + stream.Seek (0, SeekOrigin.Begin); + CopyStreamChunk (stream, crypto_stream, buffer, header_size); + + stream.Seek (text_section_pointer, SeekOrigin.Begin); + CopyStreamChunk (stream, crypto_stream, buffer, (int)strong_name_pointer - text_section_pointer); + + stream.Seek (strong_name_length, SeekOrigin.Current); + CopyStreamChunk (stream, crypto_stream, buffer, (int)(stream.Length - (strong_name_pointer + strong_name_length))); + } + + return sha1.Hash; + } + + static void CopyStreamChunk (Stream stream, Stream dest_stream, byte [] buffer, int length) + { + while (length > 0) { + int read = stream.Read (buffer, 0, System.Math.Min (buffer.Length, length)); + dest_stream.Write (buffer, 0, read); + length -= read; + } + } + + public static byte [] ComputeHash (string file) + { + if (!File.Exists (file)) + return Empty.Array; + + using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) + return ComputeHash (stream); + } + + public static byte [] ComputeHash (Stream stream) + { + const int buffer_size = 8192; + + var sha1 = new SHA1Managed (); + var buffer = new byte [buffer_size]; + + using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) + CopyStreamChunk (stream, crypto_stream, buffer, (int)stream.Length); + + return sha1.Hash; + } + + public static byte [] ComputeHash (params ByteBuffer [] buffers) + { + var sha1 = new SHA1Managed (); + + using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) { + for (int i = 0; i < buffers.Length; i++) { + crypto_stream.Write (buffers [i].buffer, 0, buffers [i].length); + } + } + + return sha1.Hash; + } + + public static Guid ComputeGuid (byte [] hash) + { + // From corefx/src/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobContentId.cs + var guid = new byte [16]; + Buffer.BlockCopy (hash, 0, guid, 0, 16); + + // modify the guid data so it decodes to the form of a "random" guid ala rfc4122 + guid [7] = (byte)((guid [7] & 0x0f) | (4 << 4)); + guid [8] = (byte)((guid [8] & 0x3f) | (2 << 6)); + + return new Guid (guid); + } + } + + static partial class Mixin { + + public static RSA CreateRSA (this WriterParameters writer_parameters) + { + byte [] key; + string key_container; + + if (writer_parameters.StrongNameKeyBlob != null) + return CryptoConvert.FromCapiKeyBlob (writer_parameters.StrongNameKeyBlob); + + if (writer_parameters.StrongNameKeyContainer != null) + key_container = writer_parameters.StrongNameKeyContainer; + else if (!TryGetKeyContainer (writer_parameters.StrongNameKeyPair, out key, out key_container)) + return CryptoConvert.FromCapiKeyBlob (key); + + var parameters = new CspParameters { + Flags = CspProviderFlags.UseMachineKeyStore, + KeyContainerName = key_container, + KeyNumber = 2, + }; + + return new RSACryptoServiceProvider (parameters); + } + + static bool TryGetKeyContainer (ISerializable key_pair, out byte [] key, out string key_container) + { + var info = new SerializationInfo (typeof (StrongNameKeyPair), new FormatterConverter ()); + key_pair.GetObjectData (info, new StreamingContext ()); + + key = (byte [])info.GetValue ("_keyPairArray", typeof (byte [])); + key_container = info.GetString ("_keyPairContainer"); + return key_container != null; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs.meta new file mode 100644 index 0000000..13f5dd0 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Security.Cryptography/CryptoService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c49085888b0afc047af3a03b536acdc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.meta new file mode 100644 index 0000000..5cf9349 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e55573663ea38f0408c4c465c48fceac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs new file mode 100644 index 0000000..37c3e93 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs @@ -0,0 +1,45 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN { + + static class Disposable { + + public static Disposable Owned (T value) where T : class, IDisposable + { + return new Disposable (value, owned: true); + } + + public static Disposable NotOwned (T value) where T : class, IDisposable + { + return new Disposable (value, owned: false); + } + } + + struct Disposable : IDisposable where T : class, IDisposable { + + internal readonly T value; + readonly bool owned; + + public Disposable (T value, bool owned) + { + this.value = value; + this.owned = owned; + } + + public void Dispose () + { + if (value != null && owned) + value.Dispose (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs.meta new file mode 100644 index 0000000..03c0571 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Disposable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1aa8d86dc5c9323419e8b535d582fccf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs new file mode 100644 index 0000000..63a91e3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs @@ -0,0 +1,62 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN { + + static class Empty { + + public static readonly T [] Array = new T [0]; + } + + class ArgumentNullOrEmptyException : ArgumentException { + + public ArgumentNullOrEmptyException (string paramName) + : base ("Argument null or empty", paramName) + { + } + } +} + +namespace MonoFN.Cecil { + + static partial class Mixin { + + public static bool IsNullOrEmpty (this T [] self) + { + return self == null || self.Length == 0; + } + + public static bool IsNullOrEmpty (this Collection self) + { + return self == null || self.size == 0; + } + + public static T [] Resize (this T [] self, int length) + { + Array.Resize (ref self, length); + return self; + } + + public static T [] Add (this T [] self, T item) + { + if (self == null) { + self = new [] { item }; + return self; + } + + self = self.Resize (self.Length + 1); + self [self.Length - 1] = item; + return self; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs.meta new file mode 100644 index 0000000..76bd34a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/Empty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4662c38d1a951c24b89aeae3390acd39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs new file mode 100644 index 0000000..4fde695 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs @@ -0,0 +1,66 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; + +namespace MonoFN { + + class MergeSort { + private readonly T [] elements; + private readonly T [] buffer; + private readonly IComparer comparer; + + private MergeSort (T [] elements, IComparer comparer) + { + this.elements = elements; + this.buffer = new T [elements.Length]; + Array.Copy (this.elements, this.buffer, elements.Length); + this.comparer = comparer; + } + + public static void Sort (T [] source, IComparer comparer) + { + Sort (source, 0, source.Length, comparer); + } + + public static void Sort (T [] source, int start, int length, IComparer comparer) + { + new MergeSort (source, comparer).Sort (start, length); + } + + private void Sort (int start, int length) + { + TopDownSplitMerge (this.buffer, this.elements, start, length); + } + + private void TopDownSplitMerge (T [] a, T [] b, int start, int end) + { + if (end - start < 2) + return; + + int middle = (end + start) / 2; + TopDownSplitMerge (b, a, start, middle); + TopDownSplitMerge (b, a, middle, end); + TopDownMerge (a, b, start, middle, end); + } + + private void TopDownMerge (T [] a, T [] b, int start, int middle, int end) + { + for (int i = start, j = middle, k = start; k < end; k++) { + if (i < middle && (j >= end || comparer.Compare (a [i], a [j]) <= 0)) { + b [k] = a [i++]; + } else { + b [k] = a [j++]; + } + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs.meta new file mode 100644 index 0000000..5e6a613 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono/MergeSort.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c35ecf3bff670b4c8b367ed632eee37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef new file mode 100644 index 0000000..c52c300 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef @@ -0,0 +1,15 @@ +{ + "name": "FishNet.Codegen.Cecil", + "references": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": true, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef.meta new file mode 100644 index 0000000..b5ca406 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/MonoFN.Cecil.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 23311a592bb0c5640b641143d87bf5b7 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs new file mode 100644 index 0000000..fe89134 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs @@ -0,0 +1,20 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// +// Licensed under the MIT/X11 license. +// + +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyProduct (Consts.AssemblyName)] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2018 Jb Evain")] + +[assembly: ComVisible (false)] + +[assembly: AssemblyVersion ("0.11.4.0")] +[assembly: AssemblyFileVersion ("0.11.4.0")] +[assembly: AssemblyInformationalVersion ("0.11.4.0")] diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs.meta new file mode 100644 index 0000000..8fac323 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/ProjectInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 468fd5ab13cb01b4381e9c667167b2e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md new file mode 100644 index 0000000..c052e4c --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md @@ -0,0 +1,17 @@ +Cecil +===== + +Mono.Cecil is a library to generate and inspect programs and libraries in the ECMA CIL form. + +To put it simply, you can use Cecil to: + +* Analyze .NET binaries using a simple and powerful object model, without having to load assemblies to use Reflection. +* Modify .NET binaries, add new metadata structures and alter the IL code. + +Cecil has been around since 2004 and is [widely used](https://github.com/jbevain/cecil/wiki/Users) in the .NET community. If you're using Cecil, or depend on a framework, project, or product using it, please consider [sponsoring Cecil](https://github.com/sponsors/jbevain/). + +Read about the Cecil development on the [development log](http://cecil.pe). + +To discuss Cecil, the best place is the [mono-cecil](https://groups.google.com/group/mono-cecil) Google Group. + +Cecil is a project under the benevolent umbrella of the [.NET Foundation](http://www.dotnetfoundation.org/). diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md.meta new file mode 100644 index 0000000..28851a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3bca5ad696a6f8e47b4651fa04b2cd96 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk new file mode 100644 index 0000000000000000000000000000000000000000..c0380d194f28fc76a32d609b60da01d7f75657ff GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50096iT%UggG;A_TF?RUV?t(kNEnx54!(WE| zo@MGjY|$Id%cG-Hy@5ZU6GjEe_m6m7Uv$xpOcIN1B2`p7e>sB3~cm zDW?cfd({<#QDET<$3xN#qdK`)4E<=-dHnFad3ts`>|GE5@D-l+8RrSv6_;LzzU!~G zDm71|RX2O{FNU*iu>_zkxxvYHzN7NP0U`%U6b2c#K#i!@kbU;m&G}wLoGQ8MzvN7I zVps}ItYiDqW&pNdSAEmIua6gslpwgz;|JK$fk347H3pq@PT~VnK2Cagr>-!#sS2uz z?Er147%=gTx1{Lwitv&hd-PjTZ*up+3wSwrgYZA@SdqYdIwefG0Jr1>3uCU`_Oz%+ zMjn{Y&tQb2iHN9%LAqS3jJRp%Gg_`=^CZ;s4Qs6+7iARLaJNyT32*%p!zfQ#{mx4S z^}RMT_mkhK%9Qzrqfd8knqfVM&6bEaW+rN;I$~OI74DrrYP|z(;tRA<^x+KVX6+Tg zCfUqOu zs^7YOICxFn@|;LrrzlTuQ-2P8i@R^W>ZK`(uUnbRg&hZ6grggv>|2HE2rKJ?CnnA8 zR{HQmyK%WDlW?y{ryW|@-1NcKWy;Fh^T>F;uh}LqMwg+;(p+)^E|s(wxvCLpH<1nQ i{y?rxRw8t*>j7s<@|KG8kMC+K`9c~&xPULDw@({VAtYk} literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk.meta new file mode 100644 index 0000000..1ad02ba --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/cecil.snk.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 71693fd731252cb4a9bd4d8abf7846c0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks.meta new file mode 100644 index 0000000..c070af3 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c13f8d2e52ed89246b2f0dbc1f6ba1aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks.meta new file mode 100644 index 0000000..ab82924 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15700071751bd1349a26170e9f6a1f14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs new file mode 100644 index 0000000..4c82583 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs @@ -0,0 +1,15 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +//[assembly: AssemblyTitle ("MonoFN.Cecil.Rocks")] + +[assembly: CLSCompliant (false)] diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs.meta new file mode 100644 index 0000000..a9fbe70 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9ceb0221cb78b247b676d0ea5d57fc8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs new file mode 100644 index 0000000..783dbde --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs @@ -0,0 +1,261 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MonoFN.Cecil.Rocks { + + public class DocCommentId { + StringBuilder id; + + DocCommentId () + { + id = new StringBuilder (); + } + + void WriteField (FieldDefinition field) + { + WriteDefinition ('F', field); + } + + void WriteEvent (EventDefinition @event) + { + WriteDefinition ('E', @event); + } + + void WriteType (TypeDefinition type) + { + id.Append ('T').Append (':'); + WriteTypeFullName (type); + } + + void WriteMethod (MethodDefinition method) + { + WriteDefinition ('M', method); + + if (method.HasGenericParameters) { + id.Append ('`').Append ('`'); + id.Append (method.GenericParameters.Count); + } + + if (method.HasParameters) + WriteParameters (method.Parameters); + + if (IsConversionOperator (method)) + WriteReturnType (method); + } + + static bool IsConversionOperator (MethodDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + return self.IsSpecialName + && (self.Name == "op_Explicit" || self.Name == "op_Implicit"); + } + + void WriteReturnType (MethodDefinition method) + { + id.Append ('~'); + WriteTypeSignature (method.ReturnType); + } + + void WriteProperty (PropertyDefinition property) + { + WriteDefinition ('P', property); + + if (property.HasParameters) + WriteParameters (property.Parameters); + } + + void WriteParameters (IList parameters) + { + id.Append ('('); + WriteList (parameters, p => WriteTypeSignature (p.ParameterType)); + id.Append (')'); + } + + void WriteTypeSignature (TypeReference type) + { + switch (type.MetadataType) { + case MetadataType.Array: + WriteArrayTypeSignature ((ArrayType)type); + break; + case MetadataType.ByReference: + WriteTypeSignature (((ByReferenceType)type).ElementType); + id.Append ('@'); + break; + case MetadataType.FunctionPointer: + WriteFunctionPointerTypeSignature ((FunctionPointerType)type); + break; + case MetadataType.GenericInstance: + WriteGenericInstanceTypeSignature ((GenericInstanceType)type); + break; + case MetadataType.Var: + id.Append ('`'); + id.Append (((GenericParameter)type).Position); + break; + case MetadataType.MVar: + id.Append ('`').Append ('`'); + id.Append (((GenericParameter)type).Position); + break; + case MetadataType.OptionalModifier: + WriteModiferTypeSignature ((OptionalModifierType)type, '!'); + break; + case MetadataType.RequiredModifier: + WriteModiferTypeSignature ((RequiredModifierType)type, '|'); + break; + case MetadataType.Pointer: + WriteTypeSignature (((PointerType)type).ElementType); + id.Append ('*'); + break; + default: + WriteTypeFullName (type); + break; + } + } + + void WriteGenericInstanceTypeSignature (GenericInstanceType type) + { + if (type.ElementType.IsTypeSpecification ()) + throw new NotSupportedException (); + + WriteTypeFullName (type.ElementType, stripGenericArity: true); + id.Append ('{'); + WriteList (type.GenericArguments, WriteTypeSignature); + id.Append ('}'); + } + + void WriteList (IList list, Action action) + { + for (int i = 0; i < list.Count; i++) { + if (i > 0) + id.Append (','); + + action (list [i]); + } + } + + void WriteModiferTypeSignature (IModifierType type, char id) + { + WriteTypeSignature (type.ElementType); + this.id.Append (id); + WriteTypeSignature (type.ModifierType); + } + + void WriteFunctionPointerTypeSignature (FunctionPointerType type) + { + id.Append ("=FUNC:"); + WriteTypeSignature (type.ReturnType); + + if (type.HasParameters) + WriteParameters (type.Parameters); + } + + void WriteArrayTypeSignature (ArrayType type) + { + WriteTypeSignature (type.ElementType); + + if (type.IsVector) { + id.Append ("[]"); + return; + } + + id.Append ("["); + + WriteList (type.Dimensions, dimension => { + if (dimension.LowerBound.HasValue) + id.Append (dimension.LowerBound.Value); + + id.Append (':'); + + if (dimension.UpperBound.HasValue) + id.Append (dimension.UpperBound.Value - (dimension.LowerBound.GetValueOrDefault () + 1)); + }); + + id.Append ("]"); + } + + void WriteDefinition (char id, IMemberDefinition member) + { + this.id.Append (id) + .Append (':'); + + WriteTypeFullName (member.DeclaringType); + this.id.Append ('.'); + WriteItemName (member.Name); + } + + void WriteTypeFullName (TypeReference type, bool stripGenericArity = false) + { + if (type.DeclaringType != null) { + WriteTypeFullName (type.DeclaringType); + id.Append ('.'); + } + + if (!string.IsNullOrEmpty (type.Namespace)) { + id.Append (type.Namespace); + id.Append ('.'); + } + + var name = type.Name; + + if (stripGenericArity) { + var index = name.LastIndexOf ('`'); + if (index > 0) + name = name.Substring (0, index); + } + + id.Append (name); + } + + void WriteItemName (string name) + { + id.Append (name.Replace ('.', '#').Replace ('<', '{').Replace ('>', '}')); + } + + public override string ToString () + { + return id.ToString (); + } + + public static string GetDocCommentId (IMemberDefinition member) + { + if (member == null) + throw new ArgumentNullException ("member"); + + var documentId = new DocCommentId (); + + switch (member.MetadataToken.TokenType) { + case TokenType.Field: + documentId.WriteField ((FieldDefinition)member); + break; + case TokenType.Method: + documentId.WriteMethod ((MethodDefinition)member); + break; + case TokenType.TypeDef: + documentId.WriteType ((TypeDefinition)member); + break; + case TokenType.Event: + documentId.WriteEvent ((EventDefinition)member); + break; + case TokenType.Property: + documentId.WriteProperty ((PropertyDefinition)member); + break; + default: + throw new NotSupportedException (member.FullName); + } + + return documentId.ToString (); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs.meta new file mode 100644 index 0000000..7cc833e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/DocCommentId.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 370e40931a1b9cf478e08e66fd2a9eac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs new file mode 100644 index 0000000..90c24ed --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs @@ -0,0 +1,41 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; + +namespace MonoFN.Cecil.Rocks { + + static class Functional { + + public static System.Func Y (System.Func, System.Func> f) + { + System.Func g = null; + g = f (a => g (a)); + return g; + } + + public static IEnumerable Prepend (this IEnumerable source, TSource element) + { + if (source == null) + throw new ArgumentNullException ("source"); + + return PrependIterator (source, element); + } + + static IEnumerable PrependIterator (IEnumerable source, TSource element) + { + yield return element; + + foreach (var item in source) + yield return item; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs.meta new file mode 100644 index 0000000..15f593e --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/Functional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b481a942e0bdf8649b6b5b20db207190 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs new file mode 100644 index 0000000..9e814a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs @@ -0,0 +1,228 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using MonoFN.Collections.Generic; +using System; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + interface IILVisitor { + void OnInlineNone (OpCode opcode); + void OnInlineSByte (OpCode opcode, sbyte value); + void OnInlineByte (OpCode opcode, byte value); + void OnInlineInt32 (OpCode opcode, int value); + void OnInlineInt64 (OpCode opcode, long value); + void OnInlineSingle (OpCode opcode, float value); + void OnInlineDouble (OpCode opcode, double value); + void OnInlineString (OpCode opcode, string value); + void OnInlineBranch (OpCode opcode, int offset); + void OnInlineSwitch (OpCode opcode, int [] offsets); + void OnInlineVariable (OpCode opcode, VariableDefinition variable); + void OnInlineArgument (OpCode opcode, ParameterDefinition parameter); + void OnInlineSignature (OpCode opcode, CallSite callSite); + void OnInlineType (OpCode opcode, TypeReference type); + void OnInlineField (OpCode opcode, FieldReference field); + void OnInlineMethod (OpCode opcode, MethodReference method); + } + +#if UNITY_EDITOR + public +#endif + static class ILParser { + + class ParseContext { + public CodeReader Code { get; set; } + public int Position { get; set; } + public MetadataReader Metadata { get; set; } + public Collection Variables { get; set; } + public IILVisitor Visitor { get; set; } + } + + public static void Parse (MethodDefinition method, IILVisitor visitor) + { + if (method == null) + throw new ArgumentNullException ("method"); + if (visitor == null) + throw new ArgumentNullException ("visitor"); + if (!method.HasBody || !method.HasImage) + throw new ArgumentException (); + + method.Module.Read (method, (m, _) => { + ParseMethod (m, visitor); + return true; + }); + } + + static void ParseMethod (MethodDefinition method, IILVisitor visitor) + { + var context = CreateContext (method, visitor); + var code = context.Code; + + var flags = code.ReadByte (); + + switch (flags & 0x3) { + case 0x2: // tiny + int code_size = flags >> 2; + ParseCode (code_size, context); + break; + case 0x3: // fat + code.Advance (-1); + ParseFatMethod (context); + break; + default: + throw new NotSupportedException (); + } + + code.MoveBackTo (context.Position); + } + + static ParseContext CreateContext (MethodDefinition method, IILVisitor visitor) + { + var code = method.Module.Read (method, (_, reader) => reader.code); + var position = code.MoveTo (method); + + return new ParseContext { + Code = code, + Position = position, + Metadata = code.reader, + Visitor = visitor, + }; + } + + static void ParseFatMethod (ParseContext context) + { + var code = context.Code; + + code.Advance (4); + var code_size = code.ReadInt32 (); + var local_var_token = code.ReadToken (); + + if (local_var_token != MetadataToken.Zero) + context.Variables = code.ReadVariables (local_var_token); + + ParseCode (code_size, context); + } + + static void ParseCode (int code_size, ParseContext context) + { + var code = context.Code; + var metadata = context.Metadata; + var visitor = context.Visitor; + + var start = code.Position; + var end = start + code_size; + + while (code.Position < end) { + var il_opcode = code.ReadByte (); + var opcode = il_opcode != 0xfe + ? OpCodes.OneByteOpCode [il_opcode] + : OpCodes.TwoBytesOpCode [code.ReadByte ()]; + + switch (opcode.OperandType) { + case OperandType.InlineNone: + visitor.OnInlineNone (opcode); + break; + case OperandType.InlineSwitch: + var length = code.ReadInt32 (); + var branches = new int [length]; + for (int i = 0; i < length; i++) + branches [i] = code.ReadInt32 (); + visitor.OnInlineSwitch (opcode, branches); + break; + case OperandType.ShortInlineBrTarget: + visitor.OnInlineBranch (opcode, code.ReadSByte ()); + break; + case OperandType.InlineBrTarget: + visitor.OnInlineBranch (opcode, code.ReadInt32 ()); + break; + case OperandType.ShortInlineI: + if (opcode == OpCodes.Ldc_I4_S) + visitor.OnInlineSByte (opcode, code.ReadSByte ()); + else + visitor.OnInlineByte (opcode, code.ReadByte ()); + break; + case OperandType.InlineI: + visitor.OnInlineInt32 (opcode, code.ReadInt32 ()); + break; + case OperandType.InlineI8: + visitor.OnInlineInt64 (opcode, code.ReadInt64 ()); + break; + case OperandType.ShortInlineR: + visitor.OnInlineSingle (opcode, code.ReadSingle ()); + break; + case OperandType.InlineR: + visitor.OnInlineDouble (opcode, code.ReadDouble ()); + break; + case OperandType.InlineSig: + visitor.OnInlineSignature (opcode, code.GetCallSite (code.ReadToken ())); + break; + case OperandType.InlineString: + visitor.OnInlineString (opcode, code.GetString (code.ReadToken ())); + break; + case OperandType.ShortInlineArg: + visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadByte ())); + break; + case OperandType.InlineArg: + visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadInt16 ())); + break; + case OperandType.ShortInlineVar: + visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadByte ())); + break; + case OperandType.InlineVar: + visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadInt16 ())); + break; + case OperandType.InlineTok: + case OperandType.InlineField: + case OperandType.InlineMethod: + case OperandType.InlineType: + var member = metadata.LookupToken (code.ReadToken ()); + switch (member.MetadataToken.TokenType) { + case TokenType.TypeDef: + case TokenType.TypeRef: + case TokenType.TypeSpec: + visitor.OnInlineType (opcode, (TypeReference)member); + break; + case TokenType.Method: + case TokenType.MethodSpec: + visitor.OnInlineMethod (opcode, (MethodReference)member); + break; + case TokenType.Field: + visitor.OnInlineField (opcode, (FieldReference)member); + break; + case TokenType.MemberRef: + var field_ref = member as FieldReference; + if (field_ref != null) { + visitor.OnInlineField (opcode, field_ref); + break; + } + + var method_ref = member as MethodReference; + if (method_ref != null) { + visitor.OnInlineMethod (opcode, method_ref); + break; + } + + throw new InvalidOperationException (); + } + break; + } + } + } + + static VariableDefinition GetVariable (ParseContext context, int index) + { + return context.Variables [index]; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs.meta new file mode 100644 index 0000000..65cbdbe --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2916628c81c279046adb746612d6067b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs new file mode 100644 index 0000000..feaabbf --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs @@ -0,0 +1,411 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using MonoFN.Cecil.Cil; +using System; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class MethodBodyRocks { + + public static void SimplifyMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + foreach (var instruction in self.Instructions) { + if (instruction.OpCode.OpCodeType != OpCodeType.Macro) + continue; + + switch (instruction.OpCode.Code) { + case Code.Ldarg_0: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0)); + break; + case Code.Ldarg_1: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1)); + break; + case Code.Ldarg_2: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2)); + break; + case Code.Ldarg_3: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3)); + break; + case Code.Ldloc_0: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]); + break; + case Code.Ldloc_1: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]); + break; + case Code.Ldloc_2: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]); + break; + case Code.Ldloc_3: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]); + break; + case Code.Stloc_0: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]); + break; + case Code.Stloc_1: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]); + break; + case Code.Stloc_2: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]); + break; + case Code.Stloc_3: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]); + break; + case Code.Ldarg_S: + instruction.OpCode = OpCodes.Ldarg; + break; + case Code.Ldarga_S: + instruction.OpCode = OpCodes.Ldarga; + break; + case Code.Starg_S: + instruction.OpCode = OpCodes.Starg; + break; + case Code.Ldloc_S: + instruction.OpCode = OpCodes.Ldloc; + break; + case Code.Ldloca_S: + instruction.OpCode = OpCodes.Ldloca; + break; + case Code.Stloc_S: + instruction.OpCode = OpCodes.Stloc; + break; + case Code.Ldc_I4_M1: + ExpandMacro (instruction, OpCodes.Ldc_I4, -1); + break; + case Code.Ldc_I4_0: + ExpandMacro (instruction, OpCodes.Ldc_I4, 0); + break; + case Code.Ldc_I4_1: + ExpandMacro (instruction, OpCodes.Ldc_I4, 1); + break; + case Code.Ldc_I4_2: + ExpandMacro (instruction, OpCodes.Ldc_I4, 2); + break; + case Code.Ldc_I4_3: + ExpandMacro (instruction, OpCodes.Ldc_I4, 3); + break; + case Code.Ldc_I4_4: + ExpandMacro (instruction, OpCodes.Ldc_I4, 4); + break; + case Code.Ldc_I4_5: + ExpandMacro (instruction, OpCodes.Ldc_I4, 5); + break; + case Code.Ldc_I4_6: + ExpandMacro (instruction, OpCodes.Ldc_I4, 6); + break; + case Code.Ldc_I4_7: + ExpandMacro (instruction, OpCodes.Ldc_I4, 7); + break; + case Code.Ldc_I4_8: + ExpandMacro (instruction, OpCodes.Ldc_I4, 8); + break; + case Code.Ldc_I4_S: + ExpandMacro (instruction, OpCodes.Ldc_I4, (int)(sbyte)instruction.Operand); + break; + case Code.Br_S: + instruction.OpCode = OpCodes.Br; + break; + case Code.Brfalse_S: + instruction.OpCode = OpCodes.Brfalse; + break; + case Code.Brtrue_S: + instruction.OpCode = OpCodes.Brtrue; + break; + case Code.Beq_S: + instruction.OpCode = OpCodes.Beq; + break; + case Code.Bge_S: + instruction.OpCode = OpCodes.Bge; + break; + case Code.Bgt_S: + instruction.OpCode = OpCodes.Bgt; + break; + case Code.Ble_S: + instruction.OpCode = OpCodes.Ble; + break; + case Code.Blt_S: + instruction.OpCode = OpCodes.Blt; + break; + case Code.Bne_Un_S: + instruction.OpCode = OpCodes.Bne_Un; + break; + case Code.Bge_Un_S: + instruction.OpCode = OpCodes.Bge_Un; + break; + case Code.Bgt_Un_S: + instruction.OpCode = OpCodes.Bgt_Un; + break; + case Code.Ble_Un_S: + instruction.OpCode = OpCodes.Ble_Un; + break; + case Code.Blt_Un_S: + instruction.OpCode = OpCodes.Blt_Un; + break; + case Code.Leave_S: + instruction.OpCode = OpCodes.Leave; + break; + } + } + } + + static void ExpandMacro (Instruction instruction, OpCode opcode, object operand) + { + instruction.OpCode = opcode; + instruction.Operand = operand; + } + + static void MakeMacro (Instruction instruction, OpCode opcode) + { + instruction.OpCode = opcode; + instruction.Operand = null; + } + + public static void Optimize (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + OptimizeLongs (self); + OptimizeMacros (self); + } + + static void OptimizeLongs (this MethodBody self) + { + for (var i = 0; i < self.Instructions.Count; i++) { + var instruction = self.Instructions [i]; + if (instruction.OpCode.Code != Code.Ldc_I8) + continue; + var l = (long)instruction.Operand; + if (l >= int.MaxValue || l <= int.MinValue) + continue; + ExpandMacro (instruction, OpCodes.Ldc_I4, (int)l); + self.Instructions.Insert (++i, Instruction.Create (OpCodes.Conv_I8)); + } + } + + public static void OptimizeMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + var method = self.Method; + + foreach (var instruction in self.Instructions) { + int index; + switch (instruction.OpCode.Code) { + case Code.Ldarg: + index = ((ParameterDefinition)instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldarg_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldarg_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldarg_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldarg_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand); + break; + } + break; + case Code.Ldloc: + index = ((VariableDefinition)instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand); + break; + } + break; + case Code.Stloc: + index = ((VariableDefinition)instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Stloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Stloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Stloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Stloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand); + break; + } + break; + case Code.Ldarga: + index = ((ParameterDefinition)instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand); + break; + case Code.Ldloca: + if (((VariableDefinition)instruction.Operand).Index < 256) + ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand); + break; + case Code.Ldc_I4: + int i = (int)instruction.Operand; + switch (i) { + case -1: + MakeMacro (instruction, OpCodes.Ldc_I4_M1); + break; + case 0: + MakeMacro (instruction, OpCodes.Ldc_I4_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldc_I4_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldc_I4_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldc_I4_3); + break; + case 4: + MakeMacro (instruction, OpCodes.Ldc_I4_4); + break; + case 5: + MakeMacro (instruction, OpCodes.Ldc_I4_5); + break; + case 6: + MakeMacro (instruction, OpCodes.Ldc_I4_6); + break; + case 7: + MakeMacro (instruction, OpCodes.Ldc_I4_7); + break; + case 8: + MakeMacro (instruction, OpCodes.Ldc_I4_8); + break; + default: + if (i >= -128 && i < 128) + ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte)i); + break; + } + break; + } + } + + OptimizeBranches (self); + } + + static void OptimizeBranches (MethodBody body) + { + ComputeOffsets (body); + + foreach (var instruction in body.Instructions) { + if (instruction.OpCode.OperandType != OperandType.InlineBrTarget) + continue; + + if (OptimizeBranch (instruction)) + ComputeOffsets (body); + } + } + + static bool OptimizeBranch (Instruction instruction) + { + var offset = ((Instruction)instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4); + if (!(offset >= -128 && offset <= 127)) + return false; + + switch (instruction.OpCode.Code) { + case Code.Br: + instruction.OpCode = OpCodes.Br_S; + break; + case Code.Brfalse: + instruction.OpCode = OpCodes.Brfalse_S; + break; + case Code.Brtrue: + instruction.OpCode = OpCodes.Brtrue_S; + break; + case Code.Beq: + instruction.OpCode = OpCodes.Beq_S; + break; + case Code.Bge: + instruction.OpCode = OpCodes.Bge_S; + break; + case Code.Bgt: + instruction.OpCode = OpCodes.Bgt_S; + break; + case Code.Ble: + instruction.OpCode = OpCodes.Ble_S; + break; + case Code.Blt: + instruction.OpCode = OpCodes.Blt_S; + break; + case Code.Bne_Un: + instruction.OpCode = OpCodes.Bne_Un_S; + break; + case Code.Bge_Un: + instruction.OpCode = OpCodes.Bge_Un_S; + break; + case Code.Bgt_Un: + instruction.OpCode = OpCodes.Bgt_Un_S; + break; + case Code.Ble_Un: + instruction.OpCode = OpCodes.Ble_Un_S; + break; + case Code.Blt_Un: + instruction.OpCode = OpCodes.Blt_Un_S; + break; + case Code.Leave: + instruction.OpCode = OpCodes.Leave_S; + break; + } + + return true; + } + + static void ComputeOffsets (MethodBody body) + { + var offset = 0; + foreach (var instruction in body.Instructions) { + instruction.Offset = offset; + offset += instruction.GetSize (); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs.meta new file mode 100644 index 0000000..3067d55 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c47d4756ed8120429bad0887cff0366 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs new file mode 100644 index 0000000..040f795 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs @@ -0,0 +1,72 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class MethodDefinitionRocks { + + public static MethodDefinition GetBaseMethod (this MethodDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (!self.IsVirtual) + return self; + if (self.IsNewSlot) + return self; + + var base_type = ResolveBaseType (self.DeclaringType); + while (base_type != null) { + var @base = GetMatchingMethod (base_type, self); + if (@base != null) + return @base; + + base_type = ResolveBaseType (base_type); + } + + return self; + } + + public static MethodDefinition GetOriginalBaseMethod (this MethodDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + while (true) { + var @base = self.GetBaseMethod (); + if (@base == self) + return self; + + self = @base; + } + } + + static TypeDefinition ResolveBaseType (TypeDefinition type) + { + if (type == null) + return null; + + var base_type = type.BaseType; + if (base_type == null) + return null; + + return base_type.Resolve (); + } + + static MethodDefinition GetMatchingMethod (TypeDefinition type, MethodDefinition method) + { + return MetadataResolver.GetMethod (type.Methods, method); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs.meta new file mode 100644 index 0000000..af399f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a5d7596633ddb043b9785a7fa7bfa6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs new file mode 100644 index 0000000..7eeab2b --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs @@ -0,0 +1,32 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class ModuleDefinitionRocks { + + public static IEnumerable GetAllTypes (this ModuleDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + // it was fun to write, but we need a somewhat less convoluted implementation + return self.Types.SelectMany ( + Functional.Y> (f => type => type.NestedTypes.SelectMany (f).Prepend (type))); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs.meta new file mode 100644 index 0000000..682485f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d90334a1cd085c047b9b8eddaa65cf09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs new file mode 100644 index 0000000..30bbb70 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs @@ -0,0 +1,11 @@ + +namespace MonoFN.Cecil.Rocks { + + public static class ParameterReferenceRocks { + + public static int GetSequence (this ParameterReference self) + { + return self.Index + 1; + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs.meta new file mode 100644 index 0000000..30bde11 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d276fe9256961b847b51a9bfc735384b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs new file mode 100644 index 0000000..bf22572 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs @@ -0,0 +1,157 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +#if !NET_CORE + +using System; +using System.Security; +using SSP = System.Security.Permissions; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class SecurityDeclarationRocks { + + public static PermissionSet ToPermissionSet (this SecurityDeclaration self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + PermissionSet set; + if (TryProcessPermissionSetAttribute (self, out set)) + return set; + + return CreatePermissionSet (self); + } + + static bool TryProcessPermissionSetAttribute (SecurityDeclaration declaration, out PermissionSet set) + { + set = null; + + if (!declaration.HasSecurityAttributes && declaration.SecurityAttributes.Count != 1) + return false; + + var security_attribute = declaration.SecurityAttributes [0]; + if (!security_attribute.AttributeType.IsTypeOf ("System.Security.Permissions", "PermissionSetAttribute")) + return false; + + var attribute = new SSP.PermissionSetAttribute ((SSP.SecurityAction)declaration.Action); + + var named_argument = security_attribute.Properties [0]; + string value = (string)named_argument.Argument.Value; + switch (named_argument.Name) { + case "XML": + attribute.XML = value; + break; + case "Name": + attribute.Name = value; + break; + default: + throw new NotImplementedException (named_argument.Name); + } + + set = attribute.CreatePermissionSet (); + return true; + } + + static PermissionSet CreatePermissionSet (SecurityDeclaration declaration) + { + var set = new PermissionSet (SSP.PermissionState.None); + + foreach (var attribute in declaration.SecurityAttributes) { + var permission = CreatePermission (declaration, attribute); + set.AddPermission (permission); + } + + return set; + } + + static IPermission CreatePermission (SecurityDeclaration declaration, SecurityAttribute attribute) + { + var attribute_type = Type.GetType (attribute.AttributeType.FullName); + if (attribute_type == null) + throw new ArgumentException ("attribute"); + + var security_attribute = CreateSecurityAttribute (attribute_type, declaration); + if (security_attribute == null) + throw new InvalidOperationException (); + + CompleteSecurityAttribute (security_attribute, attribute); + + return security_attribute.CreatePermission (); + } + + static void CompleteSecurityAttribute (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + if (attribute.HasFields) + CompleteSecurityAttributeFields (security_attribute, attribute); + + if (attribute.HasProperties) + CompleteSecurityAttributeProperties (security_attribute, attribute); + } + + static void CompleteSecurityAttributeFields (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + var type = security_attribute.GetType (); + + foreach (var named_argument in attribute.Fields) + type.GetField (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value); + } + + static void CompleteSecurityAttributeProperties (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + var type = security_attribute.GetType (); + + foreach (var named_argument in attribute.Properties) + type.GetProperty (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value, null); + } + + static SSP.SecurityAttribute CreateSecurityAttribute (Type attribute_type, SecurityDeclaration declaration) + { + SSP.SecurityAttribute security_attribute; + try { + security_attribute = (SSP.SecurityAttribute)Activator.CreateInstance ( + attribute_type, new object [] { (SSP.SecurityAction)declaration.Action }); + } + catch (MissingMethodException) { + security_attribute = (SSP.SecurityAttribute)Activator.CreateInstance (attribute_type, new object [0]); + } + + return security_attribute; + } + + public static SecurityDeclaration ToSecurityDeclaration (this PermissionSet self, SecurityAction action, ModuleDefinition module) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (module == null) + throw new ArgumentNullException ("module"); + + var declaration = new SecurityDeclaration (action); + + var attribute = new SecurityAttribute ( + module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute")); + + attribute.Properties.Add ( + new CustomAttributeNamedArgument ( + "XML", + new CustomAttributeArgument ( + module.TypeSystem.String, self.ToXml ().ToString ()))); + + declaration.SecurityAttributes.Add (attribute); + + return declaration; + } + } +} + +#endif diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs.meta new file mode 100644 index 0000000..c659e1a --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9d89d937b712004089aafb3a1391907 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs new file mode 100644 index 0000000..7b7d78f --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs @@ -0,0 +1,65 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class TypeDefinitionRocks { + + public static IEnumerable GetConstructors (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return Empty.Array; + + return self.Methods.Where (method => method.IsConstructor); + } + + public static MethodDefinition GetStaticConstructor (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return null; + + return self.GetConstructors ().FirstOrDefault (ctor => ctor.IsStatic); + } + + public static IEnumerable GetMethods (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return Empty.Array; + + return self.Methods.Where (method => !method.IsConstructor); + } + + public static TypeReference GetEnumUnderlyingType (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (!self.IsEnum) + throw new ArgumentException (); + + return Mixin.GetEnumUnderlyingType (self); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs.meta new file mode 100644 index 0000000..620eacd --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4d5393ac3307a84ca5babfbdcad9eea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs new file mode 100644 index 0000000..1fdd284 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs @@ -0,0 +1,87 @@ +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2015 Jb Evain +// Copyright (c) 2008 - 2011 Novell, Inc. +// +// Licensed under the MIT/X11 license. +// + +using System; + +namespace MonoFN.Cecil.Rocks { + +#if UNITY_EDITOR + public +#endif + static class TypeReferenceRocks { + + public static ArrayType MakeArrayType (this TypeReference self) + { + return new ArrayType (self); + } + + public static ArrayType MakeArrayType (this TypeReference self, int rank) + { + if (rank == 0) + throw new ArgumentOutOfRangeException ("rank"); + + var array = new ArrayType (self); + + for (int i = 1; i < rank; i++) + array.Dimensions.Add (new ArrayDimension ()); + + return array; + } + + public static PointerType MakePointerType (this TypeReference self) + { + return new PointerType (self); + } + + public static ByReferenceType MakeByReferenceType (this TypeReference self) + { + return new ByReferenceType (self); + } + + public static OptionalModifierType MakeOptionalModifierType (this TypeReference self, TypeReference modifierType) + { + return new OptionalModifierType (modifierType, self); + } + + public static RequiredModifierType MakeRequiredModifierType (this TypeReference self, TypeReference modifierType) + { + return new RequiredModifierType (modifierType, self); + } + + public static GenericInstanceType MakeGenericInstanceType (this TypeReference self, params TypeReference [] arguments) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (arguments == null) + throw new ArgumentNullException ("arguments"); + if (arguments.Length == 0) + throw new ArgumentException (); + if (self.GenericParameters.Count != arguments.Length) + throw new ArgumentException (); + + var instance = new GenericInstanceType (self, arguments.Length); + + foreach (var argument in arguments) + instance.GenericArguments.Add (argument); + + return instance; + } + + public static PinnedType MakePinnedType (this TypeReference self) + { + return new PinnedType (self); + } + + public static SentinelType MakeSentinelType (this TypeReference self) + { + return new SentinelType (self); + } + } +} diff --git a/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs.meta b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs.meta new file mode 100644 index 0000000..0239366 --- /dev/null +++ b/UnityProject/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 25d089a650c8e0f45a6f9086aaf0004a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/DOCUMENTATION.txt b/UnityProject/Assets/FishNet/DOCUMENTATION.txt new file mode 100644 index 0000000..8318532 --- /dev/null +++ b/UnityProject/Assets/FishNet/DOCUMENTATION.txt @@ -0,0 +1,3 @@ +Please view our online documentation for the most up to date information: https://fish-networking.gitbook.io/docs/ + +Support is available on our discord. Please contact FirstGearGames#0001 @ https://discord.gg/Ta9HgDh4Hj \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/DOCUMENTATION.txt.meta b/UnityProject/Assets/FishNet/DOCUMENTATION.txt.meta new file mode 100644 index 0000000..65996b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/DOCUMENTATION.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b8eb79f9866e25342b4565ac8c981645 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example.meta b/UnityProject/Assets/FishNet/Example.meta new file mode 100644 index 0000000..ad5b2cf --- /dev/null +++ b/UnityProject/Assets/FishNet/Example.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 79bbd25806bd92d4c90cd527b542fd2f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All.meta b/UnityProject/Assets/FishNet/Example/All.meta new file mode 100644 index 0000000..1b57a73 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b7816b0f21ed6947b4bdfa22c415e42 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator.meta b/UnityProject/Assets/FishNet/Example/All/Authenticator.meta new file mode 100644 index 0000000..2152fd0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: faf238f4c9ee3f24eaf0485ba10b8baa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity b/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity new file mode 100644 index 0000000..dd4d190 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity @@ -0,0 +1,375 @@ +%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.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &279669268 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 279669271} + - component: {fileID: 279669270} + - component: {fileID: 279669269} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &279669269 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 279669268} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &279669270 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 279669268} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &279669271 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 279669268} + 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: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1689326519 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + 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: 1 + 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: 4393252310969058994, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: _autoStartType + value: 1 + 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!114 &1759771918 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408886491481971} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 226e4eaf2fa685f48bdc3dfaa87c1453, type: 3} + m_Name: + m_EditorClassIdentifier: + _password: HelloWorld +--- !u!4 &7443408886491481969 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408886491481971} + 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: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7443408886491481970 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408886491481971} + 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} + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 +--- !u!1 &7443408886491481971 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7443408886491481969} + - component: {fileID: 7443408886491481970} + - component: {fileID: 1759771918} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity.meta b/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity.meta new file mode 100644 index 0000000..13af204 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Authenticator.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0bc02b628363de5499d5e7c00bd63b1b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts.meta b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts.meta similarity index 77% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts.meta rename to UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts.meta index 7ecdffd..fbd38e5 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts.meta +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e2898db03f0b9654498df19a98dc9503 +guid: a21030a9aa6adbe409485ca049602ba6 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs new file mode 100644 index 0000000..eba2a77 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs @@ -0,0 +1,17 @@ + +using FishNet.Broadcast; + +namespace FishNet.Example.Authenticating +{ + + public struct PasswordBroadcast : IBroadcast + { + public string Password; + } + + public struct ResponseBroadcast : IBroadcast + { + public bool Passed; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs.meta b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs.meta new file mode 100644 index 0000000..c2d9e65 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/Broadcasts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d26bb0c99070e9b49bc8632dc0b68214 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs new file mode 100644 index 0000000..4fb9fab --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs @@ -0,0 +1,114 @@ +using FishNet.Authenticating; +using FishNet.Connection; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Example.Authenticating +{ + + /// + /// This is an example of a password authenticator. + /// Never send passwords without encryption. + /// + public class PasswordAuthenticator : Authenticator + { + #region Public. + /// + /// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. + /// Server listens for this event automatically. + /// + public override event Action OnAuthenticationResult; + #endregion + + #region Serialized. + /// + /// Password to authenticate. + /// + [Tooltip("Password to authenticate.")] + [SerializeField] + private string _password = "HelloWorld"; + #endregion + + public override void InitializeOnce(NetworkManager networkManager) + { + base.InitializeOnce(networkManager); + + //Listen for connection state change as client. + base.NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; + //Listen for broadcast from client. Be sure to set requireAuthentication to false. + base.NetworkManager.ServerManager.RegisterBroadcast(OnPasswordBroadcast, false); + //Listen to response from server. + base.NetworkManager.ClientManager.RegisterBroadcast(OnResponseBroadcast); + } + + /// + /// Called when a connection state changes for the local client. + /// + private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs args) + { + /* If anything but the started state then exit early. + * Only try to authenticate on started state. The server + * doesn't have to send an authentication request before client + * can authenticate, that is entirely optional and up to you. In this + * example the client tries to authenticate soon as they connect. */ + if (args.ConnectionState != LocalConnectionState.Started) + return; + + PasswordBroadcast pb = new PasswordBroadcast() + { + Password = _password + }; + + base.NetworkManager.ClientManager.Broadcast(pb); + } + + + /// + /// Received on server when a client sends the password broadcast message. + /// + /// Connection sending broadcast. + /// + private void OnPasswordBroadcast(NetworkConnection conn, PasswordBroadcast pb) + { + /* If client is already authenticated this could be an attack. Connections + * are removed when a client disconnects so there is no reason they should + * already be considered authenticated. */ + if (conn.Authenticated) + { + conn.Disconnect(true); + return; + } + + bool correctPassword = (pb.Password == _password); + /* Tell client if they authenticated or not. This is + * entirely optional but does demonstrate that you can send + * broadcasts to client on pass or fail. */ + ResponseBroadcast rb = new ResponseBroadcast() + { + Passed = correctPassword + }; + base.NetworkManager.ServerManager.Broadcast(conn, rb, false); + + /* Invoke result. This is handled internally to complete the connection or kick client. + * It's important to call this after sending the broadcast so that the broadcast + * makes it out to the client before the kick. */ + OnAuthenticationResult?.Invoke(conn, correctPassword); + } + + /// + /// Received on client after server sends an authentication response. + /// + /// + private void OnResponseBroadcast(ResponseBroadcast rb) + { + string result = (rb.Passed) ? "Authentication complete." : "Authenitcation failed."; + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.Log(result); + } + } + + +} diff --git a/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs.meta b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs.meta new file mode 100644 index 0000000..135ee06 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Authenticator/Scripts/PasswordAuthenticator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 226e4eaf2fa685f48bdc3dfaa87c1453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType.meta new file mode 100644 index 0000000..b828a51 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8bfe7bb849f1524fb53a1029c93cddc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync.meta new file mode 100644 index 0000000..e8dbf47 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bca1763a5b81adc4f8a467bb085aa78a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs new file mode 100644 index 0000000..8a62bed --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace FishNet.Example.ComponentStateSync +{ + + + public class AMonoScript : MonoBehaviour + { + + private void Start() + { + //Start is here to show enabled toggle within inspector. + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs.meta new file mode 100644 index 0000000..703535d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/AMonoScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5821b28e5b90ef44b4910a640482c15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs new file mode 100644 index 0000000..ba6dea7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs @@ -0,0 +1,157 @@ +using FishNet.Managing.Logging; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Example.ComponentStateSync +{ + + + /// + /// It's very important to exclude this from codegen. + /// However, whichever value you are synchronizing must not be excluded. This is why the value is outside the StructySync class. + /// + public class ComponentStateSync : SyncBase, ICustomSync where T : MonoBehaviour + { + #region Public. + /// + /// Gets or Sets the enabled state for Component. + /// + public bool Enabled + { + get => (Component == null) ? false : GetState(); + set => SetState(value); + } + /// + /// Component to state sync. + /// + public T Component { get; private set; } + /// + /// Delegate signature for when the component changes. + /// + public delegate void StateChanged(T component, bool prevState, bool nextState, bool asServer); + /// + /// Called when the component state changes. + /// + public event StateChanged OnChange; + #endregion + + /// + /// Initializes this StateSync with a component. + /// + /// + public void Initialize(T component) + { + Component = component; + } + + /// + /// Sets the enabled state for Component. + /// + /// + private void SetState(bool enabled) + { + if (base.NetworkManager == null) + return; + + if (Component == null) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"State cannot be changed as Initialize has not been called with a valid component."); + } + + //If hasn't changed then ignore. + bool prev = GetState(); + if (enabled == prev) + return; + + //Set to new value and add operation. + Component.enabled = enabled; + AddOperation(Component, prev, enabled); + } + + /// + /// Gets the enabled state for Component. + /// + /// + private bool GetState() + { + return Component.enabled; + } + + /// + /// Adds an operation to synchronize. + /// + private void AddOperation(T component, bool prev, bool next) + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + base.Dirty(); + + //Data can currently only be set from server, so this is always asServer. + bool asServer = true; + OnChange?.Invoke(component, prev, next, asServer); + } + /// + /// Writes all changed values. + /// + ///True to set the next time data may sync. + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + base.WriteDelta(writer, resetSyncTick); + writer.WriteBoolean(Component.enabled); + } + + /// + /// Writes all values. + /// + public override void WriteFull(PooledWriter writer) + { + /* Always write full for this custom sync type. + * It would be difficult to know if the + * state has changed given it's a boolean, and + * may or may not be true/false after pooling is added. */ + WriteDelta(writer, false); + } + + /// + /// Reads and sets the current values. + /// + public override void Read(PooledReader reader) + { + //Read is always on client side. + bool asServer = false; + bool nextValue = reader.ReadBoolean(); + if (base.NetworkManager == null) + return; + + bool prevValue = GetState(); + + /* When !asServer don't make changes if server is running. + * This is because changes would have already been made on + * the server side and doing so again would result in duplicates + * and potentially overwrite data not yet sent. */ + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + if (!asClientAndHost) + Component.enabled = nextValue; + + OnChange?.Invoke(Component, prevValue, nextValue, asServer); + } + + /// + /// Return the serialized type. + /// + /// + public object GetSerializedType() => typeof(bool); + } +} diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs.meta new file mode 100644 index 0000000..7ba490b --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentStateSync.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce7cdae4a8f3d914fa9141b4bd760faa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs new file mode 100644 index 0000000..f9adbce --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs @@ -0,0 +1,43 @@ +using FishNet.Object; +using FishNet.Object.Synchronizing; +using UnityEngine; + +namespace FishNet.Example.ComponentStateSync +{ + + public class ComponentSyncStateBehaviour : NetworkBehaviour + { + /// + /// Using my custom SyncType for Structy. + /// + [SyncObject] + private readonly ComponentStateSync _syncScript = new ComponentStateSync(); + + private void Awake() + { + AMonoScript ams = GetComponent(); + //Initialize with the component of your choice. + _syncScript.Initialize(ams); + //Optionally listen for changes. + _syncScript.OnChange += _syncScript_OnChange; + } + + /// + /// Called when enabled state changes for SyncScript. + /// + private void _syncScript_OnChange(AMonoScript component, bool prevState, bool nextState, bool asServer) + { + Debug.Log($"Change received on {component.GetType().Name}. New value is {nextState}. Received asServer {asServer}."); + } + + private void Update() + { + //Every so often flip the state of the component. + if (base.IsServer && Time.frameCount % 200 == 0) + _syncScript.Enabled = !_syncScript.Enabled; + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs.meta new file mode 100644 index 0000000..eba67fc --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Component State Sync/ComponentSyncStateBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7327b94eff9c7d4aa876aa54ca6b439 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync.meta new file mode 100644 index 0000000..5cc762d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 449825c1f60f1e443b081834b84df95d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs new file mode 100644 index 0000000..c6d2e57 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs @@ -0,0 +1,44 @@ +using FishNet.Object; +using FishNet.Object.Synchronizing; +using UnityEngine; + +namespace FishNet.Example.CustomSyncObject +{ + + public class StructSyncBehaviour : NetworkBehaviour + { + /// + /// Using my custom SyncType for Structy. + /// + [SyncObject] + private readonly StructySync _structy = new StructySync(); + + private void Awake() + { + //Listen for change events. + _structy.OnChange += _structy_OnChange; + } + + private void _structy_OnChange(StructySync.CustomOperation op, Structy oldItem, Structy newItem, bool asServer) + { + Debug.Log("Changed " + op.ToString() + ", " + newItem.Age + ", " + asServer); + } + + private void Update() + { + //Every so often increase the age property on structy using StructySync, my custom sync type. + if (base.IsServer && Time.frameCount % 200 == 0) + { + /* Custom code inside StructySync to return + * current value. You can expose this, or don't, however + * you like. */ + Structy s = _structy.GetValue(true); + //Increase age. + _structy.SetAge((ushort)(s.Age + 1)); + } + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs.meta new file mode 100644 index 0000000..fc5e85e --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructSyncBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2cc7cbbeb4170642ac60367303222ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs new file mode 100644 index 0000000..f425d58 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs @@ -0,0 +1,332 @@ +using FishNet.Managing.Logging; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Example.CustomSyncObject +{ + /// + /// This is the data type I want to create a custom SyncType for. + /// + public struct Structy + { + public string Name; + public ushort Age; + + public Structy(string name, ushort age) + { + Name = name; + Age = age; + } + } + + /// + /// It's very important to exclude this from codegen. + /// However, whichever value you are synchronizing must not be excluded. This is why the value is outside the StructySync class. + /// + public class StructySync : SyncBase, ICustomSync + { + #region Types. + /// + /// Information about how the struct has changed. + /// You could send the entire struct on every change + /// but this is an example of how you might send individual changed + /// fields. + /// + private struct ChangeData + { + internal CustomOperation Operation; + internal Structy Data; + + public ChangeData(CustomOperation operation, Structy data) + { + Operation = operation; + Data = data; + } + } + /// + /// Types of changes. This is related to ChangedData + /// where you can specify what has changed. + /// + public enum CustomOperation : byte + { + Full = 0, + Name = 1, + Age = 2 + } + #endregion + + #region Public. + /// + /// Delegate signature for when Structy changes. + /// + /// + /// + /// + public delegate void CustomChanged(CustomOperation op, Structy oldItem, Structy newItem, bool asServer); + /// + /// Called when the Structy changes. + /// + public event CustomChanged OnChange; + #endregion + + #region Private. + /// + /// Initial value when initialized. + /// + private Structy _initialValue; + /// + /// Value this SyncType is for, which is Structy. + /// + private Structy _value = new Structy(); + /// + /// Copy of value on client portion when acting as a host. + /// This is not mandatory but this setup separates server values + /// from client, creating a more reliable test environment when running as host. + /// + private Structy _clientValue = new Structy(); + /// + /// Changed data which will be sent next tick. + /// + private readonly List _changed = new List(); + /// + /// True if values have changed since initialization. + /// The only reasonable way to reset this during a Reset call is by duplicating the original list and setting all values to it on reset. + /// + private bool _valuesChanged; + #endregion + + + protected override void Registered() + { + base.Registered(); + _initialValue = _value; + } + + /// + /// Adds an operation and invokes locally. + /// + /// + /// + /// + /// + private void AddOperation(CustomOperation operation, Structy prev, Structy next) + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + /* Set as changed even if cannot dirty. + * Dirty is only set when there are observers, + * but even if there are not observers + * values must be marked as changed so when + * there are observers, new values are sent. */ + _valuesChanged = true; + base.Dirty(); + + //Data can currently only be set from server, so this is always asServer. + bool asServer = true; + //Add to changed. + ChangeData cd = new ChangeData(operation, next); + _changed.Add(cd); + OnChange?.Invoke(operation, prev, next, asServer); + } + + /// + /// Writes all changed values. + /// + /// + ///True to set the next time data may sync. + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + base.WriteDelta(writer, resetSyncTick); + writer.WriteUInt32((uint)_changed.Count); + + for (int i = 0; i < _changed.Count; i++) + { + ChangeData change = _changed[i]; + writer.WriteByte((byte)change.Operation); + + //Clear does not need to write anymore data so it is not included in checks. + if (change.Operation == CustomOperation.Age) + { + writer.WriteUInt16(change.Data.Age); + } + else if (change.Operation == CustomOperation.Name) + { + writer.WriteString(change.Data.Name); + } + } + + _changed.Clear(); + } + + /// + /// Writes all values if not initial values. + /// + /// + public override void WriteFull(PooledWriter writer) + { + if (!_valuesChanged) + return; + + base.WriteHeader(writer, false); + //Write one change. + writer.WriteInt32(1); + //Write if changed is from the server, so always use the server _value. + writer.WriteByte((byte)CustomOperation.Full); + //Write value. + writer.Write(_value); + } + + /// + /// Sets current values. + /// + /// + public override void Read(PooledReader reader) + { + //Read is always on client side. + bool asServer = false; + /* When !asServer don't make changes if server is running. + * This is because changes would have already been made on + * the server side and doing so again would result in duplicates + * and potentially overwrite data not yet sent. */ + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + + int changes = (int)reader.ReadUInt32(); + for (int i = 0; i < changes; i++) + { + CustomOperation operation = (CustomOperation)reader.ReadByte(); + Structy prev = GetValue(asServer); + Structy next = default(Structy); + + //Full. + if (operation == CustomOperation.Full) + { + next = reader.Read(); + } + //Name. + else if (operation == CustomOperation.Name) + { + next = prev; + next.Name = reader.ReadString(); + } + //Age + else if (operation == CustomOperation.Age) + { + next = prev; + next.Age = reader.ReadUInt16(); + } + + OnChange?.Invoke(operation, prev, next, asServer); + } + + } + + /// + /// Resets to initialized values. + /// + public override void Reset() + { + base.Reset(); + _changed.Clear(); + _value = _initialValue; + _clientValue = _initialValue; + _valuesChanged = false; + } + + /// + /// Sets name value. + /// + public void SetName(string name) + { + SetName(name, true, true); + } + private void SetName(string name, bool asServer, bool force) + { + Structy data = GetValue(asServer); + bool sameValue = (!force && (name == data.Name)); + if (!sameValue) + { + Structy prev = data; + + Structy next = data; + next.Name = name; + SetValue(asServer, next); + + if (asServer) + { + if (base.NetworkManager == null) + _clientValue = next; + AddOperation(CustomOperation.Name, prev, next); + } + } + } + + /// + /// Sets age value. + /// + public void SetAge(ushort age) + { + SetAge(age, true, true); + } + private void SetAge(ushort age, bool asServer, bool force) + { + Structy data = GetValue(asServer); + bool sameValue = (!force && (age == data.Age)); + if (!sameValue) + { + Structy prev = data; + + Structy next = data; + next.Age = age; + SetValue(asServer, next); + + if (asServer) + { + if (base.NetworkManager == null) + _clientValue = next; + AddOperation(CustomOperation.Age, prev, next); + } + } + } + + /// + /// Gets value depending if being called asServer or not. + /// + /// + /// + public Structy GetValue(bool asServer) + { + return (asServer) ? _value : _clientValue; + } + + + /// + /// Sets value depending if being called asServer or not. + /// + /// + /// + private void SetValue(bool asServer, Structy data) + { + if (asServer) + _value = data; + else + _clientValue = data; + } + + /// + /// Return the serialized type. + /// + /// + public object GetSerializedType() => typeof(Structy); + } +} diff --git a/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs.meta b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs.meta new file mode 100644 index 0000000..68e9a15 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/CustomSyncType/Custom Struct Sync/StructySync.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c0a84e32efc60f4aa471e3a42cf2e0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction.meta b/UnityProject/Assets/FishNet/Example/All/Prediction.meta new file mode 100644 index 0000000..37365d3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7dc64eb2abeb610469822b75eaa92650 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController.meta new file mode 100644 index 0000000..ad3e5b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 79558f739187b5848bff30f39a16aaa7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity new file mode 100644 index 0000000..eecbd22 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity @@ -0,0 +1,1264 @@ +%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: 11 + 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_UseShadowmask: 1 +--- !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 + 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: + _tickRate: 15 + _pingInterval: 1 + _timingInterval: 2 + _physicsMode: 1 + _maximumBufferedInputs: 15 +--- !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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 49a3799e31595ea478b5dd6fa163fcbd, 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 4 + 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_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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 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: Cube (1) + 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 49a3799e31595ea478b5dd6fa163fcbd, 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !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_Children: + - {fileID: 1112005916} + - {fileID: 1470934491} + - {fileID: 1852016427} + - {fileID: 872683031} + - {fileID: 555580085} + 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} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 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_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_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_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_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_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_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_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_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_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_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: 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} + _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_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 +--- !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_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_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: 7443408886491487337} + - component: {fileID: 192429404} + - component: {fileID: 7443408886491487336} + - component: {fileID: 7443408886491487339} + - component: {fileID: 7443408886491487338} + 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: + _logging: {fileID: 0} + _spawnablePrefabs: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, type: 2} + _refreshDefaultPrefabs: 0 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 +--- !u!114 &7443408886491487336 +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: + _placement: 1 +--- !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: 9117857247562382210, guid: b2991431a5f893e49937d01b6da44ff8, + type: 3} + _addToDefaultScene: 1 + Spawns: [] +--- !u!114 &7443408886491487338 +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 + _attackResponseType: 1 + _ipv4BindAddress: + _ipv6BindAddress: + _port: 7771 + _maximumClients: 9999 + _clientAddress: localhost + _timeout: 15 +--- !u!114 &7443408886491487339 +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: 7443408886491487338} +--- !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_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/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity.meta new file mode 100644 index 0000000..0530583 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/CharacterControllerPrediction.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ec1a6e85f57626a4cbacaf306766bdfd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs.meta new file mode 100644 index 0000000..1be0a57 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26b1206536a5ae44792afd5292ad29b7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab new file mode 100644 index 0000000..1a6fb3b --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab @@ -0,0 +1,221 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &50058147544064912 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8274935638305073705} + - component: {fileID: 5937955550093657123} + - component: {fileID: 8512892203317417748} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8274935638305073705 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 50058147544064912} + 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: [] + m_Father: {fileID: 9117857247562382215} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5937955550093657123 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 50058147544064912} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8512892203317417748 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 50058147544064912} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!1 &9117857247562382221 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9117857247562382215} + - component: {fileID: 9117857247562382208} + - component: {fileID: 9117857247562382210} + - component: {fileID: 9144896207351220584} + - component: {fileID: 9144896207351220583} + - component: {fileID: 4742920392281400910} + m_Layer: 0 + m_Name: CharacterControllerPrediction + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9117857247562382215 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + 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_Children: + - {fileID: 8274935638305073705} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &9117857247562382208 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + 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!114 &9117857247562382210 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: 27 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 14762131302109388384 + _sceneNetworkObjects: + - {fileID: 9117857247562382210} + k__BackingField: 0 + k__BackingField: 0 + ObjectId: 0 + _networkBehaviours: + - {fileID: 9144896207351220584} + - {fileID: 4742920392281400910} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &9144896207351220584 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6bb7bd88fd11b5d4aa7fca3d42172ab8, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 9117857247562382210} + _networkObjectCache: {fileID: 9117857247562382210} + _moveRate: 5 +--- !u!143 &9144896207351220583 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + 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!114 &4742920392281400910 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9117857247562382221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 402926ef33e0a894d9fec352693988ac, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: 9117857247562382210} + _networkObjectCache: {fileID: 9117857247562382210} + _graphicalObject: {fileID: 8274935638305073705} + _smoothTicks: 1 + _durationType: 0 + _smoothingDuration: 0.125 + _enableTeleport: 0 + _teleportThreshold: 1 + _predictionType: 0 + _rigidbody: {fileID: 0} + _rigidbody2d: {fileID: 0} + _networkTransform: {fileID: 0} + _predictionRatio: 0 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta similarity index 74% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab.meta rename to UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta index 1a63d00..2ffd376 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab.meta +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5339554c46006dd4e91cae9ff34c095d +guid: b2991431a5f893e49937d01b6da44ff8 PrefabImporter: externalObjects: {} userData: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts.meta new file mode 100644 index 0000000..e18185d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17c942141382c1c45abd049b9f01c633 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs new file mode 100644 index 0000000..79f1a59 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs @@ -0,0 +1,115 @@ +using FishNet; +using FishNet.Object; +using FishNet.Object.Prediction; +using UnityEngine; + +/* +* +* See TransformPrediction.cs for more detailed notes. +* +*/ + +namespace FishNet.Example.Prediction.CharacterControllers +{ + + public class CharacterControllerPrediction : NetworkBehaviour + { + #region Types. + public struct MoveData + { + public float Horizontal; + public float Vertical; + } + public struct ReconcileData + { + public Vector3 Position; + public Quaternion Rotation; + public ReconcileData(Vector3 position, Quaternion rotation) + { + Position = position; + Rotation = rotation; + } + } + #endregion + + #region Serialized. + [SerializeField] + private float _moveRate = 5f; + #endregion + + #region Private. + private CharacterController _characterController; + #endregion + + private void Awake() + { + InstanceFinder.TimeManager.OnTick += TimeManager_OnTick; + _characterController = GetComponent(); + } + + public override void OnStartClient() + { + base.OnStartClient(); + _characterController.enabled = (base.IsServer || base.IsOwner); + } + + private void OnDestroy() + { + if (InstanceFinder.TimeManager != null) + { + InstanceFinder.TimeManager.OnTick -= TimeManager_OnTick; + } + } + + private void TimeManager_OnTick() + { + if (base.IsOwner) + { + Reconciliation(default, false); + CheckInput(out MoveData md); + Move(md, false); + } + if (base.IsServer) + { + Move(default, true); + ReconcileData rd = new ReconcileData(transform.position, transform.rotation); + Reconciliation(rd, true); + } + } + + private void CheckInput(out MoveData md) + { + md = default; + + float horizontal = Input.GetAxisRaw("Horizontal"); + float vertical = Input.GetAxisRaw("Vertical"); + + if (horizontal == 0f && vertical == 0f) + return; + + md = new MoveData() + { + Horizontal = horizontal, + Vertical = vertical + }; + } + + [Replicate] + private void Move(MoveData md, bool asServer, bool replaying = false) + { + Vector3 move = new Vector3(md.Horizontal, 0f, md.Vertical).normalized + new Vector3(0f, Physics.gravity.y, 0f); + _characterController.Move(move * _moveRate * (float)base.TimeManager.TickDelta); + } + + [Reconcile] + private void Reconciliation(ReconcileData rd, bool asServer) + { + transform.position = rd.Position; + transform.rotation = rd.Rotation; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs.meta new file mode 100644 index 0000000..04a2558 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/CharacterController/Scripts/CharacterControllerPrediction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bb7bd88fd11b5d4aa7fca3d42172ab8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials.meta new file mode 100644 index 0000000..e174353 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3efb1eab37402045a64161aba21ed29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat new file mode 100644 index 0000000..df63253 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat @@ -0,0 +1,77 @@ +%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: _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + 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: 0 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 1 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.15970986, g: 0.50941056, b: 0.9150943, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat.meta similarity index 63% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab.meta rename to UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat.meta index f6d6f53..fde4d4f 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab.meta +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/BlueMat.mat.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: a85b24263182aae4bbc1829bb2b73d7a +guid: ea31fef5ca1bc7344a72c71a5f9a0cd2 NativeFormatImporter: externalObjects: {} - mainObjectFileID: 100100000 + mainObjectFileID: 2100000 userData: assetBundleName: assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat new file mode 100644 index 0000000..8c769b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat @@ -0,0 +1,77 @@ +%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: GroundMat + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + 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: 0 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 1 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.3679245, g: 0.36271805, b: 0.36271805, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat.meta similarity index 63% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab.meta rename to UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat.meta index 84850be..3a74ead 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab.meta +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/GroundMat.mat.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: da367a4c269be6d4a855ee1a9a68256b +guid: 0bb31cf72dfcef449a1a4a5aab857f63 NativeFormatImporter: externalObjects: {} - mainObjectFileID: 100100000 + mainObjectFileID: 2100000 userData: assetBundleName: assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat new file mode 100644 index 0000000..e9f384c --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat @@ -0,0 +1,77 @@ +%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: PurpleMat + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + 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: 0 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 1 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.3364354, g: 0.0990566, b: 0.3962264, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat.meta new file mode 100644 index 0000000..8c782d4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/PurpleMat.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49a3799e31595ea478b5dd6fa163fcbd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat new file mode 100644 index 0000000..0f8028c --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat @@ -0,0 +1,77 @@ +%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: YellowishMat + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + 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: 0 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 1 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.62352943, g: 0.5504006, b: 0.17254901, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat.meta new file mode 100644 index 0000000..9f32cc6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Materials/YellowishMat.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6273444b68d517449aadb36abebaf561 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody.meta new file mode 100644 index 0000000..06da42f --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d851e0508fe14f44dae11c460021a6c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs.meta new file mode 100644 index 0000000..c67282a --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 185d003306f80ff4cb148c3f06bf3318 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab new file mode 100644 index 0000000..2b91a0c --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab @@ -0,0 +1,459 @@ +%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_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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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: 303449598114786578} + - component: {fileID: 201277551} + - component: {fileID: 201277550} + - component: {fileID: 201277549} + - component: {fileID: 2286220694416623513} + 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_Children: + - {fileID: 303449599178274091} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !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: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &201277551 +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: 9e123f937d4b4f94c9cb6cc03944f786, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 201277550} + _networkObjectCache: {fileID: 201277550} + _jumpForce: 40 + _moveRate: 15 +--- !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: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 7596993593060998472 + _sceneNetworkObjects: + - {fileID: 201277550} + k__BackingField: 0 + k__BackingField: 0 + ObjectId: 0 + _networkBehaviours: + - {fileID: 201277551} + - {fileID: 2286220694416623513} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !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: 0 + m_CollisionDetection: 0 +--- !u!114 &2286220694416623513 +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: 402926ef33e0a894d9fec352693988ac, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: 201277550} + _networkObjectCache: {fileID: 201277550} + _graphicalObject: {fileID: 303449599178274091} + _smoothTicks: 1 + _durationType: 0 + _smoothingDuration: 0.05 + _enableTeleport: 0 + _teleportThreshold: 1 + _predictionType: 1 + _rigidbody: {fileID: 201277549} + _rigidbody2d: {fileID: 0} + _networkTransform: {fileID: 0} + _predictionRatio: 0 +--- !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_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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta new file mode 100644 index 0000000..1df735c --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d904f93bc171bb144ba33c5155282f6f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity new file mode 100644 index 0000000..3701f24 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity @@ -0,0 +1,759 @@ +%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: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &192429403 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 7443408887813606051, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + m_PrefabInstance: {fileID: 1364334277} + m_PrefabAsset: {fileID: 0} +--- !u!114 &192429404 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192429403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} + m_Name: + m_EditorClassIdentifier: + _tickRate: 30 + _pingInterval: 1 + _timingInterval: 2 + _physicsMode: 1 + _maximumBufferedInputs: 25 +--- !u!114 &192429405 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192429403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} + m_Name: + m_EditorClassIdentifier: + _unreliableMTU: 1023 + _attackResponseType: 1 + _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: 192429403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f9b6b565cd9533c4ebc18003f0fc18a2, type: 3} + m_Name: + m_EditorClassIdentifier: + _placement: 1 +--- !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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 2 + 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_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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1364334277 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 4393252310584637056, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: AutoStart + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4393252310584637056, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: _autoStartType + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606050, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: _spawnablePrefabs + value: + objectReference: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, + type: 2} + - target: {fileID: 7443408887813606051, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_Name + value: NetworkManager + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606060, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: _playerPrefab + value: + objectReference: {fileID: 201277550, guid: d904f93bc171bb144ba33c5155282f6f, + type: 3} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 0b650fca685f2eb41a86538aa883e4c1, type: 3} +--- !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: Cube (1) + 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !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_Children: + - {fileID: 1112005916} + - {fileID: 1470934491} + - {fileID: 555580085} + - {fileID: 1852016427} + - {fileID: 872683031} + 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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity.meta new file mode 100644 index 0000000..2edff22 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/RigidbodyPrediction.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 005289ca292137448ba5edc0e1163f4a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts.meta new file mode 100644 index 0000000..f4324aa --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 789e9c92c35f6aa4bb179f6ee73a3061 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs new file mode 100644 index 0000000..8ca8c80 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs @@ -0,0 +1,161 @@ +using FishNet; +using FishNet.Object; +using FishNet.Object.Prediction; +using UnityEngine; + +/* +* +* See TransformPrediction.cs for more detailed notes. +* +*/ + +namespace FishNet.Example.Prediction.Rigidbodies +{ + + public class RigidbodyPrediction : NetworkBehaviour + { + #region Types. + public struct MoveData + { + public bool Jump; + public float Horizontal; + public float Vertical; + public MoveData(bool jump, float horizontal, float vertical) + { + Jump = jump; + Horizontal = horizontal; + Vertical = vertical; + } + } + public struct ReconcileData + { + 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; + } + } + #endregion + + #region Serialized. + [SerializeField] + private float _jumpForce = 15f; + [SerializeField] + private float _moveRate = 15f; + #endregion + + #region Private. + /// + /// Rigidbody on this object. + /// + private Rigidbody _rigidbody; + /// + /// Next time a jump is allowed. + /// + private float _nextJumpTime; + /// + /// True to jump next frame. + /// + private bool _jump; + #endregion + + + + private void Awake() + { + + _rigidbody = GetComponent(); + InstanceFinder.TimeManager.OnTick += TimeManager_OnTick; + InstanceFinder.TimeManager.OnPostTick += TimeManager_OnPostTick; + } + + private void OnDestroy() + { + if (InstanceFinder.TimeManager != null) + { + InstanceFinder.TimeManager.OnTick -= TimeManager_OnTick; + InstanceFinder.TimeManager.OnPostTick -= TimeManager_OnPostTick; + } + } + + private void Update() + { + if (base.IsOwner) + { + if (Input.GetKeyDown(KeyCode.Space) && Time.time > _nextJumpTime) + { + _nextJumpTime = Time.time + 1f; + _jump = true; + } + } + } + + private void TimeManager_OnTick() + { + if (base.IsOwner) + { + Reconciliation(default, false); + CheckInput(out MoveData md); + Move(md, false); + } + if (base.IsServer) + { + Move(default, true); + } + } + + + private void TimeManager_OnPostTick() + { + if (base.IsServer) + { + ReconcileData rd = new ReconcileData(transform.position, transform.rotation, _rigidbody.velocity, _rigidbody.angularVelocity); + Reconciliation(rd, true); + } + } + + private void CheckInput(out MoveData md) + { + md = default; + + float horizontal = Input.GetAxisRaw("Horizontal"); + float vertical = Input.GetAxisRaw("Vertical"); + + if (horizontal == 0f && vertical == 0f && !_jump) + return; + + md = new MoveData(_jump, horizontal, vertical); + _jump = false; + } + + [Replicate] + private void Move(MoveData md, bool asServer, bool replaying = false) + { + //Add extra gravity for faster falls. + Vector3 forces = new Vector3(md.Horizontal, Physics.gravity.y, md.Vertical) * _moveRate; + _rigidbody.AddForce(forces); + + if (md.Jump) + _rigidbody.AddForce(new Vector3(0f, _jumpForce, 0f), ForceMode.Impulse); + } + + [Reconcile] + private void Reconciliation(ReconcileData rd, bool asServer) + { + transform.position = rd.Position; + transform.rotation = rd.Rotation; + _rigidbody.velocity = rd.Velocity; + _rigidbody.angularVelocity = rd.AngularVelocity; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs.meta new file mode 100644 index 0000000..b80d6e4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Rigidbody/Scripts/RigidbodyPrediction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e123f937d4b4f94c9cb6cc03944f786 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform.meta new file mode 100644 index 0000000..af337f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49d8c9756de86004c802a5ce8448fdad +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs.meta new file mode 100644 index 0000000..abbd684 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52874c2b0ae3cc74d9b6be4650f3a24a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab new file mode 100644 index 0000000..92167b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab @@ -0,0 +1,246 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &27039729695437544 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 27039729695437538} + - component: {fileID: 27039729695437541} + - component: {fileID: 27039729695437542} + - component: {fileID: 27039729695437543} + - component: {fileID: 8399567158492483659} + - component: {fileID: -4118712540632748398} + m_Layer: 0 + m_Name: TransformPrediction + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &27039729695437538 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + 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_Children: + - {fileID: 7846666075604890595} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &27039729695437541 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + 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!114 &27039729695437542 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 13cad243fdfd7294e8a6a393735726eb, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 27039729695437543} + _networkObjectCache: {fileID: 27039729695437543} + _moveRate: 5 +--- !u!114 &27039729695437543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 139770397801111289 + _sceneNetworkObjects: + - {fileID: 27039729695437543} + k__BackingField: 0 + k__BackingField: 0 + ObjectId: 0 + _networkBehaviours: + - {fileID: 27039729695437542} + - {fileID: 8399567158492483659} + - {fileID: -4118712540632748398} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &8399567158492483659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 402926ef33e0a894d9fec352693988ac, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: 0} + _networkObjectCache: {fileID: 27039729695437543} + _graphicalObject: {fileID: 7846666075604890595} + _smoothTicks: 1 + _durationType: 0 + _smoothingDuration: 0.05 + _enableTeleport: 0 + _teleportThreshold: 1 + _predictionType: 0 + _rigidbody: {fileID: 0} + _rigidbody2d: {fileID: 0} + _networkTransform: {fileID: 0} + _predictionRatio: 0 +--- !u!114 &-4118712540632748398 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 27039729695437544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a2836e36774ca1c4bbbee976e17b649c, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 2 + _addedNetworkObject: {fileID: 27039729695437543} + _networkObjectCache: {fileID: 27039729695437543} + _synchronizeParent: 0 + _packing: + Position: 1 + Rotation: 1 + Scale: 0 + _interpolation: 2 + _extrapolation: 0 + _enableTeleport: 0 + _teleportThreshold: 0 + _clientAuthoritative: 0 + _sendToOwner: 0 + _interval: 0 + _synchronizePosition: 1 + _positionSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeRotation: 1 + _rotationSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeScale: 1 + _scaleSnapping: + X: 0 + Y: 0 + Z: 0 +--- !u!1 &907868826061293566 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7846666075604890595} + - component: {fileID: 3240451035359699034} + - component: {fileID: 85305618895715439} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7846666075604890595 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 907868826061293566} + 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: [] + m_Father: {fileID: 27039729695437538} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3240451035359699034 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 907868826061293566} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &85305618895715439 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 907868826061293566} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab.meta new file mode 100644 index 0000000..6ef3a43 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Prefabs/TransformPrediction.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f820efff6a2871447b961fc755212ba3 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts.meta new file mode 100644 index 0000000..a24d6b2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 99b192b05caa072458c66dbd47086403 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs new file mode 100644 index 0000000..31e84f3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs @@ -0,0 +1,197 @@ +using FishNet; +using FishNet.Object; +using FishNet.Object.Prediction; +using UnityEngine; + +namespace FishNet.Example.Prediction.Transforms +{ + public class TransformPrediction : NetworkBehaviour + { + /// + /// Data on how to move. + /// This is processed locally as well sent to the server for processing. + /// Any inputs or values which may affect your move should be placed in your own MoveData. + /// The structure type may be named anything. Classes can also be used but will generate garbage, so structures + /// are recommended. + /// + public struct MoveData + { + public float Horizontal; + public float Vertical; + + public MoveData(float horizontal, float vertical) + { + Horizontal = horizontal; + Vertical = vertical; + } + } + + /// + /// Data on how to reconcile. + /// Server sends this back to the client. Once the client receives this they + /// will reset their object using this information. Like with MoveData anything that may + /// affect your movement should be reset. Since this is just a transform only position and + /// rotation would be reset. But a rigidbody would include velocities as well. If you are using + /// an asset it's important to know what systems in that asset affect movement and need + /// to be reset as well. + /// + public struct ReconcileData + { + public Vector3 Position; + public Quaternion Rotation; + public ReconcileData(Vector3 position, Quaternion rotation) + { + Position = position; + Rotation = rotation; + } + } + + #region Serialized. + /// + /// How many units to move per second. + /// + [Tooltip("How many units to move per second.")] + [SerializeField] + private float _moveRate = 5f; + #endregion + + private void Awake() + { + /* Prediction is tick based so you must + * send datas during ticks. You can use whichever + * tick best fits your need, such as PreTick, Tick, or PostTick. + * In most cases you will send/move using Tick. For rigidbodies + * you will send using PostTick. I subscribe to ticks using + * the InstanceFinder class, which finds the first NetworkManager + * loaded. If you are using several NetworkManagers you would want + * to subscrube in OnStartServer/Client using base.TimeManager. */ + InstanceFinder.TimeManager.OnTick += TimeManager_OnTick; + } + + private void OnDestroy() + { + //Unsubscribe as well. + if (InstanceFinder.TimeManager != null) + { + InstanceFinder.TimeManager.OnTick -= TimeManager_OnTick; + } + } + + private void TimeManager_OnTick() + { + if (base.IsOwner) + { + /* Call reconcile using default, and false for + * asServer. This will reset the client to the latest + * values from server and replay cached inputs. */ + Reconciliation(default, false); + /* CheckInput builds MoveData from user input. When there + * is no input CheckInput returns default. You can handle this + * however you like but Move should be called when default if + * there is no input which needs to be sent to the server. */ + CheckInput(out MoveData md); + /* Move using the input, and false for asServer. + * Inputs are automatically sent with redundancy. How many past + * inputs will be configurable at a later time. + * When a default value is used the most recent past inputs + * are sent a predetermined amount of times. It's important you + * call Move whether your data is default or not. FishNet will + * automatically determine how to send the data, and run the logic. */ + Move(md, false); + } + if (base.IsServer) + { + /* Move using default data with true for asServer. + * The server will use stored data from the client automatically. + * You may also run any sanity checks on the input as demonstrated + * in the method. */ + Move(default, true); + /* After the server has processed input you will want to send + * the result back to clients. You are welcome to skip + * a few sends if you like, eg only send every few ticks. + * Generate data required on how the client will reset and send it by calling your Reconcile + * method with the data, again using true for asServer. Like the + * Replicate method (Move) this will send with redundancy a certain + * amount of times. If there is no input to process from the client this + * will not continue to send data. */ + ReconcileData rd = new ReconcileData(transform.position, transform.rotation); + Reconciliation(rd, true); + } + } + + + /// + /// A simple method to get input. This doesn't have any relation to the prediction. + /// + private void CheckInput(out MoveData md) + { + md = default; + + float horizontal = Input.GetAxisRaw("Horizontal"); + float vertical = Input.GetAxisRaw("Vertical"); + + //No input to send. + if (horizontal == 0f && vertical == 0f) + return; + + //Make movedata with input. + md = new MoveData() + { + Horizontal = horizontal, + Vertical = vertical + }; + } + + /// + /// Replicate attribute indicates the data is being sent from the client to the server. + /// When Replicate is present data is automatically sent with redundancy. + /// The replay parameter becomes true automatically when client inputs are + /// being replayed after a reconcile. This is useful for a variety of things, + /// such as if you only want to show effects the first time input is run you will + /// do so when replaying is false. + /// + [Replicate] + private void Move(MoveData md, bool asServer, bool replaying = false) + { + /* You can check if being run as server to + * add security checks such as normalizing + * the inputs. */ + if (asServer) + { + //Sanity check! + } + /* You may also use replaying to know + * if a client is replaying inputs rather + * than running them for the first time. This can + * be useful because you may only want to run + * VFX during the first input and not during + * replayed inputs. */ + if (!replaying) + { + //VFX! + } + + Vector3 move = new Vector3(md.Horizontal, 0f, md.Vertical); + transform.position += (move * _moveRate * (float)base.TimeManager.TickDelta); + } + + /// + /// A Reconcile attribute indicates the client will reconcile + /// using the data and logic within the method. When asServer + /// is true the data is sent to the client with redundancy, + /// and the server will not run the logic. + /// When asServer is false the client will reset using the logic + /// you supply then replay their inputs. + /// + [Reconcile] + private void Reconciliation(ReconcileData rd, bool asServer) + { + transform.position = rd.Position; + transform.rotation = rd.Rotation; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs.meta new file mode 100644 index 0000000..01cb9f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/Scripts/TransformPrediction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13cad243fdfd7294e8a6a393735726eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity new file mode 100644 index 0000000..3b8f38b --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity @@ -0,0 +1,736 @@ +%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: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &192429403 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 7443408887813606051, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + m_PrefabInstance: {fileID: 1364334277} + m_PrefabAsset: {fileID: 0} +--- !u!114 &192429404 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192429403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} + m_Name: + m_EditorClassIdentifier: + _tickRate: 15 + _pingInterval: 1 + _timingInterval: 2 + _physicsMode: 1 + _maximumBufferedInputs: 15 +--- !u!114 &192429405 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 192429403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} + m_Name: + m_EditorClassIdentifier: + _unreliableMTU: 1023 + _attackResponseType: 1 + _ipv4BindAddress: + _ipv6BindAddress: + _port: 7770 + _maximumClients: 4095 + _clientAddress: localhost + _timeout: 15 +--- !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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ea31fef5ca1bc7344a72c71a5f9a0cd2, 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 2 + 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_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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1364334277 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606049, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606050, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: _spawnablePrefabs + value: + objectReference: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, + type: 2} + - target: {fileID: 7443408887813606051, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: m_Name + value: NetworkManager + objectReference: {fileID: 0} + - target: {fileID: 7443408887813606060, guid: 0b650fca685f2eb41a86538aa883e4c1, + type: 3} + propertyPath: _playerPrefab + value: + objectReference: {fileID: 27039729695437543, guid: f820efff6a2871447b961fc755212ba3, + type: 3} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 0b650fca685f2eb41a86538aa883e4c1, type: 3} +--- !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: Cube (1) + 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_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ea31fef5ca1bc7344a72c71a5f9a0cd2, 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 +--- !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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !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_Children: + - {fileID: 1112005916} + - {fileID: 1470934491} + - {fileID: 555580085} + - {fileID: 1852016427} + - {fileID: 872683031} + 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_Children: [] + m_Father: {fileID: 1784594015} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity.meta b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity.meta new file mode 100644 index 0000000..f444295 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/Prediction/Transform/TransformPrediction.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 23d8c720c2338a54c9787668c81290f6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager.meta new file mode 100644 index 0000000..5a149c0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ce919ae77eaee5459c4c0b47a7c13f9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials.meta new file mode 100644 index 0000000..dd18bf4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e72a8e512b2ca5142857eaab157e8f03 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat new file mode 100644 index 0000000..99f4278 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat @@ -0,0 +1,78 @@ +%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: Black + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + 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: 10 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0.177 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 0.39215687} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat.meta new file mode 100644 index 0000000..b7dfa60 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Black.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e7517d1496ae784f94a2307a88e2bb5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat new file mode 100644 index 0000000..cd9821d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat @@ -0,0 +1,78 @@ +%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: Blue + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + 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: 10 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0, g: 0.6867471, b: 1, a: 0.39215687} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat.meta new file mode 100644 index 0000000..abdab7d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Blue.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0a99caade0a68842b2274726d1bc7c3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat new file mode 100644 index 0000000..04c1cf8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat @@ -0,0 +1,78 @@ +%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: Green + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + 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: 10 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0, g: 1, b: 0.030314445, a: 0.39215687} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat.meta new file mode 100644 index 0000000..92fd8a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Green.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0dd7b8c357813f4ba3ae9b60783a6cd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat new file mode 100644 index 0000000..19a839c --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat @@ -0,0 +1,78 @@ +%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: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + 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: 10 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 0.018451946, b: 0, a: 0.39215687} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat.meta new file mode 100644 index 0000000..7dd93d4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Materials/Red.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a35bce0c956282a42a90a04b25492fb6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs.meta new file mode 100644 index 0000000..6dcfebb --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff677f3c29d59764f917114e0ddf4323 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab new file mode 100644 index 0000000..9709db3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab @@ -0,0 +1,342 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1659630665519808908 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2767813079423793104} + - component: {fileID: 2155251397865338026} + - component: {fileID: 6670251115109007609} + m_Layer: 2 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2767813079423793104 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1659630665519808908} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.893, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5090726670223187106} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2155251397865338026 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1659630665519808908} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6670251115109007609 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1659630665519808908} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!1 &5090726669533971462 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5090726669533971481} + - component: {fileID: 5090726669533971480} + - component: {fileID: 5090726669533971463} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &5090726669533971481 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726669533971462} + m_LocalRotation: {x: 0.04100376, y: 0, z: 0, w: 0.99915904} + m_LocalPosition: {x: 0, y: 1.56, z: -4.5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5090726670223187106} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 4.7, y: 0, z: 0} +--- !u!20 &5090726669533971480 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726669533971462} + 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!81 &5090726669533971463 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726669533971462} + m_Enabled: 1 +--- !u!1 &5090726670223187118 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5090726670223187106} + - component: {fileID: 5090726670223187108} + - component: {fileID: 3514369712614123748} + - component: {fileID: 474764807019926078} + - component: {fileID: 611616139817875448} + - component: {fileID: 6420552185407096997} + - component: {fileID: 6654616088585099699} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5090726670223187106 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5090726669533971481} + - {fileID: 2767813079423793104} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5090726670223187108 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26e4f626a9ca9704f9befe7673a8dd15, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 611616139817875448} + _networkObjectCache: {fileID: 611616139817875448} + _camera: {fileID: 5090726669533971462} + _moveRate: 10 + _clientAuth: 1 +--- !u!54 &3514369712614123748 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!136 &474764807019926078 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 1 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &611616139817875448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 15644345540858261432 + _sceneNetworkObjects: [] + k__BackingField: 0 + k__BackingField: 0 + ObjectId: 0 + _networkBehaviours: + - {fileID: 5090726670223187108} + - {fileID: 6420552185407096997} + - {fileID: 6654616088585099699} + - {fileID: 0} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &6420552185407096997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71fd7f855ec523429999fc4e14a1928, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: 611616139817875448} + _networkObjectCache: {fileID: 611616139817875448} + _overrideType: 3 + _setHostVisibility: 1 + _observerConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!114 &6654616088585099699 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5090726670223187118} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a2836e36774ca1c4bbbee976e17b649c, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 2 + _addedNetworkObject: {fileID: 611616139817875448} + _networkObjectCache: {fileID: 611616139817875448} + _synchronizeParent: 0 + _packing: + Position: 1 + Rotation: 1 + Scale: 0 + _interpolation: 2 + _extrapolation: 0 + _enableTeleport: 0 + _teleportThreshold: 0 + _clientAuthoritative: 1 + _sendToOwner: 1 + _interval: 1 + _synchronizePosition: 1 + _positionSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeRotation: 1 + _rotationSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeScale: 1 + _scaleSnapping: + X: 0 + Y: 0 + Z: 0 diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..a7f29b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Prefabs/Player.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bf5f023b4017a5e41a9815ec5745df3d +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png b/UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..de8858be547b80ed95625e647ad78ba294db93f5 GIT binary patch literal 45367 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

mHVGPGm}y`7lOc`|kw$C z2y*v)t~S^H23%Q`!!{hgW_W&lTw&WcYJm!0)l1R3f)~SF;3!XZ}6l-+U;y`Tx5gdM4`f$o2(Cd!8x$sr>PmZg!?|SAb zo*}u6td5;{)EMz2`}3&{pT%MWyvt4HBD%BLW5qYOwkMiz+qPxfmXc6nA#arAcHF^X z+pXtxZ-&3$PcCK#bM8L>R(o#LOlnz&x=ozQ;P+Woy?MHKl@2TQ7d6~nMxMFn$a#gJ zvH(_VzbvJEKJlWp)3A-wTd52w{vp>r*O&n-9v06lYJJQ( zXDmG@`9<3%*#pf%O{YE(Hf#)Bi9l9a8(5k=GEV)CRDJOMM~_7pR=F3sZTL*P75j7n z0_n7xoT65%TD94*YxRlV4bod9a}VVzp23;#YLY-8vm%+5GTqXgJAmu@Va1TeruA!V zr05z+Np67%q;*+aXNYGA0pS|$E4AgyQWtrRIryjwi(DfFGOg8vutl#}7vcK9jr;)C zSXU;KcI|_k&a!L0qr-h_T=To-vU_88Hn;Z0RTbps%Imx6DcbA4mvP=}vKxKuamVaH zb4e7zD%N#bGi?{yV0F0i#ve8Dbe(rA&)w(>^gJ$cf9vZul`k=v_-j`_C zn=k|@U5oi1 zbI@1nqhK>16!7TzR*UUvfnTvsR!h#h%nVS(0G$;A@&-UzSDC@qmR-NY-1A`@?T1rk zi(zzHh|wItD6)5WH|N4_#MV1ucdGUp%sE^pkPHISihQ>=)1$w!Nf#oh;g!7*e)fRC_p9!kXbH7raMAgt>cHMv<)>$ zZ-2O}-ZefFL2c4XF*`KmK4vX<@!3B6WcB(`g}!1~PmJhfHL19;_F&z`%YcEAeH)|& zOL~UAFNwDB1#MZ1ixq7mmf7Y+-A+qWO`+!AXB{YbdEdo|vywm~B7dO*%` zqS2N)YsKL7N(WdjK5Vwf$&mx8_OLL49RtGOosfb zm<6?;sU%zbwi5jww4O)=c7~WSFbQdcFN>zZ83AUyPrCdPC@JZL{*Le2t5xx5| zAMyz?vGGn;`>7`%#N<~p!RgLUOdro7gr^m<_*qp{zYHrIzwnq?`#R>`@dKW=IecBG zoG}~iF<(z_o1u+_(3WhnlbFk^@514rI1T%*%GjqA7q;7E)qS;Q*uPF7J=}$Q0@p@t z9Kpl-wbo=FE6|_FPIQBI4Jcr3VQN?!!euR#5s%ljxApy59Oax^S&A|)K9f7rQPpLT z<1_1BC#QN)v5xdTC;F+gW&cSc#gAkVgD-L>rxa4fX$2oj^w$a)P-oi%yGHZH$r*N|=}E9ZWk@=unE&*Ftk4>Z1)v5yN2F;Uu_HsC8&EYv7omFkTv z-Lvl34M;@omCA2+%-UQxbRpi^tm%Zsul_EqM7Iil;vCqbYQin*ywl6u@R2&Ogo>!^^uc?MZ#s4r)Uvf)@K*xmLK#O*rmi-39l}b;FMO)b5M`r^){^6#eJ7qYvW0d zd41FY$f%d4P)=ALs+g<=$g35rgi}*+y40DOVQQRBS=$xHzd){wb*f;tWtUbuQM3YM z7}Sg(4r{t8MjK(;_jldH6&}fI=B9r>m+A@n{^RtW%Uracx~CF(#Vfi3t0#rZ!`&up zWMQj+4_nUIR!UrywDt?&2+GK(+vqm2glL40=B`s2dH6W(EvmgJx1k zpr?qi{7IAB&iXS+`+yPGcF@saIXSuCN}Yr4cLwX;HG}PkK9+iqn3N zb8X%K=BECCd-C5E!tEgUY~VjXx^*tz#wG&Y77`LQJFe#7$qMA%eO!upZ`oJAdWY`{ z;o_M{;t=ocS+{g6EexQ499tiQQSfpPPz$KRo%Z_e)PpoUQWj4z3wHkcWCD2J=9xw@mYJ zkJF(&jNbclCHrU|pEqZ|GL&aU4Ds?8i-tXKIJ^(@yJriK{AC(d9UDob)u^cD?|kzB zmfv7kO(pU74T@nqyvIj}_YAfkBl~H68ESUB)S*+=pd0vN2_BQ?Z<=yR$!dyWBq>7i z8P=?3Fw7aR7I-smhHwo0_>c5``jhErdYZRW#SiNa;?r~N)NAn}NTX=i4hJ%l)$XXg z9W;6m(n_FHUeHuXUk-Ug17rB-6N|F#d9#R;k&C+npCj)_?Y3?EHC<7@%yG>vZ`w8; z6u5S2P(Z|sgr>O9E10vcC=oTQ52njHXl_BikV5OIQR91=^6(WzRUd;nwU{9m?#PzY z#7CHfD_>9AMOJPdUi3gP&)u#-%*TztW!oNu=E0zB(!=Jtk~RWfx*KG=4HN})9MU}U z9L>=*`cxeeA~R?d1caz!9&{7!E#%t$-0hXyORI;BB9WN3H!O7fu~S_5fz(G#`G=oo zZ%06(9--g<6;ag!*vei@w$)im5EFhdsom%<5emyTHA14DzqYF2GV)`&R!q%X(SWPq zgPGn!t*Z^m`#Y{sMlmMO!9R}#etV_1$(fre%@BSNKo?L&RcH$O#!Uhn*@Az51C6}Y zCKq%k>@4Y$yXKK;PHicvNK9t|R6&p~Icpw4fd;+oK1t&}CYuaPvgICr@>oO`8W{GB zL!!5?D)hk@kL1>&AcIoHaG>gaV3K{UHbqd$a zMkD11jU)jkwnS37+-g`NV{D1aiE-D_5*d?iY!Rl6f_c>YYP0{Z6b0~VCLbyRsm|L9H!qs zxu6^gzQ^f6D!AB>CxMtQEJXz{*i^-MM-ZHdi}=|{rvng<>;NuvBVa5k1SSQ+<~S zTdge}@$lc+kgtI)as4y!e-c;9?x&U~OSZeb_F>~B-q+zd*=-I#X@9EWQi$!~5Z1M@ z)&~ySC?*LwTYUV!TJfX0WVLJylWLFPy(S_ylPumRsXf2ObDuG*t8%NYy6u9<6x*DR z4Kz{rfd`jpIyPhVw9@W_cU*kZVq&9S*WWmnY2Ov+7yY!dl&S?2teTvlBN-;ZC97$n z3B2OML~=C*ZWdP;Zc7__d1ReBGj^i_KcWBd!OeOxuU{U{$n|X9qTX6k8UxU%DTUeN zIh9o0P;R9tVc>>&k`t@G&AWzDCs|7Kex5;gT~S(XoUavFN1`&B%#doOdimhxVPb6>41FTZo}DS7k-xj!4E%VcoUYhPl@Vy&9C6X*S6o)Vbs1uqgJ zU>~^1Mn^?OIjLyhHXow#53!vJy1i>&Eij20$O@J^F43KL#>PFuiM{XUVfM04@wLu! zoguH^%M8{7p&}Gv@FxGqx{*BRhujmv&X)5OTQ0;?tn@$r7-%f{tEHjh8{$$IR;jYC zo*txFW5Gdw*jDm_xb%~?*S>74ob#~q`JuXp^$5Rj^jZN6Png_B3wc`#UO0Ot8wmVU zzq9qTbrz~WlpX&9uZwrTLtZtA3nJ*Xre18;c1eXu?^uZ+kbI4!gnAgn+r z?nVf!zLycv#$;Upt6Tr8qB&g7a{mSQq*{r?eMe7gPfw$EAS`_jgAzeBRMf$mZ)*gf)|JseRKbNnbi2O z>f5?cW9#6=+Z6~8VnPIp+^)M>T)08JzA|IzT)`|;<1XwO(V!%dpukowAzNcQJ}q*S zgFN1t{0U9W9$2#q1dXxMjC7nZ4095)t;TshQhz5M$_YO;D2honmFSg+s}32NVi7@I ztGytAfgL%5i6}9{pBAOhha4AxQ?qGc|F!ZZwE>fbV7(zvO zM^&UuOrF_@C~nFzM(IBZ9OCmA#DqD*Gpo~XjsqaQ)#3} z)^Y1?+^yz&}H=z%{MuSUFLE17J!;>b51%#D2 z!+{nSNZ+9kCf(P2oUo1{@ij{j%P)Cr9(jpa{;5wg=^oOd*aw?j&_U=GXDQV|?sNsl z^b!1X6lL}50=>Ky>1FJLfKj2fp;w}?_^~u(uK6xy-d$_7Q{&&EA1|YVnJ*4=A0+C!7b@Ce>tv+Qk!c}Un10l zE;+2S`@+{~vRv-{{ATfx6yy?~?E&%bJ1zJ5VVRj~F$=RW&m^lYGJp{7WZKj1TB39_ zmNT`}e=j3V{%Tanjm4%jrQT!gb9*myIeZ$ARqtHL} z`->xc(G@cgl1NVypL)lA{YTyi2igK zmiwu?r?O;33e198FAh|8rgI-gf=leQEr3^;*`(;p@b>@%Tgoy!&MgE<7TkBg@7 z1DHF<##!viU+Qgbqoc{-_(P@4c>{x=;~|P&~PDU#(ZAQ~aSI_!Fw>bV0vy zrzz*D1`K;>S&`0TdDy&>dlUsho=Z3BvKRYi!A2LRu5i_X%hbMaldMHa#FCx(3(tl{ zVXq5QA{t#r*JNNkI(lOE%QT-g`vy!qK%Q|gLY@tu8w3;Y+}dkVhus;Qz~vKGH%R7} zA1QA3-Asfn`sBt7(+nM3Aa*im6^L_O2jlM)z~Qrd^)bQfmL|lGbuiui7*PLtA&f7_ zgNL`~Xz$)tZ{(i0ZBi5(!-wReFTr?6bhhPx@>U1*fyrS)n=)O}Y#WUKUnf`V2%i6N zPo6G+&CQ)J!SAa@`OZk#Wsn_p@r&*2>q}u(Z*-~X8{DBZOdwZw&-;!?pF@gKCv8=4jX@cRiz};`3$50mAzO8S# zvaM5a3TJ7 zL4#hIveUElXaQVW&Ykwzj1+iDjtVt@u}_7YHzYn4#Jy&IAUN6L@h*xQ)Po*TEFbW8 z{%(mgGd?D`oFNKx(T6jtb<^2DN8q(>xRhIXzmbb(yfpgpTsoI?EVCw!Idys<)EON@y#6 z!kp_uJ!#8MR*bBz$}W&=#+fBmWLfTZKH;15R@O+c$>&{<+TTYU!#_)~@o#M5KloHP zJG-Kzzl5krt(plhfhln#8jx)_Qb@00KhXHY)duf!oj1m z6kn|+#*Hqd)YKiVxW26v6i5pu66G^h``&d<9M6xoWfiFOY0RwSu7%}-K0yUS$%#;l zm;9L7lyNd=fMb(p+ezh(v)vZ*p(tcB*cpiHe|zNQ3DSP*I%}46mDe_Eqni6b9*0`< zvrVjdlBI3oiL8zk>avEMj=Fy9q2at#gP~>7Mt^tSE;6Doakpv5G+aH*CZCNwB?c#kFpfHBOWULz%s6L5uv+uSLziH5#n#-7z|}!YW&~B(b;!xPvg#{5niP| zbfPFdcKP8Ks)B}>r8$)`_Ke}>ZaXvpcMVjrXm2{(ayI@Wtp?GTAa11KwMVlxCFK-E z9?DMZ;zp|NZQwT83m^P~%P2NMJ;zbh=`SP`;#B3(LA;+~lTV1XZKZFWh^OxDhBM(U zl}){{CDztMJ%eRU(7!QizLJJ3k!$vIVEHcmSQ~l#%w+-uQ-l(;eK~c! zqHy%|WrDCw2T4x;$#wf1BM%cCY22|JUJI)|!;!GjiebxZux8f1p~cLua*f(!$OG;V zWO+`IE;aQgwl!?A5Fh(kd9iS8s1;zUMEMVQ7~Ve3hPZ}&ro~5isaQb=mCS!g(XcvJ zVQbQTnBBJv_P?u|XB5vCe6Np{h43ar+u`wJ6RyK;{==HfadOXB3j#iqN@T3Hk~iL= z8QC~It{I^+n&hAF`8+l3Yz+U6>42>^fmW!idp$0wEQRAbQkIAVr>c<7U+Mq(x89Y7 z6TkH)FNnndKR)d2 zcyFieXz7FvX<$BS_xQlXAPe4_{DJB^_peaVrj9cwxRx)y#=DtOywM(Jqx`xQwGW8~ zeeWoib6xZOH*3>Zx2CMTXvt&mrdF~u<3?)v%93^5XS)rL)^TbF^ZbI!MjA5XU}92V zXRyjdaIb0MkX&mNiKpo@Ii>lt*7V6*04ykosY9s^@ET+PA=}l#4pPA_gDv6yjL|{z z=zLqhQCAYfcW9S?+$fhkwvr&0>VBcAH#@E)@rjdHWe;s-7>liUh`op?C>iPY;56{> z9;A-fXH)A=8=l7nm*w~|>l9Bh#yP|Owxo`s@pnybU1xkhkNEHN8*OWi@}HQ4Az0== z(l=4@hB*IDgudTdRDXC#E~pG?aaa79?Kr!T@x!`_H$(n$zC$C0yT?Z-#tm_Ka~1k; zN4exf2a9x$f&`T~>Ri<7W0&uoOZS0mXR?Y~>llCCjsJh#m^DmDefZ6X6pn zr!6%mdMEgnt(GJ}pm8*~kkGo$?eZUufc}x#vci#LD)sU|4i#{np+@0AqxbQO^3z%| z&UA?{R+bu6{PFsEQQGXCZiHNV2j?y>FEwmYj6tKvFbkS?8Eb##5^;hoI}}W&U(C>6 zI55w3zw1>CZDKw{vqg(T5wl+PeGdMc(?~rjhx#du44<=TUr8kal~$y-k%^YjxKoXs zhHYR34cv~R)!VcUL1|8!a&Gs=sG)@#REA++;*bq@cHRKz;81KChd~*s?<5)$nGQOk zjNVS__>=iBH7CYx*@y-WL8%=SXI4ME5p${ThnMzqBUouHD9Wn$cBGd{^W{r?86SS- zKTq-Rn;0Fg3>`7g<7xomHR`?ZIuGtl&0m~5KAL!_x3e?`&Kfh5(vZwbp~`c|yR)e& zhT0H_J*idaluPd>0?OFIrjIf$wYhq&G(ivsTUdLSb)6}v_D}c?oM^54p|H|$XSQ^q=k0OL;GJ z`d_wI4joNx9B(dfIyK~4*YG_k4jY^dJ8CUiQ|CJJ4F1aCmG`)|Hs*B|{u}+6*A!eJ z-33TEYM4+@7xk`i8}98r)#8y#jNNOKH#g}Wav%Q6v<1%64!QabAbs!yzhN-8jD7vt zKwp=xjYccKVWXbj!4a*6>v;g;tpLOxumxZ_qM~W=-7-R>7^;p4*ZC<_h7qH?Z1RDHeWRw>Bj@JNQVqoHCy`S@t{~5S6F=e7C zpZKb#rY5wIMC^ML`J>=NnD00rx-KM`TB!9axprJ7RT$XJC@eq9~VL8wv_u(^1mJK z>guZ9l$U@1GbLQb=zZU;(k0XFqUk=#x{nF`lERcBpY|{~ul72=-rfh0B|K5Z%qnXM zzTD*d1UJne|ASMK>FC|j)pfFaOtv%SqIN-LC9TO#TZc=rYZ&TD`o7zDv&uBD@DC2l zfnxe2KBJU<@W^T7M*cQG4&?+TxQIQXO(v7!?e7NRhFKwPl3~-zsQ>6^ZGCN;;(9Pc z_cMEt^lE^m0Ya2`npH}+{zqE>uk^qEi@2K?m+y)_t-!w0UoLyqOdyi}+8-Cy&J&&U z@4%6u!dbGuzcYmz3Acw6+M{OFZ~jjYWc?qF&lL_FEZj%x)AslHd*U~#`}dpp|4RB& zq=NUO*UFB=8=qF8t6FsaDYnL&80VE05QkpET_!jU4Gl{4Qx$l!wT;AWdx<`WPJV(umG#f;Mwi~$w@1zC zx{n1H58YQ=Bsa~^PVb*T@p*nLyj`tBw6@Z}5z2QU6t){%+9F7@X-pIPA67OFzwttK zMbsaPPz29*V!&2~?=WM|RLcIj@ic|*+p03rqf&;huSrS#e9V9FSQ%Uc+&FLS;n|sj zWS~Ao)22DOvnYCcdMgnbK#p6MjF_O3UI&7?bEe_!#zq%aLxB=Cf;@ba?Ed!yD_kcA zU8B&AHwt_Q5iddY!GDYmL&!wV)_0Eq+)v&Mcbeb}cHJpj3*n;}SH=PC!)J1~bH|({ zh&OlEqBNIe0@VJ*KtOnp*)rgcab#|fL-*yjn1v&>ijGGRaB-T@A~VZQYUvG@-JL=9 zANTf#7YUZZRVlXULZYMXQAHu6@J4xcCfQJvS2#h!zDAcC^_!l%y%m+$q=bFA@m}WS z-LORu#fKHaIERYS;bKlKnH&YNEDcRfQ}qNJJU(&Qp}D`oyX|)GTN9OeW9#Je;7#<& z^u9NGkT0q}@H;B*=oAmzq4Wf-$t~Xjrz5T|hq}`F>0EHBXq}D*2sRyO+j@LhggNikH10igk&C;&)o^5&1oWpl`YWX2- zMOc>6j?Mis9{g;l@Y@iNn0I(AuQKJTO~MxS1mDq~($<2Z23P~>Vz^r0(g0p~A7?we zYsoLDoQfb;dMC^df}xAgUuDj~qKN@jx53V#D0Ys&%F=>R9N@I?J1g4&F|^g;-$H=& zd!yXq^AV8Gvs415F4c9gcQl&QZ?e{3+yklt|*(u|mAt?bAqKq0sdXZ%PO(e)Wu$I!5_!fBboR)dkx zBSuTEpw#RGwcM570e%8FijD_`MclQC&yT5)Y(ws$a|~Ali(*eqJD#=K_n#ZW`GIge zwh0YlUYnoFvL0%y%CBGbfYD1K)~izz^UFp;Jq;TxV;trsjNo1JcR=;+c1*B9`IF8q zUD1+hc8Y0T_WD2+4db;!?Fa1cp+u()s|dJjBwihNtb$A!>Ml=oL$Bk_ld6%g3Ozm4 zXEWq?T;jYC$*wgEBuCHr+Zf z-V0)(P-l=>CHpN_+V}(#;i&E5z%+yJcpcQ;fRTQ}g*HKndCGO7m7adRjrH+8+&xOg zwe|M)KG<=<*?fBN)c*~wW1!NkzLRsnd7Jk7Bq(%oZfwj>iKp?pvp>01Fnh{Noqbkw zC_h$ApE$&fx>afO>B;5sy+=?AQw?)AJLGkJk9uooXFRu&g?syMy;h34;1Lu z?2uS!uUK!*iH&#JlpntQ+KV)*>%o~>9P)h^;;Y2Ab`pit)mxiAra0fP{=thQeU*Eo zjTRpmyX|@i7i=G546P=~W>DdB%4+O3lc6CE4PHGC&Ntg)0`}K?KHH;i+kKwvpP%T4 ziwB1XN_VQOp{;}y9nRfl$B8F}?L(ANdD+Wc1_rqNwp8fG@hWI`tV0B*5$DA?N}NXl zCktrAs4578YMm{2!$btmn`$yH`YGi~Cq-Yk|3bW(W$k-U?>GBO8O@GStVev_h`#L* zpT=VF3)ofl&V00F{GJ@YP}q17BQqrYu6vh6*FCrMy^Np@a-CR~sYNwAA~9drfjsn! z4eRpt-hFC0e3CDrujVF1+x*{I8zzz(O9*C7*{qzj0PC@96gU7z0^vU8G*angI4BVXCF zV(WPB$rFo9pMq#|l!){1eVUuB_TkLe=@SG;8u9g-Ty-!AoINHYf{?Ft#9}g%0T|+V zJ9P55D9sR*LK#C!6q89&OYP zO$>g?YSZwwFb+%(n{!L@wXd^qQzzNwkxdJoqJ4&EN8q{i2oHTh30)B=3E;&(J{sN?g zEhblT(~pqa-DM#@7Ybf_rf^%d0Fu>7>S956ArU;aK$kB-p1ML-6cw2Ic8Uwyeiv@v z3MuO25&>~2t39>Q_W*0?C49UaCA25kW%gcJ_kW|i=sGUuDXcXLn)vG(8p@g2iT#;X zHA(8XAg4V#I@;OzbKn}OKd*8Z@!8wcx&{0k(Aq40iq_>#{(lKZ-_TGK(m4?S-23u% zqMPn*ydSr#D-{Y=PkDRSFeT?u9RIX@4_z(Jczb(Sc0p^{81J^Qg_GF*`0Af`5cKI` zwT=+z%ddjoz=|q<=aM^ye@0mGoowVodNf#eP$#i%)1P+Tbz@L_5^B8b;zfVnX00IM zpc?Q(JfBnFs$_2Z=cjQoMt0EQ`=7bzq-)_dt$UH1WPo>;&;%)jUfYWNt9$BVsHki> zdGh=(dh{RLDb@%6xt&6kSS~A?1ji6s#)Jw;y5WDKi6VWunX20_Q0V}33gq(4rUGH> z1a4Elpmm~FT=X44hpIT6Dd?AW8it&5tK9yIX zq(K8FIRTSEDT#2BtZ& zd=*g2hNP|&YU1YqacOg(WgcTv8vL2iXY~>q)q@)%muTN~lz7pCUU)LumEZ5Y4y5#2 z=*+VH^hLjMZhzCX)=1+*S^0>9$LjFVHq=EOU;$O&0%evS53LI6bZA-t$3*^C!6rCv zN0y+D{Y}uRAY^)16WgnCHMBxBm21wNeN3|)_7b}rg8IF!7^d~tr>Ian z_0zXNSFWU)YTCExMuQLF=Lxx~cm=yg;4#io;`nvc_%DhIx&`)H({lldQUKHe1FHDT zB&Npmh2O=g-y;aVGn)Etm*Bg>1a+~D?{o)6N1zB@u)^hP0^?d z;0}44au226+|-A>Sz*Q&;w*>o+npiZ%!IHnzYG>UcAuJB=SnJSVW&a$LyCV4bjur% zdHr8dY?vp-mRHWaQX$(ALC|#5k2cCxck24p(=vy(qS`}OAO;y_Y?9BTq>Nb#~QT!4B2fQ>RW*9jzPB4vDCnxOvsz{6+eU^O@I#{QmK)na(bI1iOn#cm{O^_%8pI-9XiYORFV^g4NXdV1~$ zx2Cp~_fD2_aDo!P(qW9a)RXE_*XKfeu)`u3pCea)BN+NCt5;cI*m4(F;6LO}E!3^u z*(s~IKF`WClnZ_8t1h_^ZPfE|?vHk5-dCrq*TGO&U3_-+eQ4EI{1N>@&6!veaey&Mg4@^;3;rrzj$obIqQM}u)?qSBDq(6r zg$O`$jV!jOV5sCmmyi%mlaEK$kQ9>xLAVqXgiv-MJnuT+3MR}4po=k}+$r%=B$JEL zpa?gYR0#wjM3RIGjQbpG3IAXPf^Z8aMC`w=`y2tLP*QVmfj}-nTb$4t(R0I?rUM0_ zY0{V=yfL-9ib9~(0CbZ8=#**hCL+Mp0Cbi)_MO2L71h_Uw(3o`psJQ(s>*f>X4ex8 z(L1}MjUHlx_s*^#Zwc2@t|t zn8??yG2`r>x3Z!ls0T?P{zV=qJ4(zrYdob4MeM*A5_udq#WImK;0FEILu0$Pji-*H zRB(~Z#BLMpmnNNl^jp{pli9W;%?*r&BIrN!A~)=pvjqz^W}*+$wTm3kPm#f+xpUFa z$ME{e8R(bln5K2;rwH*Uo7w26ooi4T`YF=&`rknEf6&lF{BCj+a9i*rgV{4NQ#R4( UDXC%0bHu70Tg|snjO@<+53I9EC;$Ke literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png.meta new file mode 100644 index 0000000..33e28f3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/SceneManager Event Diagram.png.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: f2231de60d345664cb1831a2e2ebe776 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes.meta new file mode 100644 index 0000000..6d8db28 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf1de1b0d2f857d41ab48f999ffc7e2c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive.meta new file mode 100644 index 0000000..2690e79 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d3192e4db2057b46bdf0b1c61bed424 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity new file mode 100644 index 0000000..4e63925 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity @@ -0,0 +1,264 @@ +%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.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &76845508 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 76845512} + - component: {fileID: 76845511} + - component: {fileID: 76845510} + - component: {fileID: 76845509} + - component: {fileID: 76845514} + - component: {fileID: 76845513} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &76845509 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + 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 &76845510 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &76845511 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &76845512 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: 10} + m_LocalScale: {x: 4, y: 4, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &76845513 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 3284346746 + k__BackingField: 14106161864781660253 + _sceneNetworkObjects: + - {fileID: 76845513} + k__BackingField: 0 + k__BackingField: 0 + _networkBehaviours: + - {fileID: 76845514} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &76845514 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71fd7f855ec523429999fc4e14a1928, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 76845513} + _networkObjectCache: {fileID: 76845513} + _overrideType: 3 + _setHostVisibility: 1 + _observerConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity.meta new file mode 100644 index 0000000..807c4f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveConnection.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cc489be8bb6ae444283f394c5e5fa8e2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity new file mode 100644 index 0000000..85d0f6f --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity @@ -0,0 +1,264 @@ +%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.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1950515027 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1950515031} + - component: {fileID: 1950515030} + - component: {fileID: 1950515029} + - component: {fileID: 1950515028} + - component: {fileID: 1950515033} + - component: {fileID: 1950515032} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &1950515028 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + 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 &1950515029 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &1950515030 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1950515031 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: 10} + m_LocalScale: {x: 4, y: 4, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1950515032 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 2384367787 + k__BackingField: 10240781668764572782 + _sceneNetworkObjects: + - {fileID: 1950515032} + k__BackingField: 0 + k__BackingField: 0 + _networkBehaviours: + - {fileID: 1950515033} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &1950515033 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71fd7f855ec523429999fc4e14a1928, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 1950515032} + _networkObjectCache: {fileID: 1950515032} + _overrideType: 3 + _setHostVisibility: 1 + _observerConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity.meta new file mode 100644 index 0000000..36036b2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveGlobal.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c43835f124dc68747a2091c4b8c42f80 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity new file mode 100644 index 0000000..c6a2b98 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity @@ -0,0 +1,1261 @@ +%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: 705507994} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + 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: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + 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 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + 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: 1 + 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_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: -2.2843354, y: 60.72741, z: -2.9938574} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1155569020} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &825925881 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 825925885} + - component: {fileID: 825925886} + - component: {fileID: 825925887} + - component: {fileID: 825925884} + - component: {fileID: 825925883} + - component: {fileID: 825925882} + m_Layer: 0 + m_Name: Connection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &825925882 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &825925883 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d0a99caade0a68842b2274726d1bc7c3, 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 +--- !u!33 &825925884 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &825925885 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -4.7799997, y: -3, z: 10} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &825925886 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 0 + _moveAllObjects: 0 + _replaceScenes: 0 + _scenes: + - AdditiveConnection + _connectionOnly: 1 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!114 &825925887 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 84ae572fef1171b41ab287d1c9b5da63, type: 3} + m_Name: + m_EditorClassIdentifier: + _scenes: + - AdditiveConnection + _connectionOnly: 1 + _unloadUnused: 1 + _onTriggerEnter: 0 +--- !u!1 &1155569019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1155569020} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1155569020 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155569019} + 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: 705507995} + - {fileID: 2114768053} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1406093434 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1406093440} + - component: {fileID: 1406093439} + - component: {fileID: 1406093438} + - component: {fileID: 1406093437} + - component: {fileID: 1406093436} + - component: {fileID: 1406093435} + m_Layer: 0 + m_Name: Global + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &1406093435 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1406093436 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a35bce0c956282a42a90a04b25492fb6, 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 +--- !u!33 &1406093437 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &1406093438 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 84ae572fef1171b41ab287d1c9b5da63, type: 3} + m_Name: + m_EditorClassIdentifier: + _scenes: + - AdditiveGlobal + _connectionOnly: 0 + _unloadUnused: 1 + _onTriggerEnter: 0 +--- !u!114 &1406093439 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 0 + _moveAllObjects: 0 + _replaceScenes: 0 + _scenes: + - AdditiveGlobal + _connectionOnly: 0 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!4 &1406093440 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 4.89, y: -3, z: 10} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2114768049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2114768053} + - component: {fileID: 2114768052} + - component: {fileID: 2114768051} + - component: {fileID: 2114768050} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!64 &2114768050 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2114768051 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &2114768052 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &2114768053 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -5, z: 0} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1155569020} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &174578014943721374 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6832184529280211084} + - component: {fileID: 9050426448999039876} + - component: {fileID: 3730311944083398519} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1661284633666962301 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7114397409874979456} + 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_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 &2085292595826649312 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292595826649325} + 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_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 &2085292595826649313 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292595826649325} + m_CullTransparentMesh: 0 +--- !u!1 &2085292595826649325 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2085292595826649326} + - component: {fileID: 2085292595826649313} + - component: {fileID: 2085292595826649312} + - component: {fileID: 2085292595826649327} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2085292595826649326 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292595826649325} + 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: 6832184529280211084} + m_Father: {fileID: 2085292596359202251} + 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 &2085292595826649327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292595826649325} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 2085292595826649312} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2085292596359202263} + 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!114 &2085292596010868064 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596010868077} + 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_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 &2085292596010868065 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596010868077} + m_CullTransparentMesh: 0 +--- !u!1 &2085292596010868077 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2085292596010868078} + - component: {fileID: 2085292596010868065} + - component: {fileID: 2085292596010868064} + - component: {fileID: 2085292596010868079} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2085292596010868078 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596010868077} + 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: 4928688179816641390} + m_Father: {fileID: 2085292596359202251} + 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 &2085292596010868079 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596010868077} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 2085292596010868064} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2085292596359202263} + 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!114 &2085292596359202248 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596359202262} + 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 &2085292596359202249 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596359202262} + 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 +--- !u!223 &2085292596359202250 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596359202262} + 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 &2085292596359202251 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596359202262} + 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_Children: + - {fileID: 2085292596010868078} + - {fileID: 2085292595826649326} + m_Father: {fileID: 7443408887680269496} + 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!1 &2085292596359202262 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2085292596359202251} + - component: {fileID: 2085292596359202250} + - component: {fileID: 2085292596359202249} + - component: {fileID: 2085292596359202248} + - component: {fileID: 2085292596359202263} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2085292596359202263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2085292596359202262} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + _autoStartType: 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} + _serverIndicator: {fileID: 1661284633666962301} + _clientIndicator: {fileID: 3730311944083398519} +--- !u!114 &3730311944083398519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 174578014943721374} + 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_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!224 &4928688179816641390 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7114397409874979456} + 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_Children: [] + m_Father: {fileID: 2085292596010868078} + 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!224 &6832184529280211084 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 174578014943721374} + 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_Children: [] + m_Father: {fileID: 2085292595826649326} + 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!1 &7114397409874979456 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4928688179816641390} + - component: {fileID: 7408958669887450887} + - component: {fileID: 1661284633666962301} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &7408958669887450887 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7114397409874979456} + m_CullTransparentMesh: 0 +--- !u!4 &7443408887680269496 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -2.2843354, y: 57.72741, z: -2.9938574} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2085292596359202251} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7443408887680269498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7443408887680269496} + - component: {fileID: 7443408887680269499} + - component: {fileID: 7443408887680269500} + - component: {fileID: 7443408887680269501} + - component: {fileID: 7443408887680269502} + - component: {fileID: 7443408887680269503} + m_Layer: 0 + m_Name: 'NetworkManager ' + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &7443408887680269499 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + 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: 1 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 +--- !u!114 &7443408887680269500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} + m_Name: + m_EditorClassIdentifier: + _tickRate: 30 + _pingInterval: 1 + _timingInterval: 2 + _physicsMode: 0 + _maximumBufferedInputs: 15 +--- !u!114 &7443408887680269501 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} + m_Name: + m_EditorClassIdentifier: + _unreliableMTU: 1023 + _attackResponseType: 1 + _ipv4BindAddress: + _ipv6BindAddress: + _port: 7770 + _maximumClients: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!114 &7443408887680269502 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 68828c85278210948b9d50a8db3aab74, type: 3} + m_Name: + m_EditorClassIdentifier: + _authenticator: {fileID: 0} + SpawnPacking: + Position: 0 + Rotation: 2 + Scale: 2 + _changeFrameRate: 1 + _frameRate: 9999 + _shareIds: 1 + _startOnHeadless: 1 + _limitClientMTU: 1 +--- !u!114 &7443408887680269503 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} + m_Name: + m_EditorClassIdentifier: + _playerPrefab: {fileID: 611616139817875448, guid: bf5f023b4017a5e41a9815ec5745df3d, + type: 3} + _addToDefaultScene: 1 + Spawns: [] +--- !u!222 &9050426448999039876 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 174578014943721374} + m_CullTransparentMesh: 0 diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity.meta new file mode 100644 index 0000000..86dfccb --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Additive/AdditiveMain.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e7d3ac2d556912042aca9aa1947aea07 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace.meta new file mode 100644 index 0000000..7b51256 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ad819293f3cbbf44b9e2790853833c5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity new file mode 100644 index 0000000..11a6aa8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity @@ -0,0 +1,617 @@ +%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: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &76845508 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 76845512} + - component: {fileID: 76845511} + - component: {fileID: 76845510} + - component: {fileID: 76845509} + - component: {fileID: 76845514} + - component: {fileID: 76845513} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &76845509 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + 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 &76845510 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &76845511 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &76845512 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -19.2, y: 3.8, z: -0.43} + m_LocalScale: {x: 4, y: 4, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &76845513 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + _prefabId: -1 + _scenePathHash: 3254454948 + _sceneId: 13977777569358682418 + _sceneNetworkObjects: + - {fileID: 76845513} + SceneTransformProperties: + Position: {x: -10.56, y: 5.5, z: -0.03} + Rotation: {x: -0, y: -0, z: -0, w: 1} + LocalScale: {x: 4, y: 4, z: 4} +--- !u!114 &76845514 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 76845508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71fd7f855ec523429999fc4e14a1928, type: 3} + m_Name: + m_EditorClassIdentifier: + _observerConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!1 &603255273 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 603255274} + m_Layer: 0 + m_Name: Triggers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &603255274 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603255273} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -22.68, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 979031081727779170} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &748707377276284900 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707377276284902} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: -2.2843354, y: 60.72741, z: -2.9938574} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 748707378658658307} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!108 &748707377276284901 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707377276284902} + 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: 1 + 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_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!1 &748707377276284902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 748707377276284900} + - component: {fileID: 748707377276284901} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &748707378551427530 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707378551427534} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -5, z: 0} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 748707378658658307} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &748707378551427531 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707378551427534} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &748707378551427532 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707378551427534} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!64 &748707378551427533 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707378551427534} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &748707378551427534 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 748707378551427530} + - component: {fileID: 748707378551427531} + - component: {fileID: 748707378551427532} + - component: {fileID: 748707378551427533} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &748707378658658307 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 748707378658658308} + 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: 748707377276284900} + - {fileID: 748707378551427530} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &748707378658658308 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 748707378658658307} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &979031081727779169 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 979031081727779174} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 1 + _moveAllObjects: 0 + _replaceScenes: 1 + _scenes: + - ReplaceMain + _connectionOnly: 1 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!4 &979031081727779170 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 979031081727779174} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 2.87, y: -3, z: 0} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 603255274} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &979031081727779171 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 979031081727779174} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &979031081727779172 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 979031081727779174} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2e7517d1496ae784f94a2307a88e2bb5, 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 +--- !u!135 &979031081727779173 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 979031081727779174} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &979031081727779174 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 979031081727779170} + - component: {fileID: 979031081727779169} + - component: {fileID: 979031081727779171} + - component: {fileID: 979031081727779172} + - component: {fileID: 979031081727779173} + m_Layer: 0 + m_Name: Connection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity.meta new file mode 100644 index 0000000..0eb3735 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceConnection.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 58053e81b62de3a499afaf0f73d01b01 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity new file mode 100644 index 0000000..15a70f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity @@ -0,0 +1,593 @@ +%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: 11 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1950515027 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1950515031} + - component: {fileID: 1950515030} + - component: {fileID: 1950515029} + - component: {fileID: 1950515028} + - component: {fileID: 1950515033} + - component: {fileID: 1950515032} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &1950515028 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + 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 &1950515029 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &1950515030 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1950515031 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 24.31, y: 3, z: -5.47} + m_LocalScale: {x: 4, y: 4, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1950515032 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 3074121493 + k__BackingField: 13203251279314293806 + k__BackingField: 0 + _sceneNetworkObjects: + - {fileID: 1950515032} + k__BackingField: 0 + k__BackingField: 0 + _networkBehaviours: [] + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 +--- !u!114 &1950515033 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1950515027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71fd7f855ec523429999fc4e14a1928, type: 3} + m_Name: + m_EditorClassIdentifier: + _overrideType: 3 + _setHostVisibility: 1 + _observerConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!1 &1722183419489630397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1722183419489630399} + - component: {fileID: 1722183419489630398} + 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 &1722183419489630398 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183419489630397} + 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: 1 + 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_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1722183419489630399 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183419489630397} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: -2.2843354, y: 60.72741, z: -2.9938574} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1722183420925353816} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!33 &1722183420764669584 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183420764669589} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1722183420764669585 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183420764669589} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -5, z: 0} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1722183420925353816} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1722183420764669589 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1722183420764669585} + - component: {fileID: 1722183420764669584} + - component: {fileID: 1722183420764669591} + - component: {fileID: 1722183420764669590} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!64 &1722183420764669590 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183420764669589} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1722183420764669591 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183420764669589} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!4 &1722183420925353816 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722183420925353823} + 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: 1722183419489630399} + - {fileID: 1722183420764669585} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1722183420925353823 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1722183420925353816} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5581392219061976576 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5581392219061976826} + - component: {fileID: 5581392219061976581} + - component: {fileID: 5581392219061976583} + - component: {fileID: 5581392219061976582} + - component: {fileID: 5581392219061976577} + m_Layer: 0 + m_Name: Global + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &5581392219061976577 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5581392219061976576} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &5581392219061976581 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5581392219061976576} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 0 + _moveAllObjects: 1 + _replaceScenes: 1 + _scenes: + - ReplaceMain + _connectionOnly: 0 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!23 &5581392219061976582 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5581392219061976576} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2e7517d1496ae784f94a2307a88e2bb5, 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 +--- !u!33 &5581392219061976583 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5581392219061976576} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &5581392219061976826 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5581392219061976576} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 30.66, y: -3, z: -1.24} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity.meta new file mode 100644 index 0000000..58f62b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceGlobal.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fddd81e62368fe9448b0eb0a80da6bb4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity new file mode 100644 index 0000000..f998cb5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity @@ -0,0 +1,1234 @@ +%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: 705507994} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + 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: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + 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_UseShadowmask: 1 +--- !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 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &40691391 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 40691392} + m_Layer: 0 + m_Name: Triggers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &40691392 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 40691391} + 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: 825925885} + - {fileID: 1406093440} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + 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 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + 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: 1 + 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_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: -2.2843354, y: 60.72741, z: -2.9938574} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1155569020} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &825925881 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 825925885} + - component: {fileID: 825925886} + - component: {fileID: 825925884} + - component: {fileID: 825925883} + - component: {fileID: 825925882} + m_Layer: 0 + m_Name: Connection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &825925882 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &825925883 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: d0a99caade0a68842b2274726d1bc7c3, 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 +--- !u!33 &825925884 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &825925885 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -2.4611313, y: -3, z: 2.2759757} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 40691392} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &825925886 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 825925881} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 1 + _moveAllObjects: 0 + _replaceScenes: 1 + _scenes: + - ReplaceConnection + _connectionOnly: 1 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!1 &1155569019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1155569020} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1155569020 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155569019} + 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: 705507995} + - {fileID: 2114768053} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1406093434 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1406093440} + - component: {fileID: 1406093439} + - component: {fileID: 1406093437} + - component: {fileID: 1406093436} + - component: {fileID: 1406093435} + m_Layer: 0 + m_Name: Global + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!135 &1406093435 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1406093436 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a35bce0c956282a42a90a04b25492fb6, 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 +--- !u!33 &1406093437 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &1406093439 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa23b6e6f9b08d74885e3707aa0d9bc7, type: 3} + m_Name: + m_EditorClassIdentifier: + _moveObject: 0 + _moveAllObjects: 1 + _replaceScenes: 1 + _scenes: + - ReplaceGlobal + _connectionOnly: 0 + _automaticallyUnload: 1 + _onTriggerEnter: 1 +--- !u!4 &1406093440 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1406093434} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 13.88, y: -3, z: 2.2759757} + m_LocalScale: {x: 15, y: 15, z: 15} + m_Children: [] + m_Father: {fileID: 40691392} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2114768049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2114768053} + - component: {fileID: 2114768052} + - component: {fileID: 2114768051} + - component: {fileID: 2114768050} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!64 &2114768050 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2114768051 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + 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 +--- !u!33 &2114768052 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &2114768053 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114768049} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -5, z: 0} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1155569020} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1357903939251608625 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2553749094314996952} + 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_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 &2553749094314996952 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9208822351047973834} + - component: {fileID: 6666759449596494018} + - component: {fileID: 1357903939251608625} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &3896340524768297019 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4875127092859136454} + 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_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 &4462211894441225126 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894441225131} + 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_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 &4462211894441225127 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894441225131} + m_CullTransparentMesh: 0 +--- !u!224 &4462211894441225128 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894441225131} + 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: 9208822351047973834} + m_Father: {fileID: 4462211894982264461} + 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 &4462211894441225129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894441225131} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 4462211894441225126} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 4462211894982264465} + 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 &4462211894441225131 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4462211894441225128} + - component: {fileID: 4462211894441225127} + - component: {fileID: 4462211894441225126} + - component: {fileID: 4462211894441225129} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &4462211894961511974 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894961511979} + 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_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 &4462211894961511975 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894961511979} + m_CullTransparentMesh: 0 +--- !u!224 &4462211894961511976 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894961511979} + 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: 7312354082057744424} + m_Father: {fileID: 4462211894982264461} + 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 &4462211894961511977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894961511979} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 4462211894961511974} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 4462211894982264465} + 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 &4462211894961511979 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4462211894961511976} + - component: {fileID: 4462211894961511975} + - component: {fileID: 4462211894961511974} + - component: {fileID: 4462211894961511977} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!223 &4462211894982264460 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894982264464} + 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 &4462211894982264461 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894982264464} + 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_Children: + - {fileID: 4462211894961511976} + - {fileID: 4462211894441225128} + m_Father: {fileID: 7443408887680269496} + 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 &4462211894982264462 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894982264464} + 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 &4462211894982264463 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894982264464} + 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 +--- !u!1 &4462211894982264464 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4462211894982264461} + - component: {fileID: 4462211894982264460} + - component: {fileID: 4462211894982264465} + - component: {fileID: 4462211894982264463} + - component: {fileID: 4462211894982264462} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &4462211894982264465 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4462211894982264464} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + _autoStartType: 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} + _serverIndicator: {fileID: 3896340524768297019} + _clientIndicator: {fileID: 1357903939251608625} +--- !u!1 &4875127092859136454 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7312354082057744424} + - component: {fileID: 5173910453633412161} + - component: {fileID: 3896340524768297019} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &5173910453633412161 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4875127092859136454} + m_CullTransparentMesh: 0 +--- !u!222 &6666759449596494018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2553749094314996952} + m_CullTransparentMesh: 0 +--- !u!224 &7312354082057744424 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4875127092859136454} + 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_Children: [] + m_Father: {fileID: 4462211894961511976} + 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!114 &7443408887680269493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} + m_Name: + m_EditorClassIdentifier: + _playerPrefab: {fileID: 611616139817875448, guid: bf5f023b4017a5e41a9815ec5745df3d, + type: 3} + _addToDefaultScene: 1 + Spawns: [] +--- !u!4 &7443408887680269496 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + 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: 4462211894982264461} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7443408887680269498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7443408887680269496} + - component: {fileID: 7443408887680269499} + - component: {fileID: 7443408887680269493} + - component: {fileID: 7443408887680269500} + - component: {fileID: 7443408887680269501} + m_Layer: 0 + m_Name: 'NetworkManager ' + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &7443408887680269499 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + 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: 1 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 +--- !u!114 &7443408887680269500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} + m_Name: + m_EditorClassIdentifier: + _tickRate: 30 + _pingInterval: 1 + _timingInterval: 2 + _physicsMode: 0 + _maximumBufferedInputs: 15 +--- !u!114 &7443408887680269501 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887680269498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} + m_Name: + m_EditorClassIdentifier: + _unreliableMTU: 1023 + _attackResponseType: 1 + _ipv4BindAddress: + _ipv6BindAddress: + _port: 7770 + _maximumClients: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!224 &9208822351047973834 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2553749094314996952} + 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_Children: [] + m_Father: {fileID: 4462211894441225128} + 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/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity.meta new file mode 100644 index 0000000..5276e6e --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scenes/Replace/ReplaceMain.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 099398b014b86004abd99a7d21cf417a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts.meta new file mode 100644 index 0000000..83ffc63 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 237bdcd1cdb63df4089e95bd92e1c69e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs new file mode 100644 index 0000000..81d8594 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs @@ -0,0 +1,75 @@ +using FishNet.Connection; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Example.Scened +{ + + + public class PlayerController : NetworkBehaviour + { + [SerializeField] + private GameObject _camera; + [SerializeField] + private float _moveRate = 4f; + [SerializeField] + private bool _clientAuth = true; + + public override void OnStartClient() + { + base.OnStartClient(); + if (base.IsOwner) + _camera.SetActive(true); + } + + private void Update() + { + if (!base.IsOwner) + return; + + float hor = Input.GetAxisRaw("Horizontal"); + float ver = Input.GetAxisRaw("Vertical"); + + /* If ground cannot be found for 20 units then bump up 3 units. + * This is just to keep player on ground if they fall through + * when changing scenes. */ + if (_clientAuth || (!_clientAuth && base.IsServer)) + { + if (!Physics.Linecast(transform.position + new Vector3(0f, 0.3f, 0f), transform.position - (Vector3.one * 20f))) + transform.position += new Vector3(0f, 3f, 0f); + } + + if (_clientAuth) + Move(hor, ver); + else + ServerMove(hor, ver); + } + + [ServerRpc] + private void ServerMove(float hor, float ver) + { + Move(hor, ver); + } + + private void Move(float hor, float ver) + { + float gravity = -10f * Time.deltaTime; + //If ray hits floor then cancel gravity. + Ray ray = new Ray(transform.position + new Vector3(0f, 0.05f, 0f), -Vector3.up); + if (Physics.Raycast(ray, 0.1f + -gravity)) + gravity = 0f; + + /* Moving. */ + Vector3 direction = new Vector3( + 0f, + gravity, + ver * _moveRate * Time.deltaTime); + + transform.position += transform.TransformDirection(direction); + transform.Rotate(new Vector3(0f, hor * 100f * Time.deltaTime, 0f)); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs.meta new file mode 100644 index 0000000..cbdc08d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/PlayerController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26e4f626a9ca9704f9befe7673a8dd15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs new file mode 100644 index 0000000..6777d67 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs @@ -0,0 +1,147 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Scened; +using FishNet.Object; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Example.Scened +{ + + ///

+ /// Loads a single scene, additive scenes, or both when a client + /// enters or exits this trigger. + /// + public class SceneLoaderExample : MonoBehaviour + { + /// + /// True to move the triggering object. + /// + [Tooltip("True to move the triggering object.")] + [SerializeField] + private bool _moveObject = true; + /// + /// True to move all connection objects (clients). + /// + [Tooltip("True to move all connection objects (clients).")] + [SerializeField] + private bool _moveAllObjects; + /// + /// True to replace current scenes with new scenes. First scene loaded will become active scene. + /// + [Tooltip("True to replace current scenes with new scenes. First scene loaded will become active scene.")] + [SerializeField] + private bool _replaceScenes; + /// + /// Scenes to load. + /// + [Tooltip("Scenes to load.")] + [SerializeField] + private string[] _scenes = new string[0]; + /// + /// True to only unload for the connectioning causing the trigger. + /// + [Tooltip("True to only unload for the connectioning causing the trigger.")] + [SerializeField] + private bool _connectionOnly; + /// + /// True to automatically unload the loaded scenes when no more connections are using them. + /// + [Tooltip("True to automatically unload the loaded scenes when no more connections are using them.")] + [SerializeField] + private bool _automaticallyUnload = true; + /// + /// True to fire when entering the trigger. False to fire when exiting the trigger. + /// + [Tooltip("True to fire when entering the trigger. False to fire when exiting the trigger.")] + [SerializeField] + private bool _onTriggerEnter = true; + + /// + /// Used to prevent excessive triggering when two clients are loaded and server is separate. + /// Client may enter trigger intentionally then when moved to a new scene will re-enter trigger + /// since original scene will still be loaded on server due to another client being in it. + /// This scenario is extremely unlikely in production but keep it in mind. + /// + private Dictionary _triggeredTimes = new Dictionary(); + + + [Server(Logging = LoggingType.Off)] + private void OnTriggerEnter(Collider other) + { + if (!_onTriggerEnter) + return; + + LoadScene(other.GetComponent()); + } + + [Server(Logging = LoggingType.Off)] + private void OnTriggerExit(Collider other) + { + if (_onTriggerEnter) + return; + + LoadScene(other.GetComponent()); + } + + private void LoadScene(NetworkObject triggeringIdentity) + { + if (!InstanceFinder.NetworkManager.IsServer) + return; + + //NetworkObject isn't necessarily needed but to ensure its the player only run if found. + if (triggeringIdentity == null) + return; + + /* Dont let trigger hit twice by same connection too frequently + * See _triggeredTimes field for more info. */ + if (_triggeredTimes.TryGetValue(triggeringIdentity.Owner, out float time)) + { + if (Time.time - time < 0.5f) + return; + } + _triggeredTimes[triggeringIdentity.Owner] = Time.time; + + //Which objects to move. + List movedObjects = new List(); + if (_moveAllObjects) + { + foreach (NetworkConnection item in InstanceFinder.ServerManager.Clients.Values) + { + foreach (NetworkObject nob in item.Objects) + movedObjects.Add(nob); + } + } + else if (_moveObject) + { + movedObjects.Add(triggeringIdentity); + } + //Load options. + LoadOptions loadOptions = new LoadOptions + { + AutomaticallyUnload = _automaticallyUnload, + }; + + //Make scene data. + SceneLoadData sld = new SceneLoadData(_scenes); + sld.ReplaceScenes = (_replaceScenes) ? ReplaceOption.All : ReplaceOption.None; + sld.Options = loadOptions; + sld.MovedNetworkObjects = movedObjects.ToArray(); + + //Load for connection only. + if (_connectionOnly) + InstanceFinder.SceneManager.LoadConnectionScenes(triggeringIdentity.Owner, sld); + //Load for all clients. + else + InstanceFinder.SceneManager.LoadGlobalScenes(sld); + + + } + + + } + + + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs.meta new file mode 100644 index 0000000..ee3fa3f --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneLoaderExample.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa23b6e6f9b08d74885e3707aa0d9bc7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs new file mode 100644 index 0000000..67c5af8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs @@ -0,0 +1,91 @@ +using FishNet.Managing.Logging; +using FishNet.Managing.Scened; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Example.Scened +{ + + /// + /// Unloads specified scenes when entering or exiting this trigger. + /// + public class SceneUnloaderExample : MonoBehaviour + { + /// + /// Scenes to unload. + /// + [Tooltip("Scenes to unload.")] + [SerializeField] + private string[] _scenes = new string[0]; + /// + /// True to only unload for the connectioning causing the trigger. + /// + [Tooltip("True to only unload for the connectioning causing the trigger.")] + [SerializeField] + private bool _connectionOnly; + /// + /// True to unload unused scenes. + /// + [Tooltip("True to unload unused scenes.")] + [SerializeField] + private bool _unloadUnused = true; + /// + /// True to fire when entering the trigger. False to fire when exiting the trigger. + /// + [Tooltip("True to fire when entering the trigger. False to fire when exiting the trigger.")] + [SerializeField] + private bool _onTriggerEnter = true; + + + [Server(Logging = LoggingType.Off)] + private void OnTriggerEnter(Collider other) + { + if (!_onTriggerEnter) + return; + + UnloadScenes(other.gameObject.GetComponent()); + } + + [Server(Logging = LoggingType.Off)] + private void OnTriggerExit(Collider other) + { + if (_onTriggerEnter) + return; + + UnloadScenes(other.gameObject.GetComponent()); + } + + /// + /// Unload scenes. + /// + /// + private void UnloadScenes(NetworkObject triggeringIdentity) + { + if (!InstanceFinder.NetworkManager.IsServer) + return; + + //NetworkObject isn't necessarily needed but to ensure its the player only run if nob is found. + if (triggeringIdentity == null) + return; + + UnloadOptions unloadOptions = new UnloadOptions() + { + Mode = (_unloadUnused) ? UnloadOptions.ServerUnloadMode.UnloadUnused : UnloadOptions.ServerUnloadMode.KeepUnused + }; + + SceneUnloadData sud = new SceneUnloadData(_scenes); + sud.Options = unloadOptions; + + //Unload only for the triggering connection. + if (_connectionOnly) + InstanceFinder.SceneManager.UnloadConnectionScenes(triggeringIdentity.Owner, sud); + //Unload for all players. + else + InstanceFinder.SceneManager.UnloadGlobalScenes(sud); + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs.meta b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs.meta new file mode 100644 index 0000000..ba09def --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/All/SceneManager/Scripts/SceneUnloaderExample.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84ae572fef1171b41ab287d1c9b5da63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef b/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef new file mode 100644 index 0000000..bc50a03 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef @@ -0,0 +1,15 @@ +{ + "name": "FishNet.Example", + "references": [ + "GUID:7c88a4a7926ee5145ad2dfa06f454c67" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef.meta b/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef.meta new file mode 100644 index 0000000..8b6f01d --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/FishNet.Example.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a5e44165775d9294ba486f89d4c07300 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/Prefabs.meta b/UnityProject/Assets/FishNet/Example/Prefabs.meta new file mode 100644 index 0000000..b4d5992 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d9b597402966d8498f81aa39427f47a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab new file mode 100644 index 0000000..a0288e4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab @@ -0,0 +1,529 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2480283714602906875 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9139860296052841449} + - component: {fileID: 6745855428185604321} + - component: {fileID: 1424052073409502226} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9139860296052841449 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2480283714602906875} + 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_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} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6745855428185604321 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2480283714602906875} + m_CullTransparentMesh: 0 +--- !u!114 &1424052073409502226 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2480283714602906875} + 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_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 &4393252310969058995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4393252310969058990} + - component: {fileID: 4393252310969058994} + - component: {fileID: 4393252310969058991} + - component: {fileID: 4393252310969058988} + - component: {fileID: 4393252310969058989} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4393252310969058990 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252310969058995} + 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_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} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &4393252310969058994 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252310969058995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + 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} + _serverIndicator: {fileID: 3965864433427628056} + _clientIndicator: {fileID: 1424052073409502226} +--- !u!223 &4393252310969058991 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252310969058995} + 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!114 &4393252310969058988 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252310969058995} + 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 +--- !u!114 &4393252310969058989 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252310969058995} + 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!1 &4393252311501663112 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4393252311501663115} + - component: {fileID: 4393252311501663108} + - component: {fileID: 4393252311501663109} + - component: {fileID: 4393252311501663114} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4393252311501663115 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311501663112} + 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: 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} + m_AnchoredPosition: {x: 16, y: -96} + m_SizeDelta: {x: 256, y: 64} + m_Pivot: {x: 0, y: 1} +--- !u!222 &4393252311501663108 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311501663112} + m_CullTransparentMesh: 0 +--- !u!114 &4393252311501663109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311501663112} + 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_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!114 &4393252311501663114 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311501663112} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 4393252311501663109} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 4393252310969058994} + 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 &4393252311652982280 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4393252311652982283} + - component: {fileID: 4393252311652982276} + - component: {fileID: 4393252311652982277} + - component: {fileID: 4393252311652982282} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4393252311652982283 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311652982280} + 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: 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} + m_AnchoredPosition: {x: 16, y: -16} + m_SizeDelta: {x: 256, y: 64} + m_Pivot: {x: 0, y: 1} +--- !u!222 &4393252311652982276 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311652982280} + m_CullTransparentMesh: 0 +--- !u!114 &4393252311652982277 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311652982280} + 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_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!114 &4393252311652982282 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4393252311652982280} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + 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: 4393252311652982277} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 4393252310969058994} + 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 &4808982256197118437 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7233259200663826443} + - component: {fileID: 5104387649082666082} + - component: {fileID: 3965864433427628056} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7233259200663826443 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4808982256197118437} + 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_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} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5104387649082666082 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4808982256197118437} + m_CullTransparentMesh: 0 +--- !u!114 &3965864433427628056 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4808982256197118437} + 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_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 diff --git a/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab.meta b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab.meta new file mode 100644 index 0000000..c4281bb --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkHudCanvas.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0570b6f7f713dc44a90463654bbcd8d0 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab new file mode 100644 index 0000000..fce3e55 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/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/UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab.meta b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab.meta new file mode 100644 index 0000000..ae648e6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Prefabs/NetworkManager.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0b650fca685f2eb41a86538aa883e4c1 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/Scripts.meta b/UnityProject/Assets/FishNet/Example/Scripts.meta new file mode 100644 index 0000000..4feee45 --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a4f0be731a103e4888691005f67a0e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs b/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs new file mode 100644 index 0000000..bd11edf --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs @@ -0,0 +1,248 @@ +using FishNet.Managing; +using FishNet.Transporting; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class NetworkHudCanvases : MonoBehaviour +{ + #region Types. + /// + /// Ways the HUD will automatically start a connection. + /// + private enum AutoStartType + { + Disabled, + Host, + Server, + Client + } + #endregion + + #region Serialized. + /// + /// What connections to automatically start on play. + /// + [Tooltip("What connections to automatically start on play.")] + [SerializeField] + private AutoStartType _autoStartType = AutoStartType.Disabled; + /// + /// Color when socket is stopped. + /// + [Tooltip("Color when socket is stopped.")] + [SerializeField] + private Color _stoppedColor; + /// + /// Color when socket is changing. + /// + [Tooltip("Color when socket is changing.")] + [SerializeField] + private Color _changingColor; + /// + /// Color when socket is started. + /// + [Tooltip("Color when socket is started.")] + [SerializeField] + private Color _startedColor; + [Header("Indicators")] + /// + /// Indicator for server state. + /// + [Tooltip("Indicator for server state.")] + [SerializeField] + private Image _serverIndicator; + /// + /// Indicator for client state. + /// + [Tooltip("Indicator for client state.")] + [SerializeField] + private Image _clientIndicator; + #endregion + + #region Private. + /// + /// Found NetworkManager. + /// + private NetworkManager _networkManager; + /// + /// Current state of client socket. + /// + private LocalConnectionState _clientState = LocalConnectionState.Stopped; + /// + /// Current state of server socket. + /// + private LocalConnectionState _serverState = LocalConnectionState.Stopped; +#if !ENABLE_INPUT_SYSTEM + /// + /// EventSystem for the project. + /// + private EventSystem _eventSystem; +#endif + #endregion + + void OnGUI() + { +#if ENABLE_INPUT_SYSTEM + string GetNextStateText(LocalConnectionState state) + { + if (state == LocalConnectionState.Stopped) + return "Start"; + else if (state == LocalConnectionState.Starting) + return "Starting"; + else if (state == LocalConnectionState.Stopping) + return "Stopping"; + else if (state == LocalConnectionState.Started) + return "Stop"; + else + return "Invalid"; + } + + GUILayout.BeginArea(new Rect(16, 16, 256, 9000)); + Vector2 defaultResolution = new Vector2(1920f, 1080f); + GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Screen.width / defaultResolution.x, Screen.height / defaultResolution.y, 1)); + + GUIStyle style = GUI.skin.GetStyle("button"); + int originalFontSize = style.fontSize; + + Vector2 buttonSize = new Vector2(256f, 64f); + style.fontSize = 28; + //Server button. + if (Application.platform != RuntimePlatform.WebGLPlayer) + { + if (GUILayout.Button($"{GetNextStateText(_serverState)} Server", GUILayout.Width(buttonSize.x), GUILayout.Height(buttonSize.y))) + OnClick_Server(); + GUILayout.Space(10f); + } + + //Client button. + if (GUILayout.Button($"{GetNextStateText(_clientState)} Client", GUILayout.Width(buttonSize.x), GUILayout.Height(buttonSize.y))) + OnClick_Client(); + + style.fontSize = originalFontSize; + + GUILayout.EndArea(); +#endif + } + + private void Start() + { +#if !ENABLE_INPUT_SYSTEM + SetEventSystem(); + BaseInputModule inputModule = FindObjectOfType(); + if (inputModule == null) + gameObject.AddComponent(); +#else + _serverIndicator.transform.parent.gameObject.SetActive(false); + _clientIndicator.transform.parent.gameObject.SetActive(false); +#endif + + _networkManager = FindObjectOfType(); + if (_networkManager == null) + { + Debug.LogError("NetworkManager not found, HUD will not function."); + return; + } + else + { + UpdateColor(LocalConnectionState.Stopped, ref _serverIndicator); + UpdateColor(LocalConnectionState.Stopped, ref _clientIndicator); + _networkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState; + _networkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; + } + + if (_autoStartType == AutoStartType.Host || _autoStartType == AutoStartType.Server) + OnClick_Server(); + if (!Application.isBatchMode && (_autoStartType == AutoStartType.Host || _autoStartType == AutoStartType.Client)) + OnClick_Client(); + } + + + private void OnDestroy() + { + if (_networkManager == null) + return; + + _networkManager.ServerManager.OnServerConnectionState -= ServerManager_OnServerConnectionState; + _networkManager.ClientManager.OnClientConnectionState -= ClientManager_OnClientConnectionState; + } + + /// + /// Updates img color baased on state. + /// + /// + /// + private void UpdateColor(LocalConnectionState state, ref Image img) + { + Color c; + if (state == LocalConnectionState.Started) + c = _startedColor; + else if (state == LocalConnectionState.Stopped) + c = _stoppedColor; + else + c = _changingColor; + + img.color = c; + } + + + private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj) + { + _clientState = obj.ConnectionState; + UpdateColor(obj.ConnectionState, ref _clientIndicator); + } + + + private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj) + { + _serverState = obj.ConnectionState; + UpdateColor(obj.ConnectionState, ref _serverIndicator); + } + + + public void OnClick_Server() + { + if (_networkManager == null) + return; + + if (_serverState != LocalConnectionState.Stopped) + _networkManager.ServerManager.StopConnection(true); + else + _networkManager.ServerManager.StartConnection(); + + DeselectButtons(); + } + + + public void OnClick_Client() + { + if (_networkManager == null) + return; + + if (_clientState != LocalConnectionState.Stopped) + _networkManager.ClientManager.StopConnection(); + else + _networkManager.ClientManager.StartConnection(); + + DeselectButtons(); + } + + + private void SetEventSystem() + { +#if !ENABLE_INPUT_SYSTEM + if (_eventSystem != null) + return; + _eventSystem = FindObjectOfType(); + if (_eventSystem == null) + _eventSystem = gameObject.AddComponent(); +#endif + } + + private void DeselectButtons() + { +#if !ENABLE_INPUT_SYSTEM + SetEventSystem(); + _eventSystem?.SetSelectedGameObject(null); +#endif + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs.meta b/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs.meta new file mode 100644 index 0000000..e2e25fb --- /dev/null +++ b/UnityProject/Assets/FishNet/Example/Scripts/NetworkHudCanvases.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d3606bfdac5a4743890fc1a5ecd8f24 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/LICENSE.txt b/UnityProject/Assets/FishNet/LICENSE.txt new file mode 100644 index 0000000..a76aaf2 --- /dev/null +++ b/UnityProject/Assets/FishNet/LICENSE.txt @@ -0,0 +1,35 @@ +0. Definitions. + +"Fish-Net" means FishNet, FishNetworking, Fish-Networking, networking for Unity Engine. + +"Repository Service" means the respository service through which Fish-Net is made available. + +“Software” means the software (including code in source or object format as applicable) of Fish-Net that accompanies this License. + +"FirstGearGames" means Benjamin Berwick of FirstGearGames LLC, registered 2018, North Carolina. + +1. License Grant to the Software. FirstGearGames grants to you a worldwide, non-exclusive, no-charge, and royalty-free license to reproduce, modify, and use the Software for developed game, or other content with Software. + +1.1 Exclusions. Other products of like Software (eg: networking solutions) may not use, reverse engineer, or implement Software in part or full. Exclusions do not apply to parts of Software which are governed by a third-party license, nor to content or works created specifically to be used with Software, such as tools, add-ons, games, or improvements for Software. + +2. Trademarks. You are not granted any right or license under this License to use any trademarks, service marks, trade names, products names, or branding of FirstGearGames or its affiliates (“Trademarks”). + +3. Notice & Third-Party Terms. This License, including notices of copyright associated with the Software, must be provided in all substantial portions of the Software (or, if that is impracticable, in any other location where such notices are customarily placed). If the Software is accompanied by a “third-party notices” or similar file, you acknowledge and agree that software identified in that file is governed exclusively by those separate license terms. + +4. DISCLAIMER, LIMITATION OF LIABILITY. THE SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND IS PROVIDED WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR NONINFRINGEMENT. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES (WHETHER DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL, INCLUDING PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, AND BUSINESS INTERRUPTION), OR OTHER LIABILITY WHATSOEVER, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM OR OUT OF, OR IN CONNECTION WITH, THE SOFTWARE OR THE USE OF OR OTHER DEALINGS IN IT, EVEN WHERE ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +5. USE IS ACCEPTANCE and License Versions. Your access to and use of the Software, and/or any other indications of acceptance where required, constitutes your acceptance of this License and its terms and conditions. This License may be modified or updated; upon any such modification or update, you will comply with the terms of the updated License for any use of any of the Software under the updated License. + +6. Use in Compliance with Law and Termination. + +6.1 Compliance. Your exercise of the license granted herein will at all times be in compliance with applicable law and will not infringe any proprietary rights (including intellectual property rights). + +6.2 Termination. This License will terminate immediately (i) on any breach by you of this License; and (ii) if you commence any form of patent litigation, including a cross-claim or counterclaim, against anyone wherein you allege that the Software constitutes direct or secondary/indirect patent infringement. + +7. Severability. If any provision of this License is held to be unenforceable or invalid, that provision will be enforced to the maximum extent possible and the other provisions will remain in full force and effect. + +8. Governing Law and Venue. This License is governed by and construed in accordance with the laws of North Carolina, United States. You and FirstGearGames agree to submit to the personal and exclusive jurisdiction of and venue in the state and federal courts located in Onslow County, North Carolina concerning any dispute arising out of this License (“Dispute”). + +9. You agree by submitting ideas, modifications, or changes (content) of any kind to Software within Repository Service does not grant you ownership to Software nor additional rights to Software. + +9.1 By submitting to Repository Service you are granting FirstGearGames with a no-charge, and royalty-free license to reproduce, modify, and use submitted content. \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/LICENSE.txt.meta b/UnityProject/Assets/FishNet/LICENSE.txt.meta new file mode 100644 index 0000000..5ba5b4f --- /dev/null +++ b/UnityProject/Assets/FishNet/LICENSE.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 83c5a6d0014103d48a0028f0ab7fec8d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins.meta b/UnityProject/Assets/FishNet/Plugins.meta similarity index 77% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins.meta rename to UnityProject/Assets/FishNet/Plugins.meta index def60ed..efa9301 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins.meta +++ b/UnityProject/Assets/FishNet/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e8bd04b9965420e40ac911fbf4294e1c +guid: 42cadfdebb9b32c42941efb731593966 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishNet/Plugins/Addressables.meta b/UnityProject/Assets/FishNet/Plugins/Addressables.meta new file mode 100644 index 0000000..c8753ac --- /dev/null +++ b/UnityProject/Assets/FishNet/Plugins/Addressables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6163c005fc817b14cb4c4750343b9a1a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs b/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs new file mode 100644 index 0000000..3ad8778 --- /dev/null +++ b/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs @@ -0,0 +1,24 @@ +//Remove on 2023/01/01 +//using UnityEngine; +//using UnityEngine.ResourceManagement.AsyncOperations; +//using UnitySceneManager = UnityEngine.SceneManagement; + +//namespace FishNet.Managing.Scened.Addressable +//{ + +// public static class AddressablesExtensions +// { +// public static AsyncOperationHandle LoadAsync(string sceneName, UnityEngine.SceneManagement.LoadSceneMode loadSceneMode) +// { +// return default; +// //return Addressables.LoadSceneAsync(sceneName, loadSceneMode); +// } +// public static AsyncOperationHandle UnloadAsync(string sceneName, UnityEngine.SceneManagement.LoadSceneMode loadSceneMode) +// { +// return default; +// //return Addressables.UnloadSceneAsync() .UnloadSceneAsync(sceneName); +// } + +// } + +//} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs.meta b/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs.meta new file mode 100644 index 0000000..0cbec5a --- /dev/null +++ b/UnityProject/Assets/FishNet/Plugins/Addressables/AddressablesExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56f2c0f01d19eb5419b34a813abf6e06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Plugins/CodeAnalysis.meta b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis.meta new file mode 100644 index 0000000..a7fb576 --- /dev/null +++ b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90f5de37ae0e3184fb0d662879ba060b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll new file mode 100644 index 0000000000000000000000000000000000000000..46373a3134fa595ce0215e3b3142c904fed619ab GIT binary patch literal 22016 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 Yo~Ll_k^hGp{TKYdcmDJG|IY*e7vz?06951J literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so.meta b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll.meta similarity index 78% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so.meta rename to UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll.meta index c57aeaa..73913eb 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so.meta +++ b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.Analyzers.dll.meta @@ -1,11 +1,14 @@ fileFormatVersion: 2 -guid: ba78b07719f786c4cae4c52b9528903f +guid: 1907658b89c1bbe42a0063df40b7ca24 +labels: +- RoslynAnalyzer PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} - defineConstraints: [] + defineConstraints: + - UNITY_2020_3_OR_NEWER isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 @@ -16,19 +19,11 @@ PluginImporter: second: enabled: 0 settings: - Exclude Android: 0 Exclude Editor: 1 Exclude Linux64: 1 Exclude OSXUniversal: 1 Exclude Win: 1 Exclude Win64: 1 - Exclude iOS: 1 - - first: - Android: Android - second: - enabled: 1 - settings: - CPU: x86 - first: Any: second: @@ -67,14 +62,11 @@ PluginImporter: settings: CPU: None - first: - iPhone: iOS + Windows Store Apps: WindowsStoreApps second: enabled: 0 settings: - AddToEmbeddedBinaries: false CPU: AnyCPU - CompileFlags: - FrameworkDependencies: userData: assetBundleName: assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.dll b/UnityProject/Assets/FishNet/Plugins/CodeAnalysis/FishNet.CodeAnalysis.dll new file mode 100644 index 0000000000000000000000000000000000000000..e8e307779b58370b08615323e4567807b3499c4a GIT binary patch literal 5120 zcmeHLU5Fdk6+U-Hl6UP`SvPCPCbc{EI>BD2LL1v5PTf?y(#lr4yIxzeH?e7VN77yG z)T0?OGg@0DZd}q96Vleuv`{D{C5F|Gk5On^x3PV6Hx-!&6`9oX%_OwUddO$nXK?;ig! z_V!QOV{8&xqC3Dzh1_qA;%?x|;UXGRxE99E431xo%YfkX&}rd&tjd4Adqgq|V>|4g zU?fNMEEi(+SO~-Tct6n>SIcfi8$<(r@&VAt`{+y{F9x7n8v!6wxkhn=Qo|rx$aub2 z1Epfi0pUc`xcWv8(PunqyHMnk(E={E^#xpgBS$pRM=ErR>x#j#X_TZt8ASIF5(#F0 zhOtZAx0z_;=r_Z=cJ~iZd~xqK{pXipGBNsa#Mf7oh&M61OM3!qkQm*g>6a7|n}Yy} zD}^NA&veZ&TT5J0T*Nz3esn@a(Q_@94`s5MgV}>)M>v@z*?2z?ZkySie^7t=djkVYT-Rao3ueaMav2v79VJL(tb=&(N%FxOVKy9e*peR zF#MH*Zzy;`@y{vz-^3Q4(f$UVAL|Tv3Wm>t1Ba1ERVOh-f1z{wVesG|R7ngfiZdIc z0-`vKh!Z40dBOvwBP*taq7vxy`{*HkFW~dqK3JKd1GF1iX8<1noHf|z_qV@~2n0RW zrN%(Dy3~W9p6XI8`(a28T+@$&`e{VHuIE5K-_=YZx?e`JD>Mn}*AexKqF(B1mQ>{h z{ftwi7l~KmEgGcvQTZ)^DcS+Jk@f=)(U^iq6dYHuq~J*fA6L)>Oi>4LD_IK9&?cHg z&UeuQ;63yd;0Rp-JV1W{JV<{9{0jXGFi-CRew{u7ECc5091V*+DmN@lh1Vj;oEp_= zhxm@-JRL#iKMj6Pyr4M0Q1C@?8sasDU#C6P64$X6ECbf)Nh~vaF%-l)qOZ6m-qLv& zd=_yKy$Z;Cfv%)F@BvU7Dz$+Um$`QRqln&AO%*Zkp(kVU(P_8dw&f#qwAi-o&dIiE zTZ@*gS2`^@V>aa@=jZ1q%-VT8d__yzbvimNn^ozpFPkuZnKx~Fy6p!OvS@jJP!7yM zHl-7+vE<0W4@{?SdUa~ZV1E4oXmQ=R)Qnyz)a*t@lZdZgm-X=gdq%Y#NXom-mSs!t zm~^CvaQZ~Eo?J$7r+u>_OO9{VWp7#+Q_?O)1zBx38fMk*)15(-D>>u7kC^OE#R~cr zPb^E%gBvapmx@c)GhHz~l%j}tv%KJX=X-+KS`m4ik)Ch4&RSu~S#-Uo89->-|5GdP zI*V4LjY6z25*A4@Pf6Rns4#!6lUWZPQww^6ICa?NH)c-|$IO;Zr_&RhYCD0|l!_l% zRm--5KIudUOSWvrf^rJP0Q#>yqXClVK4Zq({J@)k&lPxmI~p+{?gq)DZTl@_2WO*V zw7!otT6>#Cw{oAb=pjO$EZtjQKHLS@NwFZcp_;hyxMpdFc+$qIG~wHe$W zt?*ZuAIM~3AwArE9txJQIPgO{a;c$T; zUh#sGiXiOKG`wE#;9S8Q=Y4{{d!Bd9ine*&w%rTUZ9A}9wgh9aIj|@w1-U}P6-K;hEIp;Q309_C7+lel(3_>**q0iUwS&zRR9?KDBaT16}RzC#v z3{DdBfRl6zSP5TRGoVX=#qg_(exG>nlkh|l_hWefT4adN$l;S5TP7+16|icO2Rjzd z^b$55S|nE~?Zs)8r~;`8t`E6M0rXr@;rLDBDvS!m6hO-YAN&0pOSaO*I9Bv9wmi z${Ic`!M+5a&x|hBfsZ3*6P7!WvIdVV_QsygGs-_p + /// When inherited from this can be used to create a custom authentication process before clients may communicate with the server. + /// + public abstract class Authenticator : MonoBehaviour + { + #region Protected. + /// + /// NetworkManager for this Authenticator. + /// + protected NetworkManager NetworkManager { get; private set; } + #endregion + + + /// + /// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. + /// Server listens for this event automatically. + /// + public abstract event Action OnAuthenticationResult; + + /// + /// Initializes this script for use. + /// + /// + public virtual void InitializeOnce(NetworkManager networkManager) + { + NetworkManager = networkManager; + } + + /// + /// Called on the server immediately after a client connects. Can be used to send data to the client for authentication. + /// + /// Connection which is not yet authenticated. + public virtual void OnRemoteConnection(NetworkConnection connection) { } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Authenticating/Authenticator.cs.meta b/UnityProject/Assets/FishNet/Runtime/Authenticating/Authenticator.cs.meta new file mode 100644 index 0000000..fe94f3f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Authenticating/Authenticator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9adfb82407774645a1f455ceb9298f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast.meta b/UnityProject/Assets/FishNet/Runtime/Broadcast.meta new file mode 100644 index 0000000..2268277 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25caa1205d1af6742a85ede29e1a672e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping.meta b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping.meta new file mode 100644 index 0000000..06cb025 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d0473552b6e6834abb8a336d060797a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs new file mode 100644 index 0000000..c1452da --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs @@ -0,0 +1,19 @@ +using FishNet.Object.Helping; + +namespace FishNet.Broadcast.Helping +{ + internal static class BroadcastHelper + { + /// + /// Gets the key for a broadcast type. + /// + /// + /// + /// + public static ushort GetKey() + { + return typeof(T).FullName.GetStableHash16(); + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs.meta b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs.meta new file mode 100644 index 0000000..c8e4514 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast/Helping/BroadcastHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c314af08d630630449b7b7af740b9c7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs b/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs new file mode 100644 index 0000000..5fe07f2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs @@ -0,0 +1,8 @@ + +namespace FishNet.Broadcast +{ + /// + /// Include this interface on types intended to be used with Broadcast. + /// + public interface IBroadcast { } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs.meta b/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs.meta new file mode 100644 index 0000000..c63e51a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Broadcast/IBroadcast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88ec864df25feed49bdcdab7f880531d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Config.json b/UnityProject/Assets/FishNet/Runtime/Config.json new file mode 100644 index 0000000..a24f387 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Config.json @@ -0,0 +1 @@ +{"StripReleaseBuilds":true} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Config.json.meta b/UnityProject/Assets/FishNet/Runtime/Config.json.meta new file mode 100644 index 0000000..baa766c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Config.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f1ece47c2d48194ea4827bf592a2279 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection.meta b/UnityProject/Assets/FishNet/Runtime/Connection.meta new file mode 100644 index 0000000..4658695 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc8933915f599d44d98ae151e3fd0da7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs b/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs new file mode 100644 index 0000000..d99f9f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs @@ -0,0 +1,244 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Serializing; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Connection +{ + /// + /// A byte buffer that automatically resizes. + /// + internal class ByteBuffer + { + /// + /// How many more bytes may fit into the buffer. + /// + internal int Remaining => (Size - Length); + /// + /// Buffer data. + /// + internal byte[] Data { get; private set; } + /// + /// How many bytes currently into Data. This will include the reserve. + /// + internal int Length { get; private set; } + /// + /// Size of the buffer. Data.Length may exceed this value as it uses a pooled array. + /// + internal int Size { get; private set; } + /// + /// True if data has been written. + /// + internal bool HasData { get; private set; } + /// + /// Bytes to reserve when resetting. + /// + private int _reserve; + + internal ByteBuffer(int size, int reserve = 0) + { + Data = ByteArrayPool.Retrieve(size); + Size = size; + _reserve = reserve; + Reset(); + } + + ~ByteBuffer() + { + if (Data != null) + ByteArrayPool.Store(Data); + } + + /// + /// Resets instance without clearing Data. + /// + internal void Reset() + { + Length = _reserve; + HasData = false; + } + + /// + /// Copies segments without error checking. + /// + /// + internal void CopySegment(uint tick, ArraySegment segment) + { + /* If data has not been written to buffer yet + * then write tick to the start. */ + if (!HasData) + { + int pos = 0; + WriterExtensions.WriteUInt32(Data, tick, ref pos); + } + + Buffer.BlockCopy(segment.Array, segment.Offset, Data, Length, segment.Count); + Length += segment.Count; + HasData = true; + } + } + + internal class PacketBundle + { + /// + /// True if data has been written. + /// + internal bool HasData => _buffers[0].HasData; + /// + /// All buffers written. Collection is not cleared when reset but rather the index in which to write is. + /// + private List _buffers = new List(); + /// + /// Buffer which is being written to. + /// + private int _bufferIndex; + /// + /// Maximum size packet the transport can handle. + /// + private int _maximumTransportUnit; + /// + /// Number of buffers written to. Will return 0 if nothing has been written. + /// + public int WrittenBuffers => (!HasData) ? 0 : (_bufferIndex + 1); + /// + /// Number of bytes to reserve at the beginning of each buffer. + /// + private int _reserve; + /// + /// NetworkManager this is for. + /// + private NetworkManager _networkManager; + + internal PacketBundle(NetworkManager manager, int mtu, int reserve = 0) + { + //Allow bytes for the tick. + reserve += TransportManager.TICK_BYTES; + + _networkManager = manager; + _maximumTransportUnit = mtu; + _reserve = reserve; + AddBuffer(); + + Reset(); + } + + /// + /// Adds a buffer using current settings. + /// + private ByteBuffer AddBuffer() + { + ByteBuffer ba = new ByteBuffer(_maximumTransportUnit, _reserve); + _buffers.Add(ba); + return ba; + } + + /// + /// Resets using current settings. + /// + internal void Reset() + { + _bufferIndex = 0; + + for (int i = 0; i < _buffers.Count; i++) + _buffers[i].Reset(); + } + + /// + /// Writes a segment to this packet bundle using the current WriteIndex. + /// + /// True to force data into a new buffer. + internal void Write(ArraySegment segment, bool forceNewBuffer = false) + { + //Nothing to be written. + if (segment.Count == 0) + return; + + /* If the segment count is larger than the mtu then + * something went wrong. Nothing should call this method + * directly except the TransportManager, which will automatically + * split packets that exceed MTU into reliable ordered. */ + if (segment.Count > _maximumTransportUnit) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Segment is length of {segment.Count} while MTU is {_maximumTransportUnit}. Packet was not split properly and will not be sent."); + return; + } + + ByteBuffer ba = _buffers[_bufferIndex]; + /* Make a new buffer if... + * forcing a new buffer and data has already been written to the current. + * or--- + * segment.Count is more than what is remaining in the buffer. */ + bool useNewBuffer = (forceNewBuffer && ba.Length > _reserve) || + (segment.Count > ba.Remaining); + if (useNewBuffer) + { + _bufferIndex++; + //If need to make a new buffer then do so. + if (_buffers.Count <= _bufferIndex) + { + ba = AddBuffer(); + } + else + { + ba = _buffers[_bufferIndex]; + ba.Reset(); + } + } + + uint tick = _networkManager.TimeManager.LocalTick; + ba.CopySegment(tick, segment); + } + + /// + /// Gets a buffer for the specified index. Returns true and outputs the buffer if it was successfully found. + /// + /// Index of the buffer to retrieve. + /// Buffer retrieved from the list. Null if the specified buffer was not found. + internal bool GetBuffer(int index, out ByteBuffer bb) + { + bb = null; + + if (index >= _buffers.Count || index < 0) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Index of {index} is out of bounds. There are {_buffers.Count} available."); + return false; + } + if (index > _bufferIndex) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Index of {index} exceeds the number of written buffers. There are {WrittenBuffers} written buffers."); + return false; + } + + bb = _buffers[index]; + return bb.HasData; + } + + /// + /// Returns a PacketBundle for a channel. ResetPackets must be called afterwards. + /// + /// + /// True if PacketBundle is valid on the index and contains data. + internal static bool GetPacketBundle(int channel, List bundles, out PacketBundle mtuBuffer) + { + //Out of bounds. + if (channel >= bundles.Count) + { + mtuBuffer = null; + return false; + } + + mtuBuffer = bundles[channel]; + return mtuBuffer.HasData; + } + } + + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs.meta new file mode 100644 index 0000000..85d9ae8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/Buffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb2f3ce9b5ac27f40b7daa9364fb4d60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs new file mode 100644 index 0000000..2fee9ad --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs @@ -0,0 +1,115 @@ +using FishNet.Broadcast; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Connection +{ + public partial class NetworkConnection + { + + #region Private. + /// + /// PacketBundles to send to this connection. An entry will be made for each channel. + /// + private List _toClientBundles = new List(); + /// + /// True if this object has been dirtied. + /// + private bool _serverDirtied; + #endregion + + /// + /// Initializes this script. + /// + private void InitializeBuffer() + { + for (byte i = 0; i < TransportManager.CHANNEL_COUNT; i++) + { + int mtu = NetworkManager.TransportManager.Transport.GetMTU(i); + _toClientBundles.Add(new PacketBundle(NetworkManager, mtu)); + } + } + + + /// + /// Sends a broadcast to this connection. + /// + /// Type of broadcast to send. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the client must be authenticated for this broadcast to send. + /// Channel to send on. + public void Broadcast(T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!IsActive) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Connection is not valid, cannot send broadcast."); + } + else + { + NetworkManager.ServerManager.Broadcast(this, message, requireAuthenticated, channel); + } + } + + /// + /// Sends data from the server to a client. + /// + /// True to force data into a new buffer. + internal void SendToClient(byte channel, ArraySegment segment, bool forceNewBuffer = false) + { + //Cannot send data when disconnecting. + if (Disconnecting) + return; + if (!IsActive) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Data cannot be sent to connection {ClientId} because it is not active."); + return; + } + //If channel is out of bounds then default to the first channel. + if (channel >= _toClientBundles.Count) + channel = 0; + + _toClientBundles[channel].Write(segment, forceNewBuffer); + ServerDirty(); + } + + /// + /// Returns a PacketBundle for a channel. ResetPackets must be called afterwards. + /// + /// + /// True if PacketBundle is valid on the index and contains data. + internal bool GetPacketBundle(int channel, out PacketBundle packetBundle) + { + return PacketBundle.GetPacketBundle(channel, _toClientBundles, out packetBundle); + } + + /// + /// Indicates the server has data to send to this connection. + /// + private void ServerDirty() + { + bool wasDirty = _serverDirtied; + _serverDirtied = true; + + //If not yet dirty then tell transport manager this is dirty. + if (!wasDirty) + NetworkManager.TransportManager.ServerDirty(this); + } + + /// + /// Resets that there is data to send. + /// + internal void ResetServerDirty() + { + _serverDirtied = false; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs.meta new file mode 100644 index 0000000..2b3f00e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.Buffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bc17ee5bac499347a6fbad9dd24b7b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs new file mode 100644 index 0000000..c917e54 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs @@ -0,0 +1,104 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Timing; +using System; +using UnityEngine; + +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 + { + #region Private. + /// + /// Last tick this connection sent a ping. + /// + private uint _lastPingTick; + /// + /// Number of times client has excessively sent a ping. + /// + private float _excessivePingCount; + /// + /// Ticks expected between each ping. + /// + private uint _requiredPingTicks; + #endregion + + #region Const. + /// + /// Number of times a ping may occur excessively before server will punish connection. + /// + private const byte EXCESSIVE_PING_LIMIT = 10; + #endregion + + /// + /// Initializes for ping. + /// + private void InitializePing() + { + //Give the client some room for error. + float requiredInterval = (NetworkManager.TimeManager.PingInterval * 0.85f); + //Round down so required ticks is lower. + _requiredPingTicks = NetworkManager.TimeManager.TimeToTicks(requiredInterval, TickRounding.RoundDown); + } + + + /// + /// Resets PingPong values. + /// + private void ResetPingPong() + { + _excessivePingCount = 0; + _lastPingTick = 0; + } + + /// + /// Called when a ping is received from this connection. Returns if can respond to ping. + /// + /// True to respond to ping, false to kick connection. + internal bool CanPingPong() + { + /* Only check ping conditions in build. Editors are prone to pausing which can + * improperly kick clients. */ +#if !UNITY_EDITOR + return true; +#else + TimeManager tm = (NetworkManager == null) ? InstanceFinder.TimeManager : NetworkManager.TimeManager; + //Server FPS is running low, timing isn't reliable enough to kick clients. + if (tm.LowFrameRate) + return true; + + uint currentTick = tm.Tick; + uint difference = (currentTick - _lastPingTick); + _lastPingTick = currentTick; + + //Ping sent too quickly. + if (difference < _requiredPingTicks) + { + _excessivePingCount += 1f; + //Ping limit hit. + if (_excessivePingCount >= EXCESSIVE_PING_LIMIT) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Kicked connectionId {ClientId} for excessive pings."); + Disconnect(true); + } + + //Return to not send pong back. + return false; + } + //Ping isnt too fast. + else + { + _excessivePingCount = Mathf.Max(0f, _excessivePingCount - 0.5f); + return true; + } +#endif + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs.meta b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs.meta new file mode 100644 index 0000000..edf2c73 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.PingPong.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20633bf6995f6534ba2b27e1eab3054d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs new file mode 100644 index 0000000..ae40754 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs @@ -0,0 +1,29 @@ +using FishNet.Managing; +using System; + +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 + { + + /// + /// Returns the address of this connection. + /// + /// + public string GetAddress() + { + if (!IsValid) + return string.Empty; + if (NetworkManager == null) + return string.Empty; + + return NetworkManager.TransportManager.Transport.GetConnectionAddress(ClientId); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs.meta new file mode 100644 index 0000000..b92ca8e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d45abc242399194b85e6c16bcb3676b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs new file mode 100644 index 0000000..168fb10 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs @@ -0,0 +1,308 @@ +using FishNet.Documenting; +using FishNet.Managing; +using FishNet.Object; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine.SceneManagement; + +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 + { + + #region Public. + /// + /// Called after this connection has loaded start scenes. Boolean will be true if asServer. Available to this connection and server. + /// + public event Action OnLoadedStartScenes; + /// + /// Called after connection gains ownership of an object, and after the object has been added to Objects. Available to this connection and server. + /// + public event Action OnObjectAdded; + /// + /// Called after connection loses ownership of an object, and after the object has been removed from Objects. Available to this connection and server. + /// + public event Action OnObjectRemoved; + /// + /// NetworkManager managing this class. + /// + public NetworkManager NetworkManager { get; private set; } + /// + /// True if connection has loaded start scenes. Available to this connection and server. + /// + public bool LoadedStartScenes => (_loadedStartScenesAsServer || _loadedStartScenesAsClient); + /// + /// True if loaded start scenes as server. + /// + private bool _loadedStartScenesAsServer; + /// + /// True if loaded start scenes as client. + /// + private bool _loadedStartScenesAsClient; + /// + /// True if this connection is authenticated. Only available to server. + /// + public bool Authenticated { get; private set; } + /// + /// True if this connection IsValid and not Disconnecting. + /// + public bool IsActive => (ClientId >= 0 && !Disconnecting); + /// + /// True if this connection is valid. An invalid connection indicates no client is set for this reference. + /// + public bool IsValid => (ClientId >= 0); + /// + /// Unique Id for this connection. + /// + public int ClientId = -1; + /// + /// Returns if this connection is for the local client. + /// + public bool IsLocalClient => (NetworkManager == null) ? false : (NetworkManager.ClientManager.Connection == this); + /// + /// + /// + private HashSet _objects = new HashSet(); + /// + /// Objects owned by this connection. Available to this connection and server. + /// + public IReadOnlyCollection Objects => _objects; + /// + /// The first object within Objects. + /// + public NetworkObject FirstObject { get; private set; } + /// + /// Scenes this connection is in. Available to this connection and server. + /// + public HashSet Scenes { get; private set; } = new HashSet(); + /// + /// True if this connection is being disconnected. Only available to server. + /// + 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; + #endregion + + #region Comparers. + public override bool Equals(object obj) + { + if (obj is NetworkConnection nc) + return (nc.ClientId == this.ClientId); + else + return false; + } + public bool Equals(NetworkConnection nc) + { + if (nc is null) + return false; + //If either is -1 Id. + if (this.ClientId == -1 || nc.ClientId == -1) + return false; + //Same object. + if (System.Object.ReferenceEquals(this, nc)) + return true; + + return (this.ClientId == nc.ClientId); + } + public override int GetHashCode() + { + return ClientId; + } + public static bool operator ==(NetworkConnection a, NetworkConnection b) + { + if (a is null && b is null) + return true; + if (a is null && !(b is null)) + return false; + + return (b == null) ? a.Equals(b) : b.Equals(a); + } + public static bool operator !=(NetworkConnection a, NetworkConnection b) + { + return !(a == b); + } + #endregion + + [APIExclude] + public NetworkConnection() { } + [APIExclude] + public NetworkConnection(NetworkManager manager, int clientId) + { + Initialize(manager, clientId); + } + + /// + /// Initializes this for use. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Initialize(NetworkManager nm, int clientId) + { + NetworkManager = nm; + ClientId = clientId; + InitializeBuffer(); + InitializePing(); + } + + /// + /// Resets this instance. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reset() + { + ClientId = -1; + ClearObjects(); + Authenticated = false; + NetworkManager = null; + _loadedStartScenesAsClient = false; + _loadedStartScenesAsServer = false; + SetDisconnecting(false); + Scenes.Clear(); + ResetPingPong(); + } + + /// + /// Sets Disconnecting boolean for this connection. + /// + internal void SetDisconnecting(bool value) + { + Disconnecting = value; + if (Disconnecting) + DisconnectingTick = NetworkManager.TimeManager.LocalTick; + } + + /// + /// Disconnects this connection. + /// + /// True to disconnect immediately. False to send any pending data first. + public void Disconnect(bool immediately) + { + SetDisconnecting(true); + //If immediately then force disconnect through transport. + if (immediately) + NetworkManager.TransportManager.Transport.StopConnection(ClientId, true); + //Otherwise mark dirty so server will push out any pending information, and then disconnect. + else + ServerDirty(); + } + + /// + /// Returns if just loaded start scenes and sets them as loaded if not. + /// + /// + internal bool SetLoadedStartScenes(bool asServer) + { + bool loadedToCheck = (asServer) ? _loadedStartScenesAsServer : _loadedStartScenesAsClient; + //Result becomes true if not yet loaded start scenes. + bool result = !loadedToCheck; + if (asServer) + _loadedStartScenesAsServer = true; + else + _loadedStartScenesAsClient = true; + + OnLoadedStartScenes?.Invoke(this, asServer); + + return result; + } + + /// + /// Sets connection as authenticated. + /// + internal void ConnectionAuthenticated() + { + Authenticated = true; + } + + /// + /// Adds to Objects owned by this connection. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AddObject(NetworkObject nob) + { + _objects.Add(nob); + //If adding the first object then set new FirstObject. + if (_objects.Count == 1) + FirstObject = nob; + + OnObjectAdded?.Invoke(nob); + } + + /// + /// Removes from Objects owned by this connection. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void RemoveObject(NetworkObject nob) + { + _objects.Remove(nob); + //If removing the first object then set a new one. + if (nob == FirstObject) + SetFirstObject(); + + OnObjectRemoved?.Invoke(nob); + } + + /// + /// Clears all Objects. + /// + private void ClearObjects() + { + _objects.Clear(); + FirstObject = null; + } + + /// + /// Sets FirstObject using the first element in Objects. + /// + private void SetFirstObject() + { + if (_objects.Count == 0) + { + FirstObject = null; + } + else + { + foreach (NetworkObject nob in Objects) + { + FirstObject = nob; + break; + } + } + } + + /// + /// Adds a scene to this connections Scenes. + /// + /// + /// + internal bool AddToScene(Scene scene) + { + return Scenes.Add(scene); + } + + /// + /// Removes a scene to this connections Scenes. + /// + /// + /// + internal bool RemoveFromScene(Scene scene) + { + return Scenes.Remove(scene); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs.meta b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs.meta new file mode 100644 index 0000000..20973ee --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Connection/NetworkConnection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01c7bfc71e29621408451fa2fa6b1a0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset b/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset new file mode 100644 index 0000000..97f5f2f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset @@ -0,0 +1,21 @@ +%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: 3ad70174b079c2f4ebc7931d3dd1af6f, type: 3} + m_Name: DefaultPrefabObjects + m_EditorClassIdentifier: + _prefabs: + - {fileID: 744839112580503729, guid: f86c53b4b7ca9ca47ada8b4674970afb, type: 3} + - {fileID: 1022466107096954536, guid: 3b6afe29d22f1fc458cbbcaa766322ac, type: 3} + - {fileID: 611616139817875448, guid: bf5f023b4017a5e41a9815ec5745df3d, type: 3} + - {fileID: 9117857247562382210, guid: b2991431a5f893e49937d01b6da44ff8, type: 3} + - {fileID: 201277550, guid: d904f93bc171bb144ba33c5155282f6f, type: 3} + - {fileID: 27039729695437543, guid: f820efff6a2871447b961fc755212ba3, type: 3} diff --git a/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset.meta b/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset.meta new file mode 100644 index 0000000..a38e6d0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/DefaultPrefabObjects.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec64eb18c93ab344892891f33edbf82a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Documenting.meta b/UnityProject/Assets/FishNet/Runtime/Documenting.meta new file mode 100644 index 0000000..213ed84 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Documenting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0478042f95cb685419656df549fdd04c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs b/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs new file mode 100644 index 0000000..c25e901 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs @@ -0,0 +1,8 @@ + +using System; + +namespace FishNet.Documenting +{ + public class APIExcludeAttribute : Attribute { } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs.meta new file mode 100644 index 0000000..5c4e30d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Documenting/Attributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d101aaaeb244ac48bfe2d7d05308c1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Editor.meta new file mode 100644 index 0000000..4ec053b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98bf936e4684b214fa9c05c45955ed0d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs b/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs new file mode 100644 index 0000000..2582f34 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs @@ -0,0 +1,118 @@ + +using FishNet.Configuring; +using System.IO; +using UnityEngine; +using System.Xml.Serialization; + +#if UNITY_EDITOR +using FishNet.Editing.PrefabCollectionGenerator; +using UnityEditor.Compilation; +using UnityEditor.Build.Reporting; +using UnityEditor; +using UnityEditor.Build; +#endif + +namespace FishNet.Configuring +{ + + + public class CodeStripping + + { + + /// + /// True if making a release build for client. + /// + public static bool ReleasingForClient => (Configuration.ConfigurationData.IsBuilding && !Configuration.ConfigurationData.IsHeadless && !Configuration.ConfigurationData.IsDevelopment); + /// + /// True if making a release build for server. + /// + public static bool ReleasingForServer => (Configuration.ConfigurationData.IsBuilding && Configuration.ConfigurationData.IsHeadless && !Configuration.ConfigurationData.IsDevelopment); + /// + /// Returns if to remove server logic. + /// + /// + public static bool RemoveServerLogic + { + get + { + + + /* This is to protect non pro users from enabling this + * without the extra logic code. */ +#pragma warning disable CS0162 // Unreachable code detected + return false; +#pragma warning restore CS0162 // Unreachable code detected + } + } + /// + /// True if building and stripping is enabled. + /// + public static bool StripBuild + { + get + { + + + /* This is to protect non pro users from enabling this + * without the extra logic code. */ +#pragma warning disable CS0162 // Unreachable code detected + return false; +#pragma warning restore CS0162 // Unreachable code detected + } + } + /// + /// Technique to strip methods. + /// + public static StrippingTypes StrippingType => (StrippingTypes)Configuration.ConfigurationData.StrippingType; + + private static object _compilationContext; + public int callbackOrder => 0; +#if UNITY_EDITOR + + public void OnPreprocessBuild(BuildReport report) + { + Generator.IgnorePostProcess = true; + Generator.GenerateFull(); + CompilationPipeline.compilationStarted += CompilationPipelineOnCompilationStarted; + CompilationPipeline.compilationFinished += CompilationPipelineOnCompilationFinished; + + + } + /* Solution for builds ending with errors and not triggering OnPostprocessBuild. + * Link: https://gamedev.stackexchange.com/questions/181611/custom-build-failure-callback + */ + private void CompilationPipelineOnCompilationStarted(object compilationContext) + { + _compilationContext = compilationContext; + } + + private void CompilationPipelineOnCompilationFinished(object compilationContext) + { + if (compilationContext != _compilationContext) + return; + + _compilationContext = null; + + CompilationPipeline.compilationStarted -= CompilationPipelineOnCompilationStarted; + CompilationPipeline.compilationFinished -= CompilationPipelineOnCompilationFinished; + + BuildingEnded(); + } + + private void BuildingEnded() + { + + + Generator.IgnorePostProcess = false; + } + + public void OnPostprocessBuild(BuildReport report) + { + + BuildingEnded(); + } +#endif + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs.meta new file mode 100644 index 0000000..dec4f86 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/CodeStripping.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c7409efe2f84e7428d5c6c97ed7d32e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuration.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration.meta new file mode 100644 index 0000000..05acca1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb610f9af82907e409daec82557d2f89 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs new file mode 100644 index 0000000..6e23e2b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs @@ -0,0 +1 @@ +//File intentionally left blank. //remove on 2023/01/01 \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs.meta new file mode 100644 index 0000000..d934905 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuration/SettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1aae686ffa9973d4da2e76ba9a738366 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring.meta new file mode 100644 index 0000000..bf77916 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e789fd90a3d65864bbead2949dbdbb36 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs new file mode 100644 index 0000000..5bbb9f6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs @@ -0,0 +1,124 @@ + +using System; +using System.IO; +using System.Xml.Serialization; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace FishNet.Configuring +{ + + public enum StrippingTypes : int + { + Redirect = 0, + Empty_Experimental = 1, + //MoveAndEmpty = 2 + } + + public class ConfigurationData + { + //Non serialized doesn't really do anything, its just for me. + [System.NonSerialized] + public bool Loaded; + + public bool IsBuilding; + public bool IsDevelopment; + public bool IsHeadless; + + public bool StripReleaseBuilds = false; + public int StrippingType; + } + + public static class ConfigurationDataExtension + { + + /// + /// Returns if a differs from b. + /// + public static bool HasChanged(this ConfigurationData a, ConfigurationData b) + { + return (a.StripReleaseBuilds != b.StripReleaseBuilds); + } + /// + /// Copies all values from source to target. + /// + public static void CopyTo(this ConfigurationData source, ConfigurationData target) + { + target.StripReleaseBuilds = source.StripReleaseBuilds; + } + + + /// + /// Writes a configuration data. + /// + public static void Write(this ConfigurationData cd, bool refreshAssetDatabase) + { + /* Why is this a thing you ask? Because Unity makes it VERY difficult to read values from + * memory during builds since on some Unity versions the building application is on a different + * processor. In result instead of using memory to read configurationdata the values + * must be written to disk then load the disk values as needed. + * + * Fortunatelly the file is extremely small and this does not occur often at all. The disk read + * will occur once per script save, and once per assembly when building. */ + try + { + string path = Configuration.GetAssetsPath(Configuration.CONFIG_FILE_NAME); + XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData)); + TextWriter writer = new StreamWriter(path); + serializer.Serialize(writer, cd); + writer.Close(); +#if UNITY_EDITOR + if (refreshAssetDatabase) + { + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } +#endif + } + catch (Exception ex) + { + throw new Exception($"An error occurred while writing ConfigurationData. Message: {ex.Message}"); + } + + } + + + /// + /// Writes a configuration data. + /// + public static void Write(this ConfigurationData cd, string path, bool refreshAssetDatabase) + { + /* Why is this a thing you ask? Because Unity makes it VERY difficult to read values from + * memory during builds since on some Unity versions the building application is on a different + * processor. In result instead of using memory to read configurationdata the values + * must be written to disk then load the disk values as needed. + * + * Fortunatelly the file is extremely small and this does not occur often at all. The disk read + * will occur once per script save, and once per assembly when building. */ + try + { + XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData)); + TextWriter writer = new StreamWriter(path); + serializer.Serialize(writer, cd); + writer.Close(); +#if UNITY_EDITOR + if (refreshAssetDatabase) + { + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } +#endif + } + catch (Exception ex) + { + throw new Exception($"An error occurred while writing ConfigurationData. Message: {ex.Message}"); + } + + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs.meta new file mode 100644 index 0000000..95ea289 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4be37e1b0afd29944ad4fa0b92ed8c7e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs new file mode 100644 index 0000000..fe4c4cf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs @@ -0,0 +1,86 @@ +#if UNITY_EDITOR +using FishNet.Editing.PrefabCollectionGenerator; +using FishNet.Object; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Editing +{ + public class ConfigurationEditor : EditorWindow + { + + [MenuItem("Fish-Networking/Configuration", false, 0)] + public static void ShowConfiguration() + { + SettingsService.OpenProjectSettings("Project/Fish-Networking/Configuration"); + } + + } + + public class OpenDocumentationMenu : MonoBehaviour + { + /// + /// Opens the documentation. + /// + [MenuItem("Fish-Networking/Documentation", false, int.MaxValue)] + public static void OpenDocumentation() + { + System.Diagnostics.Process.Start("https://fish-networking.gitbook.io/docs/"); + } + + + } + + + public class RebuildSceneIdMenu : MonoBehaviour + { + /// + /// Rebuilds sceneIds for open scenes. + /// + [MenuItem("Fish-Networking/Rebuild SceneIds", false, 20)] + public static void RebuildSceneIds() + { + int generatedCount = 0; + for (int i = 0; i < SceneManager.sceneCount; i++) + { + Scene s = SceneManager.GetSceneAt(i); + + ListCache nobs; + SceneFN.GetSceneNetworkObjects(s, false, out nobs); + for (int z = 0; z < nobs.Written; z++) + { + NetworkObject nob = nobs.Collection[z]; + nob.TryCreateSceneID(); + EditorUtility.SetDirty(nob); + } + generatedCount += nobs.Written; + + ListCaches.StoreCache(nobs); + } + + Debug.Log($"Generated sceneIds for {generatedCount} objects over {SceneManager.sceneCount} scenes. Please save your open scenes."); + } + + + } + + public class RefreshDefaultPrefabsMenu : MonoBehaviour + { + /// + /// Rebuilds the DefaultPrefabsCollection file. + /// + [MenuItem("Fish-Networking/Refresh Default Prefabs", false, 21)] + public static void RebuildDefaultPrefabs() + { + Debug.Log("Refreshing default prefabs."); + Generator.GenerateFull(null, true); + } + + + } + +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs.meta new file mode 100644 index 0000000..1106133 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8135b3a4c31cfb74896f1e9e77059c89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs new file mode 100644 index 0000000..6c4ce06 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs @@ -0,0 +1,95 @@ +using System.IO; +using System.Xml.Serialization; + +#if UNITY_EDITOR +using UnityEditor.Compilation; +using UnityEditor.Build.Reporting; +using UnityEditor; +using UnityEditor.Build; +#endif + +namespace FishNet.Configuring +{ + + + public class Configuration + { + + /// + /// + /// + private static ConfigurationData _configurationData; + /// + /// ConfigurationData to use. + /// + public static ConfigurationData ConfigurationData + { + get + { + if (_configurationData == null) + _configurationData = LoadConfigurationData(); + if (_configurationData == null) + throw new System.Exception("Fish-Networking ConfigurationData could not be loaded. Certain features such as code-stripping may not function."); + return _configurationData; + } + private set + { + _configurationData = value; + } + } + + /// + /// File name for configuration disk data. + /// + public const string CONFIG_FILE_NAME = "FishNet.Config.XML"; + + /// + /// Returns the path for the configuration file. + /// + /// + internal static string GetAssetsPath(string additional = "") + { + string a = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Assets"); + if (additional != "") + a = Path.Combine(a, additional); + return a; + } + /// + /// Returns FishNetworking ConfigurationData. + /// + /// + internal static ConfigurationData LoadConfigurationData() + { + //return new ConfigurationData(); + if (_configurationData == null || !_configurationData.Loaded) + { + string configPath = GetAssetsPath(CONFIG_FILE_NAME); + //string configPath = string.Empty; + //File is on disk. + if (File.Exists(configPath)) + { + XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData)); + FileStream fs = new FileStream(configPath, FileMode.Open, FileAccess.Read, FileShare.Read); + _configurationData = (ConfigurationData)serializer.Deserialize(fs); + fs.Close(); + + _configurationData.Loaded = true; + } + else + { + //If null then make a new instance. + if (_configurationData == null) + _configurationData = new ConfigurationData(); + //Don't unset loaded, if its true then it should have proper info. + //_configurationData.Loaded = false; + } + } + + return _configurationData; + + } + + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs.meta new file mode 100644 index 0000000..0d34195 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/Configuring.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d05bf07ec9af2c46a1fe6c24871cccb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs new file mode 100644 index 0000000..23a3779 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs @@ -0,0 +1,86 @@ +#if UNITY_EDITOR + +using UnityEngine; +using UnityEditor; +using FishNet.Configuring; + +using UnitySettingsProviderAttribute = UnityEditor.SettingsProviderAttribute; +using UnitySettingsProvider = UnityEditor.SettingsProvider; +using System.Collections.Generic; + +namespace FishNet.Configuring.Editing +{ + internal static class SettingsProvider + { + private static Vector2 _scrollView; + + [UnitySettingsProvider] + private static UnitySettingsProvider Create() + { + return new UnitySettingsProvider("Project/Fish-Networking/Configuration", SettingsScope.Project) + { + label = "Configuration", + + guiHandler = OnGUI, + + keywords = new string[] + { + "Fish", + "Networking", + "Configuration", + }, + }; + } + + private static void OnGUI(string searchContext) + { + ConfigurationData configuration = Configuration.LoadConfigurationData(); + + if (configuration == null) + { + EditorGUILayout.HelpBox("Unable to load configuration data.", MessageType.Error); + + return; + } + + EditorGUI.BeginChangeCheck(); + + GUIStyle scrollViewStyle = new GUIStyle() + { + padding = new RectOffset(10, 10, 10, 10), + }; + + _scrollView = GUILayout.BeginScrollView(_scrollView, scrollViewStyle); + + EditorGUILayout.BeginHorizontal(); + + GUIStyle toggleStyle = new GUIStyle(EditorStyles.toggle) + { + richText = true, + }; + + configuration.StripReleaseBuilds = GUILayout.Toggle(configuration.StripReleaseBuilds, $"{ObjectNames.NicifyVariableName(nameof(configuration.StripReleaseBuilds))} (Pro Only)", toggleStyle); + + EditorGUILayout.EndHorizontal(); + + if (configuration.StripReleaseBuilds) + { + EditorGUI.indentLevel++; + //Stripping Method. + List enumStrings = new List(); + foreach (string item in System.Enum.GetNames(typeof(StrippingTypes))) + enumStrings.Add(item); + configuration.StrippingType = EditorGUILayout.Popup($"{ObjectNames.NicifyVariableName(nameof(configuration.StrippingType))}", (int)configuration.StrippingType, enumStrings.ToArray()); + + EditorGUILayout.HelpBox("Development builds will not have code stripped. Additionally, if you plan to run as host disable code stripping.", MessageType.Warning); + EditorGUI.indentLevel--; + } + + GUILayout.EndScrollView(); + + if (EditorGUI.EndChangeCheck()) Configuration.ConfigurationData.Write(true); + } + } +} + +#endif diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs.meta new file mode 100644 index 0000000..d668951 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Configuring/SettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3d7d3c45d53dea4e8a0a7da73d64021 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs new file mode 100644 index 0000000..1e8523d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs @@ -0,0 +1,13 @@ +using FishNet.Documenting; + +namespace FishNet.Editing +{ + [APIExclude] + public static class EditingConstants + { + public const string PRO_ASSETS_LOCKED_TEXT = "Fields marked with * are only active with Fish-Networking Pro."; + public const string PRO_ASSETS_UNLOCKED_TEXT = "Thank you for supporting Fish-Networking! Pro asset features are unlocked."; + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs.meta new file mode 100644 index 0000000..bfee3c7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Constants.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d2683b3becd2c5488c1f338972d49e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs b/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs new file mode 100644 index 0000000..626cabc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs @@ -0,0 +1,126 @@ +//#if UNITY_EDITOR +//using FishNet.Managing.Object; +//using FishNet.Object; +//using System.Collections.Generic; +//using System.IO; +//using UnityEditor; +//using UnityEngine; + +//namespace FishNet.Editing +//{ + +// [InitializeOnLoad] +// internal static class DefaultPrefabsFinder +// { +// /// +// /// True if initialized. +// /// +// [System.NonSerialized] +// private static bool _initialized; +// /// +// /// Found default prefabs. +// /// +// private static DefaultPrefabObjects _defaultPrefabs; + +// static DefaultPrefabsFinder() +// { +// EditorApplication.update += InitializeOnce; +// } + +// /// +// /// Finds and sets the default prefabs reference. +// /// +// internal static DefaultPrefabObjects GetDefaultPrefabsFile(out bool justPopulated) +// { +// if (_defaultPrefabs == null) +// { +// List results = Finding.GetScriptableObjects(true, true); +// if (results.Count > 0) +// _defaultPrefabs = (DefaultPrefabObjects)results[0]; +// } + +// justPopulated = false; +// //If not found then try to create file. +// if (_defaultPrefabs == null) +// { +// if (DefaultPrefabObjects.CanAutomate) +// { +// DefaultPrefabObjects dpo = ScriptableObject.CreateInstance(); +// //Get save directory. +// string savePath = Finding.GetFishNetRuntimePath(true); +// AssetDatabase.CreateAsset(dpo, Path.Combine(savePath, $"{nameof(DefaultPrefabObjects)}.asset")); +// } +// else +// { +// Debug.LogError($"Cannot create DefaultPrefabs because auto create is blocked."); +// } +// } + +// //If still null. +// if (_defaultPrefabs == null) +// Debug.LogWarning($"DefaultPrefabObjects not found. Prefabs list will not be automatically populated."); +// else +// justPopulated = PopulateDefaultPrefabs(); + +// return _defaultPrefabs; +// } + +// /// +// /// Initializes the default prefab. +// /// +// private static void InitializeOnce() +// { +// if (_initialized) +// return; +// _initialized = true; + +// Finding.GetFishNetRuntimePath(false); +// GetDefaultPrefabsFile(out _); + +// if (_defaultPrefabs != null) +// { +// //Populate any missing. +// if (_defaultPrefabs.GetObjectCount() == 0) +// PopulateDefaultPrefabs(); +// } +// } + + +// /// +// /// Finds all NetworkObjects in project and adds them to defaultPrefabs. +// /// +// /// True if was populated from assets. +// internal static bool PopulateDefaultPrefabs(bool log = true, bool clear = false) +// { +// if (_defaultPrefabs == null) +// return false; +// if (!DefaultPrefabObjects.CanAutomate) +// return false; +// if (clear) +// _defaultPrefabs.Clear(); +// if (_defaultPrefabs.GetObjectCount() > 0) +// return false; + +// List gameObjects = Finding.GetGameObjects(true, true, false); +// foreach (GameObject go in gameObjects) +// { +// if (go.TryGetComponent(out NetworkObject nob)) +// _defaultPrefabs.AddObject(nob); +// } + +// _defaultPrefabs.Sort(); + +// int entriesAdded = _defaultPrefabs.GetObjectCount(); +// //Only print if some were added. +// if (log && entriesAdded > 0) +// Debug.Log($"Default prefabs was populated with {entriesAdded} prefabs."); + +// EditorUtility.SetDirty(_defaultPrefabs); +// return true; +// } + +// } + + +//} +//#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs.meta new file mode 100644 index 0000000..1ee03df --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/DefaultPrefabsFinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bd002f6c85dd4341bcaf163eaaa3ddf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs b/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs new file mode 100644 index 0000000..2d260c8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs @@ -0,0 +1,216 @@ +#if UNITY_EDITOR +using FishNet.Utility.Constant; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Editing +{ + public static class Finding + { + #region Private. + /// + /// Path where the FishNet.Runtime assembly is. + /// + [System.NonSerialized] + private static string _fishNetRuntimePath = string.Empty; + /// + /// Path where the FishNet.Generated assembly is. + /// + private static string _fishNetGeneratedPath = string.Empty; + #endregion + + /// + /// Sets FishNet assembly paths. + /// + /// + private static void SetPaths(bool error) + { + if (_fishNetGeneratedPath != string.Empty && _fishNetRuntimePath != string.Empty) + return; + + string[] guids = AssetDatabase.FindAssets("t:asmdef", new string[] { "Assets" }); + string[] objectPaths = new string[guids.Length]; + for (int i = 0; i < guids.Length; i++) + objectPaths[i] = AssetDatabase.GUIDToAssetPath(guids[i]); + + string runtimeName = (UtilityConstants.RUNTIME_ASSEMBLY_NAME + ".asmdef").ToLower(); + string generatedName = (UtilityConstants.GENERATED_ASSEMBLY_NAME + ".asmdef").ToLower(); + /* Find all network managers which use Single prefab linking + * as well all network object prefabs. */ + foreach (string item in objectPaths) + { + //Found directory to create object in. + if (item.ToLower().Contains(runtimeName)) + _fishNetRuntimePath = System.IO.Path.GetDirectoryName(item); + else if (item.ToLower().Contains(generatedName)) + _fishNetGeneratedPath = System.IO.Path.GetDirectoryName(item); + + if (_fishNetGeneratedPath != string.Empty && _fishNetRuntimePath != string.Empty) + return; + } + } + /// + /// Gets path for where the FishNet.Runtime assembly is. + /// + /// + public static string GetFishNetRuntimePath(bool error) + { + SetPaths(error); + return _fishNetRuntimePath; + } + /// + /// Gets path for where the FishNet.Generated assembly is. + /// + /// + /// + public static string GetFishNetGeneratedPath(bool error) + { + SetPaths(error); + return _fishNetGeneratedPath; + } + + /// + /// Gets all GameObjects in Assets and optionally scenes. + /// + /// + /// + public static List GetGameObjects(bool userAssemblies, bool fishNetAssembly, bool includeScenes, string[] ignoredPaths = null) + { + List results = new List(); + + string[] guids; + string[] objectPaths; + + guids = AssetDatabase.FindAssets("t:GameObject", null); + objectPaths = new string[guids.Length]; + for (int i = 0; i < guids.Length; i++) + objectPaths[i] = AssetDatabase.GUIDToAssetPath(guids[i]); + + foreach (string item in objectPaths) + { + bool inFishNet = item.Contains(_fishNetRuntimePath); + if (inFishNet && !fishNetAssembly) + continue; + if (!inFishNet && !userAssemblies) + continue; + if (ignoredPaths != null) + { + bool ignore = false; + foreach (string path in ignoredPaths) + { + if (item.Contains(path)) + { + ignore = true; + break; + } + } + if (ignore) + continue; + } + + GameObject go = (GameObject)AssetDatabase.LoadAssetAtPath(item, typeof(GameObject)); + results.Add(go); + } + + if (includeScenes) + results.AddRange(GetSceneGameObjects()); + + return results; + } + + /// + /// Gets all GameObjects in all open scenes. + /// + /// + private static List GetSceneGameObjects() + { + List results = new List(); + + for (int i = 0; i < SceneManager.sceneCount; i++) + results.AddRange(GetSceneGameObjects(SceneManager.GetSceneAt(i))); + + return results; + } + /// + /// Gets all GameObjects in a scene. + /// + private static List GetSceneGameObjects(Scene s) + { + List results = new List(); + List buffer = new List(); + //Iterate all root objects for the scene. + GameObject[] gos = s.GetRootGameObjects(); + for (int i = 0; i < gos.Length; i++) + { + /* Get GameObjects within children of each + * root object then add them to the cache. */ + gos[i].GetComponentsInChildren(true, buffer); + foreach (Transform t in buffer) + results.Add(t.gameObject); + } + + return results; + } + + + /// + /// Gets created ScriptableObjects of T. + /// + /// + /// + public static List GetScriptableObjects(bool fishNetAssembly, bool breakOnFirst = false) + { + System.Type tType = typeof(T); + List results = new List(); + + string[] guids = AssetDatabase.FindAssets("t:ScriptableObject", new string[] { "Assets" }); + string[] objectPaths = new string[guids.Length]; + for (int i = 0; i < guids.Length; i++) + objectPaths[i] = AssetDatabase.GUIDToAssetPath(guids[i]); + + + /* This might be faster than using directory comparers. + * Don't really care since this occurs only at edit. */ + List fishNetPaths = new List(); + fishNetPaths.Add(_fishNetGeneratedPath.Replace(@"/", @"\")); + fishNetPaths.Add(_fishNetGeneratedPath.Replace(@"\", @"/")); + fishNetPaths.Add(_fishNetRuntimePath.Replace(@"/", @"\")); + fishNetPaths.Add(_fishNetRuntimePath.Replace(@"\", @"/")); + /* Find all network managers which use Single prefab linking + * as well all network object prefabs. */ + foreach (string item in objectPaths) + { + //This will skip hidden unity types. + if (!item.EndsWith(".asset")) + continue; + if (fishNetAssembly) + { + bool found = false; + foreach (string path in fishNetPaths) + { + if (item.Contains(path)) + { + found = true; + break; + } + } + if (!found) + continue; + } + UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(item, tType); + if (obj != null && tType != null && obj.GetType() == tType) + { + results.Add(obj); + if (breakOnFirst) + return results; + } + } + + return results; + } + + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs.meta new file mode 100644 index 0000000..23a2fb5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Finding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b777233d19062274f9eec6a982d8ff37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs b/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs new file mode 100644 index 0000000..45f7b7c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR +using System; +using UnityEditor; +using UnityEngine; + +namespace FishNet.Editing +{ + + [InitializeOnLoad] + public class PlayModeTracker + { + static PlayModeTracker() + { + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + ~PlayModeTracker() + { + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + } + + /// + /// DateTime when the editor last exited playmode. + /// + private static DateTime _quitTime = DateTime.MaxValue; + + /// + /// True if the editor has exited playmode within past. + /// + /// + /// + internal static bool QuitRecently(float past) + { + past *= 1000; + return ((DateTime.Now - _quitTime).TotalMilliseconds < past); + } + + private static void OnPlayModeStateChanged(PlayModeStateChange stateChange) + { + switch (stateChange) + { + case (PlayModeStateChange.ExitingPlayMode): + _quitTime = DateTime.Now; + break; + } + } + + } +} + +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs.meta new file mode 100644 index 0000000..d5fd5a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PlayModeTracker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4a1d20c6a03a524ab21c7aebed106d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator.meta new file mode 100644 index 0000000..873aa1e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3da51acfc7419a544887f9eab923b0a7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs new file mode 100644 index 0000000..580cc11 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs @@ -0,0 +1,557 @@ +#if UNITY_EDITOR + +using FishNet.Configuring; +using FishNet.Managing.Object; +using FishNet.Object; +using FishNet.Object.Helping; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityDebug = UnityEngine.Debug; + +namespace FishNet.Editing.PrefabCollectionGenerator +{ + internal sealed class Generator : AssetPostprocessor + { + public Generator() + { + if (!_subscribed) + { + _subscribed = true; + EditorApplication.update += OnEditorUpdate; + } + } + ~Generator() + { + if (_subscribed) + { + _subscribed = false; + EditorApplication.update -= OnEditorUpdate; + } + } + + #region Types. + private struct SpecifiedFolder + { + public string Path; + public bool Recursive; + + public SpecifiedFolder(string path, bool recursive) + { + Path = path; + Recursive = recursive; + } + } + #endregion + + #region Public. + /// + /// True to ignore post process changes. + /// + public static bool IgnorePostProcess = false; + #endregion + + #region Private. + /// + /// Last asset to import when there was only one imported asset and no other changes. + /// + private static string _lastSingleImportedAsset = string.Empty; + /// + /// Cached DefaultPrefabObjects reference. + /// + private static DefaultPrefabObjects _cachedDefaultPrefabs; + /// + /// True to refresh prefabs next update. + /// + private static bool _retryRefreshDefaultPrefabs; + /// + /// True if already subscribed to EditorApplication.Update. + /// + private static bool _subscribed; + /// + /// True if ran once since editor started. + /// + [System.NonSerialized] + private static bool _ranOnce; + #endregion + + private static string[] GetPrefabFiles(string startingPath, HashSet excludedPaths, bool recursive) + { + //Opportunity to exit early if there are no excluded paths. + if (excludedPaths.Count == 0) + { + string[] strResults = Directory.GetFiles(startingPath, "*.prefab", SearchOption.AllDirectories); + return strResults; + } + //starting path is excluded. + if (excludedPaths.Contains(startingPath)) + return new string[0]; + + //Folders remaining to be iterated. + List enumeratedCollection = new List() { startingPath }; + //Only check other directories if recursive. + if (recursive) + { + //Find all folders which aren't excluded. + for (int i = 0; i < enumeratedCollection.Count; i++) + { + string[] allFolders = Directory.GetDirectories(enumeratedCollection[i], "*", SearchOption.TopDirectoryOnly); + for (int z = 0; z < allFolders.Length; z++) + { + string current = allFolders[z]; + //Not excluded. + if (!excludedPaths.Contains(current)) + enumeratedCollection.Add(current); + } + } + } + + //Valid prefab files. + List results = new List(); + //Build files from folders. + int count = enumeratedCollection.Count; + for (int i = 0; i < count; i++) + { + string[] r = Directory.GetFiles(enumeratedCollection[i], "*.prefab", SearchOption.TopDirectoryOnly); + results.AddRange(r); + } + + return results.ToArray(); + } + + /// + /// Removes paths which may overlap each other, such as sub directories. + /// + private static void RemoveOverlappingFolders(List folders) + { + for (int z = 0; z < folders.Count; z++) + { + for (int i = 0; i < folders.Count; i++) + { + //Do not check against self. + if (i == z) + continue; + + //Duplicate. + if (folders[z].Path.Equals(folders[i].Path, System.StringComparison.OrdinalIgnoreCase)) + { + UnityDebug.LogError($"The same path is specified multiple times in the DefaultPrefabGenerator settings. Remove the duplicate to clear this error."); + folders.RemoveAt(i); + break; + } + + /* We are checking if i can be within + * z. This is only possible if i is longer + * than z. */ + if (folders[i].Path.Length < folders[z].Path.Length) + continue; + /* Do not need to check if not recursive. + * Only recursive needs to be checked because + * a shorter recursive path could contain + * a longer path. */ + if (!folders[z].Recursive) + continue; + + //Compare paths. + string zPath = GetPathWithSeparator(folders[z].Path); + string iPath = zPath.Substring(0, zPath.Length); + //If paths match. + if (iPath.Equals(zPath, System.StringComparison.OrdinalIgnoreCase)) + { + UnityDebug.LogError($"Path {folders[i].Path} is included within recursive path {folders[z].Path}. Remove path {folders[i].Path} to clear this error."); + folders.RemoveAt(i); + break; + } + } + } + + string GetPathWithSeparator(string txt) + { + return txt.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + + Path.DirectorySeparatorChar; + } + } + + /// + /// Returns a message to attach to logs if objects were dirtied. + /// + private static string GetDirtiedMessage(Settings settings, bool dirtied) + { + if (!settings.SaveChanges && dirtied) + return " One or more NetworkObjects were dirtied. Please save your project."; + else + return string.Empty; + } + + /// + /// Updates prefabs by using only changed information. + /// + public static void GenerateChanged(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, Settings settings = null) + { + if (settings == null) + settings = Settings.Load(); + if (!settings.Enabled) + return; + + bool log = settings.LogToConsole; + Stopwatch sw = (log) ? Stopwatch.StartNew() : null; + + DefaultPrefabObjects prefabCollection = GetDefaultPrefabObjects(settings); + //No need to error if nto found, GetDefaultPrefabObjects will. + if (prefabCollection == null) + return; + + System.Type goType = typeof(UnityEngine.GameObject); + IterateAssetCollection(importedAssets); + IterateAssetCollection(movedAssets); + + //True if dirtied by changes. + bool dirtied; + //First remove null entries. + int startCount = prefabCollection.GetObjectCount(); + prefabCollection.RemoveNull(); + dirtied = (prefabCollection.GetObjectCount() != startCount); + //First index which new objects will be added to. + int firstAddIndex = (prefabCollection.GetObjectCount() - 1); + + //Iterates strings adding prefabs to collection. + void IterateAssetCollection(string[] c) + { + foreach (string item in c) + { + System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(item); + if (assetType != goType) + continue; + + NetworkObject nob = AssetDatabase.LoadAssetAtPath(item); + if (nob != null) + { + prefabCollection.AddObject(nob, true); + dirtied = true; + } + } + } + + //To prevent out of range. + if (firstAddIndex < 0 || firstAddIndex >= prefabCollection.GetObjectCount()) + firstAddIndex = 0; + dirtied |= prefabCollection.SetAssetPathHashes(firstAddIndex); + + if (log && dirtied) + UnityEngine.Debug.Log($"Default prefab generator updated prefabs in {sw.ElapsedMilliseconds}ms.{GetDirtiedMessage(settings, dirtied)}"); + + EditorUtility.SetDirty(prefabCollection); + if (dirtied && settings.SaveChanges) + AssetDatabase.SaveAssets(); + } + + + /// + /// Generates prefabs by iterating all files within settings parameters. + /// + public static void GenerateFull(Settings settings = null, bool forced = false) + { + if (settings == null) + settings = Settings.Load(); + if (!forced && !settings.Enabled) + return; + bool log = settings.LogToConsole; + + Stopwatch sw = (log) ? Stopwatch.StartNew() : null; + List foundNobs = new List(); + HashSet excludedPaths = new HashSet(settings.ExcludedFolders); + + //If searching the entire project. + if (settings.SearchScope == Settings.SearchScopeType.EntireProject) + { + foreach (string path in GetPrefabFiles("Assets", excludedPaths, true)) + { + NetworkObject nob = AssetDatabase.LoadAssetAtPath(path); + if (nob != null) + foundNobs.Add(nob); + } + } + //Specific folders. + else if (settings.SearchScope == Settings.SearchScopeType.SpecificFolders) + { + List folders = GetSpecifiedFolders(settings.IncludedFolders); + RemoveOverlappingFolders(folders); + + foreach (SpecifiedFolder sf in folders) + { + //If specified folder doesn't exist then continue. + if (!Directory.Exists(sf.Path)) + continue; + + foreach (string path in GetPrefabFiles(sf.Path, excludedPaths, sf.Recursive)) + { + NetworkObject nob = AssetDatabase.LoadAssetAtPath(path); + if (nob != null) + foundNobs.Add(nob); + } + } + } + //Unhandled. + else + { + UnityEngine.Debug.LogError($"{settings.SearchScope} is not handled; default prefabs will not generator properly."); + } + + DefaultPrefabObjects prefabCollection = GetDefaultPrefabObjects(settings); + //No need to error if not found, GetDefaultPrefabObjects will throw. + if (prefabCollection == null) + return; + + //Clear and add built list. + prefabCollection.Clear(); + prefabCollection.AddObjects(foundNobs, false); + bool dirtied = prefabCollection.SetAssetPathHashes(0); + + if (log) + UnityEngine.Debug.Log($"Default prefab generator found {prefabCollection.GetObjectCount()} prefabs in {sw.ElapsedMilliseconds}ms.{GetDirtiedMessage(settings, dirtied)}"); + + EditorUtility.SetDirty(prefabCollection); + if (settings.SaveChanges) + AssetDatabase.SaveAssets(); + } + + /// + /// Iterates folders building them into SpecifiedFolders. + /// + private static List GetSpecifiedFolders(List folders) + { + List results = new List(); + //Remove astericks. + foreach (string path in folders) + { + int pLength = path.Length; + if (pLength == 0) + continue; + + bool recursive; + string p; + //If the last character indicates resursive. + if (path.Substring(pLength - 1, 1) == "*") + { + p = path.Substring(0, pLength - 1); + recursive = true; + } + else + { + p = path; + recursive = false; + } + + results.Add(new SpecifiedFolder(p, recursive)); + } + + return results; + } + + /// + /// Returns the DefaultPrefabObjects file. + /// + private static DefaultPrefabObjects GetDefaultPrefabObjects(Settings settings = null) + { + if (settings == null) + settings = Settings.Load(); + + //Load the prefab collection + string assetPath = settings.AssetPath; + + //If cached prefabs is not the same path as assetPath. + if (_cachedDefaultPrefabs != null) + { + string foundPath = Path.GetFullPath(AssetDatabase.GetAssetPath(_cachedDefaultPrefabs)); + string assetPathFull = Path.GetFullPath(assetPath); + if (foundPath != assetPathFull) + _cachedDefaultPrefabs = null; + } + + //If cached is null try to get it. + if (_cachedDefaultPrefabs == null) + { + //Only try to load it if file exist. + if (File.Exists(assetPath)) + { + _cachedDefaultPrefabs = AssetDatabase.LoadAssetAtPath(assetPath); + if (_cachedDefaultPrefabs == null) + { + //If already retried then throw an error. + if (_retryRefreshDefaultPrefabs) + { + UnityEngine.Debug.LogError("DefaultPrefabObjects file exists but it could not be loaded by Unity. Use the Fish-Networking menu to Refresh Default Prefabs."); + } + else + { + UnityEngine.Debug.Log("DefaultPrefabObjects file exists but it could not be loaded by Unity. Trying to reload the file next frame."); + _retryRefreshDefaultPrefabs = true; + } + return null; + } + } + } + + if (_cachedDefaultPrefabs == null) + { + UnityEngine.Debug.Log($"Creating a new DefaultPrefabsObject at {assetPath}."); + string directory = Path.GetDirectoryName(assetPath); + + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + AssetDatabase.Refresh(); + } + + _cachedDefaultPrefabs = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(_cachedDefaultPrefabs, assetPath); + AssetDatabase.SaveAssets(); + } + + if (_cachedDefaultPrefabs != null && _retryRefreshDefaultPrefabs) + UnityEngine.Debug.Log("DefaultPrefabObjects found on the second iteration."); + return _cachedDefaultPrefabs; + } + + /// + /// Called every frame the editor updates. + /// + private static void OnEditorUpdate() + { + if (!_retryRefreshDefaultPrefabs) + return; + + GenerateFull(); + _retryRefreshDefaultPrefabs = false; + } + + /// + /// Called by Unity when assets are modified. + /// + private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + //If retrying next frame don't bother updating, next frame will do a full refresh. + if (_retryRefreshDefaultPrefabs) + return; + //Post process is being ignored. Could be temporary or user has disabled this feature. + if (IgnorePostProcess) + return; + /* Don't iterate if updating or compiling as that could cause an infinite loop + * due to the prefabs being generated during an update, which causes the update + * to start over, which causes the generator to run again, which... you get the idea. */ + if (EditorApplication.isCompiling) + return; + + DefaultPrefabObjects prefabCollection = GetDefaultPrefabObjects(); + if (prefabCollection == null) + return; + Settings settings = Settings.Load(); + + if (prefabCollection.GetObjectCount() == 0) + { + //If there are no prefabs then do a full rebuild. Odds of there being none are pretty much nill. + GenerateFull(settings); + } + else + { + int totalChanges = importedAssets.Length + deletedAssets.Length + movedAssets.Length + movedFromAssetPaths.Length; + //Nothing has changed. This shouldn't occur but unity is funny so we're going to check anyway. + if (totalChanges == 0) + return; + + //normalizes path. + string dpoPath = Path.GetFullPath(settings.AssetPath); + //If total changes is 1 and the only changed file is the default prefab collection then do nothing. + if (totalChanges == 1) + { + //Do not need to check movedFromAssetPaths because that's not possible for this check. + if ((importedAssets.Length == 1 && Path.GetFullPath(importedAssets[0]) == dpoPath) + || (deletedAssets.Length == 1 && Path.GetFullPath(deletedAssets[0]) == dpoPath) + || (movedAssets.Length == 1 && Path.GetFullPath(movedAssets[0]) == dpoPath)) + return; + + /* If the only change is an import then check if the imported file + * is the same as the last, and if so check into returning early. + * For some reason occasionally when files are saved unity runs postprocess + * multiple times on the same file. */ + string imported = (importedAssets.Length == 1) ? importedAssets[0] : null; + if (imported != null && imported == _lastSingleImportedAsset) + { + //If here then the file is the same. Make sure it's already in the collection before returning. + System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(imported); + //Not a gameObject, no reason to continue. + if (assetType != typeof(GameObject)) + return; + + NetworkObject nob = AssetDatabase.LoadAssetAtPath(imported); + //If is a networked object. + if (nob != null) + { + //Already added! + if (prefabCollection.Prefabs.Contains(nob)) + return; + } + } + else if (imported != null) + { + _lastSingleImportedAsset = imported; + } + } + + + bool fullRebuild = settings.FullRebuild; + /* If updating FN. This needs to be done a better way. + * Parsing the actual version file would be better. + * I'll get to it next release. */ + if (!_ranOnce) + { + _ranOnce = true; + fullRebuild = true; + } + else + { + 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++) + { + 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; + } + } + } + + if (fullRebuild) + GenerateFull(settings); + else + GenerateChanged(importedAssets, deletedAssets, movedAssets, movedFromAssetPaths, settings); + } + } + } +} + +#endif diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs.meta new file mode 100644 index 0000000..20b7c5c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68e990388e202d54aa0fe9e7aa8cc716 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs new file mode 100644 index 0000000..9440e1c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs @@ -0,0 +1,103 @@ +#if UNITY_EDITOR + +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace FishNet.Editing.PrefabCollectionGenerator +{ + internal sealed class Settings + { + #region Types. + public enum SearchScopeType : byte + { + EntireProject = 0, + SpecificFolders = 1 + } + #endregion + + #region Public. + /// + /// True if prefab generation is enabled. + /// + public bool Enabled; + /// + /// True to rebuild all prefabs during any change. False to only check changed prefabs. + /// + public bool FullRebuild; + /// + /// True to log results to console. + /// + public bool LogToConsole; + /// + /// True to automatically save assets when default prefabs change. + /// + public bool SaveChanges; + /// + /// Path where prefabs file is created. + /// + public string AssetPath; + /// + /// How to search for files. + /// + public SearchScopeType SearchScope = SearchScopeType.EntireProject; + /// + /// Folders to exclude when using SearchScopeType.SpecificFolders. + /// + public List ExcludedFolders = new List(); + /// + /// Folders to include when using SearchScopeType.SpecificFolders. + /// + public List IncludedFolders = new List(); + #endregion + + #region Private. + /// + /// Library folder for project. Presumably where files are saved, but this is changing. This is going away in favor of FN config. //fnconfig. + /// + private static string DirectoryPath => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Library"); + /// + /// Full path of settings file. This is going away in favor of FN config. //fnconfig. + /// + private static string FilePath => Path.Combine(DirectoryPath, $"FishNet.Runtime.Editor.PrefabObjects.Generation.{nameof(Settings)}.json"); + #endregion + + public Settings() + { + Enabled = true; + LogToConsole = true; + FullRebuild = false; + SaveChanges = true; + SearchScope = SearchScopeType.EntireProject; + + AssetPath = $"Assets{Path.DirectorySeparatorChar}FishNet{Path.DirectorySeparatorChar}Runtime{Path.DirectorySeparatorChar}DefaultPrefabObjects.asset"; + } + + public void Save() + { + //Create save folder if it doesn't exist. This is going away in favor of FN config. //fnconfig. + if (!Directory.Exists(DirectoryPath)) + Directory.CreateDirectory(DirectoryPath); + + File.WriteAllText(FilePath, JsonUtility.ToJson(this)); + } + + public static Settings Load() + { + try + { + if (File.Exists(FilePath)) + return JsonUtility.FromJson(File.ReadAllText(FilePath)); + } + catch (Exception ex) + { + Debug.LogError($"An error has occurred when loading the prefab collection generator settings: {ex}"); + } + + return new Settings(); + } + } +} + +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs.meta new file mode 100644 index 0000000..ef397a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Settings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0fa5ae5e1c43e004c87577ab53180f70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs new file mode 100644 index 0000000..f52f6fe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs @@ -0,0 +1,230 @@ +#if UNITY_EDITOR + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +using UnitySettingsProviderAttribute = UnityEditor.SettingsProviderAttribute; +using UnitySettingsProvider = UnityEditor.SettingsProvider; + +namespace FishNet.Editing.PrefabCollectionGenerator +{ + internal static class SettingsProvider + { + private static readonly Regex SlashRegex = new Regex(@"[\\//]"); + + private static Settings _settings; + + private static GUIContent _folderIcon; + private static GUIContent _deleteIcon; + + private static Vector2 _scrollVector; + + private static bool _showFolders; + + [UnitySettingsProvider] + private static UnitySettingsProvider Create() + { + return new UnitySettingsProvider("Project/Fish-Networking/Prefab Objects Generator", SettingsScope.Project) + { + label = "Prefab Objects Generator", + + guiHandler = OnGUI, + + keywords = new string[] + { + "Fish", + "Networking", + "Prefab", + "Objects", + "Generator", + }, + }; + } + + private static void OnGUI(string searchContext) + { + if (_settings == null) + _settings = Settings.Load(); + if (_folderIcon == null) + _folderIcon = EditorGUIUtility.IconContent("d_FolderOpened Icon"); + if (_deleteIcon == null) + _deleteIcon = EditorGUIUtility.IconContent("P4_DeletedLocal"); + + EditorGUI.BeginChangeCheck(); + GUIStyle scrollViewStyle = new GUIStyle() + { + padding = new RectOffset(10, 10, 10, 10), + }; + + _scrollVector = EditorGUILayout.BeginScrollView(_scrollVector, scrollViewStyle); + + _settings.Enabled = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.Enabled)), _settings.Enabled); + _settings.LogToConsole = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.LogToConsole)), _settings.LogToConsole); + _settings.FullRebuild = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.FullRebuild)), _settings.FullRebuild); + _settings.SaveChanges = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.SaveChanges)), _settings.SaveChanges); + + GUILayoutOption iconWidthConstraint = GUILayout.MaxWidth(32.0f); + GUILayoutOption iconHeightConstraint = GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight); + + EditorGUILayout.BeginHorizontal(); + + string oldAssetPath = _settings.AssetPath; + string newAssetPath = EditorGUILayout.DelayedTextField(ObjectNames.NicifyVariableName(nameof(_settings.AssetPath)), oldAssetPath); + + if (GUILayout.Button(_folderIcon, iconWidthConstraint, iconHeightConstraint)) + { + if (TrySaveFilePathInsideAssetsFolder(null, Application.dataPath, "DefaultPrefabObjects", "asset", out string result)) + newAssetPath = result; + else + EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{ObjectNames.NicifyVariableName(nameof(_settings.AssetPath))} must be inside the Assets folder.")); + } + + if (!newAssetPath.Equals(oldAssetPath, StringComparison.OrdinalIgnoreCase)) + { + if (newAssetPath.StartsWith($"Assets{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase)) + { + if (File.Exists(newAssetPath)) + { + EditorWindow.focusedWindow.ShowNotification(new GUIContent("Another asset already exists at the new path.")); + } + else + { + Generator.IgnorePostProcess = true; + + if (File.Exists(oldAssetPath)) + AssetDatabase.MoveAsset(oldAssetPath, newAssetPath); + _settings.AssetPath = newAssetPath; + + Generator.IgnorePostProcess = false; + } + } + else + { + EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{ObjectNames.NicifyVariableName(nameof(_settings.AssetPath))} must be inside the Assets folder.")); + } + } + + EditorGUILayout.EndHorizontal(); + + _settings.SearchScope = (Settings.SearchScopeType)EditorGUILayout.EnumPopup(ObjectNames.NicifyVariableName(nameof(_settings.SearchScope)), _settings.SearchScope); + if (_settings.SearchScope == Settings.SearchScopeType.EntireProject) + { + EditorGUILayout.HelpBox("Searching the entire project for prefabs can become very slow. Consider switching the search scope to specific folders instead.", MessageType.Warning); + + if (GUILayout.Button("Switch")) + _settings.SearchScope = Settings.SearchScopeType.SpecificFolders; + } + + List folders = null; + string foldersName = null; + + if (_settings.SearchScope == Settings.SearchScopeType.EntireProject) + { + folders = _settings.ExcludedFolders; + foldersName = ObjectNames.NicifyVariableName(nameof(_settings.ExcludedFolders)); + } + else if (_settings.SearchScope == Settings.SearchScopeType.SpecificFolders) + { + folders = _settings.IncludedFolders; + foldersName = ObjectNames.NicifyVariableName(nameof(_settings.IncludedFolders)); + } + + string folderName = foldersName.Substring(0, foldersName.Length - 1); + + if ((_showFolders = EditorGUILayout.Foldout(_showFolders, $"{foldersName} ({folders.Count})")) && folders != null) + { + EditorGUI.indentLevel++; + + for (int i = 0; i < folders.Count; i++) + { + EditorGUILayout.BeginHorizontal(); + + string oldFolder = folders[i]; + string newFolder = SlashRegex.Replace(EditorGUILayout.DelayedTextField(oldFolder), Path.DirectorySeparatorChar.ToString()); + if (!newFolder.Equals(oldFolder, StringComparison.OrdinalIgnoreCase)) + { + if (newFolder.StartsWith($"Assets{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase)) + folders[i] = newFolder; + else + EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder.")); + } + + if (GUILayout.Button(_folderIcon, iconWidthConstraint, iconHeightConstraint)) + { + if (TryOpenFolderPathInsideAssetsFolder(null, Application.dataPath, null, out string result)) + folders[i] = result; + else + EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder.")); + } + + if (GUILayout.Button(_deleteIcon, iconWidthConstraint, iconHeightConstraint)) folders.RemoveAt(i); + + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel--; + + if (_settings.SearchScope == Settings.SearchScopeType.SpecificFolders) EditorGUILayout.HelpBox("You can include subfolders by appending an asterisk (*) to a path.", MessageType.None); + + if (GUILayout.Button("Browse")) + { + if (TryOpenFolderPathInsideAssetsFolder(null, Application.dataPath, null, out string result)) + { + folders.Add(result); + } + else + { + EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder.")); + } + } + } + + if (EditorGUI.EndChangeCheck()) + _settings.Save(); + if (GUILayout.Button("Generate")) + Generator.GenerateFull(); + + EditorGUILayout.HelpBox("Consider pressing 'Generate' after changing the settings.", MessageType.Info); + + EditorGUILayout.EndScrollView(); + } + + private static bool TrySaveFilePathInsideAssetsFolder(string title, string directory, string name, string extension, out string result) + { + result = null; + + string selectedPath = EditorUtility.SaveFilePanel(title, directory, name, extension); + + if (selectedPath.StartsWith(Application.dataPath, StringComparison.OrdinalIgnoreCase)) + { + result = SlashRegex.Replace(selectedPath.Remove(0, Path.GetDirectoryName(Application.dataPath).Length + 1), Path.DirectorySeparatorChar.ToString()); + + return true; + } + + return false; + } + + private static bool TryOpenFolderPathInsideAssetsFolder(string title, string folder, string name, out string result) + { + result = null; + + string selectedPath = EditorUtility.OpenFolderPanel(title, folder, name); + + if (selectedPath.StartsWith(Application.dataPath, StringComparison.OrdinalIgnoreCase)) + { + result = SlashRegex.Replace(selectedPath.Remove(0, Path.GetDirectoryName(Application.dataPath).Length + 1), Path.DirectorySeparatorChar.ToString()); + + return true; + } + + return false; + } + } +} + +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs.meta new file mode 100644 index 0000000..01a488e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/SettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7451fcc5eeb5b89468ab2ce22f678b26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs new file mode 100644 index 0000000..ea1fa69 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs @@ -0,0 +1,85 @@ +//#if UNITY_EDITOR +//using FishNet.Managing.Object; +//using FishNet.Object; +//using UnityEditor; +//using UnityEngine; + +//namespace FishNet.Editing +//{ +// internal class PrefabProcessor : AssetPostprocessor +// { +// #region Private. +// /// +// /// ScriptableObject to store default prefabs. +// /// +// private static DefaultPrefabObjects _defaultPrefabs; +// #endregion + +// /// +// /// Called after assets are created or imported. +// /// +// /// +// /// +// /// +// /// +//#if UNITY_2021_3_OR_NEWER +// private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) +//#else +// private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) +//#endif +// { + +//#if UNITY_2021_3_OR_NEWER +// if (didDomainReload) +// return; +//#endif +// bool justPopulated; +// if (_defaultPrefabs == null) +// _defaultPrefabs = DefaultPrefabsFinder.GetDefaultPrefabsFile(out justPopulated); +// else +// justPopulated = DefaultPrefabsFinder.PopulateDefaultPrefabs(); +// //Not found. +// if (_defaultPrefabs == null) +// return; + +// //True if null must be removed as well. +// bool removeNull = (deletedAssets.Length > 0 || movedAssets.Length > 0 || movedFromAssetPaths.Length > 0); +// if (removeNull) +// _defaultPrefabs.RemoveNull(); + +// /* Only need to add new prefabs if not justPopulated. +// * justPopulated would have already picked up the new prefabs. */ +// if (justPopulated) +// return; + +// System.Type goType = typeof(UnityEngine.GameObject); +// foreach (string item in importedAssets) +// { +// System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(item); +// if (assetType != goType) +// continue; + +// GameObject go = (GameObject)AssetDatabase.LoadAssetAtPath(item, typeof(GameObject)); +// //If is a gameobject. +// if (go != null) +// { + +// NetworkObject nob; +// //Not a network object. +// if (!go.TryGetComponent(out nob)) +// continue; + +// /* Check for duplicates because adding a component to a prefab will also call this function +// * which will result in this function calling multiple times for the same object. */ +// _defaultPrefabs.AddObject(nob, true); +// } +// } + +// EditorUtility.SetDirty(_defaultPrefabs); +// } + +// } + +//} + +//#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs.meta new file mode 100644 index 0000000..5c1d41e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/PrefabProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f78656ace4bbad94288ff6238a2b518c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs b/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs new file mode 100644 index 0000000..dfd25cf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs @@ -0,0 +1,50 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace FishNet +{ + internal static class ScriptingDefines + { + [InitializeOnLoadMethod] + public static void AddDefineSymbols() + { + string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + /* Convert current defines into a hashset. This is so we can + * determine if any of our defines were added. Only save playersettings + * when a define is added. */ + HashSet definesHs = new HashSet(); + string[] currentArr = currentDefines.Split(';'); + //Add current defines into hs. + foreach (string item in currentArr) + definesHs.Add(item); + + string proDefine = "FISHNET_PRO"; + string[] fishNetDefines = new string[] + { + "FISHNET", + + }; + bool modified = false; + //Now add FN defines. + foreach (string item in fishNetDefines) + modified |= definesHs.Add(item); + + /* Remove pro define if not on pro. This might look a little + * funny because the code below varies depending on if pro or not. */ + +#pragma warning disable CS0162 // Unreachable code detected + modified |= definesHs.Remove(proDefine); +#pragma warning restore CS0162 // Unreachable code detected + + if (modified) + { + Debug.Log("Added Fish-Networking defines to player settings."); + string changedDefines = string.Join(";", definesHs); + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, changedDefines); + } + } + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs.meta b/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs.meta new file mode 100644 index 0000000..4ebc6d2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 893e5074d486a0e4aaf7803436fef791 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Textures.meta similarity index 77% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures.meta rename to UnityProject/Assets/FishNet/Runtime/Editor/Textures.meta index 793f2f2..c8e8ef0 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures.meta +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Textures.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 23b5913b9b8b2e1419a41acde1b49883 +guid: 0c9efa228205fac47af86971242e97f9 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon.meta new file mode 100644 index 0000000..ed9af2f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc19ac8f58640dd4bb062b1024d23ecc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon/fishnet_light.png b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/Icon/fishnet_light.png new file mode 100644 index 0000000000000000000000000000000000000000..084c0e6e72afce3e99d539e25ee751517c2fad53 GIT binary patch literal 41016 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 literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Client_Background.png.meta similarity index 83% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png.meta rename to UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Client_Background.png.meta index 6253866..be69e05 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png.meta +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Client_Background.png.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 824ee62c0fc357b4081855e43253a948 +guid: 2d50394614f8feb4eb0567fb7618d84d TextureImporter: internalIDToNameTable: [] externalObjects: {} @@ -31,12 +31,12 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: 0 - aniso: -1 - mipBias: -100 + filterMode: 1 + aniso: 1 + mipBias: 0 wrapU: 1 wrapV: 1 - wrapW: -1 + wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 @@ -64,7 +64,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 @@ -76,7 +76,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 @@ -88,19 +88,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..80192f5c3b75d720fe814c5d2e1efc17c621a068 GIT binary patch literal 2891 zcmcIm4QvzV8Gg@LjYCBtguj&~9M_gDr04tb|1D0O#wl@%QwZ6BvaLDaontq#&$TbH z!${(lNrXQwYFU3m(nghNw``(_qG~DasMc*^o7!a4wlWpakd%fsj3sREIgZ;+ zfuTxRw(ooIp6~gd_wV~|_lCN43+CTG9{?8kYP|IT1{^}#bPN7>Z2rToc*&2|Y)t^% zTB!dB=gk>ZZnzpP(_GZZ?Qx)Z8SxP{Hh@y#PD$){72q`y};T3SK-)1N> z1JRn@RHeQkxy8SMtWx6&=`eG&#Ih{uaG6D?!@>nzcauEJa}4XkFU_)o#UWUnWcEYh za&b8*)O+vEE{2wy3TawQV3=ewX--L`c1c zAGyalZ(>4KToE-j-k_>2vzgj3%R=%NGfRGbb2uui$wY~+C_6#%ikjl4^sLbwN3+%j zjuSYSz}j#uu;^$yh4hP$B1nTz-zGy-dqmttDx+xT84u@qy zlx2&Jm29-cDK1*!txnn*pBr7tNy&aw-dN-zXhBg^ekn}pqpMfRR zpq3QlN@Wv9`u`Reb1m@+vF-ZOt#+1IWQ&A5hl``FL90XuB*{rzoYtU|54boRXPkm|c|dZe~AxnlVJce{^2*VDhg`RF&E7~S7z z{`QjZe0J~4=WRbJec`qKr6X?b&((Xo=hxjy`kp(u>Qr@m1g{HjqbtEAwx3%!77QdSGy{x4*xC z`q6*g2A`f9>3}zWI`~jqXXn+6XV0G9G`0;+zFwGa{MK-n^Q&jd^U~{$9#S1XaroTn zuMs`F!Su_^^N!Slv2lt>-3OQYF6O79G11*i_+eXjt5!_Y@$DTxUv(a;(Zu;OD&TV`PpCY)I zga>|gdEV#}Vs!CuR;AZm__#cMU~GJR+{`dt9jVmMi*DN$wjcbcJU{((Av{Gd+pD#< z{^RY5iHQp#Ywg}&Q{u^Ln;!ToNuT z{--)F4JpPc?wOHw2#ORy(T2xAdjC^j+60ZI z7>#boM57x`49@T?`_r$wA6yLwUo0*h-iOqf$z5K6cPZFjYlKg1hJj%; zA4IbbO_zZLl)TMAn((rgScGcct1ysH{>bF)t9yQEgdhuvMWehS8hr7u&Pf_R+=%_u zSAV5^aY^a{{*WH$Nt<8 literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/pogchamp.png.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png.meta similarity index 79% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/pogchamp.png.meta rename to UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png.meta index 41f17f3..7eb6afd 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/pogchamp.png.meta +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Indicator.png.meta @@ -1,9 +1,9 @@ fileFormatVersion: 2 -guid: 160d53f9f2b149c418d6d07e95438e53 +guid: 2b3dca501a9d8c8479dc71dd068aa8b8 TextureImporter: - fileIDToRecycleName: {} + internalIDToNameTable: [] externalObjects: {} - serializedVersion: 9 + serializedVersion: 11 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -31,12 +31,12 @@ TextureImporter: maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: -1 - aniso: -1 - mipBias: -100 + filterMode: 1 + aniso: 1 + mipBias: 0 wrapU: 1 wrapV: 1 - wrapW: -1 + wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 @@ -57,8 +57,9 @@ TextureImporter: maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 + applyGammaDecoding: 0 platformSettings: - - serializedVersion: 2 + - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 @@ -69,7 +70,8 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - serializedVersion: 2 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 @@ -80,19 +82,9 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: WebGL + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 @@ -102,17 +94,20 @@ TextureImporter: allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] - spriteID: 1a75587224e4a5f468c03dbd1af78d0b + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 vertices: [] indices: edges: [] weights: [] + secondaryTextures: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png new file mode 100644 index 0000000000000000000000000000000000000000..f4d8573a31783396f036b118ea9fd01a0a932a88 GIT binary patch literal 9320 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 IYS@SU7bo}6y#N3J literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png.meta b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png.meta new file mode 100644 index 0000000..54f3c33 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Editor/Textures/UI/Button_Dark_Server_Background.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: 1b187e63031bf7849b249c8212440c3b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef b/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef new file mode 100644 index 0000000..ea60e5c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef @@ -0,0 +1,17 @@ +{ + "name": "FishNet.Runtime", + "references": [ + "GUID:9e24947de15b9834991c9d8411ea37cf", + "GUID:84651a3751eca9349aac36a66bba901b", + "GUID:69448af7b92c7f342b298e06a37122aa" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef.meta b/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef.meta new file mode 100644 index 0000000..f153703 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/FishNet.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7c88a4a7926ee5145ad2dfa06f454c67 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated.meta b/UnityProject/Assets/FishNet/Runtime/Generated.meta new file mode 100644 index 0000000..396b552 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff7d76a12b1ab04449cefe1ba58b5cde +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component.meta new file mode 100644 index 0000000..9074fd6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 953b8f1e48e9769439f19dc81a0406dc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator.meta new file mode 100644 index 0000000..b910d85 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40310629b512873468cfaf757b6fd377 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor.meta new file mode 100644 index 0000000..a5402a7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5ab06c5b11d85d4688a573ad0fdefdd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs new file mode 100644 index 0000000..6ed84e9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs @@ -0,0 +1,184 @@ +#if UNITY_EDITOR +using FishNet.Editing; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Animations; +using UnityEngine; + +namespace FishNet.Component.Animating.Editing +{ + + [CustomEditor(typeof(NetworkAnimator), true)] + [CanEditMultipleObjects] + public class NetworkAnimatorEditor : Editor + { + private SerializedProperty _animator; + private SerializedProperty _synchronizeInterval; + private SerializedProperty _smoothFloats; + private SerializedProperty _clientAuthoritative; + private SerializedProperty _sendToOwner; + private RuntimeAnimatorController _lastRuntimeAnimatorController; + private AnimatorController _lastAnimatorController; + + protected virtual void OnEnable() + { + _animator = serializedObject.FindProperty("_animator"); + + _synchronizeInterval = serializedObject.FindProperty("_synchronizeInterval"); + _smoothFloats = serializedObject.FindProperty("_smoothFloats"); + + _clientAuthoritative = serializedObject.FindProperty("_clientAuthoritative"); + _sendToOwner = serializedObject.FindProperty("_sendToOwner"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + NetworkAnimator na = (NetworkAnimator)target; + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(na), typeof(NetworkAnimator), false); + GUI.enabled = true; + + +#pragma warning disable CS0162 // Unreachable code detected + EditorGUILayout.HelpBox(EditingConstants.PRO_ASSETS_LOCKED_TEXT, MessageType.Warning); +#pragma warning restore CS0162 // Unreachable code detected + + //Animator + EditorGUILayout.LabelField("Animator", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_animator, new GUIContent("Animator", "The animator component to synchronize.")); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Synchronization Processing. + EditorGUILayout.LabelField("Synchronization Processing", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_synchronizeInterval, new GUIContent("Synchronize Interval", "How often to synchronize this animator.")); + EditorGUILayout.PropertyField(_smoothFloats, new GUIContent("Smooth Floats", "True to smooth floats on spectators rather than snap to their values immediately. Commonly set to true for smooth blend tree animations.")); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Authority. + EditorGUILayout.LabelField("Authority", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_clientAuthoritative, new GUIContent("Client Authoritative", "True if using client authoritative movement.")); + if (_clientAuthoritative.boolValue == false) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_sendToOwner, new GUIContent("Synchronize To Owner", "True to synchronize server results back to owner. Typically used when you are sending inputs to the server and are relying on the server response to move the transform.")); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + DrawParameters(na); + + serializedObject.ApplyModifiedProperties(); + } + + + private void DrawParameters(NetworkAnimator na) + { + EditorGUILayout.LabelField("* Synchronized Parameters", EditorStyles.boldLabel); + + if (Application.isPlaying) + { + EditorGUILayout.HelpBox("This feature can only be configured while out of play mode.", MessageType.Info); + return; + } + if (na == null) + return; + Animator animator = na.Animator; + if (animator == null) + return; + + RuntimeAnimatorController runtimeController = (animator.runtimeAnimatorController is AnimatorOverrideController aoc) ? aoc.runtimeAnimatorController : animator.runtimeAnimatorController; + if (runtimeController == null) + { + na.IgnoredParameters.Clear(); + return; + } + + /* If runtime controller changed + * or editor controller is null + * then get new editor controller. */ + if (runtimeController != _lastRuntimeAnimatorController || _lastAnimatorController == null) + _lastAnimatorController = (AnimatorController)AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(runtimeController), typeof(AnimatorController)); + _lastRuntimeAnimatorController = runtimeController; + + Color defaultColor = GUI.backgroundColor; + float width = Screen.width; + float spacePerEntry = 125f; + //Buttons seem to be longer than spacePerEntry. Why, because who knows... + float extraSpaceJustBecause = 60; + float spacer = 20f; + width -= spacer; + int entriesPerWidth = Mathf.Max(1, Mathf.FloorToInt(width / (spacePerEntry + extraSpaceJustBecause))); + + List aps = new List(); + //Create a parameter detail for each parameter that can be synchronized. + int count = 0; + foreach (AnimatorControllerParameter item in _lastAnimatorController.parameters) + { + count++; + //Over 240 parameters; who would do this!? + if (count >= 240) + continue; + + aps.Add(item); + } + + int apsCount = aps.Count; + for (int i = 0; i < apsCount; i++) + { + using (GUILayout.HorizontalScope hs = new GUILayout.HorizontalScope()) + { + GUILayout.Space(spacer); + int z = 0; + while (z < entriesPerWidth && (z + i < apsCount)) + { + //If this z+i would exceed entries then break. + if (z + i >= apsCount) + break; + + AnimatorControllerParameter item = aps[i + z]; + string parameterName = item.name; + bool ignored = na.IgnoredParameters.Contains(parameterName); + + Color c = (ignored) ? Color.gray : Color.green; + GUI.backgroundColor = c; + if (GUILayout.Button(item.name, GUILayout.Width(spacePerEntry))) + { + if (Application.isPlaying) + { + Debug.Log("Synchronized parameters may not be changed while playing."); + } + else + { + if (ignored) + na.IgnoredParameters.Remove(parameterName); + else + na.IgnoredParameters.Add(parameterName); + } + } + + z++; + } + + i += (z - 1); + } + + GUI.backgroundColor = defaultColor; + } + } + + + + } + +} + + +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs.meta new file mode 100644 index 0000000..c72bdf3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65609e99a0823a347a2f615b0e6f736e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs new file mode 100644 index 0000000..87f97b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs @@ -0,0 +1,1332 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Utility; +using System; +using System.Collections.Generic; +using UnityEngine; + + +namespace FishNet.Component.Animating +{ + [AddComponentMenu("FishNet/Component/NetworkAnimator")] + public class NetworkAnimator : NetworkBehaviour + { + #region Types. + private struct StateChange + { + /// + /// True if a crossfade. + /// + public bool IsCrossfade; + /// + /// Hash to crossfade into. + /// + public int Hash; + /// + /// True if using FixedTime. + /// + public bool FixedTime; + /// + /// Duration of crossfade. + /// + public float DurationTime; + /// + /// Offset time of crossfade. + /// + public float OffsetTime; + /// + /// Normalized transition time of crossfade. + /// + public float NormalizedTransitionTime; + + public StateChange(int hash, bool fixedTime, float duration, float offset, float normalizedTransition) + { + IsCrossfade = true; + Hash = hash; + FixedTime = fixedTime; + DurationTime = duration; + OffsetTime = offset; + NormalizedTransitionTime = normalizedTransition; + } + } + /// + /// Animator updates received from clients when using Client Authoritative. + /// + private class ClientAuthoritativeUpdate + { + /// + /// + /// + public ClientAuthoritativeUpdate() + { + //Start buffers off at 8 bytes nad grow them as needed. + for (int i = 0; i < MAXIMUM_BUFFER_COUNT; i++) + _buffers.Add(new byte[MAXIMUM_DATA_SIZE]); + + _bufferLengths = new int[MAXIMUM_BUFFER_COUNT]; + } + + #region Public. + /// + /// True to force all animator data and ignore buffers. + /// + public bool ForceAll { get; private set; } + /// + /// Number of entries in Buffers. + /// + public int BufferCount = 0; + #endregion + + #region Private. + /// + /// Length of buffers. + /// + private int[] _bufferLengths; + /// + /// Buffers. + /// + private List _buffers = new List(); + #endregion + + #region Const. + /// + /// Maximum size data may be. + /// + private const int MAXIMUM_DATA_SIZE = 1000; + /// + /// Maximum number of allowed buffers. + /// + public const int MAXIMUM_BUFFER_COUNT = 2; + #endregion + + public void AddToBuffer(ref ArraySegment data) + { + int dataCount = data.Count; + /* Data will never get this large, it's quite impossible. + * Just ignore the data if it does, client is likely performing + * an attack. */ + if (dataCount > MAXIMUM_DATA_SIZE) + return; + + //If index exceeds buffer count. + if (BufferCount >= MAXIMUM_BUFFER_COUNT) + { + ForceAll = true; + return; + } + + /* If here, can write to buffer. */ + byte[] buffer = _buffers[BufferCount]; + + Buffer.BlockCopy(data.Array, data.Offset, buffer, 0, dataCount); + _bufferLengths[BufferCount] = dataCount; + BufferCount++; + } + + /// + /// Sets referenced data to buffer and it's length for index. + /// + /// + /// + /// + public void GetBuffer(int index, ref byte[] buffer, ref int length) + { + if (index > _buffers.Count) + { + Debug.LogWarning("Index exceeds Buffers count."); + return; + } + if (index > _bufferLengths.Length) + { + Debug.LogWarning("Index exceeds BufferLengths count."); + return; + } + + buffer = _buffers[index]; + length = _bufferLengths[index]; + } + /// + /// Resets buffers. + /// + public void Reset() + { + BufferCount = 0; + ForceAll = false; + } + + } + /// + /// Information on how to smooth to a float value. + /// + private struct SmoothedFloat + { + public SmoothedFloat(float rate, float target) + { + Rate = rate; + Target = target; + } + + public readonly float Rate; + public readonly float Target; + } + + /// + /// Details about a trigger update. + /// + private struct TriggerUpdate + { + public byte ParameterIndex; + public bool Setting; + + public TriggerUpdate(byte parameterIndex, bool setting) + { + ParameterIndex = parameterIndex; + Setting = setting; + } + } + /// + /// Details about an animator parameter. + /// + private class ParameterDetail + { + /// + /// Parameter information. + /// + public readonly AnimatorControllerParameter ControllerParameter = null; + /// + /// Index within the types collection for this parameters value. The exception is with triggers; if the parameter type is a trigger then a value of 1 is set, 0 is unset. + /// + public readonly byte TypeIndex = 0; + /// + /// Hash for the animator string. + /// + public readonly int Hash; + + public ParameterDetail(AnimatorControllerParameter controllerParameter, byte typeIndex) + { + ControllerParameter = controllerParameter; + TypeIndex = typeIndex; + Hash = controllerParameter.nameHash; + } + } + #endregion + + #region Public. + /// + /// Parameters which will not be synchronized. + /// Internal use only. + /// + [SerializeField, HideInInspector] + internal List IgnoredParameters = new List(); + #endregion + + #region Serialized. + /// + /// The animator component to synchronize. + /// + [Tooltip("The animator component to synchronize.")] + [SerializeField] + private Animator _animator; + /// + /// The animator component to synchronize. + /// + public Animator Animator { get { return _animator; } } + /// + /// True to smooth float value changes for spectators. + /// + [Tooltip("True to smooth float value changes for spectators.")] + [SerializeField] + private bool _smoothFloats = true; + /// + /// How often to synchronize this animator. + /// + [Tooltip("How often to synchronize this animator.")] + [Range(0.01f, 0.5f)] + [SerializeField] + private float _synchronizeInterval = 0.1f; + /// + /// + /// + [Tooltip("True if using client authoritative animations.")] + [SerializeField] + private bool _clientAuthoritative = true; + /// + /// True if using client authoritative animations. + /// + public bool ClientAuthoritative { get { return _clientAuthoritative; } } + /// + /// True to synchronize server results back to owner. Typically used when you are changing animations on the server and are relying on the server response to update the clients animations. + /// + [Tooltip("True to synchronize server results back to owner. Typically used when you are changing animations on the server and are relying on the server response to update the clients animations.")] + [SerializeField] + private bool _sendToOwner; + #endregion + + #region Private. + /// + /// All parameter values, excluding triggers. + /// + private List _parameterDetails = new List(); + /// + /// Last int values. + /// + private List _ints = new List(); + /// + /// Last float values. + /// + private List _floats = new List(); + /// + /// Last bool values. + /// + private List _bools = new List(); + /// + /// Last layer weights. + /// + private float[] _layerWeights; + /// + /// Last speed. + /// + private float _speed; + /// + /// Next time client may send parameter updates. + /// + private float _nextClientSendTime = -1f; + /// + /// Next time server may send parameter updates. + /// + private float _nextServerSendTime = -1f; + /// + /// Trigger values set by using SetTrigger and ResetTrigger. + /// + private List _triggerUpdates = new List(); + /// + /// Updates going to clients. + /// + private List _toClientsBuffer = new List(); + /// + /// Returns if the animator is exist and is active. + /// + private bool _isAnimatorEnabled + { + get + { + bool failedChecks = (_animator == null || !_animator.enabled || _animator.runtimeAnimatorController == null); + return !failedChecks; + } + } + /// + /// Float valeus to smooth towards. + /// + private Dictionary _smoothedFloats = new Dictionary(); + /// + /// Returns if floats can be smoothed for this client. + /// + private bool _canSmoothFloats + { + get + { + //Don't smooth on server only. + if (!base.IsClient) + return false; + //Smoothing is disabled. + if (!_smoothFloats) + return false; + //No reason to smooth for self. + if (base.IsOwner && ClientAuthoritative) + return false; + + //Fall through. + return true; + } + } + /// + /// Layers which need to have their state synchronized. Key is the layer, Value is the state change information. + /// + 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; + /// + /// Last Controller set. + /// + private RuntimeAnimatorController _lastController; + /// + /// PooledWriter for this animator. + /// + private PooledWriter _writer = new PooledWriter(); + /// + /// Holds client authoritative updates received to send to other clients. + /// + private ClientAuthoritativeUpdate _clientAuthoritativeUpdates; + /// + /// True to forceAll next timed send. + /// + private bool _forceAllOnTimed; + #endregion + + #region Const. + /// + /// How much time to fall behind when using smoothing. Only increase value if the smoothing is sometimes jittery. Recommended values are between 0 and 0.04. + /// + private const float INTERPOLATION = 0.02f; + /// + /// ParameterDetails index which indicates a layer weight change. + /// + private const byte LAYER_WEIGHT = 240; + /// + /// ParameterDetails index which indicates an animator speed change. + /// + private const byte SPEED = 241; + /// + /// ParameterDetails index which indicates a layer state change. + /// + private const byte STATE = 242; + /// + /// ParameterDetails index which indicates a crossfade change. + /// + private const byte CROSSFADE = 243; + #endregion + + private void Awake() + { + InitializeOnce(); + } + + [APIExclude] + public override void OnSpawnServer(NetworkConnection connection) + { + base.OnSpawnServer(connection); + if (!_isAnimatorEnabled) + return; + if (AnimatorUpdated(out ArraySegment updatedBytes, true)) + TargetAnimatorUpdated(connection, updatedBytes); + } + + [APIExclude] + public override void OnStartServer() + { + base.OnStartServer(); + //If using client authoritative then initialize clientAuthoritativeUpdates. + if (_clientAuthoritative) + { + _clientAuthoritativeUpdates = new ClientAuthoritativeUpdate(); + //Expand to clients buffer count to however many buffers can be held. + for (int i = 0; i < ClientAuthoritativeUpdate.MAXIMUM_BUFFER_COUNT; i++) + _toClientsBuffer.Add(new byte[0]); + } + else + { + _toClientsBuffer.Add(new byte[0]); + } + } + + private void Update() + { + //One check rather than per each method. + if (!_isAnimatorEnabled) + return; + + if (base.IsClient) + { + CheckSendToServer(); + SmoothFloats(); + } + if (base.IsServer) + { + CheckSendToClients(); + } + } + + + /// + /// Initializes this script for use. + /// + private void InitializeOnce() + { + if (_animator == null) + _animator = GetComponent(); + + //Don't run the rest if not in play mode. + if (!ApplicationState.IsPlaying()) + return; + + if (!_isAnimatorEnabled) + { + //Debug.LogWarning("Animator is null or not enabled; unable to initialize for animator. Use SetAnimator if animator was changed or enable the animator."); + return; + } + + //Speed. + _speed = _animator.speed; + + //Build layer weights. + _layerWeights = new float[_animator.layerCount]; + for (int i = 0; i < _layerWeights.Length; i++) + _layerWeights[i] = _animator.GetLayerWeight(i); + + _parameterDetails.Clear(); + _bools.Clear(); + _floats.Clear(); + _ints.Clear(); + //Create a parameter detail for each parameter that can be synchronized. + foreach (AnimatorControllerParameter item in _animator.parameters) + { + bool process = !_animator.IsParameterControlledByCurve(item.name); + + if (process) + { + //Over 250 parameters; who would do this!? + if (_parameterDetails.Count == 240) + { + Debug.LogError($"Parameter {item.name} exceeds the allowed 240 parameter count and is being ignored."); + continue; + } + + int typeIndex = 0; + //Bools. + if (item.type == AnimatorControllerParameterType.Bool) + { + typeIndex = _bools.Count; + _bools.Add(_animator.GetBool(item.nameHash)); + } + //Floats. + else if (item.type == AnimatorControllerParameterType.Float) + { + typeIndex = _floats.Count; + _floats.Add(_animator.GetFloat(item.name)); + } + //Ints. + else if (item.type == AnimatorControllerParameterType.Int) + { + typeIndex = _ints.Count; + _ints.Add(_animator.GetInteger(item.nameHash)); + } + //Triggers. + else if (item.type == AnimatorControllerParameterType.Trigger) + { + /* Triggers aren't persistent so they don't use stored values + * but I do need to make a parameter detail to track the hash. */ + typeIndex = -1; + } + + _parameterDetails.Add(new ParameterDetail(item, (byte)typeIndex)); + } + } + } + + /// + /// Sets which animator to use. You must call this with the appropriate animator on all clients and server. This change is not automatically synchronized. + /// + /// + public void SetAnimator(Animator animator) + { + //No update required. + if (animator == _lastAnimator) + return; + + _animator = animator; + InitializeOnce(); + _lastAnimator = animator; + } + + /// + /// Sets which controller to use. You must call this with the appropriate controller on all clients and server. This change is not automatically synchronized. + /// + /// + public void SetController(RuntimeAnimatorController controller) + { + //No update required. + if (controller == _lastController) + return; + + _animator.runtimeAnimatorController = controller; + InitializeOnce(); + _lastController = controller; + } + + /// + /// Checks to send animator data from server to clients. + /// + private void CheckSendToServer() + { + //Cannot send to server if is server or not client. + if (base.IsServer || !base.IsClient) + return; + //Cannot send to server if not client authoritative or don't have authority. + if (!ClientAuthoritative || !base.IsOwner) + return; + //Not enough time passed to send. + if (Time.time < _nextClientSendTime) + return; + _nextClientSendTime = Time.time + _synchronizeInterval; + + /* If there are updated parameters to send. + * Don't really need to worry about mtu here + * because there's no way the sent bytes are + * ever going to come close to the mtu + * when sending a single update. */ + if (AnimatorUpdated(out ArraySegment updatedBytes, _forceAllOnTimed)) + ServerAnimatorUpdated(updatedBytes); + + _forceAllOnTimed = false; + } + + /// + /// Checks to send animator data from server to clients. + /// + private void CheckSendToClients() + { + //Cannot send to clients if not server. + if (!base.IsServer) + return; + //Not enough time passed to send. + if (Time.time < _nextServerSendTime) + return; + _nextServerSendTime = Time.time + _synchronizeInterval; + + bool sendFromServer; + //If client authoritative. + if (ClientAuthoritative) + { + //If has no owner then use latest values on server. + if (!base.Owner.IsValid) + { + sendFromServer = true; + } + //If has a owner. + else + { + //If is owner then send latest values on server. + if (base.IsOwner) + { + sendFromServer = true; + } + //Not owner. + else + { + //Haven't received any data from clients, cannot send yet. + if (_clientAuthoritativeUpdates.BufferCount == 0) + { + return; + } + //Data was received from client; check eligibility to send it. + else + { + /* If forceAll is true then the latest values on + * server must be used, rather than what was received + * from client. This can occur if the client is possibly + * trying to use an attack or if the client is + * excessively sending updates. To prevent relaying that + * same data to others the server will send it's current + * animator settings in this scenario. */ + if (_clientAuthoritativeUpdates.ForceAll) + { + sendFromServer = true; + _clientAuthoritativeUpdates.Reset(); + } + else + { + sendFromServer = false; + } + } + } + } + } + //Not client authoritative, always send from server. + else + { + sendFromServer = true; + } + + /* If client authoritative then use what was received from clients + * if data exist. */ + if (!sendFromServer) + { + byte[] buffer = null; + int bufferLength = 0; + for (int i = 0; i < _clientAuthoritativeUpdates.BufferCount; i++) + { + _clientAuthoritativeUpdates.GetBuffer(i, ref buffer, ref bufferLength); + + //If null was returned then something went wrong. + if (buffer == null || bufferLength == 0) + continue; + + ObserversAnimatorUpdated(new ArraySegment(buffer, 0, bufferLength)); + } + //Reset client auth buffer. + _clientAuthoritativeUpdates.Reset(); + } + //Sending from server, send what's changed. + else + { + if (AnimatorUpdated(out ArraySegment updatedBytes, _forceAllOnTimed)) + ObserversAnimatorUpdated(updatedBytes); + + _forceAllOnTimed = false; + } + } + + + /// + /// Smooths floats on clients. + /// + private void SmoothFloats() + { + //Don't need to smooth on authoritative client. + if (!_canSmoothFloats) + return; + //Nothing to smooth. + if (_smoothedFloats.Count == 0) + return; + + float deltaTime = Time.deltaTime; + + List finishedEntries = new List(); + + /* Cycle through each target float and move towards it. + * Once at a target float mark it to be removed from floatTargets. */ + foreach (KeyValuePair item in _smoothedFloats) + { + float current = _animator.GetFloat(item.Key); + float next = Mathf.MoveTowards(current, item.Value.Target, item.Value.Rate * deltaTime); + _animator.SetFloat(item.Key, next); + + if (next == item.Value.Target) + finishedEntries.Add(item.Key); + } + + //Remove finished entries from dictionary. + for (int i = 0; i < finishedEntries.Count; i++) + _smoothedFloats.Remove(finishedEntries[i]); + } + + /// + /// Returns if animator is updated and bytes of updated values. + /// + /// + private bool AnimatorUpdated(out ArraySegment updatedBytes, bool forceAll = false) + { + updatedBytes = default; + //Something isn't setup right. + if (_layerWeights == null) + return false; + //Reset the writer. + _writer.Reset(); + + /* Every time a parameter is updated a byte is added + * for it's index, this is why requiredBytes increases + * by 1 when a value updates. ChangedParameter contains + * the index updated and the new value. The requiresBytes + * is increased also by however many bytes are required + * for the type which has changed. Some types use special parameter + * detail indexes, such as layer weights; these can be found under const. */ + for (byte parameterIndex = 0; parameterIndex < _parameterDetails.Count; parameterIndex++) + { + ParameterDetail pd = _parameterDetails[parameterIndex]; + /* Bool. */ + if (pd.ControllerParameter.type == AnimatorControllerParameterType.Bool) + { + bool next = _animator.GetBool(pd.Hash); + //If changed. + if (forceAll || _bools[pd.TypeIndex] != next) + { + _writer.WriteByte(parameterIndex); + _writer.WriteBoolean(next); + _bools[pd.TypeIndex] = next; + } + } + /* Float. */ + else if (pd.ControllerParameter.type == AnimatorControllerParameterType.Float) + { + float next = _animator.GetFloat(pd.Hash); + //If changed. + if (forceAll || _floats[pd.TypeIndex] != next) + { + _writer.WriteByte(parameterIndex); + _writer.WriteSingle(next, AutoPackType.Packed); + _floats[pd.TypeIndex] = next; + } + } + /* Int. */ + else if (pd.ControllerParameter.type == AnimatorControllerParameterType.Int) + { + int next = _animator.GetInteger(pd.Hash); + //If changed. + if (forceAll || _ints[pd.TypeIndex] != next) + { + _writer.WriteByte(parameterIndex); + _writer.WriteInt32(next, AutoPackType.Packed); + _ints[pd.TypeIndex] = next; + } + } + } + + /* Don't need to force trigger sends since + * they're one-shots. */ + for (int i = 0; i < _triggerUpdates.Count; i++) + { + _writer.WriteByte(_triggerUpdates[i].ParameterIndex); + _writer.WriteBoolean(_triggerUpdates[i].Setting); + } + _triggerUpdates.Clear(); + + /* States. */ + if (forceAll) + { + //Add all layers to layer states. + for (int i = 0; i < _animator.layerCount; i++) + _unsynchronizedLayerStates[i] = new StateChange(); + } + + //Go through each layer which needs to be synchronized. + foreach (KeyValuePair item in _unsynchronizedLayerStates) + { + int layerIndex = item.Key; + StateChange sc = item.Value; + //If a regular state change. + if (!sc.IsCrossfade) + { + if (ReturnCurrentLayerState(out int stateHash, out float normalizedTime, layerIndex)) + { + _writer.WriteByte(STATE); + _writer.WriteByte((byte)layerIndex); + //Current hash will always be too large to compress. + _writer.WriteInt32(stateHash); + _writer.WriteSingle(normalizedTime, AutoPackType.Packed); + } + } + //When it's a crossfade then send crossfade data. + else + { + _writer.WriteByte(CROSSFADE); + _writer.WriteByte((byte)layerIndex); + //Current hash will always be too large to compress. + _writer.WriteInt32(sc.Hash); + _writer.WriteBoolean(sc.FixedTime); + //Times usually can be compressed. + _writer.WriteSingle(sc.DurationTime, AutoPackType.Packed); + _writer.WriteSingle(sc.OffsetTime, AutoPackType.Packed); + _writer.WriteSingle(sc.NormalizedTransitionTime, AutoPackType.Packed); + } + } + _unsynchronizedLayerStates.Clear(); + + /* Layer weights. */ + for (int layerIndex = 0; layerIndex < _layerWeights.Length; layerIndex++) + { + float next = _animator.GetLayerWeight(layerIndex); + if (forceAll || _layerWeights[layerIndex] != next) + { + _writer.WriteByte(LAYER_WEIGHT); + _writer.WriteByte((byte)layerIndex); + _writer.WriteSingle(next, AutoPackType.Packed); + _layerWeights[layerIndex] = next; + } + } + + /* Speed is similar to layer weights but we don't need the index, + * only the indicator and value. */ + float speedNext = _animator.speed; + if (forceAll || _speed != speedNext) + { + _writer.WriteByte(SPEED); + _writer.WriteSingle(speedNext, AutoPackType.Packed); + _speed = speedNext; + } + + //Nothing to update. + if (_writer.Position == 0) + { + return false; + } + else + { + updatedBytes = _writer.GetArraySegment(); + return true; + } + } + + /// + /// Applies changed parameters to the animator. + /// + /// + private void ApplyParametersUpdated(ref ArraySegment updatedParameters) + { + if (!_isAnimatorEnabled) + return; + if (_layerWeights == null) + return; + if (updatedParameters.Count == 0) + return; + //Exit if client authoritative and has authority. + if (ClientAuthoritative && base.IsOwner) + return; + //Exit if not client authoritative, but also not sync to owner, and is owner. + if (!ClientAuthoritative && !_sendToOwner && base.IsOwner) + return; + //Exit if trying to apply when server and not client authoritative. + if (base.IsServer && !ClientAuthoritative) + return; + + try + { + using (PooledReader reader = ReaderPool.GetReader(updatedParameters, base.NetworkManager)) + { + while (reader.Remaining > 0) + { + byte parameterIndex = reader.ReadByte(); + //Layer weight + if (parameterIndex == LAYER_WEIGHT) + { + byte layerIndex = reader.ReadByte(); + float value = reader.ReadSingle(AutoPackType.Packed); + _animator.SetLayerWeight((int)layerIndex, value); + } + //Speed. + else if (parameterIndex == SPEED) + { + float value = reader.ReadSingle(AutoPackType.Packed); + _animator.speed = value; + } + //State. + else if (parameterIndex == STATE) + { + byte layerIndex = reader.ReadByte(); + //Hashes will always be too large to compress. + int hash = reader.ReadInt32(); + float normalizedTime = reader.ReadSingle(AutoPackType.Packed); + //Play results. + _animator.Play(hash, layerIndex, normalizedTime); + } + //Crossfade. + else if (parameterIndex == CROSSFADE) + { + byte layerIndex = reader.ReadByte(); + //Hashes will always be too large to compress. + int hash = reader.ReadInt32(); + bool useFixedTime = reader.ReadBoolean(); + //Get time values. + float durationTime = reader.ReadSingle(AutoPackType.Packed); + float offsetTime = reader.ReadSingle(AutoPackType.Packed); + float normalizedTransitionTime = reader.ReadSingle(AutoPackType.Packed); + //If using fixed. + if (useFixedTime) + _animator.CrossFadeInFixedTime(hash, durationTime, layerIndex, offsetTime, normalizedTransitionTime); + else + _animator.CrossFade(hash, durationTime, layerIndex, offsetTime, normalizedTransitionTime); + } + //Not a predetermined index, is an actual parameter. + else + { + AnimatorControllerParameterType acpt = _parameterDetails[parameterIndex].ControllerParameter.type; + if (acpt == AnimatorControllerParameterType.Bool) + { + bool value = reader.ReadBoolean(); + _animator.SetBool(_parameterDetails[parameterIndex].Hash, value); + } + //Float. + else if (acpt == AnimatorControllerParameterType.Float) + { + float value = reader.ReadSingle(AutoPackType.Packed); + //If able to smooth floats. + if (_canSmoothFloats) + { + float currentValue = _animator.GetFloat(_parameterDetails[parameterIndex].Hash); + float past = _synchronizeInterval + INTERPOLATION; + float rate = Mathf.Abs(currentValue - value) / past; + _smoothedFloats[_parameterDetails[parameterIndex].Hash] = new SmoothedFloat(rate, value); + } + else + { + _animator.SetFloat(_parameterDetails[parameterIndex].Hash, value); + } + } + //Integer. + else if (acpt == AnimatorControllerParameterType.Int) + { + int value = reader.ReadInt32(); + _animator.SetInteger(_parameterDetails[parameterIndex].Hash, value); + } + //Trigger. + else if (acpt == AnimatorControllerParameterType.Trigger) + { + bool value = reader.ReadBoolean(); + if (value) + _animator.SetTrigger(_parameterDetails[parameterIndex].Hash); + else + _animator.ResetTrigger(_parameterDetails[parameterIndex].Hash); + } + //Unhandled. + else + { + Debug.LogWarning($"Unhandled parameter type of {acpt}."); + } + } + } + } + } + catch + { + Debug.LogWarning("An error occurred while applying updates. This may occur when malformed data is sent or when you change the animator or controller but not on all connections."); + } + } + + /// + /// Outputs the current state and time for a layer. Returns true if stateHash is not 0. + /// + /// + /// + /// + /// + /// + private bool ReturnCurrentLayerState(out int stateHash, out float normalizedTime, int layerIndex) + { + stateHash = 0; + normalizedTime = 0f; + + if (!_isAnimatorEnabled) + return false; + + AnimatorStateInfo st = _animator.GetCurrentAnimatorStateInfo(layerIndex); + stateHash = st.fullPathHash; + normalizedTime = st.normalizedTime; + + return (stateHash != 0); + } + + /// + /// Forces values to send next update regardless of time remaining. + /// Can be useful if you have a short lasting parameter that you want to ensure goes through. + /// + public void ForceSend() + { + _nextClientSendTime = 0f; + _nextServerSendTime = 0f; + } + + /// + /// Immediately sends all variables and states of layers. + /// This is a very bandwidth intensive operation. + /// + public void SendAll() + { + _forceAllOnTimed = true; + ForceSend(); + } + + #region Play. + /// + /// Plays a state. + /// + public void Play(string name) + { + Play(Animator.StringToHash(name)); + } + /// + /// Plays a state. + /// + public void Play(int hash) + { + for (int i = 0; i < _animator.layerCount; i++) + Play(hash, i, 0f); + } + /// + /// Plays a state. + /// + public void Play(string name, int layer) + { + Play(Animator.StringToHash(name), layer); + } + /// + /// Plays a state. + /// + public void Play(int hash, int layer) + { + Play(hash, layer, 0f); + } + /// + /// Plays a state. + /// + public void Play(string name, int layer, float normalizedTime) + { + Play(Animator.StringToHash(name), layer, normalizedTime); + } + /// + /// Plays a state. + /// + public void Play(int hash, int layer, float normalizedTime) + { + if (!_isAnimatorEnabled) + return; + if (_animator.HasState(layer, hash)) + { + _animator.Play(hash, layer, normalizedTime); + _unsynchronizedLayerStates[layer] = new StateChange(); + } + } + /// + /// Plays a state. + /// + public void PlayInFixedTime(string name, float fixedTime) + { + PlayInFixedTime(Animator.StringToHash(name), fixedTime); + } + /// + /// Plays a state. + /// + public void PlayInFixedTime(int hash, float fixedTime) + { + for (int i = 0; i < _animator.layerCount; i++) + PlayInFixedTime(hash, i, fixedTime); + } + /// + /// Plays a state. + /// + public void PlayInFixedTime(string name, int layer, float fixedTime) + { + PlayInFixedTime(Animator.StringToHash(name), layer, fixedTime); + } + /// + /// Plays a state. + /// + public void PlayInFixedTime(int hash, int layer, float fixedTime) + { + if (!_isAnimatorEnabled) + return; + if (_animator.HasState(layer, hash)) + { + _animator.PlayInFixedTime(hash, layer, fixedTime); + _unsynchronizedLayerStates[layer] = new StateChange(); + } + } + #endregion + + #region Crossfade. + /// + /// Creates a crossfade from the current state to any other state using normalized times. + /// + /// + /// + /// + /// + /// + public void CrossFade(string stateName, float normalizedTransitionDuration, int layer, float normalizedTimeOffset = float.NegativeInfinity, float normalizedTransitionTime = 0.0f) + { + CrossFade(Animator.StringToHash(stateName), normalizedTransitionDuration, layer, normalizedTimeOffset, normalizedTransitionTime); + } + /// + /// Creates a crossfade from the current state to any other state using normalized times. + /// + /// + /// + /// + /// + /// + public void CrossFade(int hash, float normalizedTransitionDuration, int layer, float normalizedTimeOffset = 0.0f, float normalizedTransitionTime = 0.0f) + { + if (!_isAnimatorEnabled) + return; + if (_animator.HasState(layer, hash)) + { + _animator.CrossFade(hash, normalizedTransitionDuration, layer, normalizedTimeOffset, normalizedTransitionTime); + _unsynchronizedLayerStates[layer] = new StateChange(hash, false, normalizedTransitionDuration, normalizedTimeOffset, normalizedTransitionTime); + } + } + /// + /// Creates a crossfade from the current state to any other state using times in seconds. + /// + /// + /// + /// + /// + /// + public void CrossFadeInFixedTime(string stateName, float fixedTransitionDuration, int layer, float fixedTimeOffset = 0.0f, float normalizedTransitionTime = 0.0f) + { + CrossFadeInFixedTime(Animator.StringToHash(stateName), fixedTransitionDuration, layer, fixedTimeOffset, normalizedTransitionTime); + } + /// + /// Creates a crossfade from the current state to any other state using times in seconds. + /// + /// + /// + /// + /// + /// + public void CrossFadeInFixedTime(int hash, float fixedTransitionDuration, int layer, float fixedTimeOffset = 0.0f, float normalizedTransitionTime = 0.0f) + { + if (!_isAnimatorEnabled) + return; + if (_animator.HasState(layer, hash)) + { + _animator.CrossFadeInFixedTime(hash, fixedTransitionDuration, layer, fixedTimeOffset, normalizedTransitionTime); + _unsynchronizedLayerStates[layer] = new StateChange(hash, true, fixedTransitionDuration, fixedTimeOffset, normalizedTransitionTime); + } + } + #endregion + + #region Triggers. + /// + /// Sets a trigger on the animator and sends it over the network. + /// + /// + public void SetTrigger(int hash) + { + if (!_isAnimatorEnabled) + return; + UpdateTrigger(hash, true); + } + /// + /// Sets a trigger on the animator and sends it over the network. + /// + /// + public void SetTrigger(string name) + { + SetTrigger(Animator.StringToHash(name)); + } + + /// + /// Resets a trigger on the animator and sends it over the network. + /// + /// + public void ResetTrigger(int hash) + { + UpdateTrigger(hash, false); + } + /// + /// Resets a trigger on the animator and sends it over the network. + /// + /// + public void ResetTrigger(string name) + { + ResetTrigger(Animator.StringToHash(name)); + } + + /// + /// Updates a trigger, sets or resets. + /// + /// + private void UpdateTrigger(int hash, bool set) + { + if (!_isAnimatorEnabled) + return; + /* Allow triggers to run on owning client if using client authority, + * as well when not using client authority but also not using synchronize to owner. + * This allows clients to run animations locally while maintaining server authority. */ + //Using client authority but not owner. + if (ClientAuthoritative && !base.IsOwner) + return; + + //Also block if not using client authority, synchronizing to owner, and not server. + if (!ClientAuthoritative && _sendToOwner && !base.IsServer) + return; + + //Update locally. + if (set) + _animator.SetTrigger(hash); + else + _animator.ResetTrigger(hash); + + /* Can send if not client auth but is server, + * or if client auth and owner. */ + bool canSend = (!ClientAuthoritative && base.IsServer) || + (ClientAuthoritative && base.IsOwner); + //Only queue a send if proper side. + if (canSend) + { + for (byte i = 0; i < _parameterDetails.Count; i++) + { + if (_parameterDetails[i].Hash == hash) + { + _triggerUpdates.Add(new TriggerUpdate(i, set)); + return; + } + } + //Fall through, hash not found. + Debug.LogWarning($"Hash {hash} not found while trying to update a trigger."); + } + } + #endregion + + #region Remote actions. + /// + /// Called on clients to receive an animator update. + /// + /// + [ObserversRpc] + private void ObserversAnimatorUpdated(ArraySegment data) + { + ServerDataReceived(ref data); + } + /// + /// Called on clients to receive an animator update. + /// + /// + [TargetRpc] + private void TargetAnimatorUpdated(NetworkConnection connection, ArraySegment data) + { + ServerDataReceived(ref data); + } + /// + /// Called on server to receive an animator update. + /// + /// + [ServerRpc] + private void ServerAnimatorUpdated(ArraySegment data) + { + if (!_isAnimatorEnabled) + return; + if (!ClientAuthoritative) + return; + + ApplyParametersUpdated(ref data); + _clientAuthoritativeUpdates.AddToBuffer(ref data); + } + /// + /// Called on clients to receive an animator update. + /// + /// + private void ServerDataReceived(ref ArraySegment data) + { + if (!_isAnimatorEnabled) + return; + //If also server, client host, then do nothing. Animations already ran on server. + if (base.IsServer) + return; + + //If has authority. + if (base.IsOwner) + { + //No need to sync to self if client authoritative. + if (ClientAuthoritative) + return; + //Not client authoritative, but also don't sync to owner. + else if (!ClientAuthoritative && !_sendToOwner) + return; + } + + ApplyParametersUpdated(ref data); + } + #endregion + + #region Editor. +#if UNITY_EDITOR + protected override void Reset() + { + base.Reset(); + if (_animator == null) + SetAnimator(GetComponent()); + } +#endif + #endregion + + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs.meta new file mode 100644 index 0000000..0d7e115 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e8cac635f24954048aad3a6ff9110beb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform.meta new file mode 100644 index 0000000..c0513ca --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 63eb855bc9013d54d9ea73088d204790 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor.meta new file mode 100644 index 0000000..de2183e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c1769e2b4cabd744a4b875f6849ef76 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs new file mode 100644 index 0000000..2e701b1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs @@ -0,0 +1,135 @@ +#if UNITY_EDITOR +using FishNet.Editing; +using UnityEditor; +using UnityEngine; + +namespace FishNet.Component.Transforming.Editing +{ + + + [CustomEditor(typeof(NetworkTransform), true)] + [CanEditMultipleObjects] + public class NetworkTransformEditor : Editor + { + private SerializedProperty _packing; + private SerializedProperty _synchronizeParent; + private SerializedProperty _interpolation; + private SerializedProperty _extrapolation; + private SerializedProperty _enableTeleport; + private SerializedProperty _teleportThreshold; + private SerializedProperty _clientAuthoritative; + private SerializedProperty _sendToOwner; + private SerializedProperty _interval; + private SerializedProperty _synchronizePosition; + private SerializedProperty _positionSnapping; + private SerializedProperty _synchronizeRotation; + private SerializedProperty _rotationSnapping; + private SerializedProperty _synchronizeScale; + private SerializedProperty _scaleSnapping; + + + protected virtual void OnEnable() + { + _packing = serializedObject.FindProperty("_packing"); + _synchronizeParent = serializedObject.FindProperty("_synchronizeParent"); + _interpolation = serializedObject.FindProperty("_interpolation"); + _extrapolation = serializedObject.FindProperty("_extrapolation"); + _enableTeleport = serializedObject.FindProperty("_enableTeleport"); + _teleportThreshold = serializedObject.FindProperty("_teleportThreshold"); + _clientAuthoritative = serializedObject.FindProperty("_clientAuthoritative"); + _sendToOwner = serializedObject.FindProperty("_sendToOwner"); + _interval = serializedObject.FindProperty("_interval"); + _synchronizePosition = serializedObject.FindProperty("_synchronizePosition"); + _positionSnapping = serializedObject.FindProperty("_positionSnapping"); + _synchronizeRotation = serializedObject.FindProperty("_synchronizeRotation"); + _rotationSnapping = serializedObject.FindProperty("_rotationSnapping"); + _synchronizeScale = serializedObject.FindProperty("_synchronizeScale"); + _scaleSnapping = serializedObject.FindProperty("_scaleSnapping"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((NetworkTransform)target), typeof(NetworkTransform), false); + GUI.enabled = true; + + +#pragma warning disable CS0162 // Unreachable code detected + EditorGUILayout.HelpBox(EditingConstants.PRO_ASSETS_LOCKED_TEXT, MessageType.Warning); +#pragma warning restore CS0162 // Unreachable code detected + + //Misc. + EditorGUILayout.LabelField("Misc", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_synchronizeParent, new GUIContent("* Synchronize Parent")); + EditorGUILayout.PropertyField(_packing); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Smoothing. + EditorGUILayout.LabelField("Smoothing", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_interpolation); + EditorGUILayout.PropertyField(_extrapolation, new GUIContent("* Extrapolation")); + EditorGUILayout.PropertyField(_enableTeleport); + if (_enableTeleport.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_teleportThreshold); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Authority. + EditorGUILayout.LabelField("Authority", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_clientAuthoritative); + if (!_clientAuthoritative.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_sendToOwner); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Synchronizing. + EditorGUILayout.LabelField("Synchronizing.", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + //Interval. + EditorGUILayout.PropertyField(_interval, new GUIContent("Interval (experimental)", "How often in ticks to synchronize. A value of 1 will synchronize every tick, a value of 10 will synchronize every 10 ticks.")); + //Position. + EditorGUILayout.PropertyField(_synchronizePosition); + if (_synchronizePosition.boolValue) + { + EditorGUI.indentLevel += 2; + EditorGUILayout.PropertyField(_positionSnapping); + EditorGUI.indentLevel -= 2; + } + //Rotation. + EditorGUILayout.PropertyField(_synchronizeRotation); + if (_synchronizeRotation.boolValue) + { + EditorGUI.indentLevel += 2; + EditorGUILayout.PropertyField(_rotationSnapping); + EditorGUI.indentLevel -= 2; + } + //Scale. + EditorGUILayout.PropertyField(_synchronizeScale); + if (_synchronizeScale.boolValue) + { + EditorGUI.indentLevel += 2; + EditorGUILayout.PropertyField(_scaleSnapping); + EditorGUI.indentLevel -= 2; + } + EditorGUI.indentLevel--; + + serializedObject.ApplyModifiedProperties(); + } + } + +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs.meta new file mode 100644 index 0000000..7c5a2ca --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/Editor/NetworkTransformEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ed56c899b8ecf241a2bc3e40a2dabc1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs new file mode 100644 index 0000000..508ff26 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs @@ -0,0 +1,1743 @@ +/* If nested then the nested NB should be sent every tick. + * This is because if that tick happens to drop then the + * sent data is now wrong given the parent information is wrong. + * Once EC is added in we won't have to send every time since + * it will eventually correct itself. */ + + +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Transforming +{ + /// + /// A somewhat basic but reliable NetworkTransform that will be improved upon greatly after release. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Component/NetworkTransform")] + public class NetworkTransform : NetworkBehaviour + { + #region Types. + private struct ReceivedData + { + public bool HasData; + public PooledWriter Writer; + public Channel Channel; + } + [System.Serializable] + public struct SnappedAxes + { + public bool X; + public bool Y; + public bool Z; + } + private enum ChangedDelta + { + Unset = 0, + PositionX = 1, + PositionY = 2, + PositionZ = 4, + Rotation = 8, + Extended = 16, + ScaleX = 32, + ScaleY = 64, + ScaleZ = 128, + Nested = 256 + } + private enum ChangedFull + { + Unset = 0, + Position = 1, + Rotation = 2, + Scale = 4, + Nested = 8 + } + + private enum UpdateFlagA : byte + { + Unset = 0, + X2 = 1, + X4 = 2, + Y2 = 4, + Y4 = 8, + Z2 = 16, + Z4 = 32, + Rotation = 64, + Extended = 128 + } + private enum UpdateFlagB : byte + { + Unset = 0, + X2 = 1, + X4 = 2, + Y2 = 4, + Y4 = 8, + Z2 = 16, + Z4 = 32, + Nested = 64 + } + public class GoalData + { + public uint ReceivedTick; + public RateData Rates = new RateData(); + public TransformData Transforms = new TransformData(); + + public GoalData() { } + public void Reset() + { + ReceivedTick = 0; + Transforms.Reset(); + Rates.Reset(); + } + } + public class RateData + { + /// + /// Rate for position after smart calculations. + /// + public float Position; + /// + /// Rate for rotation after smart calculations. + /// + public float Rotation; + /// + /// Rate for scale after smart calculations. + /// + public float Scale; + /// + /// Unaltered rate for position calculated through position change and tickspan. + /// + public float LastUnalteredPositionRate; + /// + /// Number of ticks the rates are calculated for. + /// If TickSpan is 2 then the rates are calculated under the assumption the transform changed over 2 ticks. + /// + public uint TickSpan; + /// + /// True if the rate is believed to be fluctuating unusually. + /// + internal bool AbnormalRateDetected; + /// + /// Time remaining until transform is expected to reach it's goal. + /// + internal float TimeRemaining; + + public RateData() { } + + public void Reset() + { + Position = 0f; + Rotation = 0f; + Scale = 0f; + LastUnalteredPositionRate = 0f; + TickSpan = 0; + AbnormalRateDetected = false; + TimeRemaining = 0f; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Update(RateData rd) + { + Update(rd.Position, rd.Rotation, rd.Scale, rd.LastUnalteredPositionRate, rd.TickSpan, rd.AbnormalRateDetected, rd.TimeRemaining); + } + + /// + /// Updates rates. + /// + public void Update(float position, float rotation, float scale, float unalteredPositionRate, uint tickSpan, bool abnormalRateDetected, float timeRemaining) + { + Position = position; + Rotation = rotation; + Scale = scale; + LastUnalteredPositionRate = unalteredPositionRate; + TickSpan = tickSpan; + AbnormalRateDetected = abnormalRateDetected; + TimeRemaining = timeRemaining; + } + } + + public class TransformData + { + public enum ExtrapolateState : byte + { + Disabled = 0, + Available = 1, + Active = 2 + } + public uint Tick; + public bool Snapped; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Scale; + public Vector3 ExtrapolatedPosition; + public ExtrapolateState ExtrapolationState; + public NetworkBehaviour ParentBehaviour; + public TransformData() { } + + internal void Reset() + { + Tick = 0; + Snapped = false; + Position = Vector3.zero; + Rotation = Quaternion.identity; + Scale = Vector3.zero; + ExtrapolatedPosition = Vector3.zero; + ExtrapolationState = ExtrapolateState.Disabled; + ParentBehaviour = null; + } + internal void Update(TransformData copy) + { + Update(copy.Tick, copy.Position, copy.Rotation, copy.Scale, copy.ExtrapolatedPosition, copy.ParentBehaviour); + } + internal void Update(uint tick, Vector3 position, Quaternion rotation, Vector3 scale, Vector3 extrapolatedPosition, NetworkBehaviour parentBehaviour) + { + Tick = tick; + Position = position; + Rotation = rotation; + Scale = scale; + ExtrapolatedPosition = extrapolatedPosition; + ParentBehaviour = parentBehaviour; + } + } + + #endregion + + #region Public. + /// + /// + /// + /// + /// + [APIExclude] + public delegate void DataReceivedChanged(TransformData prev, TransformData next); + /// + /// Called when new data is received. Previous and next data are provided. Next data may be manipulated. + /// This feature is experimental. + /// + public event DataReceivedChanged OnDataReceived; + /// + /// Called when GoalData is updated. + /// + public event Action OnNextGoal; + /// + /// Called when the transform has reached it's goal. + /// + public event Action OnInterpolationComplete; + #endregion + + #region Serialized. + /// + /// True to synchronize when this transform changes parent. + /// + [Tooltip("True to synchronize when this transform changes parent.")] + [SerializeField] + private bool _synchronizeParent; + /// + /// How much to compress each transform property. + /// + [Tooltip("How much to compress each transform property.")] + [SerializeField] + private TransformPackingData _packing = new TransformPackingData() + { + Position = AutoPackType.Packed, + Rotation = AutoPackType.Packed, + Scale = AutoPackType.Unpacked + }; + /// + /// How many ticks to interpolate. + /// + [Tooltip("How many ticks to interpolate.")] + [Range(1, MAX_INTERPOLATION)] + [SerializeField] + private ushort _interpolation = 2; + /// + /// How many ticks to extrapolate. + /// + [Tooltip("How many ticks to extrapolate.")] + [Range(0, 1024)] + [SerializeField] +#pragma warning disable CS0414 //Not in use. + private ushort _extrapolation = 2; +#pragma warning restore CS0414 //Not in use. + /// + /// True to enable teleport threshhold. + /// + [Tooltip("True to enable teleport threshhold.")] + [SerializeField] + private bool _enableTeleport; + /// + /// How far the transform must travel in a single update to cause a teleport rather than smoothing. Using 0f will teleport every update. + /// + [Tooltip("How far the transform must travel in a single update to cause a teleport rather than smoothing. Using 0f will teleport every update.")] + [Range(0f, float.MaxValue)] + [SerializeField] + private float _teleportThreshold = 1f; + /// + /// True if owner controls how the object is synchronized. + /// + [Tooltip("True if owner controls how the object is synchronized.")] + [SerializeField] + private bool _clientAuthoritative = true; + /// + /// True to synchronize movements on server to owner when not using client authoritative movement. + /// + [Tooltip("True to synchronize movements on server to owner when not using client authoritative movement.")] + [SerializeField] + private bool _sendToOwner = true; + /// + /// How often in ticks to synchronize. A value of 1 will synchronize every tick, a value of 10 will synchronize every 10 ticks. + /// + [Tooltip("How often in ticks to synchronize. A value of 1 will synchronize every tick, a value of 10 will synchronize every 10 ticks.")] + [Range(1, 255)] + [SerializeField] + private byte _interval = 1; + /// + /// True to synchronize position. Even while checked only changed values are sent. + /// + [Tooltip("True to synchronize position. Even while checked only changed values are sent.")] + [SerializeField] + private bool _synchronizePosition = true; + /// + /// Sets if to synchronize position. + /// + /// New value. + public void SetSynchronizePosition(bool value) => _synchronizePosition = value; + /// + /// Axes to snap on position. + /// + [Tooltip("Axes to snap on position.")] + [SerializeField] + private SnappedAxes _positionSnapping = new SnappedAxes(); + /// + /// Sets which Position axes to snap. + /// + /// Axes to snap. + public void SetPositionSnapping(SnappedAxes axes) => _positionSnapping = axes; + /// + /// True to synchronize rotation. Even while checked only changed values are sent. + /// + [Tooltip("True to synchronize rotation. Even while checked only changed values are sent.")] + [SerializeField] + private bool _synchronizeRotation = true; + /// + /// Sets if to synchronize rotation. + /// + /// New value. + public void SetSynchronizeRotation(bool value) => _synchronizeRotation = value; + /// + /// Axes to snap on rotation. + /// + [Tooltip("Axes to snap on rotation.")] + [SerializeField] + private SnappedAxes _rotationSnapping = new SnappedAxes(); + /// + /// Sets which Scale axes to snap. + /// + /// Axes to snap. + public void SetRotationSnapping(SnappedAxes axes) => _rotationSnapping = axes; + /// + /// True to synchronize scale. Even while checked only changed values are sent. + /// + [Tooltip("True to synchronize scale. Even while checked only changed values are sent.")] + [SerializeField] + private bool _synchronizeScale = true; + /// + /// Sets if to synchronize scale. + /// + /// New value. + public void SetSynchronizeScale(bool value) => _synchronizeScale = value; + /// + /// Axes to snap on scale. + /// + [Tooltip("Axes to snap on scale.")] + [SerializeField] + private SnappedAxes _scaleSnapping = new SnappedAxes(); + /// + /// Sets which Scale axes to snap. + /// + /// Axes to snap. + public void SetScaleSnapping(SnappedAxes axes) => _scaleSnapping = axes; + #endregion + + #region Private. + /// + /// Packing data with all values set to uncompressed. + /// + private TransformPackingData _unpacked = new TransformPackingData() + { + Position = AutoPackType.Unpacked, + Rotation = AutoPackType.Unpacked, + Scale = AutoPackType.Unpacked + }; + /// + /// True if the last DataReceived was on the reliable channel. Default to true so initial values do not extrapolate. + /// + 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; + /// + /// Values changed over time that server has sent to clients since last reliable has been sent. + /// + private ChangedDelta _serverChangedSinceReliable = ChangedDelta.Unset; + /// + /// Values changed over time that client has sent to server since last reliable has been sent. + /// + private ChangedDelta _clientChangedSinceReliable = ChangedDelta.Unset; + /// + /// Last tick an ObserverRpc passed checks. + /// + private uint _lastObserversRpcTick; + /// + /// Last tick a ServerRpc passed checks. + /// + private uint _lastServerRpcTick; + /// + /// Last received data from an authoritative client. + /// + private ReceivedData _receivedClientData = new ReceivedData(); + /// + /// True if subscribed to TimeManager for ticks. + /// + private bool _subscribedToTicks; + /// + /// Last TransformData to be sent. + /// + private TransformData _lastSentTransformData = new TransformData(); + /// + /// Last TransformData to be received. + /// + private TransformData _lastReceivedTransformData = new TransformData(); + /// + /// Last RateData to be calculated from LastReceivedTransformData. + /// + private RateData _lastCalculatedRateData = new RateData(); + /// + /// GoalDatas to move towards. + /// + private Queue _goalDataQueue = new Queue(); + /// + /// Current GoalData being used. + /// + private GoalData _currentGoalData = new GoalData(); + /// + /// True if queue can be read. While true objects will move to CurrentGoalData. + /// + private bool _queueReady = false; + /// + /// Cache of GoalDatas to prevent allocations. + /// + private static Stack _goalDataCache = new Stack(); + /// + /// True if the transform has changed since it started. + /// + private bool _changedSinceStart; + /// + /// Number of intervals remaining before synchronization. + /// + private byte _intervalsRemaining; + #endregion + + #region Const. + /// + /// Maximum possible interpolation value. + /// + public const ushort MAX_INTERPOLATION = 250; + #endregion + + private void Awake() + { + _interval = Math.Max(_interval, (byte)1); + } + + private void OnDestroy() + { + if (_receivedClientData.Writer != null) + { + _receivedClientData.Writer.Dispose(); + _receivedClientData.Writer = null; + } + } + + public override void OnStartServer() + { + base.OnStartServer(); + SetDefaultGoalData(); + /* Server must always subscribe. + * Server needs to relay client auth in + * ticks or send non-auth/non-owner to + * clients in tick. */ + ChangeTickSubscription(true); + } + + public override void OnSpawnServer(NetworkConnection connection) + { + base.OnSpawnServer(connection); + /* If not on the root then the initial properties may need to be synchronized + * since the spawn message only sends root information. If initial + * properties have changed update spawning connection. */ + if (base.NetworkObject.gameObject != gameObject && _changedSinceStart) + { + //Send latest. + using (PooledWriter writer = WriterPool.GetWriter()) + { + ChangedDelta fullTransform = (ChangedDelta.PositionX | ChangedDelta.PositionY | ChangedDelta.PositionZ | ChangedDelta.Extended | ChangedDelta.ScaleX | ChangedDelta.ScaleY | ChangedDelta.ScaleZ | ChangedDelta.Rotation); + SerializeChanged(fullTransform, writer); + TargetUpdateTransform(connection, writer.GetArraySegment(), Channel.Reliable); + } + } + + + } + + public override void OnStartClient() + { + base.OnStartClient(); + SetDefaultGoalData(); + } + + public override void OnOwnershipServer(NetworkConnection prevOwner) + { + base.OnOwnershipServer(prevOwner); + _intervalsRemaining = 0; + //Reset last tick since each client sends their own ticks. + _lastServerRpcTick = 0; + } + + public override void OnOwnershipClient(NetworkConnection prevOwner) + { + base.OnOwnershipClient(prevOwner); + _intervalsRemaining = 0; + /* If newOwner is self then client + * must subscribe to ticks. Client can also + * unsubscribe from ticks if not owner, + * long as the server is also not active. */ + if (base.IsOwner) + { + ChangeTickSubscription(true); + } + //Not new owner. + else + { + /* If client authoritative and ownership was lost + * then default goals must be set to force the + * object to it's last transform. */ + if (_clientAuthoritative) + SetDefaultGoalData(); + + if (!base.IsServer) + ChangeTickSubscription(false); + } + } + + public override void OnStopServer() + { + base.OnStopServer(); + //Always unsubscribe; if the server stopped so did client. + ChangeTickSubscription(false); + } + + public override void OnStopClient() + { + base.OnStopClient(); + //If not also server unsubscribe from ticks. + if (!base.IsServer) + ChangeTickSubscription(false); + } + + private void Update() + { + MoveToTarget(); + } + + + /// + /// Called when a tick occurs. + /// + private void TimeManager_OnPostTick() + { + /* If more than 1 interval is remaining than then means + * there are more ticks to be waited upon. */ + if (_intervalsRemaining > 1) + { + _intervalsRemaining--; + return; + } + /* If there is 0 or 1 interval remaining then this + * tick would be the one to send data and reset the interval. */ + else + { + _intervalsRemaining = _interval; + } + + + if (base.IsServer) + SendToClients(); + if (base.IsClient) + SendToServer(); + } + + /* + * //todo make a special method for handling network transforms that iterates all + * of them at once and ALWAYS send the packetId TransformUpdate. This packet will + * have the total length of all updates. theres a chance a nob might not exist since + * these packets are unreliable and can arrive after a nob destruction. if thats + * the case then the packet can still be parsed out and recovered because the updateflags + * indicates exactly what data needs to be read. + */ + + + /// + /// Tries to subscribe to TimeManager ticks. + /// + private void ChangeTickSubscription(bool subscribe) + { + if (subscribe == _subscribedToTicks) + return; + + _subscribedToTicks = subscribe; + if (subscribe) + base.NetworkManager.TimeManager.OnPostTick += TimeManager_OnPostTick; + else + base.NetworkManager.TimeManager.OnPostTick -= TimeManager_OnPostTick; + } + + + /// + /// Creates goal data using current position. + /// + private void SetDefaultGoalData() + { + Transform t = transform; + NetworkBehaviour parentBehaviour = null; + //If there is a parent try to output the behaviour on it. + if (_synchronizeParent && transform.parent != null) + { + transform.parent.TryGetComponent(out parentBehaviour); + if (parentBehaviour == null) + { + LogInvalidParent(); + } + else + { + _parentTransform = transform.parent; + _parentBehaviour = parentBehaviour; + } + } + + _lastReceivedTransformData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, parentBehaviour); + SetInstantRates(_currentGoalData.Rates); + } + + /// + /// Prints an invalid parent debug. + /// + private void LogInvalidParent() + { + Debug.LogWarning($"{gameObject.name} [Id {base.ObjectId}] is nested but the parent {transform.parent.name} does not contain a NetworkBehaviour component. To synchronize parents the parent object must have a NetworkBehaviour component, even if empty."); + } + + /// + /// Serializes only changed data into writer. + /// + /// + /// + private void SerializeChanged(ChangedDelta changed, PooledWriter writer) + { + UpdateFlagA flagsA = UpdateFlagA.Unset; + UpdateFlagB flagsB = UpdateFlagB.Unset; + /* Do not use compression when nested. Depending + * on the scale of the parent compression may + * not be accurate enough. */ + TransformPackingData packing = (ChangedContains(changed, ChangedDelta.Nested)) ? + _unpacked : _packing; + + int startIndexA = writer.Position; + writer.Reserve(1); + //Original axis value. + float original; + //Compressed axis value. + float compressed; + //Multiplier for compression. + float multiplier = 100f; + /* Maximum value compressed may be + * to send as compressed. */ + float maxValue = (short.MaxValue - 1); + + Transform t = transform; + /* Position. */ + if (_synchronizePosition) + { + AutoPackType localPacking = packing.Position; + //PositionX + if (ChangedContains(changed, ChangedDelta.PositionX)) + { + original = t.localPosition.x; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsA |= UpdateFlagA.X2; + writer.WriteInt16((short)compressed); + } + else + { + flagsA |= UpdateFlagA.X4; + writer.WriteSingle(original); + } + } + //PositionY + if (ChangedContains(changed, ChangedDelta.PositionY)) + { + original = t.localPosition.y; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsA |= UpdateFlagA.Y2; + writer.WriteInt16((short)compressed); + } + else + { + flagsA |= UpdateFlagA.Y4; + writer.WriteSingle(original); + } + } + //PositionZ + if (ChangedContains(changed, ChangedDelta.PositionZ)) + { + original = t.localPosition.z; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsA |= UpdateFlagA.Z2; + writer.WriteInt16((short)compressed); + } + else + { + flagsA |= UpdateFlagA.Z4; + writer.WriteSingle(original); + } + } + } + + /* Rotation. */ + if (_synchronizeRotation) + { + if (ChangedContains(changed, ChangedDelta.Rotation)) + { + flagsA |= UpdateFlagA.Rotation; + /* Rotation can always use pack settings even + * if nested. Unsual transform scale shouldn't affect rotation. */ + writer.WriteQuaternion(t.localRotation, _packing.Rotation); + } + } + + if (ChangedContains(changed, ChangedDelta.Extended)) + { + AutoPackType localPacking = packing.Position; + flagsA |= UpdateFlagA.Extended; + int startIndexB = writer.Position; + writer.Reserve(1); + + /* Scale. */ + if (_synchronizeScale) + { + //ScaleX + if (ChangedContains(changed, ChangedDelta.ScaleX)) + { + original = t.localScale.x; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsB |= UpdateFlagB.X2; + writer.WriteInt16((short)compressed); + } + else + { + flagsB |= UpdateFlagB.X4; + writer.WriteSingle(original); + } + } + //ScaleY + if (ChangedContains(changed, ChangedDelta.ScaleY)) + { + original = t.localScale.y; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsB |= UpdateFlagB.Y2; + writer.WriteInt16((short)compressed); + } + else + { + flagsB |= UpdateFlagB.Y4; + writer.WriteSingle(original); + } + } + //ScaleZ + if (ChangedContains(changed, ChangedDelta.ScaleZ)) + { + original = t.localScale.z; + compressed = original * multiplier; + if (localPacking != AutoPackType.Unpacked && Math.Abs(compressed) <= maxValue) + { + flagsB |= UpdateFlagB.Z2; + writer.WriteInt16((short)compressed); + } + else + { + flagsB |= UpdateFlagB.Z4; + writer.WriteSingle(original); + } + } + } + + //Nested. + if (ChangedContains(changed, ChangedDelta.Nested) && _parentBehaviour != null) + { + flagsB |= UpdateFlagB.Nested; + writer.WriteNetworkBehaviour(_parentBehaviour); + } + + writer.FastInsertByte((byte)flagsB, startIndexB); + } + + //Insert flags. + writer.FastInsertByte((byte)flagsA, startIndexA); + bool ChangedContains(ChangedDelta whole, ChangedDelta part) + { + return (whole & part) == part; + } + } + + /// + /// Deerializes a received packet. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void DeserializePacket(ArraySegment data, TransformData prevTransformData, TransformData nextTransformData, ref ChangedFull changedFull) + { + using (PooledReader r = ReaderPool.GetReader(data, base.NetworkManager)) + { + UpdateFlagA flagsA = (UpdateFlagA)r.ReadByte(); + + int readerRemaining; + readerRemaining = r.Remaining; + //X + if (UpdateFlagAContains(flagsA, UpdateFlagA.X2)) + nextTransformData.Position.x = r.ReadInt16() / 100f; + else if (UpdateFlagAContains(flagsA, UpdateFlagA.X4)) + nextTransformData.Position.x = r.ReadSingle(); + else + nextTransformData.Position.x = prevTransformData.Position.x; + //Y + if (UpdateFlagAContains(flagsA, UpdateFlagA.Y2)) + nextTransformData.Position.y = r.ReadInt16() / 100f; + else if (UpdateFlagAContains(flagsA, UpdateFlagA.Y4)) + nextTransformData.Position.y = r.ReadSingle(); + else + nextTransformData.Position.y = prevTransformData.Position.y; + //Z + if (UpdateFlagAContains(flagsA, UpdateFlagA.Z2)) + nextTransformData.Position.z = r.ReadInt16() / 100f; + else if (UpdateFlagAContains(flagsA, UpdateFlagA.Z4)) + nextTransformData.Position.z = r.ReadSingle(); + else + nextTransformData.Position.z = prevTransformData.Position.z; + //If remaining has changed then a position was read. + if (readerRemaining != r.Remaining) + changedFull |= ChangedFull.Position; + + //Rotation. + if (UpdateFlagAContains(flagsA, UpdateFlagA.Rotation)) + { + //Always use _packing value even if nested. + nextTransformData.Rotation = r.ReadQuaternion(_packing.Rotation); + changedFull |= ChangedFull.Rotation; + } + else + { + nextTransformData.Rotation = prevTransformData.Rotation; + } + + //Extended settings. + if (UpdateFlagAContains(flagsA, UpdateFlagA.Extended)) + { + UpdateFlagB flagsB = (UpdateFlagB)r.ReadByte(); + readerRemaining = r.Remaining; + + //X + if (UpdateFlagBContains(flagsB, UpdateFlagB.X2)) + nextTransformData.Scale.x = r.ReadInt16() / 100f; + else if (UpdateFlagBContains(flagsB, UpdateFlagB.X4)) + nextTransformData.Scale.x = r.ReadSingle(); + else + nextTransformData.Scale.x = prevTransformData.Scale.x; + //Y + if (UpdateFlagBContains(flagsB, UpdateFlagB.Y2)) + nextTransformData.Scale.y = r.ReadInt16() / 100f; + else if (UpdateFlagBContains(flagsB, UpdateFlagB.Y4)) + nextTransformData.Scale.y = r.ReadSingle(); + else + nextTransformData.Scale.y = prevTransformData.Scale.y; + //X + if (UpdateFlagBContains(flagsB, UpdateFlagB.Z2)) + nextTransformData.Scale.z = r.ReadInt16() / 100f; + else if (UpdateFlagBContains(flagsB, UpdateFlagB.Z4)) + nextTransformData.Scale.z = r.ReadSingle(); + else + nextTransformData.Scale.z = prevTransformData.Scale.z; + + if (r.Remaining != readerRemaining) + changedFull |= ChangedFull.Scale; + else + nextTransformData.Scale = prevTransformData.Scale; + + if (UpdateFlagBContains(flagsB, UpdateFlagB.Nested)) + { + nextTransformData.ParentBehaviour = r.ReadNetworkBehaviour(); + changedFull |= ChangedFull.Nested; + } + else + { + Unnest(); + } + } + //No extended settings. + else + { + nextTransformData.Scale = prevTransformData.Scale; + Unnest(); + } + } + + void Unnest() + { + nextTransformData.ParentBehaviour = null; + } + + //Returns if whole contains part. + bool UpdateFlagAContains(UpdateFlagA whole, UpdateFlagA part) + { + return (whole & part) == part; + } + //Returns if whole contains part. + bool UpdateFlagBContains(UpdateFlagB whole, UpdateFlagB part) + { + return (whole & part) == part; + } + } + + + + /// + /// Moves to a GoalData. Automatically determins if to use data from server or client. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveToTarget(float deltaOverride = -1f) + { + if (!_queueReady) + return; + //Cannot move if neither is active. + if (!base.IsServer && !base.IsClient) + return; + //If client auth and the owner don't move towards target. + if (_clientAuthoritative && base.IsOwner) + return; + //If not client authoritative, is owner, and don't sync to owner. + if (!_clientAuthoritative && base.IsOwner && !_sendToOwner) + return; + //True if not client controlled. + bool controlledByClient = (_clientAuthoritative && base.Owner.IsActive); + //If not controlled by client and is server then no reason to move. + if (!controlledByClient && base.IsServer) + return; + + float delta = (deltaOverride != -1f) ? deltaOverride : Time.deltaTime; + /* Once here it's safe to assume the object will be moving. + * Any checks which would stop it from moving be it client + * auth and owner, or server controlled and server, ect, + * would have already been run. */ + TransformData td = _currentGoalData.Transforms; + RateData rd = _currentGoalData.Rates; + + + + float multiplier = 1f; + int queueCount = _goalDataQueue.Count; + //For every entry past interpolation increase move rate. + if (queueCount > (_interpolation + 1)) + multiplier += (0.05f * queueCount); + + //Rate to update. Changes per property. + float rate; + Transform t = transform; + + //Snap any positions that should be. + SnapProperties(td); + + //Position. + if (_synchronizePosition) + { + rate = rd.Position; + Vector3 posGoal = (td.ExtrapolationState == TransformData.ExtrapolateState.Active && !_lastReceiveReliable) ? td.ExtrapolatedPosition : td.Position; + if (rate == -1f) + t.localPosition = td.Position; + else + t.localPosition = Vector3.MoveTowards(t.localPosition, posGoal, rate * delta * multiplier); + } + + //Rotation. + if (_synchronizeRotation) + { + rate = rd.Rotation; + if (rate == -1f) + t.localRotation = td.Rotation; + else + t.localRotation = Quaternion.RotateTowards(t.localRotation, td.Rotation, rate * delta); + } + + //Scale. + if (_synchronizeScale) + { + rate = rd.Scale; + if (rate == -1f) + t.localScale = td.Scale; + else + t.localScale = Vector3.MoveTowards(t.localScale, td.Scale, rate * delta); + } + + float timeRemaining = rd.TimeRemaining - (delta * multiplier); + if (timeRemaining < -delta) + timeRemaining = -delta; + rd.TimeRemaining = timeRemaining; + + if (rd.TimeRemaining <= 0f) + { + float leftOver = Mathf.Abs(rd.TimeRemaining); + //If more in buffer then run next buffer. + if (queueCount > 0) + { + _currentGoalData.Reset(); + _goalDataCache.Push(_currentGoalData); + SetCurrentGoalData(_goalDataQueue.Dequeue()); + if (leftOver > 0f) + MoveToTarget(leftOver); + } + //No more in buffer, see if can extrapolate. + else + { + + /* If everything matches up then end queue. + * Otherwise let it play out until stuff + * aligns. Generally the time remaining is enough + * but every once in awhile something goes funky + * and it's thrown off. */ + if (!HasChanged(td)) + _queueReady = false; + OnInterpolationComplete?.Invoke(); + + } + } + + } + + /// + /// Sends transform data to clients if needed. + /// + private void SendToClients() + { + //True if clientAuthoritative and there is an owner. + bool clientAuthoritativeWithOwner = (_clientAuthoritative && base.Owner.IsValid); + //Quick exit if client auth and there's no new data. + if (_clientAuthoritative && base.Owner.IsValid && !_receivedClientData.HasData) + return; + //Channel to send rpc on. + Channel channel = Channel.Unreliable; + //If relaying from client. + if (clientAuthoritativeWithOwner) + { + if (_receivedClientData.HasData) + { + _changedSinceStart = true; + //Resend data from clients. + ObserversUpdateTransform(_receivedClientData.Writer.GetArraySegment(), _receivedClientData.Channel); + _receivedClientData.HasData = false; + } + } + //Sending server transform state. + else + { + ChangedDelta changed = GetChanged(_lastSentTransformData); + + //If no change. + if (changed == ChangedDelta.Unset) + { + //No changes since last reliable; transform is up to date. + if (_serverChangedSinceReliable == ChangedDelta.Unset) + return; + + //Set changed to all changes over time and unset changes over time. + changed = _serverChangedSinceReliable; + _serverChangedSinceReliable = ChangedDelta.Unset; + channel = Channel.Reliable; + } + //There is change. + else + { + _serverChangedSinceReliable |= changed; + } + + _changedSinceStart = true; + 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. */ + _lastSentTransformData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, _parentBehaviour); + + //Send latest. + using (PooledWriter writer = WriterPool.GetWriter()) + { + SerializeChanged(changed, writer); + ObserversUpdateTransform(writer.GetArraySegment(), channel); + } + } + + } + + /// + /// Sends transform data to server if needed. + /// + private void SendToServer() + { + //Not client auth or not owner. + if (!_clientAuthoritative || !base.IsOwner) + return; + + //Channel to send on. + Channel channel = Channel.Unreliable; + //Values changed since last check. + ChangedDelta changed = GetChanged(_lastSentTransformData); + + //If no change. + if (changed == ChangedDelta.Unset) + { + //No changes since last reliable; transform is up to date. + if (_clientChangedSinceReliable == ChangedDelta.Unset) + return; + + //Set changed to all changes over time and unset changes over time. + changed = _clientChangedSinceReliable; + _clientChangedSinceReliable = ChangedDelta.Unset; + channel = Channel.Reliable; + } + //There is change. + else + { + _clientChangedSinceReliable |= changed; + } + + /* 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); + + //Send latest. + using (PooledWriter writer = WriterPool.GetWriter()) + { + SerializeChanged(changed, writer); + ServerUpdateTransform(writer.GetArraySegment(), channel); + } + } + + #region GetChanged. + /// + /// Returns if the transform differs from td. + /// + private bool HasChanged(TransformData td) + { + bool changed = (td.Position != transform.localPosition || + td.Rotation != transform.localRotation || + td.Scale != transform.localScale); + + return changed; + } + /// + /// Returns if there is any change between two datas. + /// + private bool HasChanged(TransformData a, TransformData b) + { + return (a.Position != b.Position) || + (a.Rotation != b.Rotation) || + (a.Scale != b.Scale) || + (a.ParentBehaviour != b.ParentBehaviour); + } + /// + /// Returns if there is any change between two datas and outputs what has changed. + /// + private bool HasChanged(TransformData a, TransformData b, ref ChangedFull changedFull) + { + bool hasChanged = false; + + if (a.Position != b.Position) + { + hasChanged = true; + changedFull |= ChangedFull.Position; + } + if (a.Rotation != b.Rotation) + { + hasChanged = true; + changedFull |= ChangedFull.Rotation; + } + if (a.Scale != b.Scale) + { + hasChanged = true; + changedFull |= ChangedFull.Scale; + } + if (a.ParentBehaviour != b.ParentBehaviour) + { + hasChanged = true; + changedFull |= ChangedFull.Nested; + } + + return hasChanged; + } + /// + /// Gets transform values that have changed against goalData. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ChangedDelta GetChanged(TransformData transformData) + { + return GetChanged(ref transformData.Position, ref transformData.Rotation, ref transformData.Scale, transformData.ParentBehaviour); + } + /// + /// Gets transform values that have changed against specified proprties. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ChangedDelta GetChanged(ref Vector3 lastPosition, ref Quaternion lastRotation, ref Vector3 lastScale, NetworkBehaviour parentBehaviour) + { + ChangedDelta changed = ChangedDelta.Unset; + Transform t = transform; + + Vector3 position = t.localPosition; + if (position.x != lastPosition.x) + changed |= ChangedDelta.PositionX; + if (position.y != lastPosition.y) + changed |= ChangedDelta.PositionY; + if (position.z != lastPosition.z) + changed |= ChangedDelta.PositionZ; + + Quaternion rotation = t.localRotation; + if (!rotation.Matches(lastRotation, true)) + changed |= ChangedDelta.Rotation; + + ChangedDelta startChanged; + startChanged = changed; + + Vector3 scale = t.localScale; + if (scale.x != lastScale.x) + changed |= ChangedDelta.ScaleX; + if (scale.y != lastScale.y) + changed |= ChangedDelta.ScaleY; + if (scale.z != lastScale.z) + changed |= ChangedDelta.ScaleZ; + + //Parent behaviour exist. + if (parentBehaviour != null) + changed |= ChangedDelta.Nested; + + //If added scale or nested then also add extended. + if (startChanged != changed) + changed |= ChangedDelta.Extended; + + return changed; + } + #endregion + + #region Rates. + /// + /// Snaps transform properties using snapping settings. + /// + private void SnapProperties(TransformData transformData) + { + //Already snapped. + if (transformData.Snapped) + return; + + transformData.Snapped = true; + Transform t = transform; + + //Position. + if (_synchronizePosition) + { + Vector3 position; + position.x = (_positionSnapping.X) ? transformData.Position.x : t.localPosition.x; + position.y = (_positionSnapping.Y) ? transformData.Position.y : t.localPosition.y; + position.z = (_positionSnapping.Z) ? transformData.Position.z : t.localPosition.z; + t.localPosition = position; + } + + //Rotation. + if (_synchronizeRotation) + { + Vector3 eulers; + Vector3 goalEulers = transformData.Rotation.eulerAngles; + eulers.x = (_rotationSnapping.X) ? goalEulers.x : t.localEulerAngles.x; + eulers.y = (_rotationSnapping.Y) ? goalEulers.y : t.localEulerAngles.y; + eulers.z = (_rotationSnapping.Z) ? goalEulers.z : t.localEulerAngles.z; + t.localEulerAngles = eulers; + } + + //Scale. + if (_synchronizeScale) + { + Vector3 scale; + scale.x = (_scaleSnapping.X) ? transformData.Scale.x : t.localScale.x; + scale.y = (_scaleSnapping.Y) ? transformData.Scale.y : t.localScale.y; + scale.z = (_scaleSnapping.Z) ? transformData.Scale.z : t.localScale.z; + t.localScale = scale; + } + } + + /// + /// Sets move rates which will occur instantly. + /// + private void SetInstantRates(RateData rd) + { + rd.Update(-1f, -1f, -1f, -1f, 1, false, -1f); + } + + /// + /// Sets move rates which will occur over time. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetCalculatedRates(uint lastTick, RateData prevRd, TransformData prevTd, GoalData nextGd, ChangedFull changedFull, bool hasChanged, Channel channel) + { + /* Only update rates if data has changed. + * When data comes in reliably for eventual consistency + * it's possible that it will be the same as the last + * unreliable packet. When this happens no change has occurred + * and the distance of change woudl also be 0; this prevents + * the NT from moving. Only need to compare data if channel is reliable. */ + TransformData td = nextGd.Transforms; + if (channel == Channel.Reliable && !hasChanged) + { + nextGd.Rates.Update(prevRd); + return; + } + + /* How much time has passed between last update and current. + * If set to 0 then that means the transform has + * settled. */ + if (lastTick == 0) + lastTick = (nextGd.Transforms.Tick - _interval); + + uint tickDifference = (td.Tick - lastTick); + float timePassed = (float)base.NetworkManager.TimeManager.TicksToTime(tickDifference); + + //Distance between properties. + float distance; + float positionRate = 0f; + float rotationRate = 0f; + float scaleRate = 0f; + + RateData rd = nextGd.Rates; + //Correction to apply towards rates when a rate change is detected as abnormal. + float abnormalCorrection = 1f; + bool abnormalRateDetected = false; + float unalteredPositionRate = rd.LastUnalteredPositionRate; + + //Position. + if (ChangedFullContains(changedFull, ChangedFull.Position)) + { + Vector3 lastPosition = prevTd.Position; + distance = Vector3.Distance(lastPosition, td.Position); + //If distance teleports assume rest do. + if (_enableTeleport && distance >= _teleportThreshold) + { + SetInstantRates(rd); + return; + } + + //Position distance already calculated. + unalteredPositionRate = distance / timePassed; + /* Try to detect abnormal rate changes. + * + * This won't occur if the user + * is moving using the tick system but will likely happen when the transform + * is being moved in update. + * + * Update will iterate a varying amount of times per tick, + * which will result in distances being slightly different. This is + * rarely an issue when the frame rate is high and the distance + * variance is very little, but for games which are running at about + * the same frame rate as the tick it's possible the object will + * move twice the distance every few ticks. EG: if running 60 fps/50 tick. + * Execution may look like this.. + * frame, tick, frame, tick, frame, frame, tick. The frame, frame would + * result in double movement distance. */ + + //If last position rate is known then compare against it. + if (unalteredPositionRate > 0f && rd.LastUnalteredPositionRate > 0f) + { + float percentage = Mathf.Abs(1f - (unalteredPositionRate / rd.LastUnalteredPositionRate)); + /* If percentage change is more than 25% then speed is considered + * to have changed drastically. */ + if (percentage > 0.25f) + { + float c = (rd.LastUnalteredPositionRate / unalteredPositionRate); + /* Sometimes stop and goes can incorrectly trigger + * an abnormal detection. Fortunately abnornalties tend + * to either skip a tick or send twice in one tick. + * Because of this it's fairly safe to assume that if the calculated + * correction is not ~0.5f or ~2f then it's a false detection. */ + float allowedDifference = 0.1f; + if ( + (c < 1f && Mathf.Abs(0.5f - c) < allowedDifference) || + (c > 1f && Mathf.Abs(2f - c) < allowedDifference)) + { + abnormalCorrection = c; + abnormalRateDetected = true; + } + /* If an abnormality has been marked then assume new rate + * is proper. When an abnormal rate occurs unintentionally + * the values will fix themselves next tick, therefor when + * rate changes drastically twice assume its intentional or + * that the rate had simply fixed itself, both which would unset + * abnormal rate detected. */ + } + } + + //abnormalCorrection = 1f; + positionRate = (unalteredPositionRate * abnormalCorrection); + } + + //Rotation. + if (ChangedFullContains(changedFull, ChangedFull.Rotation)) + { + Quaternion lastRotation = prevTd.Rotation; + distance = lastRotation.Angle(td.Rotation, true); + rotationRate = (distance / timePassed) * abnormalCorrection; + } + + //Scale. + if (ChangedFullContains(changedFull, ChangedFull.Scale)) + { + Vector3 lastScale = prevTd.Scale; + distance = Vector3.Distance(lastScale, td.Scale); + scaleRate = (distance / timePassed) * abnormalCorrection; + } + + rd.Update(positionRate, rotationRate, scaleRate, unalteredPositionRate, tickDifference, abnormalRateDetected, timePassed); + + //Returns if whole contains part. + bool ChangedFullContains(ChangedFull whole, ChangedFull part) + { + return (whole & part) == part; + } + } + #endregion + + /// + /// Sets extrapolation data on next. + /// + /// + /// + /// + private void SetExtrapolation(TransformData prev, TransformData next, Channel channel) + { + //Default value. + next.ExtrapolationState = TransformData.ExtrapolateState.Disabled; + + + } + + + /// + /// Updates a client with transform data. + /// + [TargetRpc] + private void TargetUpdateTransform(NetworkConnection conn, ArraySegment data, Channel channel) + { + DataReceived(data, channel, false); + } + + /// + /// Updates clients with transform data. + /// + [ObserversRpc] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ObserversUpdateTransform(ArraySegment data, Channel channel) + { + if (!_clientAuthoritative && base.IsOwner && !_sendToOwner) + return; + if (_clientAuthoritative && base.IsOwner) + return; + if (base.IsServer) + return; + + //Not new data. + uint lastPacketTick = base.TimeManager.LastPacketTick; + if (lastPacketTick <= _lastObserversRpcTick) + return; + _lastObserversRpcTick = lastPacketTick; + + DataReceived(data, channel, false); + } + + /// + /// Updates the transform on the server. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [ServerRpc] + private void ServerUpdateTransform(ArraySegment data, Channel channel) + { + //Not new data. + uint lastPacketTick = base.TimeManager.LastPacketTick; + if (lastPacketTick <= _lastServerRpcTick) + return; + _lastServerRpcTick = lastPacketTick; + + //Populate writer if it doesn't exist. + if (_receivedClientData.Writer == null) + _receivedClientData.Writer = WriterPool.GetWriter(); + _receivedClientData.Channel = channel; + _receivedClientData.Writer.Reset(); + _receivedClientData.Writer.WriteArraySegment(data); + _receivedClientData.HasData = true; + + DataReceived(data, channel, true); + } + + /// + /// Processes received data for lcients and server. + /// + private void DataReceived(ArraySegment data, Channel channel, bool asServer) + { + TransformData prevTd = _lastReceivedTransformData; + RateData prevRd = _lastCalculatedRateData; + ChangedFull changedFull = new ChangedFull(); + + GoalData nextGd = GetCachedGoalData(); + TransformData nextTd = nextGd.Transforms; + UpdateTransformData(data, prevTd, nextTd, ref changedFull); + OnDataReceived?.Invoke(prevTd, nextTd); + SetExtrapolation(prevTd, nextTd, channel); + + bool hasChanged = HasChanged(prevTd, nextTd); + //If server only teleport. + if (asServer && !base.IsClient) + SetInstantRates(nextGd.Rates); + //Otherwise use timed. + else + SetCalculatedRates(prevTd.Tick, prevRd, prevTd, nextGd, changedFull, hasChanged, channel); + + _lastReceivedTransformData.Update(nextTd); + + _lastReceiveReliable = (channel == Channel.Reliable); + /* If channel is reliable then this is a settled packet. + * Reset last received tick so next starting move eases + * in. */ + if (channel == Channel.Reliable) + nextTd.Tick = 0; + + prevTd.Update(nextTd); + prevRd.Update(nextGd.Rates); + + nextGd.ReceivedTick = base.TimeManager.LocalTick; + + /* If extrapolating then immediately break the extrapolation + * in favor of newest results. This will keep the buffer + * at 0 until the transform settles but the only other option is + * to stop the movement, which would defeat purpose of extrapolation, + * or slow down the transform while buffer rebuilds. Neither choice + * is great but later on I might try slowing down the transform slightly + * to give the buffer a chance to rebuild. */ + if (_currentGoalData.Transforms.ExtrapolationState == TransformData.ExtrapolateState.Active) + { + _queueReady = true; + SetCurrentGoalData(nextGd); + } + /* If queue isn't started and its buffered enough + * to satisfy interpolation then set ready + * and set current data. + * + * Also if reliable then begin moving. */ + else if (!_queueReady && _goalDataQueue.Count >= _interpolation + || channel == Channel.Reliable) + { + _queueReady = true; + if (_goalDataQueue.Count > 0) + { + SetCurrentGoalData(_goalDataQueue.Dequeue()); + /* If is reliable and has changed then also + * enqueue latest. */ + if (hasChanged) + _goalDataQueue.Enqueue(nextGd); + + } + else + { + SetCurrentGoalData(nextGd); + } + } + /* If here then there's not enough in buffer to begin + * so add onto the buffer. */ + else + { + _goalDataQueue.Enqueue(nextGd); + } + + /* If the queue is excessive beyond interpolation then + * dequeue extras to prevent from dropping behind too + * quickly. This shouldn't be an issue with normal movement + * as the NT speeds up if the buffer unexpectedly grows, but + * when connections are unstable results may come in chunks + * and for a better experience the older parts of the chunks + * will be dropped. */ + if (_goalDataQueue.Count > (_interpolation + 3)) + { + while (_goalDataQueue.Count > _interpolation) + { + GoalData tmpGd = _goalDataQueue.Dequeue(); + _goalDataCache.Push(tmpGd); + } + } + } + + /// + /// Sets CurrentGoalData value. + /// + /// + private void SetCurrentGoalData(GoalData data) + { + _currentGoalData = data; + OnNextGoal?.Invoke(data); + } + + /// + /// Immediately sets the parent of this NetworkTransform for a single connection. + /// + [TargetRpc] + private void TargetSetParent(NetworkConnection conn, NetworkBehaviour parent) + { + + } + + /// + /// Updates a TransformData from packetData. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UpdateTransformData(ArraySegment packetData, TransformData prevTransformData, TransformData nextTransformData, ref ChangedFull changedFull) + { + DeserializePacket(packetData, prevTransformData, nextTransformData, ref changedFull); + nextTransformData.Tick = base.TimeManager.LastPacketTick; + } + + /// + /// Returns a GoalData from the cache. + /// + /// + private GoalData GetCachedGoalData() + { + GoalData result = (_goalDataCache.Count > 0) ? _goalDataCache.Pop() : new GoalData(); + result.Reset(); + return result; + } + + /// + /// Configures this NetworkTransform for CSP. + /// + internal void ConfigureForCSP() + { + _clientAuthoritative = false; + _sendToOwner = false; + } + + /// + /// Updates which properties are synchronized. This feature is experimental. + /// + /// Properties to synchronize. + public void SetSynchronizedProperties(SynchronizedProperty value) + { + /* Make sure permissions are proper to change values. + * Let the server override client auth. + * + * Can send if server. + * Or owner + client auth. + */ + bool canSend = ( + base.IsServer || + (_clientAuthoritative && base.IsOwner) + ); + + if (!canSend) + return; + + //If server send out observerRpc. + if (base.IsServer) + ObserversSetSynchronizedProperties(value); + //Otherwise send to the server. + else + ServerSetSynchronizedProperties(value); + } + + /// + /// Sets synchronized values based on value. + /// + [ServerRpc] + private void ServerSetSynchronizedProperties(SynchronizedProperty value) + { + /* Client is trying to be sneaky ... + * a client should not be able to call this when NT isnt client auth. */ + if (!_clientAuthoritative) + return; + + SetSynchronizedPropertiesInternal(value); + ObserversSetSynchronizedProperties(value); + } + + /// + /// Sets synchronized values based on value. + /// + [ObserversRpc(BufferLast = true)] + private void ObserversSetSynchronizedProperties(SynchronizedProperty value) + { + //Would have already run on server if host. + if (base.IsServer) + return; + + SetSynchronizedPropertiesInternal(value); + } + + /// + /// Sets synchronized values based on value. + /// + private void SetSynchronizedPropertiesInternal(SynchronizedProperty value) + { + _synchronizeParent = SynchronizedPropertyContains(value, SynchronizedProperty.Parent); + _synchronizePosition = SynchronizedPropertyContains(value, SynchronizedProperty.Position); + _synchronizeRotation = SynchronizedPropertyContains(value, SynchronizedProperty.Rotation); + _synchronizeScale = SynchronizedPropertyContains(value, SynchronizedProperty.Scale); + + bool SynchronizedPropertyContains(SynchronizedProperty whole, SynchronizedProperty part) + { + return (whole & part) == part; + } + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs.meta new file mode 100644 index 0000000..76f2fc8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a2836e36774ca1c4bbbee976e17b649c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs new file mode 100644 index 0000000..a154521 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs @@ -0,0 +1,13 @@ +namespace FishNet.Component.Transforming +{ + + public enum SynchronizedProperty : byte + { + None = 0, + Parent = 1, + Position = 2, + Rotation = 4, + Scale = 8 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs.meta new file mode 100644 index 0000000..28fe681 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/SynchronizedProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e6005ee9abfdd542ad27023114bbe04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing.meta new file mode 100644 index 0000000..2a5b319 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ac91629faf99a548abba797e24839bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset new file mode 100644 index 0000000..10a9cb4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset @@ -0,0 +1,18 @@ +%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: 7c3e28fa2e37d1d41b4f63c8a0cc2553, type: 3} + m_Name: DistanceCondition + m_EditorClassIdentifier: + NetworkObject: {fileID: 0} + _maximumDistance: 10 + _hideDistancePercent: 0.1 + _updateFrequency: 0 diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset.meta new file mode 100644 index 0000000..1ba0a6e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/DistanceCondition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f33eb0e5b83b5546822cfe42a305657 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset new file mode 100644 index 0000000..0d44d4f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset @@ -0,0 +1,15 @@ +%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: 5afdd6c2de1c76f4faa6840cc29fda8a, type: 3} + m_Name: MatchCondition + m_EditorClassIdentifier: + NetworkObject: {fileID: 0} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset.meta new file mode 100644 index 0000000..39dd07a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/MatchCondition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: efcd7f0dfd341ed4e8671079e91e0544 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset new file mode 100644 index 0000000..625e5f1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset @@ -0,0 +1,15 @@ +%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: 1ca3d8a36a10fd344806a2df999f3eda, type: 3} + m_Name: OwnerOnlyCondition + m_EditorClassIdentifier: + NetworkObject: {fileID: 0} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset.meta new file mode 100644 index 0000000..389066f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/OwnerOnlyCondition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcf92670d91dbb74dad77c56b9b8712e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset new file mode 100644 index 0000000..0877337 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset @@ -0,0 +1,17 @@ +%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: fab85d1c51ee2c344b7dd914dc262ec4, type: 3} + m_Name: SceneCondition + m_EditorClassIdentifier: + NetworkObject: {fileID: 0} + _synchronizeScene: 1 + _timed: 0 diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset.meta new file mode 100644 index 0000000..6cc77dd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/SceneCondition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2033f54fd2794464bae08fa5a55c8996 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset new file mode 100644 index 0000000..0b33633 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset @@ -0,0 +1,15 @@ +%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: 1426e8d4eba17f743839346033d2cec7, type: 3} + m_Name: ServerOnlyCondition + m_EditorClassIdentifier: + NetworkObject: {fileID: 0} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset.meta new file mode 100644 index 0000000..babfbb0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Observing/ServerOnlyCondition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05590e7b064dc2743bc3fc39864608f6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction.meta new file mode 100644 index 0000000..aabf13e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e4f8fbf54adbf5d4781d2c88c0aaebd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs new file mode 100644 index 0000000..c356df8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs @@ -0,0 +1,11 @@ +using FishNet.Object; +using System; + +namespace FishNet.Component.Prediction +{ + [Obsolete("DesyncSmoother is obsolete. Please remove this component and use PredictedObject on your gameObject's root.")] + //remove on 2023/01/01 + public class DesyncSmoother : NetworkBehaviour { } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs.meta new file mode 100644 index 0000000..6b534c3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/DesyncSmoother.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37c39a68e17740c4ea2b1fb940e5cd53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor.meta new file mode 100644 index 0000000..9e480d2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6b05a47941365c4097d74bca5e47017 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs new file mode 100644 index 0000000..d2c3950 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs @@ -0,0 +1,93 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + + + [CustomEditor(typeof(PredictedObject), true)] + [CanEditMultipleObjects] + public class PredictionObjectEditor : Editor + { + private SerializedProperty _graphicalObject; + private SerializedProperty _smoothTicks; + private SerializedProperty _durationType; + private SerializedProperty _smoothingDuration; + private SerializedProperty _enableTeleport; + private SerializedProperty _teleportThreshold; + private SerializedProperty _predictionType; + private SerializedProperty _rigidbody; + private SerializedProperty _rigidbody2d; + private SerializedProperty _networkTransform; + private SerializedProperty _predictionRatio; + + protected virtual void OnEnable() + { + _graphicalObject = serializedObject.FindProperty("_graphicalObject"); + _smoothTicks = serializedObject.FindProperty("_smoothTicks"); + _durationType = serializedObject.FindProperty("_durationType"); + _smoothingDuration = serializedObject.FindProperty("_smoothingDuration"); + _enableTeleport = serializedObject.FindProperty("_enableTeleport"); + _teleportThreshold = serializedObject.FindProperty("_teleportThreshold"); + _predictionType = serializedObject.FindProperty("_predictionType"); + _rigidbody = serializedObject.FindProperty("_rigidbody"); + _rigidbody2d = serializedObject.FindProperty("_rigidbody2d"); + _networkTransform = serializedObject.FindProperty("_networkTransform"); + _predictionRatio = serializedObject.FindProperty("_predictionRatio"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((PredictedObject)target), typeof(PredictedObject), false); + GUI.enabled = true; + + EditorGUILayout.PropertyField(_graphicalObject); + EditorGUILayout.PropertyField(_smoothTicks); + EditorGUILayout.PropertyField(_durationType); + if ((PredictedObject.SmoothingDurationType)_durationType.intValue == PredictedObject.SmoothingDurationType.Time) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_smoothingDuration); + EditorGUI.indentLevel--; + } + EditorGUILayout.PropertyField(_enableTeleport); + if (_enableTeleport.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_teleportThreshold); + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(_predictionType); + PredictedObject.PredictionType movementType = (PredictedObject.PredictionType)_predictionType.intValue; + if (movementType != PredictedObject.PredictionType.Other) + { + EditorGUI.indentLevel++; + EditorGUILayout.HelpBox("When using physics prediction do not include a NetworkTransform; this component will synchronize instead.", MessageType.Info); + if (movementType == PredictedObject.PredictionType.Rigidbody) + EditorGUILayout.PropertyField(_rigidbody); + else + EditorGUILayout.PropertyField(_rigidbody2d, new GUIContent("Rigidbody2D", "Rigidbody2D to predict.")); + EditorGUILayout.PropertyField(_predictionRatio); + EditorGUI.indentLevel--; + } + else + { + EditorGUI.indentLevel++; + EditorGUILayout.HelpBox("When other is selected another component, such as NetworkTransform, must be used to synchronize.", MessageType.Info); + EditorGUILayout.PropertyField(_networkTransform); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + serializedObject.ApplyModifiedProperties(); + } + + } +} +#endif + diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs.meta new file mode 100644 index 0000000..2a45c05 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/Editor/PredictedObjectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0b8595657415764e9d83b6d974043af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs new file mode 100644 index 0000000..75c25f0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs @@ -0,0 +1,298 @@ +using FishNet.Managing.Timing; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + public partial class OfflineRigidbody : MonoBehaviour + { + #region Types. + /// + /// Type of prediction movement being used. + /// + private enum RigidbodyType : byte + { + Rigidbody = 0, + Rigidbody2D = 1 + } + /// + /// Data for a rigidbody before being set kinematic. + /// + private struct RigidbodyData + { + /// + /// Rigidbody for data. + /// + private Rigidbody _rigidbody; + /// + /// Cached velocity when being set kinematic. + /// + private Vector3 _velocity; + /// + /// Cached velocity when being set kinematic. + /// + private Vector3 _angularVelocity; + + public RigidbodyData(Rigidbody rigidbody) + { + _rigidbody = rigidbody; + _velocity = Vector3.zero; + _angularVelocity = Vector3.zero; + } + + /// + /// Sets isKinematic status and returns if successful. + /// + public bool SetIsKinematic(bool isKinematic) + { + if (_rigidbody == null) + return false; + + if (!isKinematic) + { + _velocity = _rigidbody.velocity; + _angularVelocity = _rigidbody.angularVelocity; + } + else + { + _rigidbody.velocity = _velocity; + _rigidbody.angularVelocity = _angularVelocity; + } + + return true; + } + } + /// + /// Data for a rigidbody2d before being set kinematic. + /// + private struct RigidbodyData2D + { + /// + /// Rigidbody for data. + /// + private Rigidbody2D _rigidbody2d; + /// + /// Cached velocity when being set kinematic. + /// + private Vector2 _velocity; + /// + /// Cached velocity when being set kinematic. + /// + private float _angularVelocity; + + public RigidbodyData2D(Rigidbody2D rigidbody) + { + _rigidbody2d = rigidbody; + _velocity = Vector2.zero; + _angularVelocity = 0f; + } + + /// + /// Sets simulated status and returns if successful. + /// + public bool SetSimulated(bool simulated) + { + if (_rigidbody2d == null) + return false; + + if (!simulated) + { + _velocity = _rigidbody2d.velocity; + _angularVelocity = _rigidbody2d.angularVelocity; + } + else + { + _rigidbody2d.velocity = _velocity; + _rigidbody2d.angularVelocity = _angularVelocity; + } + + return true; + } + } + #endregion + + #region Serialized. + [Header("This component is experimental! Please report any problems you may encounter.")] + /// + /// Type of prediction movement which is being used. + /// + [Tooltip("Type of prediction movement which is being used.")] + [SerializeField] + private RigidbodyType _rigidbodyType; + /// + /// True to also get rigidbody components within children. + /// + [Tooltip("True to also get rigidbody components within children.")] + [SerializeField] + private bool _getInChildren; + #endregion + + #region Private. + /// + /// Rigidbody datas for found rigidbodies. + /// + private List _rigidbodyDatas = new List(); + /// + /// Rigidbody2D datas for found rigidbodies; + /// + private List _rigidbodyDatas2d = new List(); + /// + /// TimeManager subscribed to. + /// + private TimeManager _timeManager; + #endregion + + + private void Awake() + { + InitializeOnce(); + } + + + private void OnDestroy() + { + ChangeSubscription(false); + } + + /// + /// Initializes this script for use. + /// + private void InitializeOnce() + { + _timeManager = InstanceFinder.TimeManager; + UpdateRigidbodies(); + ChangeSubscription(true); + } + + /// + /// Sets a new TimeManager to use. + /// + /// + public void SetTimeManager(TimeManager tm) + { + if (tm == _timeManager) + return; + + //Unsub from current. + ChangeSubscription(false); + //Sub to newest. + _timeManager = tm; + ChangeSubscription(true); + } + + /// + /// Finds and assigns rigidbodie using configured settings. + /// + public void UpdateRigidbodies() + { + //3D. + if (_rigidbodyType == RigidbodyType.Rigidbody) + { + _rigidbodyDatas.Clear(); + if (_getInChildren) + { + Rigidbody[] rbs = GetComponentsInChildren(true); + for (int i = 0; i < rbs.Length; i++) + _rigidbodyDatas.Add(new RigidbodyData(rbs[i])); + } + else + { + if (gameObject.TryGetComponent(out Rigidbody rb)) + _rigidbodyDatas.Add(new RigidbodyData(rb)); + } + } + //2D. + else + { + _rigidbodyDatas2d.Clear(); + if (_getInChildren) + { + Rigidbody2D[] rbs = GetComponentsInChildren(true); + for (int i = 0; i < rbs.Length; i++) + _rigidbodyDatas2d.Add(new RigidbodyData2D(rbs[i])); + } + else + { + if (gameObject.TryGetComponent(out Rigidbody2D rb)) + _rigidbodyDatas2d.Add(new RigidbodyData2D(rb)); + } + } + } + + /// + /// Changes the subscription to the TimeManager. + /// + private void ChangeSubscription(bool subscribe) + { + if (_timeManager == null) + return; + + if (subscribe) + { + _timeManager.OnPreReplicateReplay += _timeManager_OnPreReplicateReplay; + _timeManager.OnPostReplicateReplay += _timeManager_OnPostReplicateReplay; + } + else + { + _timeManager.OnPreReplicateReplay -= _timeManager_OnPreReplicateReplay; + _timeManager.OnPostReplicateReplay -= _timeManager_OnPostReplicateReplay; + } + } + + /// + /// Called before physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + private void _timeManager_OnPreReplicateReplay(PhysicsScene arg1, PhysicsScene2D arg2) + { + ChangeKinematic(true); + } + + /// + /// Called after physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + private void _timeManager_OnPostReplicateReplay(PhysicsScene arg1, PhysicsScene2D arg2) + { + ChangeKinematic(false); + } + + /// + /// Changes IsKinematic for rigidbodies. + /// + /// + private void ChangeKinematic(bool isKinematic) + { + if (!this.enabled) + return; + + //3D. + if (_rigidbodyType == RigidbodyType.Rigidbody) + { + for (int i = 0; i < _rigidbodyDatas.Count; i++) + { + if (!_rigidbodyDatas[i].SetIsKinematic(isKinematic)) + { + _rigidbodyDatas.RemoveAt(i); + i--; + } + } + } + //2D. + else + { + for (int i = 0; i < _rigidbodyDatas2d.Count; i++) + { + if (!_rigidbodyDatas2d[i].SetSimulated(!isKinematic)) + { + _rigidbodyDatas2d.RemoveAt(i); + i--; + } + } + } + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs.meta new file mode 100644 index 0000000..cd25d95 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/OfflineRigidbody.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b749f90d4c9961c4991179db1130fa4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs new file mode 100644 index 0000000..5cef7f5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs @@ -0,0 +1,408 @@ +using FishNet.Managing.Timing; +using FishNet.Object; +using FishNet.Transporting; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + public partial class PredictedObject : NetworkBehaviour + { + #region All. + + /// + /// Called after a tick occurs; physics would have simulated if using PhysicsMode.TimeManager. + /// + private void Rigidbodies_TimeManager_OnPostTick() + { + if (!IsRigidbodyPrediction) + return; + + bool is2D = (_predictionType == PredictionType.Rigidbody2D); + + if (CanPredict()) + { + if (!is2D) + PredictVelocity(gameObject.scene.GetPhysicsScene()); + else + PredictVelocity(gameObject.scene.GetPhysicsScene2D()); + } + + if (base.IsServer) + { + uint localTick = base.TimeManager.LocalTick; + if (localTick >= _nextSendTick || base.TransformMayChange()) + { + uint ticksRequired = base.TimeManager.TimeToTicks(SEND_INTERVAL, TickRounding.RoundUp); + _nextSendTick = localTick + ticksRequired; + + if (!is2D) + SendRigidbodyState(); + else + SendRigidbody2DState(); + } + } + } + + + /// + /// Called before physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + private void Rigidbodies_TimeManager_OnPostReplicateReplay(PhysicsScene ps, PhysicsScene2D ps2d) + { + if (!CanPredict()) + return; + + if (_predictionType == PredictionType.Rigidbody) + PredictVelocity(ps); + else if (_predictionType == PredictionType.Rigidbody2D) + PredictVelocity(ps2d); + } + + /// + /// Tries to predict velocity for a Vector3. + /// + protected bool PredictVector3Velocity(ref float? velocityBaseline, ref Vector3 lastVelocity, Vector3 velocity, out Vector3 result) + { + float velocityDifference; + float directionDifference; + + /* Velocity. */ + directionDifference = (velocityBaseline != null) ? + Vector3.SqrMagnitude(lastVelocity.normalized - velocity.normalized) : + 0f; + //If direction has changed too much then reset the baseline. + if (directionDifference > 0.01f) + { + velocityBaseline = null; + } + //Direction hasn't changed enough to reset baseline. + else + { + //Difference in velocity since last simulation. + velocityDifference = Vector3.Magnitude(lastVelocity - velocity); + //If there is no baseline. + if (velocityBaseline == null) + { + if (velocityDifference > 0) + velocityBaseline = velocityDifference; + } + //If there is a baseline. + else + { + //If the difference exceeds the baseline by 10% then reset baseline so another will be calculated. + if (velocityDifference > (velocityBaseline.Value * 1.1f) || velocityDifference < (velocityBaseline.Value * 0.9f)) + { + velocityBaseline = null; + } + //Velocity difference is close enough to the baseline to where it doesn't need to be reset, so use prediction. + else + { + result = Vector3.Lerp(velocity, lastVelocity, _predictionRatio); + return true; + } + } + } + + //Fall through. + result = Vector3.zero; + return false; + } + + + /// + /// Tries to predict velocity for a float. + /// + private bool PredictFloatVelocity(ref float? velocityBaseline, ref float lastVelocity, float velocity, out float result) + { + float velocityDifference; + float directionDifference; + + /* Velocity. */ + directionDifference = (velocityBaseline != null) ? (velocity - lastVelocity) : 0f; + + //If direction has changed too much then reset the baseline. + if (directionDifference > 0.01f) + { + velocityBaseline = null; + } + //Direction hasn't changed enough to reset baseline. + else + { + //Difference in velocity since last simulation. + velocityDifference = Mathf.Abs(lastVelocity - velocity); + //If there is no baseline. + if (velocityBaseline == null) + { + if (velocityDifference > 0) + velocityBaseline = velocityDifference; + } + //If there is a baseline. + else + { + //If the difference exceeds the baseline by 10% then reset baseline so another will be calculated. + if (velocityDifference > (velocityBaseline.Value * 1.1f) || velocityDifference < (velocityBaseline.Value * 0.9f)) + { + velocityBaseline = null; + } + //Velocity difference is close enough to the baseline to where it doesn't need to be reset, so use prediction. + else + { + result = Mathf.Lerp(velocity, lastVelocity, _predictionRatio); + return true; + } + } + } + + //Fall through. + result = 0f; + return false; + } + + + /// + /// Returns if prediction can be used on this rigidbody. + /// + /// + private bool CanPredict() + { + if (!IsRigidbodyPrediction) + return false; + if (base.IsServer || base.IsOwner) + return false; + + return true; + } + #endregion + + #region Rigidbody. + + #region Private. + /// + /// Last SpectatorMotorState received from the server. + /// + private RigidbodyState? _receivedRigidbodyState; + /// + /// Velocity from previous simulation. + /// + private Vector3 _lastVelocity; + /// + /// Angular velocity from previous simulation. + /// + private Vector3 _lastAngularVelocity; + /// + /// Baseline for velocity magnitude. + /// + private float? _velocityBaseline; + /// + /// Baseline for angular velocity magnitude. + /// + private float? _angularVelocityBaseline; + /// + /// PhysicsScene for this object when OnPreReconcile is called. + /// + private PhysicsScene _physicsScene; + #endregion + + + /// + /// Resets the rigidbody to last known data. + /// + private void ResetRigidbodyToData() + { + if (_receivedRigidbodyState == null) + return; + + //Update transform and rigidbody. + _rigidbody.transform.position = _receivedRigidbodyState.Value.Position; + _rigidbody.transform.rotation = _receivedRigidbodyState.Value.Rotation; + bool isKinematic = _receivedRigidbodyState.Value.IsKinematic; + _rigidbody.isKinematic = isKinematic; + if (!isKinematic) + { + _rigidbody.velocity = _receivedRigidbodyState.Value.Velocity; + _rigidbody.angularVelocity = _receivedRigidbodyState.Value.AngularVelocity; + } + //Set prediction defaults. + _velocityBaseline = null; + _angularVelocityBaseline = null; + _lastVelocity = _rigidbody.velocity; + _lastAngularVelocity = _rigidbody.angularVelocity; + } + + /// + /// Sets the next predicted velocity on the rigidbody. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void PredictVelocity(PhysicsScene ps) + { + if (_predictionRatio <= 0f) + return; + if (ps != _physicsScene) + return; + + Vector3 result; + if (PredictVector3Velocity(ref _velocityBaseline, ref _lastVelocity, _rigidbody.velocity, out result)) + _rigidbody.velocity = result; + if (PredictVector3Velocity(ref _angularVelocityBaseline, ref _lastAngularVelocity, _rigidbody.angularVelocity, out result)) + _rigidbody.angularVelocity = result; + + _lastVelocity = _rigidbody.velocity; + _lastAngularVelocity = _rigidbody.angularVelocity; + } + + + /// + /// Sends current states of this object to client. + /// + private void SendRigidbodyState() + { + RigidbodyState state = new RigidbodyState + { + Position = _rigidbody.transform.position, + Rotation = _rigidbody.transform.rotation, + IsKinematic = _rigidbody.isKinematic, + Velocity = _rigidbody.velocity, + AngularVelocity = _rigidbody.angularVelocity + }; + + ObserversSendRigidbodyState(state); + } + + /// + /// Sends transform and rigidbody state to spectators. + /// + /// + [ObserversRpc(IncludeOwner = false, BufferLast = true)] + private void ObserversSendRigidbodyState(RigidbodyState state, Channel channel = Channel.Unreliable) + { + if (!CanPredict()) + return; + + SetPreviousTransformProperties(); + _receivedRigidbodyState = state; + ResetRigidbodyToData(); + + ResetToTransformPreviousProperties(); + SetTransformMoveRates(); + } + #endregion + + #region Rigidbody2D. + #region Private. + /// + /// Last SpectatorMotorState received from the server. + /// + private Rigidbody2DState? _receivedRigidbody2DState; + /// + /// Velocity from previous simulation. + /// + private Vector3 _lastVelocity2D; + /// + /// Angular velocity from previous simulation. + /// + private float _lastAngularVelocity2D; + /// + /// Baseline for velocity magnitude. + /// + private float? _velocityBaseline2D; + /// + /// Baseline for angular velocity magnitude. + /// + private float? _angularVelocityBaseline2D; + /// + /// PhysicsScene for this object when OnPreReconcile is called. + /// + private PhysicsScene2D _physicsScene2D; + #endregion + + + /// + /// Resets the rigidbody to last known data. + /// + private void ResetRigidbody2DToData() + { + if (_receivedRigidbody2DState == null) + return; + + //Update transform and rigidbody. + _rigidbody2d.transform.position = _receivedRigidbody2DState.Value.Position; + _rigidbody2d.transform.rotation = _receivedRigidbody2DState.Value.Rotation; + bool simulated = _receivedRigidbody2DState.Value.Simulated; + _rigidbody2d.simulated = simulated; + if (!simulated) + { + _rigidbody2d.velocity = _receivedRigidbody2DState.Value.Velocity; + _rigidbody2d.angularVelocity = _receivedRigidbody2DState.Value.AngularVelocity; + } + //Set prediction defaults. + _velocityBaseline2D = null; + _angularVelocityBaseline2D = null; + _lastVelocity2D = _rigidbody2d.velocity; + _lastAngularVelocity2D = _rigidbody2d.angularVelocity; + } + + /// + /// Sets the next predicted velocity on the rigidbody. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void PredictVelocity(PhysicsScene2D ps) + { + if (_predictionRatio <= 0f) + return; + if (ps != _physicsScene2D) + return; + + Vector3 v3Result; + if (PredictVector3Velocity(ref _velocityBaseline2D, ref _lastVelocity2D, _rigidbody2d.velocity, out v3Result)) + _rigidbody2d.velocity = v3Result; + float floatResult; + if (PredictFloatVelocity(ref _angularVelocityBaseline2D, ref _lastAngularVelocity2D, _rigidbody2d.angularVelocity, out floatResult)) + _rigidbody2d.angularVelocity = floatResult; + + _lastVelocity2D = _rigidbody2d.velocity; + _lastAngularVelocity2D = _rigidbody2d.angularVelocity; + } + + + /// + /// Sends current states of this object to client. + /// + private void SendRigidbody2DState() + { + Rigidbody2DState state = new Rigidbody2DState + { + Position = _rigidbody2d.transform.position, + Rotation = _rigidbody2d.transform.rotation, + Simulated = _rigidbody2d.simulated, + Velocity = _rigidbody2d.velocity, + AngularVelocity = _rigidbody2d.angularVelocity + }; + + ObserversSendRigidbody2DState(state); + } + + /// + /// Sends transform and rigidbody state to spectators. + /// + /// + [ObserversRpc(IncludeOwner = false, BufferLast = true)] + private void ObserversSendRigidbody2DState(Rigidbody2DState state, Channel channel = Channel.Unreliable) + { + if (!CanPredict()) + return; + + SetPreviousTransformProperties(); + _receivedRigidbody2DState = state; + ResetRigidbody2DToData(); + + ResetToTransformPreviousProperties(); + SetTransformMoveRates(); + } + #endregion + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs.meta new file mode 100644 index 0000000..0d5f06d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.Rigidbodies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bd787cd0da2e9e4ab4bd30794ff0082 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs new file mode 100644 index 0000000..aaa117b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs @@ -0,0 +1,441 @@ +using FishNet.Component.Transforming; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + [AddComponentMenu("FishNet/Component/PredictedObject")] + public partial class PredictedObject : NetworkBehaviour + { + #region Types. + /// + /// How to smooth. Over the tick duration or specified time. + /// + public enum SmoothingDurationType : byte + { + Tick = 0, + Time = 1 + } + /// + /// Type of prediction movement being used. + /// + internal enum PredictionType : byte + { + Other = 0, + Rigidbody = 1, + Rigidbody2D = 2 + } + #endregion + + #region Public. + /// + /// True if the prediction type is for a rigidbody. + /// + public bool IsRigidbodyPrediction => (_predictionType == PredictionType.Rigidbody || _predictionType == PredictionType.Rigidbody2D); + #endregion + + #region Serialized. + /// + /// Transform which holds the graphical features of this object. This transform will be smoothed when desynchronizations occur. + /// + [Tooltip("Transform which holds the graphical features of this object. This transform will be smoothed when desynchronizations occur.")] + [SerializeField] + private Transform _graphicalObject; + /// + /// Gets GraphicalObject. + /// + public Transform GetGraphicalObject => _graphicalObject; + /// + /// Sets GraphicalObject. + /// + /// + public void SetGraphicalObject(Transform value) => _graphicalObject = value; + /// + /// True to smooth graphical object over tick durations. While true objects will be smooth even with low tick rates, but the visual representation will be behind one tick. + /// + [Tooltip("True to smooth graphical object over tick durations. While true objects will be smooth even with low tick rates, but the visual representation will be behind one tick.")] + [SerializeField] + private bool _smoothTicks = true; + /// + /// Gets the value for SmoothTicks. + /// + /// + public bool GetSmoothTicks() => _smoothTicks; + /// + /// Sets the value for SmoothTicks. + /// + /// + /// + public void SetSmoothTicks(bool value) => _smoothTicks = value; + /// + /// How to smooth desynchronizations. Tick will smooth over the tick while Time will smooth over a set duration. + /// + [Tooltip("How to smooth desynchronizations. Tick will smooth over the tick while Time will smooth over a set duration.")] + [SerializeField] + private SmoothingDurationType _durationType = SmoothingDurationType.Tick; + /// + /// Duration to smooth desynchronizations over. + /// + [Tooltip("Duration to smooth desynchronizations over.")] + [Range(0.01f, 0.5f)] + [SerializeField] + private float _smoothingDuration = 0.125f; + /// + /// True to enable teleport threshhold. + /// + [Tooltip("True to enable teleport threshhold.")] + [SerializeField] + private bool _enableTeleport; + /// + /// How far the transform must travel in a single update to cause a teleport rather than smoothing. Using 0f will teleport every update. + /// + [Tooltip("How far the transform must travel in a single update to cause a teleport rather than smoothing. Using 0f will teleport every update.")] + [Range(0f, float.MaxValue)] + [SerializeField] + private float _teleportThreshold = 1f; + /// + /// Type of prediction movement which is being used. + /// + [Tooltip("Type of prediction movement which is being used.")] + [SerializeField] + private PredictionType _predictionType; + /// + /// Rigidbody to predict. + /// + [Tooltip("Rigidbody to predict.")] + [SerializeField] + private Rigidbody _rigidbody; + /// + /// Rigidbody2D to predict. + /// + [Tooltip("Rigidbody2D to predict.")] + [SerializeField] + private Rigidbody2D _rigidbody2d; + /// + /// NetworkTransform to configure. + /// + [Tooltip("NetworkTransform to configure.")] + [SerializeField] + private NetworkTransform _networkTransform; + /// + /// How much of the previous velocity to retain when predicting. Default value is 0f. Increasing this value may result in overshooting with rigidbodies that do not behave naturally, such as controllers or vehicles. + /// + [Tooltip("How much of the previous velocity to retain when predicting. Default value is 0f. Increasing this value may result in overshooting with rigidbodies that do not behave naturally, such as controllers or vehicles.")] + [Range(0f, 1f)] + [SerializeField] + private float _predictionRatio = 0f; + #endregion + + #region Private. + /// + /// True if subscribed to events. + /// + private bool _subscribed; + /// + /// Next tick to send data. + /// + private uint _nextSendTick; + /// + /// World position before transform was predicted or reset. + /// + private Vector3 _previousPosition; + /// + /// World rotation before transform was predicted or reset. + /// + private Quaternion _previousRotation; + /// + /// Local position of transform when instantiated. + /// + private Vector3 _instantiatedLocalPosition; + /// + /// How quickly to move towards TargetPosition. + /// + private float _positionMoveRate = -2; + /// + /// Local rotation of transform when instantiated. + /// + private Quaternion _instantiatedLocalRotation; + /// + /// How quickly to move towards TargetRotation. + /// + private float _rotationMoveRate = -2; + #endregion + + #region Consts. + /// + /// How often to synchronize values from server to clients when no changes have been detected. + /// + protected const float SEND_INTERVAL = 1f; + #endregion + + private void Awake() + { + if (Application.isPlaying) + { + if (!InitializeOnce()) + { + this.enabled = false; + return; + } + } + + ConfigureNetworkTransform(); + //Set in awake so they are default. + SetPreviousTransformProperties(); + } + + private void OnEnable() + { + /* Only subscribe if client. Client may not be set + * yet but that's okay because the OnStartClient + * callback will catch the subscription. This is here + * should the user disable then re-enable the object after + * it's initialized. */ + if (base.IsClient) + ChangeSubscriptions(true); + } + private void OnDisable() + { + //Only unsubscribe if client. + if (base.IsClient) + ChangeSubscriptions(false); + } + + public override void OnStartNetwork() + { + base.OnStartNetwork(); + base.TimeManager.OnPostTick += TimeManager_OnPostTick; + _instantiatedLocalPosition = _graphicalObject.localPosition; + _instantiatedLocalRotation = _graphicalObject.localRotation; + } + + public override void OnStartClient() + { + base.OnStartClient(); + ChangeSubscriptions(true); + } + + public override void OnStopClient() + { + base.OnStopClient(); + ChangeSubscriptions(false); + } + public override void OnStopNetwork() + { + base.OnStopNetwork(); + if (base.TimeManager != null) + base.TimeManager.OnPostTick -= TimeManager_OnPostTick; + } + + private void Update() + { + MoveToTarget(); + } + + private void TimeManager_OnPreTick() + { + if (CanSmooth()) + SetPreviousTransformProperties(); + } + + protected void TimeManager_OnPostTick() + { + if (CanSmooth()) + { + ResetToTransformPreviousProperties(); + SetTransformMoveRates(); + //Move 1 frame immediately since post tick occurs after update. + MoveToTarget(); + } + Rigidbodies_TimeManager_OnPostTick(); + } + + + /// + /// Called before physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + protected virtual void TimeManager_OnPostReplicateReplay(PhysicsScene ps, PhysicsScene2D ps2d) + { + Rigidbodies_TimeManager_OnPostReplicateReplay(ps, ps2d); + } + + + /// + /// Subscribes to events needed to function. + /// + /// + private void ChangeSubscriptions(bool subscribe) + { + if (base.TimeManager == null) + return; + if (subscribe == _subscribed) + return; + + if (subscribe) + { + base.TimeManager.OnPreTick += TimeManager_OnPreTick; + base.TimeManager.OnPostReplicateReplay += TimeManager_OnPostReplicateReplay; + } + else + { + base.TimeManager.OnPreTick -= TimeManager_OnPreTick; + base.TimeManager.OnPostReplicateReplay -= TimeManager_OnPostReplicateReplay; + } + + _subscribed = subscribe; + } + + + /// + /// Initializes this script for use. Returns true for success. + /// + private bool InitializeOnce() + { + //No graphical object, cannot smooth. + if (_graphicalObject == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"GraphicalObject is not set on {gameObject.name}. Initialization will fail."); + return false; + } + + return true; + } + + + /// + /// Returns if prediction can be used on this rigidbody. + /// + /// + private bool CanSmooth() + { + if (!_smoothTicks) + return false; + //Only client needs smoothing. + if (base.IsServerOnly) + return false; + + return true; + } + + /// + /// Moves transform to target values. + /// + private void MoveToTarget() + { + //Not set, meaning movement doesnt need to happen or completed. + if (_positionMoveRate == -2f && _rotationMoveRate == -2f) + return; + + /* Only try to update properties if they have a valid move rate. + * Properties may have 0f move rate if they did not change. */ + + Transform t = _graphicalObject; + float delta = Time.deltaTime; + //Position. + if (_positionMoveRate == -1f) + t.localPosition = _instantiatedLocalPosition; + else if (_positionMoveRate > 0f) + t.localPosition = Vector3.MoveTowards(t.localPosition, _instantiatedLocalPosition, _positionMoveRate * delta); + //Rotation. + if (_rotationMoveRate == -1f) + t.localRotation = _instantiatedLocalRotation; + else if (_rotationMoveRate > 0f) + t.localRotation = Quaternion.RotateTowards(t.localRotation, _instantiatedLocalRotation, _rotationMoveRate * delta); + + if (GraphicalObjectMatches(_instantiatedLocalPosition, _instantiatedLocalRotation)) + { + _positionMoveRate = -2f; + _rotationMoveRate = -2f; + } + } + + + /// + /// Sets Position and Rotation move rates to reach Target datas. + /// + /// Smooth of this duration when not set to -1f. Otherwise TimeManager.TickDelta is used. + private void SetTransformMoveRates() + { + float timeManagerDelta = (float)base.TimeManager.TickDelta; + float delta = (_durationType == SmoothingDurationType.Tick) ? timeManagerDelta : _smoothingDuration; + /* delta can never be faster than tick rate, otherwise the object will always + * get to smoothing goal before the next tick. */ + if (delta < timeManagerDelta) + delta = timeManagerDelta; + + float distance; + distance = Vector3.Distance(_instantiatedLocalPosition, _graphicalObject.localPosition); + //If qualifies for teleporting. + if (_enableTeleport && distance >= _teleportThreshold) + { + _positionMoveRate = -1f; + _rotationMoveRate = -1f; + } + //Smoothing. + else + { + _positionMoveRate = (distance / delta); + distance = Quaternion.Angle(_instantiatedLocalRotation, _graphicalObject.localRotation); + if (distance > 0f) + _rotationMoveRate = (distance / delta); + } + } + + + /// + /// Caches the transforms current position and rotation. + /// + private void SetPreviousTransformProperties() + { + _previousPosition = _graphicalObject.position; + _previousRotation = _graphicalObject.rotation; + } + + /// + /// Resets the transform to cached position and rotation of the transform. + /// + private void ResetToTransformPreviousProperties() + { + _graphicalObject.SetPositionAndRotation(_previousPosition, _previousRotation); + } + + /// + /// Returns if this transform matches arguments. + /// + /// + protected bool GraphicalObjectMatches(Vector3 position, Quaternion rotation) + { + return (_graphicalObject.localPosition == position && _graphicalObject.localRotation == rotation); + } + + /// + /// Configures NetworkTransform for prediction. + /// + private void ConfigureNetworkTransform() + { + if (_predictionType == PredictionType.Other) + _networkTransform?.ConfigureForCSP(); + } + + +#if UNITY_EDITOR + protected override void OnValidate() + { + if (_graphicalObject != null && _graphicalObject.parent == null) + { + Debug.LogError($"The graphical object may not be the root of the transform. Your graphical objects must be beneath your prediction scripts so that they may be smoothed independently during desynchronizations."); + _graphicalObject = null; + return; + } + + ConfigureNetworkTransform(); + } +#endif + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs.meta new file mode 100644 index 0000000..82837b8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 402926ef33e0a894d9fec352693988ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs new file mode 100644 index 0000000..dda7ef9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs @@ -0,0 +1,17 @@ +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Transporting; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + [AddComponentMenu("")] + [APIExclude] + [Obsolete("PredictedRigidbody is obsolete. Please remove this component and use PredictedObject on your gameObject's root.")] + //Remove on 2023/01/01 + public class PredictedRigidbody : PredictedRigidbodyBase { } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs.meta new file mode 100644 index 0000000..91a6310 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d44ddcb9778d79a43a0dc10e4e480e08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs new file mode 100644 index 0000000..b67b8bf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs @@ -0,0 +1,17 @@ +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Transporting; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + [AddComponentMenu("")] + [APIExclude] + [Obsolete("PredictedRigidbody2D is obsolete. Please remove this component and use PredictedObject on your gameObject's root.")] + //Remove on 2023/01/01 + public class PredictedRigidbody2D : PredictedRigidbodyBase { } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs.meta new file mode 100644 index 0000000..ba44522 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbody2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f013ffeb5bd7af4fb10cb778c05be01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs new file mode 100644 index 0000000..c563ad9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs @@ -0,0 +1,17 @@ +using FishNet.Documenting; +using FishNet.Managing.Timing; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + + /// + /// Base class for predicting rigidbodies for non-owners. + /// + [AddComponentMenu("")] + [APIExclude] + public abstract class PredictedRigidbodyBase : MonoBehaviour { } + //Remove on 2023/01/01 + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs.meta new file mode 100644 index 0000000..a0fac3a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedRigidbodyBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 488cbbb5dbf987046bc461419b8565f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs new file mode 100644 index 0000000..e09ea4c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs @@ -0,0 +1,90 @@ +using FishNet.Component.Prediction; +using FishNet.Serializing; +using UnityEngine; + +namespace FishNet.Component.Prediction +{ + public struct RigidbodyState + { + public Vector3 Position; + public Quaternion Rotation; + public bool IsKinematic; + public Vector3 Velocity; + public Vector3 AngularVelocity; + } + + public struct Rigidbody2DState + { + public Vector3 Position; + public Quaternion Rotation; + public bool Simulated; + public Vector3 Velocity; + public float AngularVelocity; + } +} + +public static class RigidbodyStateSerializers +{ + + public static void WriteRigidbodyState(this Writer writer, RigidbodyState value) + { + writer.WriteVector3(value.Position); + writer.WriteQuaternion(value.Rotation); + writer.WriteBoolean(value.IsKinematic); + if (!value.IsKinematic) + { + writer.WriteVector3(value.Velocity); + writer.WriteVector3(value.AngularVelocity); + } + } + + public static RigidbodyState ReadRigidbodyState(this Reader reader) + { + RigidbodyState rbs = new RigidbodyState() + { + Position = reader.ReadVector3(), + Rotation = reader.ReadQuaternion(), + IsKinematic = reader.ReadBoolean() + }; + if (!rbs.IsKinematic) + { + rbs.Velocity = reader.ReadVector3(); + rbs.AngularVelocity = reader.ReadVector3(); + } + + return rbs; + } + + + public static void WriteRigidbody2DState(this Writer writer, Rigidbody2DState value) + { + writer.WriteVector3(value.Position); + writer.WriteQuaternion(value.Rotation); + writer.WriteBoolean(value.Simulated); + if (!value.Simulated) + { + writer.WriteVector3(value.Velocity); + writer.WriteSingle(value.AngularVelocity); + } + } + + public static Rigidbody2DState ReadRigidbody2DState(this Reader reader) + { + Rigidbody2DState rbs = new Rigidbody2DState() + { + Position = reader.ReadVector3(), + Rotation = reader.ReadQuaternion(), + Simulated = reader.ReadBoolean() + }; + if (!rbs.Simulated) + { + rbs.Velocity = reader.ReadVector3(); + rbs.AngularVelocity = reader.ReadSingle(); + } + + return rbs; + } + + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs.meta new file mode 100644 index 0000000..b3f5928 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05dbb585c2bc6bf4dbbc592bea73d2fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning.meta new file mode 100644 index 0000000..1e253fc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c4ff15ab60e92f14499393c8b415ea2f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs new file mode 100644 index 0000000..c3e006d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs @@ -0,0 +1,158 @@ +using FishNet.Connection; +using FishNet.Managing; +using FishNet.Object; +using System; +using UnityEngine; +using UnityEngine.Serialization; + +namespace FishNet.Component.Spawning +{ + + /// + /// Spawns a player object for clients when they connect. + /// Must be placed on or beneath the NetworkManager object. + /// + [AddComponentMenu("FishNet/Component/PlayerSpawner")] + public class PlayerSpawner : MonoBehaviour + { + #region Public. + /// + /// Called on the server when a player is spawned. + /// + public event Action OnSpawned; + #endregion + + #region Serialized. + /// + /// Prefab to spawn for the player. + /// + [Tooltip("Prefab to spawn for the player.")] + [SerializeField] + private NetworkObject _playerPrefab; + /// + /// True to add player to the active scene when no global scenes are specified through the SceneManager. + /// + [Tooltip("True to add player to the active scene when no global scenes are specified through the SceneManager.")] + [SerializeField] + private bool _addToDefaultScene = true; + /// + /// Areas in which players may spawn. + /// + [Tooltip("Areas in which players may spawn.")] + [FormerlySerializedAs("_spawns")] + public Transform[] Spawns = new Transform[0]; + #endregion + + #region Private. + /// + /// NetworkManager on this object or within this objects parents. + /// + private NetworkManager _networkManager; + /// + /// Next spawns to use. + /// + private int _nextSpawn; + #endregion + + private void Start() + { + InitializeOnce(); + } + + private void OnDestroy() + { + if (_networkManager != null) + _networkManager.SceneManager.OnClientLoadedStartScenes -= SceneManager_OnClientLoadedStartScenes; + } + + + /// + /// Initializes this script for use. + /// + private void InitializeOnce() + { + _networkManager = InstanceFinder.NetworkManager; + if (_networkManager == null) + { + Debug.LogWarning($"PlayerSpawner on {gameObject.name} cannot work as NetworkManager wasn't found on this object or within parent objects."); + return; + } + + _networkManager.SceneManager.OnClientLoadedStartScenes += SceneManager_OnClientLoadedStartScenes; + } + + /// + /// Called when a client loads initial scenes after connecting. + /// + private void SceneManager_OnClientLoadedStartScenes(NetworkConnection conn, bool asServer) + { + if (!asServer) + return; + if (_playerPrefab == null) + { + Debug.LogWarning($"Player prefab is empty and cannot be spawned for connection {conn.ClientId}."); + return; + } + + Vector3 position; + Quaternion rotation; + SetSpawn(_playerPrefab.transform, out position, out rotation); + + NetworkObject nob = Instantiate(_playerPrefab, position, rotation); + _networkManager.ServerManager.Spawn(nob, conn); + + //If there are no global scenes + if (_addToDefaultScene) + _networkManager.SceneManager.AddOwnerToDefaultScene(nob); + + OnSpawned?.Invoke(nob); + } + + + /// + /// Sets a spawn position and rotation. + /// + /// + /// + private void SetSpawn(Transform prefab, out Vector3 pos, out Quaternion rot) + { + //No spawns specified. + if (Spawns.Length == 0) + { + SetSpawnUsingPrefab(prefab, out pos, out rot); + return; + } + + Transform result = Spawns[_nextSpawn]; + if (result == null) + { + SetSpawnUsingPrefab(prefab, out pos, out rot); + } + else + { + pos = result.position; + rot = result.rotation; + } + + //Increase next spawn and reset if needed. + _nextSpawn++; + if (_nextSpawn >= Spawns.Length) + _nextSpawn = 0; + } + + /// + /// Sets spawn using values from prefab. + /// + /// + /// + /// + private void SetSpawnUsingPrefab(Transform prefab, out Vector3 pos, out Quaternion rot) + { + pos = prefab.position; + rot = prefab.rotation; + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs.meta new file mode 100644 index 0000000..64930b9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Spawning/PlayerSpawner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 211a9f6ec51ddc14f908f5acc0cd0423 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility.meta new file mode 100644 index 0000000..3fb63eb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4fbf39de0f731b64e97742bcbfa213d3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs new file mode 100644 index 0000000..3152823 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs @@ -0,0 +1,203 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Scened; +using FishNet.Transporting; +using FishNet.Utility; +using System.IO; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnitySceneManager = UnityEngine.SceneManagement.SceneManager; + +/// +/// Add to a NetworkManager object to change between Online and Offline scene based on connection states of the server or client. +/// +[AddComponentMenu("FishNet/Component/DefaultScene")] +public class DefaultScene : MonoBehaviour +{ + + #region Serialized. + /// + /// True to replace all scenes with the offline scene immediately. + /// + [Tooltip("True to replace all scenes with the offline scene immediately.")] + [SerializeField] + private bool _startInOffline; + /// + /// Scene to load when disconnected. Server and client will load this scene. + /// + [Tooltip("Scene to load when disconnected. Server and client will load this scene.")] + [SerializeField, Scene] + private string _offlineScene; + /// + /// Sets which offline scene to use. + /// + /// Scene name to use as the offline scene. + public void SetOfflineScene(string sceneName) => _offlineScene = sceneName; + /// + /// Scene to load when connected. Server and client will load this scene. + /// + [Tooltip("Scene to load when connected. Server and client will load this scene.")] + [SerializeField, Scene] + private string _onlineScene; + /// + /// Sets which online scene to use. + /// + /// Scene name to use as the online scene. + public void SetOnlineScene(string sceneName) => _onlineScene = sceneName; + /// + /// Which scenes to replace when loading into OnlineScene. + /// + [Tooltip("Which scenes to replace when loading into OnlineScene.")] + [SerializeField] + private ReplaceOption _replaceScenes = ReplaceOption.All; + #endregion + + #region Private. + /// + /// NetworkManager for this component. + /// + private NetworkManager _networkManager; + #endregion + + private void Awake() + { + InitializeOnce(); + } + + private void OnDestroy() + { + + if (!ApplicationState.IsQuitting() && _networkManager != null && _networkManager.Initialized) + { + _networkManager.ClientManager.OnClientConnectionState -= ClientManager_OnClientConnectionState; + _networkManager.ServerManager.OnServerConnectionState -= ServerManager_OnServerConnectionState; + _networkManager.SceneManager.OnLoadEnd -= SceneManager_OnLoadEnd; + } + } + + /// + /// Initializes this script for use. + /// + private void InitializeOnce() + { + _networkManager = GetComponentInParent(); + if (_networkManager == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"NetworkManager not found on {gameObject.name} or any parent objects. DefaultScene will not work."); + return; + } + //A NetworkManager won't be initialized if it's being destroyed. + if (!_networkManager.Initialized) + return; + if (_onlineScene == string.Empty || _offlineScene == string.Empty) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning("Online or Offline scene is not specified. Default scenes will not load."); + return; + } + + _networkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; + _networkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState; + _networkManager.SceneManager.OnLoadEnd += SceneManager_OnLoadEnd; + if (_startInOffline) + LoadOfflineScene(); + } + + /// + /// Called when a scene load ends. + /// + private void SceneManager_OnLoadEnd(SceneLoadEndEventArgs obj) + { + bool onlineLoaded = false; + foreach (Scene s in obj.LoadedScenes) + { + if (s.name == GetSceneName(_onlineScene)) + { + onlineLoaded = true; + break; + } + } + + //If online scene was loaded then unload offline. + if (onlineLoaded) + UnloadOfflineScene(); + } + + /// + /// Called after the local server connection state changes. + /// + private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj) + { + /* When server starts load online scene as global. + * Since this is a global scene clients will automatically + * join it when connecting. */ + if (obj.ConnectionState == LocalConnectionState.Started) + { + /* If not exactly one server is started then + * that means either none are started, which isnt true because + * we just got a started callback, or two+ are started. + * When a server has already started there's no reason to load + * scenes again. */ + if (!_networkManager.ServerManager.OneServerStarted()) + return; + + //If here can load scene. + SceneLoadData sld = new SceneLoadData(GetSceneName(_onlineScene)); + sld.ReplaceScenes = _replaceScenes; + _networkManager.SceneManager.LoadGlobalScenes(sld); + } + //When server stops load offline scene. + else if (obj.ConnectionState == LocalConnectionState.Stopped) + { + LoadOfflineScene(); + } + } + + /// + /// Called after the local client connection state changes. + /// + private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj) + { + if (obj.ConnectionState == LocalConnectionState.Stopped) + { + //Only load offline scene if not also server. + if (!_networkManager.IsServer) + LoadOfflineScene(); + } + } + + /// + /// Loads offlineScene as single. + /// + private void LoadOfflineScene() + { + //Already in offline scene. + if (UnitySceneManager.GetActiveScene().name == GetSceneName(_offlineScene)) + return; + //Only use scene manager if networking scenes. I may add something in later to do both local and networked. + UnitySceneManager.LoadScene(_offlineScene); + } + + /// + /// Unloads the offline scene. + /// + private void UnloadOfflineScene() + { + Scene s = UnitySceneManager.GetSceneByName(GetSceneName(_offlineScene)); + if (string.IsNullOrEmpty(s.name)) + return; + + UnitySceneManager.UnloadSceneAsync(s); + } + + /// + /// Returns a scene name from fullPath. + /// + /// + /// + private string GetSceneName(string fullPath) + { + return Path.GetFileNameWithoutExtension(fullPath); + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs.meta new file mode 100644 index 0000000..317ec62 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/DefaultScene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57ce8bbb58966cb45a7140f32da5327a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs new file mode 100644 index 0000000..d4f8096 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs @@ -0,0 +1,91 @@ +using FishNet.Managing.Timing; +using UnityEngine; + +namespace FishNet.Component.Utility +{ + /// + /// Add to any object to display current ping(round trip time). + /// + [AddComponentMenu("FishNet/Component/PingDisplay")] + public class PingDisplay : MonoBehaviour + { + #region Types. + private enum Corner + { + TopLeft, + TopRight, + BottomLeft, + BottomRight + } + #endregion + + #region Serialized. + /// + /// Which corner to display ping in. + /// + [Tooltip("Which corner to display ping in.")] + [SerializeField] + private Corner _placement = Corner.TopRight; + #endregion + + #region Private. + /// + /// Next time TimeManager can be polled. Throttle this to save performance. + /// + private float _nextTimeManagerTime; + /// + /// TimeManager to get ping from. + /// + private TimeManager _timeManager; + /// + /// Style for drawn ping. + /// + private GUIStyle _style = new GUIStyle(); + #endregion + + private void OnGUI() + { + if (_timeManager == null) + { + if (Time.unscaledTime < _nextTimeManagerTime) + return; + + _nextTimeManagerTime = Time.unscaledTime + 1f; + _timeManager = InstanceFinder.TimeManager; + } + + _style.normal.textColor = Color.white; + _style.fontSize = 15; + float width = 85f; + float height = 15f; + float edge = 10f; + + float horizontal; + float vertical; + + if (_placement == Corner.TopLeft) + { + horizontal = 10f; + vertical = 10f; + } + else if (_placement == Corner.TopRight) + { + horizontal = Screen.width - width - edge; + vertical = 10f; + } + else if (_placement == Corner.BottomLeft) + { + horizontal = 10f; + vertical = Screen.height - height - edge; + } + else + { + horizontal = Screen.width - width - edge; + vertical = Screen.height - height - edge; + } + GUI.Label(new Rect(horizontal, vertical, width, height), $"Ping: {_timeManager.RoundTripTime}ms", _style); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs.meta new file mode 100644 index 0000000..b0748f0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/Component/Utility/PingDisplay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9b6b565cd9533c4ebc18003f0fc18a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef b/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef new file mode 100644 index 0000000..0d8cac3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef @@ -0,0 +1,15 @@ +{ + "name": "FishNet.Generated", + "references": [ + "GUID:7c88a4a7926ee5145ad2dfa06f454c67" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef.meta b/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef.meta new file mode 100644 index 0000000..7b4a685 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/FishNet.Generated.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e66dbdfabf9e6a14ead1b347276e9bb7 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters.meta b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters.meta new file mode 100644 index 0000000..d2f0770 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b93cb29845edf3246a9900f7f9b2109f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs new file mode 100644 index 0000000..efebd84 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs @@ -0,0 +1,53 @@ +using FishNet.Documenting; +using FishNet.Managing.Server; +using FishNet.Serializing; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace FishNet.Runtime +{ + [APIExclude] + [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)] + public static class ConnectionReadersAndWriters + { + public static void WriteClientConnectionChangeBroadcast(this Writer writer, ClientConnectionChangeBroadcast value) + { + writer.WriteBoolean(value.Connected); + writer.WriteNetworkConnectionId((short)value.Id); + } + + public static ClientConnectionChangeBroadcast ReadClientConnectionChangeBroadcast(this Reader reader) + { + return new ClientConnectionChangeBroadcast() + { + Connected = reader.ReadBoolean(), + Id = reader.ReadNetworkConnectionId() + }; + } + + public static void WriteConnectedClientsBroadcast(this Writer writer, ConnectedClientsBroadcast value) + { + ushort count = (ushort)value.ListCache.Written; + writer.WriteUInt16(count); + + List collection = value.ListCache.Collection; + for (int i = 0; i < count; i++) + writer.WriteNetworkConnectionId((short)collection[i]); + } + + public static ConnectedClientsBroadcast ReadConnectedClientsBroadcast(this Reader reader) + { + int count = reader.ReadUInt16(); + List collection = new List(count); + ConnectedClientsBroadcast result = new ConnectedClientsBroadcast() + { + Ids = collection + }; + + for (int i = 0; i < count; i++) + collection.Add(reader.ReadNetworkConnectionId()); + + return result; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs.meta new file mode 100644 index 0000000..e417d3e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ConnectionReaderWriters.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ecca19e504d97c4897e1d7288b0eabe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs new file mode 100644 index 0000000..35a0de1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs @@ -0,0 +1,425 @@ +// Decompiled with JetBrains decompiler +// Type: FishNet.Runtime.ScenedReadersAndWriters +// Assembly: FishNet.Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// MVID: 398967D9-11C0-455C-B750-DCE87EFCCBEC +// Assembly location: D:DevelopmentPersonalFishNetsFishNet - DeveloperLibraryScriptAssembliesFishNet.Runtime.dll + +using FishNet.Documenting; +using FishNet.Managing.Scened; +using FishNet.Object; +using FishNet.Serializing; +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace FishNet.Runtime +{ + [APIExclude] + [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)] + public static class ScenedReadersAndWriters + { + + + public static void Write___FishNetu002EManagingu002EScenedu002EBroadcastu002ELoadScenesBroadcast( + this Writer writer, + LoadScenesBroadcast value) + { + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData(writer, value.QueueData); + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData( + this Writer writer, + LoadQueueData value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData(writer, value.SceneLoadData); + ScenedReadersAndWriters.Write___Systemu002EStringu005Bu005D(writer, value.GlobalScenes); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData( + this Writer writer, + SceneLoadData value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(writer, value.SceneLookupDatas); + ScenedReadersAndWriters.Write___FishNetu002EObjectu002ENetworkObjectu005Bu005D(writer, value.MovedNetworkObjects); + writer.WriteByte((byte)value.ReplaceScenes); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams(writer, value.Params); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions(writer, value.Options); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D( + this Writer writer, + SceneLookupData[] value) + { + if (value == null) + { + int num = -1; + writer.WritePackedWhole((ulong)(uint)num); + } + else + { + int length = value.Length; + writer.WritePackedWhole((ulong)(uint)length); + for (int index = 0; index < length; ++index) + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData(writer, value[index]); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData( + this Writer writer, + SceneLookupData value) + { + if ((object)value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + writer.WriteInt32(value.Handle); + writer.WriteString(value.Name); + } + } + + public static void Write___FishNetu002EObjectu002ENetworkObjectu005Bu005D( + this Writer writer, + NetworkObject[] value) + { + if (value == null) + { + int num = -1; + writer.WritePackedWhole((ulong)(uint)num); + } + else + { + int length = value.Length; + writer.WritePackedWhole((ulong)(uint)length); + for (int index = 0; index < length; ++index) + writer.WriteNetworkObject(value[index]); + } + } + + public static void Write___EmptyStartScenesBroadcast(this Writer write, EmptyStartScenesBroadcast value) { } + public static EmptyStartScenesBroadcast Read___EmptyStartScenesBroadcast(this Reader reader) { return new EmptyStartScenesBroadcast(); } + + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams( + this Writer writer, + LoadParams value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + writer.WriteBytesAndSize(value.ClientParams); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions( + this Writer writer, + LoadOptions value) + { + if (value == null) + writer.WriteBoolean(true); + else + writer.WriteBoolean(false); + } + + public static void Write___Systemu002EStringu005Bu005D(this Writer writer, string[] value) + { + if (value == null) + { + int num = -1; + writer.WritePackedWhole((ulong)(uint)num); + } + else + { + int length = value.Length; + writer.WritePackedWhole((ulong)(uint)length); + for (int index = 0; index < length; ++index) + writer.WriteString(value[index]); + } + } + + public static LoadScenesBroadcast Read___FishNetu002EManagingu002EScenedu002EBroadcastu002ELoadScenesBroadcast( + this Reader reader) + { + return new LoadScenesBroadcast() + { + QueueData = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData(reader) + }; + } + + public static LoadQueueData Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData( + this Reader reader) + { + if (reader.ReadBoolean()) + return (LoadQueueData)null; + return new LoadQueueData() + { + SceneLoadData = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData(reader), + GlobalScenes = ScenedReadersAndWriters.Read___Systemu002EStringu005Bu005D(reader) + }; + } + + public static SceneLoadData Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData( + this Reader reader) + { + if (reader.ReadBoolean()) + return (SceneLoadData)null; + return new SceneLoadData() + { + SceneLookupDatas = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(reader), + MovedNetworkObjects = ScenedReadersAndWriters.Read___FishNetu002EObjectu002ENetworkObjectu005Bu005D(reader), + ReplaceScenes = (ReplaceOption)reader.ReadByte(), + Params = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams(reader), + Options = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions(reader) + }; + } + + public static SceneLookupData[] Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D( + this Reader reader) + { + int length = (int)reader.ReadPackedWhole(); + if (length == -1) + return (SceneLookupData[])null; + SceneLookupData[] sceneLookupDataArray = new SceneLookupData[length]; + for (int index = 0; index < length; ++index) + sceneLookupDataArray[index] = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData(reader); + return sceneLookupDataArray; + } + + public static SceneLookupData Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData( + this Reader reader) + { + if (reader.ReadBoolean()) + return (SceneLookupData)null; + return new SceneLookupData() + { + Handle = reader.ReadInt32(), + Name = reader.ReadString() + }; + } + + public static NetworkObject[] Read___FishNetu002EObjectu002ENetworkObjectu005Bu005D( + this Reader reader) + { + int length = (int)reader.ReadPackedWhole(); + if (length == -1) + return (NetworkObject[])null; + NetworkObject[] networkObjectArray = new NetworkObject[length]; + for (int index = 0; index < length; ++index) + networkObjectArray[index] = reader.ReadNetworkObject(); + return networkObjectArray; + } + + public static LoadParams Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams( + this Reader reader) + { + if (reader.ReadBoolean()) + return (LoadParams)null; + return new LoadParams() + { + ClientParams = reader.ReadBytesAndSizeAllocated() + }; + } + + public static LoadOptions Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions( + this Reader reader) + { + return reader.ReadBoolean() ? (LoadOptions)null : new LoadOptions(); + } + + public static string[] Read___Systemu002EStringu005Bu005D(this Reader reader) + { + int length = (int)reader.ReadPackedWhole(); + if (length == -1) + return (string[])null; + string[] strArray = new string[length]; + for (int index = 0; index < length; ++index) + strArray[index] = reader.ReadString(); + return strArray; + } + + public static void Write___FishNetu002EManagingu002EScenedu002EBroadcastu002EUnloadScenesBroadcast( + this Writer writer, + UnloadScenesBroadcast value) + { + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData(writer, value.QueueData); + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData( + this Writer writer, + UnloadQueueData value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData(writer, value.SceneUnloadData); + ScenedReadersAndWriters.Write___Systemu002EStringu005Bu005D(writer, value.GlobalScenes); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData( + this Writer writer, + SceneUnloadData value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(writer, value.SceneLookupDatas); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams(writer, value.Params); + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions(writer, value.Options); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams( + this Writer writer, + UnloadParams value) + { + if (value == null) + { + writer.WriteBoolean(true); + } + else + { + writer.WriteBoolean(false); + writer.WriteBytesAndSize(value.ClientParams); + } + } + + public static void Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions( + this Writer writer, + UnloadOptions value) + { + if (value == null) + writer.WriteBoolean(true); + else + writer.WriteBoolean(false); + } + + public static UnloadScenesBroadcast Read___FishNetu002EManagingu002EScenedu002EBroadcastu002EUnloadScenesBroadcast( + this Reader reader) + { + return new UnloadScenesBroadcast() + { + QueueData = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData(reader) + }; + } + + public static UnloadQueueData Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData( + this Reader reader) + { + if (reader.ReadBoolean()) + return (UnloadQueueData)null; + return new UnloadQueueData() + { + SceneUnloadData = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData(reader), + GlobalScenes = ScenedReadersAndWriters.Read___Systemu002EStringu005Bu005D(reader) + }; + } + + public static SceneUnloadData Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData( + this Reader reader) + { + if (reader.ReadBoolean()) + return (SceneUnloadData)null; + return new SceneUnloadData() + { + SceneLookupDatas = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(reader), + Params = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams(reader), + Options = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions(reader) + }; + } + + public static UnloadParams Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams( + this Reader reader) + { + if (reader.ReadBoolean()) + return (UnloadParams)null; + return new UnloadParams() + { + ClientParams = reader.ReadBytesAndSizeAllocated() + }; + } + + public static UnloadOptions Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions( + this Reader reader) + { + return reader.ReadBoolean() ? (UnloadOptions)null : new UnloadOptions(); + } + + public static void Write___FishNetu002EManagingu002EScenedu002EBroadcastu002EClientScenesLoadedBroadcast( + this Writer writer, + ClientScenesLoadedBroadcast value) + { + ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(writer, value.SceneLookupDatas); + } + + public static ClientScenesLoadedBroadcast Read___FishNetu002EManagingu002EScenedu002EBroadcastu002EClientScenesLoadedBroadcast( + this Reader reader) + { + return new ClientScenesLoadedBroadcast() + { + SceneLookupDatas = ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D(reader) + }; + } + + [RuntimeInitializeOnLoadMethod] + static void InitializeOnce() + { + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EBroadcastu002ELoadScenesBroadcast); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EBroadcastu002EUnloadScenesBroadcast); + GenericWriter.Write = new Action(ScenedReadersAndWriters.Write___FishNetu002EManagingu002EScenedu002EBroadcastu002EClientScenesLoadedBroadcast); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupData); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLookupDatau005Bu005D); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadParams); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadOptions); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneLoadData); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ELoadQueueData); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EBroadcastu002ELoadScenesBroadcast); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadParams); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadOptions); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002ESceneUnloadData); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EDatau002EUnloadQueueData); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EBroadcastu002EUnloadScenesBroadcast); + GenericReader.Read = new Func(ScenedReadersAndWriters.Read___FishNetu002EManagingu002EScenedu002EBroadcastu002EClientScenesLoadedBroadcast); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs.meta b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs.meta new file mode 100644 index 0000000..ef23c30 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Generated/ReaderAndWriters/ScenedReaderWriters.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53f2a8d5ae59a9241830d9c79e70f065 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs b/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs new file mode 100644 index 0000000..6ad0a0b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs @@ -0,0 +1,178 @@ +using FishNet.Component.ColliderRollback; +using FishNet.Managing; +using FishNet.Managing.Client; +using FishNet.Managing.Logging; +using FishNet.Managing.Scened; +using FishNet.Managing.Server; +using FishNet.Managing.Statistic; +using FishNet.Managing.Timing; +using FishNet.Managing.Transporting; +using FishNet.Utility; +using System.Linq; +using UnityEngine; + +namespace FishNet +{ + + /// + /// Used to globally get information from the first found instance of NetworkManager. + /// + public static class InstanceFinder + { + + #region Public. + /// + /// Returns the first found NetworkManager instance. + /// + public static NetworkManager NetworkManager + { + get + { + if (_networkManager == null) + { + int managersCount = NetworkManager.Instances.Count; + //At least one manager. + if (managersCount > 0) + { + _networkManager = NetworkManager.Instances.First(); + if (managersCount > 1) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Multiple NetworkManagers found, the first result will be returned. If you only wish to have one NetworkManager then uncheck 'Allow Multiple' within your NetworkManagers."); + } + } + //No managers. + else + { + //If application is quitting return null without logging. + if (ApplicationState.IsQuitting()) + return null; + + Debug.Log($"NetworkManager not found in any open scenes."); + } + } + + return _networkManager; + } + } + + /// + /// Returns the first instance of ServerManager. + /// + public static ServerManager ServerManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.ServerManager; + } + } + + /// + /// Returns the first instance of ClientManager. + /// + public static ClientManager ClientManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.ClientManager; + } + } + + /// + /// Returns the first instance of TransportManager. + /// + public static TransportManager TransportManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.TransportManager; + } + } + + /// + /// Returns the first instance of TimeManager. + /// + public static TimeManager TimeManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.TimeManager; + } + } + + /// + /// Returns the first instance of SceneManager. + /// + public static SceneManager SceneManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.SceneManager; + } + } + /// + /// Returns the first instance of RollbackManager. + /// + public static RollbackManager RollbackManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.RollbackManager; + } + } + /// + /// Returns the first instance of StatisticsManager. + /// + public static StatisticsManager StatisticsManager + { + get + { + NetworkManager nm = NetworkManager; + return (nm == null) ? null : nm.StatisticsManager; + } + } + + /// + /// True if the server is active. + /// + public static bool IsServer => (NetworkManager == null) ? false : NetworkManager.IsServer; + /// + /// True if only the server is active. + /// + public static bool IsServerOnly => (NetworkManager == null) ? false : NetworkManager.IsServerOnly; + /// + /// True if the client is active and authenticated. + /// + public static bool IsClient => (NetworkManager == null) ? false : NetworkManager.IsClient; + /// + /// True if only the client is active and authenticated. + /// + public static bool IsClientOnly => (NetworkManager == null) ? false : NetworkManager.IsClientOnly; + /// + /// True if client and server are active. + /// + public static bool IsHost => (NetworkManager == null) ? false : NetworkManager.IsHost; + /// + /// True if client nor server are active. + /// + public static bool IsOffline => (NetworkManager == null) ? true : (!NetworkManager.IsServer && !NetworkManager.IsClient); + #endregion + + #region Private. + /// + /// NetworkManager instance. + /// + private static NetworkManager _networkManager; + #endregion + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs.meta b/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs.meta new file mode 100644 index 0000000..97dc53c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/InstanceFinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 528668525d755164d989cddc73e3eee5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing.meta b/UnityProject/Assets/FishNet/Runtime/Managing.meta new file mode 100644 index 0000000..f77c46d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2881da549094ec241b3a289e6151869e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client.meta new file mode 100644 index 0000000..1d0fe06 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96f81f64930875143840663a13e78564 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs new file mode 100644 index 0000000..665d46b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs @@ -0,0 +1,180 @@ +using FishNet.Broadcast; +using FishNet.Broadcast.Helping; +using FishNet.Managing.Logging; +using FishNet.Managing.Utility; +using FishNet.Object.Helping; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Client +{ + public sealed partial class ClientManager : MonoBehaviour + { + #region Private. + /// + /// Delegate to read received broadcasts. + /// + /// + private delegate void ServerBroadcastDelegate(PooledReader reader); + /// + /// Delegates for each key. + /// + private readonly Dictionary> _broadcastHandlers = new Dictionary>(); + /// + /// Delegate targets for each key. + /// + private Dictionary> _handlerTargets = new Dictionary>(); + #endregion + + /// + /// Registers a method to call when a Broadcast arrives. + /// + /// Type of broadcast being registered. + /// Method to call. + public void RegisterBroadcast(Action handler) where T : struct, IBroadcast + { + ushort key = typeof(T).FullName.GetStableHash16(); + /* Create delegate and add for + * handler method. */ + HashSet handlers; + if (!_broadcastHandlers.TryGetValueIL2CPP(key, out handlers)) + { + handlers = new HashSet(); + _broadcastHandlers.Add(key, handlers); + } + ServerBroadcastDelegate del = CreateBroadcastDelegate(handler); + handlers.Add(del); + + /* Add hashcode of target for handler. + * This is so we can unregister the target later. */ + int handlerHashCode = handler.GetHashCode(); + HashSet<(int, ServerBroadcastDelegate)> targetHashCodes; + if (!_handlerTargets.TryGetValueIL2CPP(key, out targetHashCodes)) + { + targetHashCodes = new HashSet<(int, ServerBroadcastDelegate)>(); + _handlerTargets.Add(key, targetHashCodes); + } + + targetHashCodes.Add((handlerHashCode, del)); + } + + /// + /// Unregisters a method call from a Broadcast type. + /// + /// Type of broadcast being unregistered. + /// Method to unregister. + public void UnregisterBroadcast(Action handler) where T : struct, IBroadcast + { + ushort key = BroadcastHelper.GetKey(); + + /* If key is found for T then look for + * the appropriate handler to remove. */ + if (_broadcastHandlers.TryGetValueIL2CPP(key, out HashSet handlers)) + { + HashSet<(int, ServerBroadcastDelegate)> targetHashCodes; + if (_handlerTargets.TryGetValueIL2CPP(key, out targetHashCodes)) + { + int handlerHashCode = handler.GetHashCode(); + ServerBroadcastDelegate result = null; + foreach ((int targetHashCode, ServerBroadcastDelegate del) in targetHashCodes) + { + if (targetHashCode == handlerHashCode) + { + result = del; + targetHashCodes.Remove((targetHashCode, del)); + break; + } + } + //If no more in targetHashCodes then remove from handlerTarget. + if (targetHashCodes.Count == 0) + _handlerTargets.Remove(key); + + if (result != null) + handlers.Remove(result); + } + + //If no more in handlers then remove broadcastHandlers. + if (handlers.Count == 0) + _broadcastHandlers.Remove(key); + } + } + + /// + /// Creates a ServerBroadcastDelegate. + /// + /// + /// + /// + /// + private ServerBroadcastDelegate CreateBroadcastDelegate(Action handler) + { + void LogicContainer(PooledReader reader) + { + T broadcast = reader.Read(); + handler?.Invoke(broadcast); + } + return LogicContainer; + } + + /// + /// Parses a received broadcast. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ParseBroadcast(PooledReader reader, Channel channel) + { + ushort key = reader.ReadUInt16(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.Broadcast, reader, channel); + // try to invoke the handler for that message + if (_broadcastHandlers.TryGetValueIL2CPP(key, out HashSet handlers)) + { + int readerStartPosition = reader.Position; + /* //muchlater resetting the position could be better by instead reading once and passing in + * the object to invoke with. */ + foreach (ServerBroadcastDelegate handler in handlers) + { + reader.Position = readerStartPosition; + handler.Invoke(reader); + } + } + else + { + reader.Skip(dataLength); + } + } + + + /// + /// Sends a Broadcast to the server. + /// + /// Type of broadcast to send. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// Channel to send on. + public void Broadcast(T message, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + //Check local connection state. + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to server because client is not active."); + return; + } + + using (PooledWriter writer = WriterPool.GetWriter()) + { + Broadcasts.WriteBroadcast(writer, message, channel); + ArraySegment segment = writer.GetArraySegment(); + + NetworkManager.TransportManager.SendToServer((byte)channel, segment); + } + } + + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs.meta new file mode 100644 index 0000000..6b82d50 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97ef4be4cfcc6a54d80a65a5c8d325d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs new file mode 100644 index 0000000..176d5f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs @@ -0,0 +1,472 @@ +using FishNet.Connection; +using FishNet.Managing.Debugging; +using FishNet.Managing.Logging; +using FishNet.Managing.Server; +using FishNet.Managing.Transporting; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Managing.Client +{ + /// + /// A container for local client data and actions. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/ClientManager")] + public sealed partial class ClientManager : MonoBehaviour + { + #region Public. + /// + /// Called after local client has authenticated. + /// + public event Action OnAuthenticated; + /// + /// Called after the local client connection state changes. + /// + public event Action OnClientConnectionState; + /// + /// True if the client connection is connected to the server. + /// + public bool Started { get; private set; } + /// + /// NetworkConnection the local client is using to send data to the server. + /// + public NetworkConnection Connection = NetworkManager.EmptyConnection; + /// + /// Handling and information for objects known to the local client. + /// + public ClientObjects Objects { get; private set; } + /// + /// All currently connected clients. This field only contains data while ServerManager.ShareIds is enabled. + /// + public Dictionary Clients = new Dictionary(); + /// + /// NetworkManager for client. + /// + [HideInInspector] + public NetworkManager NetworkManager { get; private set; } + #endregion + + #region Serialized. + /// + /// True to automatically set the frame rate when the client connects. + /// + [Tooltip("True to automatically set the frame rate when the client connects.")] + [SerializeField] + private bool _changeFrameRate = true; + /// + /// + /// + [Tooltip("Maximum frame rate the client may run at. When as host this value runs at whichever is higher between client and server.")] + [Range(1, NetworkManager.MAXIMUM_FRAMERATE)] + [SerializeField] + private ushort _frameRate = NetworkManager.MAXIMUM_FRAMERATE; + /// + /// Maximum frame rate the client may run at. When as host this value runs at whichever is higher between client and server. + /// + internal ushort FrameRate => (_changeFrameRate) ? _frameRate : (ushort)0; + #endregion + + #region Private. + /// + /// Used to read splits. + /// + private SplitReader _splitReader = new SplitReader(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + /// + /// Logs data about parser to help debug. + /// + private ParseLogger _parseLogger = new ParseLogger(); +#endif + #endregion + + private void OnDestroy() + { + Objects?.SubscribeToSceneLoaded(false); + } + + + /// + /// Initializes this script for use. + /// + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + NetworkManager = manager; + Objects = new ClientObjects(manager); + Objects.SubscribeToSceneLoaded(true); + /* Unsubscribe before subscribing. + * Shouldn't be an issue but better safe than sorry. */ + SubscribeToEvents(false); + SubscribeToEvents(true); + //Listen for client connections from server. + RegisterBroadcast(OnClientConnectionBroadcast); + RegisterBroadcast(OnConnectedClientsBroadcast); + } + + + /// + /// Called when the server sends a connection state change for any client. + /// + /// + private void OnClientConnectionBroadcast(ClientConnectionChangeBroadcast args) + { + if (args.Connected) + Clients[args.Id] = new NetworkConnection(NetworkManager, args.Id); + else + Clients.Remove(args.Id); + } + + /// + /// Called when the server sends all currently connected clients. + /// + /// + private void OnConnectedClientsBroadcast(ConnectedClientsBroadcast args) + { + Clients.Clear(); + + List collection = args.Ids; + int count = collection.Count; + for (int i = 0; i < count; i++) + { + int id = collection[i]; + Clients[id] = new NetworkConnection(NetworkManager, id); + } + } + + + /// + /// Changes subscription status to transport. + /// + /// + private void SubscribeToEvents(bool subscribe) + { + if (NetworkManager == null || NetworkManager.TransportManager == null || NetworkManager.TransportManager.Transport == null) + return; + + if (!subscribe) + { + NetworkManager.TransportManager.OnIterateIncomingEnd -= TransportManager_OnIterateIncomingEnd; + NetworkManager.TransportManager.Transport.OnClientReceivedData -= Transport_OnClientReceivedData; + NetworkManager.TransportManager.Transport.OnClientConnectionState -= Transport_OnClientConnectionState; + } + else + { + NetworkManager.TransportManager.OnIterateIncomingEnd += TransportManager_OnIterateIncomingEnd; + NetworkManager.TransportManager.Transport.OnClientReceivedData += Transport_OnClientReceivedData; + NetworkManager.TransportManager.Transport.OnClientConnectionState += Transport_OnClientConnectionState; + } + } + + /// + /// Stops the local client connection. + /// + public void StopConnection() + { + NetworkManager.TransportManager.Transport.StopConnection(false); + } + + /// + /// Starts the local client connection. + /// + public void StartConnection() + { + NetworkManager.TransportManager.Transport.StartConnection(false); + } + + /// + /// Sets the transport address and starts the local client connection. + /// + public void StartConnection(string address) + { + StartConnection(address, NetworkManager.TransportManager.Transport.GetPort()); + } + /// + /// Sets the transport address and port, and starts the local client connection. + /// + public void StartConnection(string address, ushort port) + { + NetworkManager.TransportManager.Transport.SetClientAddress(address); + NetworkManager.TransportManager.Transport.SetPort(port); + StartConnection(); + } + + /// + /// Called when a connection state changes for the local client. + /// + /// + private void Transport_OnClientConnectionState(ClientConnectionStateArgs args) + { + LocalConnectionState state = args.ConnectionState; + Started = (state == LocalConnectionState.Started); + Objects.OnClientConnectionState(args); + + //Clear connection after so objects can update using current Connection value. + if (!Started) + { + Connection = NetworkManager.EmptyConnection; + Clients.Clear(); + } + + if (NetworkManager.CanLog(LoggingType.Common)) + { + Transport t = NetworkManager.TransportManager.GetTransport(args.TransportIndex); + string tName = (t == null) ? "Unknown" : t.GetType().Name; + Debug.Log($"Local client is {state.ToString().ToLower()} for {tName}."); + } + + NetworkManager.UpdateFramerate(); + OnClientConnectionState?.Invoke(args); + } + + /// + /// Called when a socket receives data. + /// + private void Transport_OnClientReceivedData(ClientReceivedDataArgs args) + { + ParseReceived(args); + } + + /// + /// Called after IterateIncoming has completed. + /// + private void TransportManager_OnIterateIncomingEnd(bool server) + { + /* Should the last packet received be a spawn or despawn + * then the cache won't yet be iterated because it only + * iterates when a packet is anything but those two. Because + * of such if any object caches did come in they must be iterated + * at the end of the incoming cycle. This isn't as clean as I'd + * like but it does ensure there will be no missing network object + * references on spawned objects. */ + if (Started && !server) + Objects.IterateObjectCache(); + } + + /// + /// Parses received data. + /// + private void ParseReceived(ClientReceivedDataArgs args) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _parseLogger.Reset(); +#endif + + ArraySegment segment = args.Data; + NetworkManager.StatisticsManager.NetworkTraffic.LocalClientReceivedData((ulong)segment.Count); + if (segment.Count <= TransportManager.TICK_BYTES) + return; + + PacketId packetId = PacketId.Unset; +#if !UNITY_EDITOR && !DEVELOPMENT_BUILD + try + { +#endif + using (PooledReader reader = ReaderPool.GetReader(segment, NetworkManager)) + { + NetworkManager.TimeManager.LastPacketTick = reader.ReadUInt32(AutoPackType.Unpacked); + /* This is a special condition where a message may arrive split. + * When this occurs buffer each packet until all packets are + * received. */ + if (reader.PeekPacketId() == PacketId.Split) + { + //Skip packetId. + reader.ReadPacketId(); + int expectedMessages; + _splitReader.GetHeader(reader, out expectedMessages); + _splitReader.Write(NetworkManager.TimeManager.LastPacketTick, reader, expectedMessages); + /* If fullMessage returns 0 count then the split + * has not written fully yet. Otherwise, if there is + * data within then reinitialize reader with the + * full message. */ + ArraySegment fullMessage = _splitReader.GetFullMessage(); + if (fullMessage.Count == 0) + return; + + //Initialize reader with full message. + reader.Initialize(fullMessage, NetworkManager); + } + + while (reader.Remaining > 0) + { + packetId = reader.ReadPacketId(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _parseLogger.AddPacket(packetId); +#endif + bool spawnOrDespawn = (packetId == PacketId.ObjectSpawn || packetId == PacketId.ObjectDespawn); + /* Length of data. Only available if using unreliable. Unreliable packets + * can arrive out of order which means object orientated messages such as RPCs may + * arrive after the object for which they target has already been destroyed. When this happens + * on lesser solutions they just dump the entire packet. However, since FishNet batches data. + * it's very likely a packet will contain more than one packetId. With this mind, length is + * sent as well so if any reason the data does have to be dumped it will only be dumped for + * that single packetId but not the rest. Broadcasts don't need length either even if unreliable + * because they are not object bound. */ + + //Is spawn or despawn; cache packet. + if (spawnOrDespawn) + { + if (packetId == PacketId.ObjectSpawn) + Objects.CacheSpawn(reader); + else if (packetId == PacketId.ObjectDespawn) + Objects.CacheDespawn(reader); + } + //Not spawn or despawn. + else + { + /* Iterate object cache should any of the + * incoming packets rely on it. Objects + * in cache will always be received before any messages + * that use them. */ + Objects.IterateObjectCache(); + //Then process packet normally. + if ((ushort)packetId >= NetworkManager.StartingRpcLinkIndex) + { + Objects.ParseRpcLink(reader, (ushort)packetId, args.Channel); + } + else if (packetId == PacketId.Reconcile) + { + Objects.ParseReconcileRpc(reader, args.Channel); + } + else if (packetId == PacketId.ObserversRpc) + { + Objects.ParseObserversRpc(reader, args.Channel); + } + else if (packetId == PacketId.TargetRpc) + { + Objects.ParseTargetRpc(reader, args.Channel); + } + else if (packetId == PacketId.Broadcast) + { + ParseBroadcast(reader, args.Channel); + } + else if (packetId == PacketId.PingPong) + { + ParsePingPong(reader); + } + else if (packetId == PacketId.SyncVar) + { + Objects.ParseSyncType(reader, false, args.Channel); + } + else if (packetId == PacketId.SyncObject) + { + Objects.ParseSyncType(reader, true, args.Channel); + } + else if (packetId == PacketId.TimingUpdate) + { + NetworkManager.TimeManager.ParseTimingUpdate(); + } + else if (packetId == PacketId.OwnershipChange) + { + Objects.ParseOwnershipChange(reader); + } + else if (packetId == PacketId.Authenticated) + { + ParseAuthenticated(reader); + } + else if (packetId == PacketId.Disconnect) + { + reader.Skip(reader.Remaining); + StopConnection(); + } + else + { + if (NetworkManager.CanLog(LoggingType.Error)) + { + Debug.LogError($"Client received an unhandled PacketId of {(ushort)packetId}. Remaining data has been purged."); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _parseLogger.Print(NetworkManager); +#endif + } + return; + } + } + } + + /* Iterate cache when reader is emptied. + * This is incase the last packet received + * was a spawned, which wouldn't trigger + * the above iteration. There's no harm + * in doing this check multiple times as there's + * an exit early check. */ + Objects.IterateObjectCache(); + } +#if !UNITY_EDITOR && !DEVELOPMENT_BUILD + } + catch (Exception e) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Client encountered an error while parsing data for packetId {packetId}. Message: {e.Message}."); + } +#endif + } + + /// + /// Parses a PingPong packet. + /// + /// + private void ParsePingPong(PooledReader reader) + { + uint clientTick = reader.ReadUInt32(AutoPackType.Unpacked); + NetworkManager.TimeManager.ModifyPing(clientTick); + } + + /// + /// Parses a received connectionId. This is received before client receives connection state change. + /// + /// + private void ParseAuthenticated(PooledReader reader) + { + NetworkManager networkManager = NetworkManager; + int connectionId = reader.ReadNetworkConnectionId(); + //If only a client then make a new connection. + if (!networkManager.IsServer) + { + Clients.TryGetValueIL2CPP(connectionId, out Connection); + } + /* If also the server then use the servers connection + * for the connectionId. This is to resolve host problems + * where LocalConnection for client differs from the server Connection + * reference, which results in different field values. */ + else + { + if (networkManager.ServerManager.Clients.TryGetValueIL2CPP(connectionId, out NetworkConnection conn)) + { + Connection = conn; + } + else + { + if (networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Unable to lookup LocalConnection for {connectionId} as host."); + + Connection = new NetworkConnection(networkManager, connectionId); + } + } + + /* Set the TimeManager tick to lastReceivedTick. + * This still doesn't account for latency but + * it's the best we can do until the client gets + * a ping response. */ + networkManager.TimeManager.Tick = networkManager.TimeManager.LastPacketTick; + + //Mark as authenticated. + Connection.ConnectionAuthenticated(); + OnAuthenticated?.Invoke(); + /* Register scene objects for all scenes + * after being authenticated. This is done after + * authentication rather than when the connection + * is started because if also as server an online + * scene may already be loaded on server, but not + * for client. This means the sceneLoaded unity event + * won't fire, and since client isn't authenticated + * at the connection start phase objects won't be added. */ + Objects.RegisterAndDespawnSceneObjects(); + } + + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs.meta new file mode 100644 index 0000000..3185de7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aca43cf6f20e77c4f8fcc078fd85081f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor.meta new file mode 100644 index 0000000..bf04e9c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 934151ddc3910094daef3552e81ecf24 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs new file mode 100644 index 0000000..4208062 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs @@ -0,0 +1,46 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Managing.Client.Editing +{ + + + [CustomEditor(typeof(ClientManager), true)] + [CanEditMultipleObjects] + public class ClientManagerEditor : Editor + { + private SerializedProperty _changeFrameRate; + private SerializedProperty _frameRate; + + protected virtual void OnEnable() + { + _changeFrameRate = serializedObject.FindProperty("_changeFrameRate"); + _frameRate = serializedObject.FindProperty("_frameRate"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((ClientManager)target), typeof(ClientManager), false); + GUI.enabled = true; + + + EditorGUILayout.PropertyField(_changeFrameRate); + if (_changeFrameRate.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_frameRate); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs.meta new file mode 100644 index 0000000..404a1fd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a652d51a1efa8a442966e885e2736599 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object.meta new file mode 100644 index 0000000..0717957 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd638699438c5194ca93b15a5121d0a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs new file mode 100644 index 0000000..46a65d8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs @@ -0,0 +1,87 @@ +using FishNet.Managing.Logging; +using FishNet.Managing.Object; +using FishNet.Managing.Utility; +using FishNet.Object; +using FishNet.Object.Helping; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Client +{ + /// + /// Handles objects and information about objects for the local client. See ManagedObjects for inherited options. + /// + public partial class ClientObjects : ManagedObjects + { + + #region Private. + /// + /// RPCLinks of currently spawned objects. + /// + private Dictionary _rpcLinks = new Dictionary(); + #endregion + + /// + /// Parses a received RPCLink. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseRpcLink(PooledReader reader, ushort index, Channel channel) + { + int dataLength = Packets.GetPacketLength(ushort.MaxValue, reader, channel); + + //Link index isn't stored. + if (!_rpcLinks.TryGetValueIL2CPP(index, out RpcLink link)) + { + SkipDataLength(index, reader, dataLength); + return; + } + else + //Found NetworkObject for link. + if (Spawned.TryGetValueIL2CPP(link.ObjectId, out NetworkObject nob)) + { + NetworkBehaviour nb = nob.NetworkBehaviours[link.ComponentIndex]; + if (link.RpcType == RpcType.Target) + nb.OnTargetRpc(link.RpcHash, reader, channel); + else if (link.RpcType == RpcType.Observers) + nb.OnObserversRpc(link.RpcHash, reader, channel); + else if (link.RpcType == RpcType.Reconcile) + nb.OnReconcileRpc(link.RpcHash, reader, channel); + } + //Could not find NetworkObject. + else + { + SkipDataLength(index, reader, dataLength, link.ObjectId); + } + } + + /// + /// Sets link to rpcLinks key linkIndex. + /// + /// + /// + internal void SetRpcLink(ushort linkIndex, RpcLink link) + { + _rpcLinks[linkIndex] = link; + } + + /// + /// Removes link index keys from rpcLinks. + /// + internal void RemoveLinkIndexes(List values) + { + if (values == null) + return; + + for (int i = 0; i < values.Count; i++) + _rpcLinks.Remove(values[i]); + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs.meta new file mode 100644 index 0000000..f129249 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a20cc3f399aa614c931c9b45205937b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs new file mode 100644 index 0000000..c103cd6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs @@ -0,0 +1,746 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Managing.Object; +using FishNet.Managing.Utility; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Client +{ + /// + /// Handles objects and information about objects for the local client. See ManagedObjects for inherited options. + /// + public partial class ClientObjects : ManagedObjects + { + #region Private. + /// + /// NetworkObjects which are cached to be spawned or despawned. + /// + private ClientObjectCache _objectCache; + #endregion + + internal ClientObjects(NetworkManager networkManager) + { + base.NetworkManager = networkManager; + _objectCache = new ClientObjectCache(this, networkManager); + } + + /// + /// Called when a connection state changes for the local server. + /// + internal void OnServerConnectionState(ServerConnectionStateArgs args) + { + //Nothing needs to be done if started. + if (args.ConnectionState == LocalConnectionState.Started) + return; + + /* If not started and client is active then deinitialize + * client objects first. This will let the deinit calls + * perform before the server destroys them. Ideally this + * would be done when the user shows intent to shutdown + * the server, but realistically planning for server socket + * drops is a much more universal solution. + * + * Calling StopConnection on the client will set it's local state + * to Stopping which will result in a deinit. */ + if (NetworkManager.IsClient) + base.NetworkManager.ClientManager.StopConnection(); + } + + /// + /// Called when the connection state changes for the local client. + /// + /// + internal void OnClientConnectionState(ClientConnectionStateArgs args) + { + /* If new state is not started then reset + * environment. */ + if (args.ConnectionState != LocalConnectionState.Started) + { + _objectCache.Reset(); + base.DespawnSpawnedWithoutSynchronization(false); + /* Clear spawned and scene objects as they will be rebuilt. + * Spawned would have already be cleared if DespawnSpawned + * was called but it won't hurt anything clearing an empty collection. */ + base.Spawned.Clear(); + base.SceneObjects.Clear(); + } + } + + + /// + /// Called when a scene is loaded. + /// + /// + /// + [APIExclude] + protected internal override void SceneManager_sceneLoaded(Scene s, LoadSceneMode arg1) + { + base.SceneManager_sceneLoaded(s, arg1); + + if (!base.NetworkManager.IsClient) + return; + /* When a scene first loads for a client it should disable + * all network objects in that scene. The server will send + * spawn messages once it's aware client has loaded the scene. */ + RegisterAndDespawnSceneObjects(s); + } + + /// + /// Registers NetworkObjects in all scenes and despawns them. + /// + internal void RegisterAndDespawnSceneObjects() + { + for (int i = 0; i < SceneManager.sceneCount; i++) + RegisterAndDespawnSceneObjects(SceneManager.GetSceneAt(i)); + } + + /// + /// Adds NetworkObjects within s to SceneObjects, and despawns them. + /// + /// + private void RegisterAndDespawnSceneObjects(Scene s) + { + ListCache nobs; + SceneFN.GetSceneNetworkObjects(s, false, out nobs); + + for (int i = 0; i < nobs.Written; i++) + { + NetworkObject nob = nobs.Collection[i]; + base.UpdateNetworkBehaviours(nob, false); + if (nob.IsNetworked && nob.IsSceneObject && nob.IsNetworked) + { + base.AddToSceneObjects(nob); + //Only run if not also server, as this already ran on server. + if (!base.NetworkManager.IsServer) + nob.gameObject.SetActive(false); + } + } + + ListCaches.StoreCache(nobs); + } + + /// + /// Called when a NetworkObject runs Deactivate. + /// + /// + internal override void NetworkObjectUnexpectedlyDestroyed(NetworkObject nob) + { + nob.RemoveClientRpcLinkIndexes(); + base.NetworkObjectUnexpectedlyDestroyed(nob); + } + + /// + /// Parses an OwnershipChange packet. + /// + /// + internal void ParseOwnershipChange(PooledReader reader) + { + NetworkObject nob = reader.ReadNetworkObject(); + NetworkConnection newOwner = reader.ReadNetworkConnection(); + if (nob != null) + { + nob.GiveOwnership(newOwner, false); + } + else + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkBehaviour could not be found when trying to parse OwnershipChange packet."); + } + } + + /// + /// Parses a received syncVar. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseSyncType(PooledReader reader, bool isSyncObject, Channel channel) + { + //cleanup this is unique to synctypes where length comes first. + //this will change once I tidy up synctypes. + ushort packetId = (isSyncObject) ? (ushort)PacketId.SyncObject : (ushort)PacketId.SyncVar; + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength(packetId, reader, channel); + + if (nb != null) + { + /* Length of data to be read for syncvars. + * This is important because syncvars are never + * a set length and data must be read through completion. + * The only way to know where completion of syncvar is, versus + * when another packet starts is by including the length. */ + if (dataLength > 0) + nb.OnSyncType(reader, dataLength, isSyncObject); + } + else + { + SkipDataLength(packetId, reader, dataLength); + } + } + + /// + /// Parses a ReconcileRpc. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseReconcileRpc(PooledReader reader, Channel channel) + { + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.Reconcile, reader, channel); + + if (nb != null) + nb.OnReconcileRpc(null, reader, channel); + else + SkipDataLength((ushort)PacketId.ObserversRpc, reader, dataLength); + } + + /// + /// Parses an ObserversRpc. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseObserversRpc(PooledReader reader, Channel channel) + { + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.ObserversRpc, reader, channel); + + if (nb != null) + nb.OnObserversRpc(null, reader, channel); + else + SkipDataLength((ushort)PacketId.ObserversRpc, reader, dataLength); + } + /// + /// Parses a TargetRpc. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseTargetRpc(PooledReader reader, Channel channel) + { + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.TargetRpc, reader, channel); + + if (nb != null) + nb.OnTargetRpc(null, reader, channel); + else + SkipDataLength((ushort)PacketId.TargetRpc, reader, dataLength); + } + + /// + /// Caches a received spawn to be processed after all spawns and despawns are received for the tick. + /// + /// + internal void CacheSpawn(PooledReader reader) + { + int objectId = reader.ReadNetworkObjectId(); + int ownerId = reader.ReadNetworkConnectionId(); + ObjectSpawnType ost = (ObjectSpawnType)reader.ReadByte(); + byte componentIndex = reader.ReadByte(); + bool nested = (componentIndex > 0); + bool sceneObject = (ost == ObjectSpawnType.Scene); + int rootObjectId = (nested) ? reader.ReadNetworkObjectId() : -1; + + int? parentObjectId = null; + byte? parentComponentIndex = null; + short? prefabId = null; + + Vector3? localPosition; + Quaternion? localRotation; + Vector3? localScale; + ulong sceneId = 0; + + if (nested) + ReadNestedObject(reader, out localPosition, out localRotation, out localScale); + else if (sceneObject) + ReadSceneObject(reader, out sceneId, out localPosition, out localRotation, out localScale); + else + ReadSpawnedObject(reader, out parentObjectId, out parentComponentIndex, out prefabId, out localPosition, out localRotation, out localScale); + + ArraySegment rpcLinks = reader.ReadArraySegmentAndSize(); + ArraySegment syncValues = reader.ReadArraySegmentAndSize(); + + _objectCache.AddSpawn(base.NetworkManager, objectId, ownerId, ost, componentIndex, rootObjectId, parentObjectId, parentComponentIndex, prefabId, localPosition, localRotation, localScale, sceneId, rpcLinks, syncValues); + } + + + ///// + ///// Caches a received spawn to be processed after all spawns and despawns are received for the tick. + ///// + ///// + //internal void CacheSpawn(PooledReader reader) + //{ + // int objectId = reader.ReadNetworkObjectId(); + // int ownerId = reader.ReadNetworkConnectionId(); + // ObjectSpawnType ost = (ObjectSpawnType)reader.ReadByte(); + // byte componentIndex = reader.ReadByte(); + // bool nested = (componentIndex > 0); + // bool sceneObject = (ost == ObjectSpawnType.Scene); + // int parentObjectId = (nested) ? reader.ReadNetworkObjectId() : -1; + // NetworkObject nob; + + // if (nested) + // nob = ReadNestedObject(reader, parentObjectId, componentIndex); + // else if (sceneObject) + // nob = ReadSceneObject(reader, componentIndex); + // else + // nob = ReadSpawnedObject(reader, objectId, ost); + + // ArraySegment rpcLinks = reader.ReadArraySegmentAndSize(); + // ArraySegment syncValues = reader.ReadArraySegmentAndSize(); + + // /* If nob is null and is host see if it's in pending destroy. + // * This can occur when the networkobject is spawned and despawned on + // * the server before it's sent to the client. This happens because the + // * server spawns the object, queues spawn package, despawns, queues despawn packet, + // * then removes it from Spawned. By the time the packet sends the object cannot be found + // * except in pending. */ + // if (nob == null && NetworkManager.IsHost) + // nob = NetworkManager.ServerManager.Objects.GetFromPending(objectId); + // /*If nob is null then exit method. Since ClientObjects gets nob from + // * server objects as host this can occur sometimes + // * when the object is destroyed on server before client gets + // * spawn packet. */ + // if (nob == null) + // { + // //Only error if client only. + // if (!NetworkManager.IsHost) + // { + // if (NetworkManager.CanLog(LoggingType.Error)) + // Debug.LogError($"Spawn object could not be found or created for Id {objectId}; scene object: {sceneObject}."); + // } + // return; + // } + // else + // { + // nob.SetIsNetworked(true); + // } + // /* If not host then pre-initialize. Pre-initializing applies + // * values needed to run such as owner, network manager, and completes + // * other reference creating functions. */ + // if (!base.NetworkManager.IsHost) + // { + // //If local client is owner then use localconnection reference. + // NetworkConnection localConnection = base.NetworkManager.ClientManager.Connection; + // NetworkConnection owner; + // //If owner is self. + // if (ownerId == localConnection.ClientId) + // { + // owner = localConnection; + // } + // else + // { + // /* If owner cannot be found then share owners + // * is disabled */ + // if (!base.NetworkManager.ClientManager.Clients.TryGetValueIL2CPP(ownerId, out owner)) + // owner = NetworkManager.EmptyConnection; + // } + // nob.PreinitializeInternal(NetworkManager, objectId, owner, false); + // } + + // _objectCache.AddSpawn(nob, rpcLinks, syncValues, NetworkManager); + //} + + /// + /// Caches a received despawn to be processed after all spawns and despawns are received for the tick. + /// + /// + internal void CacheDespawn(PooledReader reader) + { + int objectId = reader.ReadNetworkObjectId(); + bool disableOnDespawn = reader.ReadBoolean(); + //Try checking already spawned objects first. + if (base.Spawned.TryGetValueIL2CPP(objectId, out NetworkObject nob)) + { + _objectCache.AddDespawn(nob, disableOnDespawn); + } + /* If not found in already spawned objects see if + * the networkObject is in the objectCache. It's possible the despawn + * came immediately or shortly after the spawn message, before + * the object has been initialized. */ + else + { + NetworkObject nob2 = _objectCache.GetInCached(objectId, ClientObjectCache.CacheSearchType.Any); + /* Nob may be null if it's a child object being despawned, and the + * parent despawn already occurred. */ + if (nob2 != null) + _objectCache.AddDespawn(nob2, disableOnDespawn); + } + } + + + /// + /// Iterates object cache which contains spawn and despawn messages. + /// Parses the packets within the cache and ensures objects are spawned and despawned before their sync values are applied. + /// This ensures there is no chance a sync value is referencing a spawned object which does not exist yet due to it normally being spawned later in the cache. + /// + internal void IterateObjectCache() + { + _objectCache.Iterate(); + } + + + ///// + ///// Finishes reading a nested object. Nested objects should always already exist beneath the parent. + ///// + //private NetworkObject ReadNestedObject(PooledReader reader, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) + //{ + // ReadTransformProperties(reader,out localPosition, out localRotation, out localScale); + // Dictionary spawned = (base.NetworkManager.IsHost) ? + // NetworkManager.ServerManager.Objects.Spawned + // : NetworkManager.ClientManager.Objects.Spawned; + + // NetworkObject parentNob; + // /* Spawns are processed after all spawns come in, + // * this ensures no reference race conditions. Turns out because of this + // * the parentNob may be in cache and not actually spawned, if it was spawned the same packet + // * as this one. So when not found in the spawned collection try to + // * find it in Spawning before throwing. */ + // if (!spawned.TryGetValueIL2CPP(parentObjectId, out parentNob)) + // _objectCache.SpawningObjects.TryGetValue(parentObjectId, out parentNob); + // //If still null, that's not good. + // if (parentNob == null) + // { + // /* Purge reader of expected values. + // * Use networkmanager transform, it doesn't really matter + // * since values are discarded anyway. */ + // ReadTransformProperties(reader, base.NetworkManager.transform, out _, out _, out _); + // if (NetworkManager.CanLog(LoggingType.Error)) + // Debug.LogError($"Nested spawned object with componentIndex of {componentIndex} and a parentId of {parentObjectId} could not be spawned because parent was not found."); + // return null; + // } + + // NetworkObject nob = null; + // List childNobs = parentNob.ChildNetworkObjects; + // //Find nob with component index. + // for (int i = 0; i < childNobs.Count; i++) + // { + // if (childNobs[i].ComponentIndex == componentIndex) + // { + // nob = childNobs[i]; + // break; + // } + // } + // //If child nob was not found. + // if (nob == null) + // { + // /* Purge reader of expected values. + // * Use networkmanager transform, it doesn't really matter + // * since values are discarded anyway. */ + // ReadTransformProperties(reader, base.NetworkManager.transform, out _, out _, out _); + // if (NetworkManager.CanLog(LoggingType.Error)) + // Debug.LogError($"Nested spawned object with componentIndex of {componentIndex} could not be found as a child NetworkObject of {parentNob.name}."); + // return null; + // } + + // ReadTransformProperties(reader, nob.transform, out Vector3 pos, out Quaternion rot, out Vector3 scale); + // nob.transform.SetLocalPositionRotationAndScale(pos, rot, scale); + + // return nob; + //} + + + /// + /// Gets a nested NetworkObject within it's root. + /// + /// + /// + internal NetworkObject GetNestedNetworkObject(CachedNetworkObject cnob) + { + NetworkObject rootNob; + int rootObjectId = cnob.RootObjectId; + byte componentIndex = cnob.ComponentIndex; + + /* Spawns are processed after all spawns come in, + * this ensures no reference race conditions. Turns out because of this + * the parentNob may be in cache and not actually spawned, if it was spawned the same packet + * as this one. So when not found in the spawned collection try to + * find it in Spawning before throwing. */ + rootNob = _objectCache.GetSpawnedObject(rootObjectId); + //If still null, that's not good. + if (rootNob == null) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Nested spawned object with componentIndex of {componentIndex} and a parentId of {rootObjectId} could not be spawned because parent was not found."); + return null; + } + + NetworkObject nob = null; + List childNobs = rootNob.ChildNetworkObjects; + //Find nob with component index. + for (int i = 0; i < childNobs.Count; i++) + { + if (childNobs[i].ComponentIndex == componentIndex) + { + nob = childNobs[i]; + break; + } + } + //If child nob was not found. + if (nob == null) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Nested spawned object with componentIndex of {componentIndex} could not be found as a child NetworkObject of {rootNob.name}."); + return null; + } + + GetTransformProperties(cnob, nob.transform, out Vector3 pos, out Quaternion rot, out Vector3 scale); + nob.transform.SetLocalPositionRotationAndScale(pos, rot, scale); + + return nob; + } + + /// + /// Finds a scene NetworkObject and sets transform values. + /// + internal NetworkObject GetSceneNetworkObject(CachedNetworkObject cnob) + { + ulong sceneId = cnob.SceneId; + NetworkObject nob; + base.SceneObjects.TryGetValueIL2CPP(sceneId, out nob); + //If found in scene objects. + if (nob != null) + { + Transform t = nob.transform; + GetTransformProperties(cnob, t, out Vector3 pos, out Quaternion rot, out Vector3 scale); + t.SetLocalPositionRotationAndScale(pos, rot, scale); + return nob; + } + //Not found in scene objects. Shouldn't ever happen. + else + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"SceneId of {sceneId} not found in SceneObjects. This may occur if your scene differs between client and server, if client does not have the scene loaded, or if networked scene objects do not have a SceneCondition. See ObserverManager in the documentation for more on conditions."); + return null; + } + } + + /// + /// Instantiates a NetworkObject if required and sets transform values. + /// + internal NetworkObject GetInstantiatedNetworkObject(CachedNetworkObject cnob) + { + if (cnob.PrefabId == null) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"PrefabId for {cnob.ObjectId} is null. Object will not spawn."); + return null; + } + + short prefabId = cnob.PrefabId.Value; + NetworkObject result = null; + + if (prefabId == -1) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Spawned object has an invalid prefabId. Make sure all objects which are being spawned over the network are within SpawnableObjects on the NetworkManager."); + } + else + { + NetworkObject prefab = NetworkManager.SpawnablePrefabs.GetObject(false, prefabId); + //Only instantiate if not host. + if (!base.NetworkManager.IsHost) + { + Transform parentTransform = null;//TODO FINISH THIS. FIND PARENT!!!! + bool hasParent = (cnob.ParentObjectId != null); + //Set parentTransform if there's a parent object. + if (hasParent) + { + int objectId = cnob.ParentObjectId.Value; + NetworkObject nob = _objectCache.GetSpawnedObject(objectId); + + if (nob == null) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"NetworkObject not found for ObjectId {objectId}. Prefab {prefab.name} will be instantiated without parent synchronization."); + } + else + { + //If parent object is a network behaviour then find the component. + if (cnob.ParentIsNetworkBehaviour) + { + byte componentIndex = cnob.ComponentIndex; + NetworkBehaviour nb = nob.GetNetworkBehaviour(componentIndex, false); + if (nb != null) + parentTransform = nb.transform; + else if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"NetworkBehaviour on index {componentIndex} could nto be found within NetworkObject {nob.name} with ObjectId {objectId}. Prefab {prefab.name} will be instantiated without parent synchronization."); + } + //The networkObject is the parent. + else + { + parentTransform = nob.transform; + } + } + } + + result = MonoBehaviour.Instantiate(prefab); + Transform t = result.transform; + t.SetParent(parentTransform, true); + GetTransformProperties(cnob, t, out Vector3 pos, out Quaternion rot, out Vector3 scale); + t.SetLocalPositionRotationAndScale(pos, rot, scale); + //Only need to set IsGlobal also if not host. + result.SetIsGlobal(cnob.ObjectSpawnType == ObjectSpawnType.InstantiatedGlobal); + } + //If host then find server instantiated object. + else + { + NetworkManager.ServerManager.Objects.Spawned.TryGetValueIL2CPP(cnob.ObjectId, out result); + } + } + + return result; + } + + /// + /// Gets transform properties from a CachedNetworkObject, and applying defaultTransform values if properties are not found within the cached objet. + /// + private void GetTransformProperties(CachedNetworkObject cnob, Transform defaultTransform, out Vector3 pos, out Quaternion rot, out Vector3 scale) + { + pos = (cnob.LocalPosition == null) ? defaultTransform.localPosition : cnob.LocalPosition.Value; + rot = (cnob.LocalRotation == null) ? defaultTransform.localRotation : cnob.LocalRotation.Value; + scale = (cnob.LocalScale == null) ? defaultTransform.localScale : cnob.LocalScale.Value; + } + + /// + /// Finishes reading a nested object. Nested objects should always already exist beneath the parent. + /// + private void ReadNestedObject(PooledReader reader, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) + { + ReadTransformProperties(reader, out localPosition, out localRotation, out localScale); + } + + /// + /// Finishes reading a scene object. + /// + private void ReadSceneObject(PooledReader reader, out ulong sceneId, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) + { + sceneId = reader.ReadUInt64(AutoPackType.Unpacked); + ReadTransformProperties(reader, out localPosition, out localRotation, out localScale); + } + + /// + /// Finishes reading a spawned object, and instantiates the object. + /// + private void ReadSpawnedObject(PooledReader reader, out int? parentObjectId, out byte? parentComponentIndex, out short? prefabId, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) + { + //Parent. + SpawnParentType spt = (SpawnParentType)reader.ReadByte(); + + //Defaults. + parentObjectId = null; + parentComponentIndex = null; + + if (spt == SpawnParentType.NetworkObject) + { + int objectId = reader.ReadNetworkObjectId(); + if (objectId != -1) + parentObjectId = objectId; + } + else if (spt == SpawnParentType.NetworkBehaviour) + { + reader.ReadNetworkBehaviour(out int objectId, out byte componentIndex); + if (objectId != -1) + { + parentObjectId = objectId; + parentComponentIndex = componentIndex; + } + } + + prefabId = reader.ReadInt16(); + ReadTransformProperties(reader, out localPosition, out localRotation, out localScale); + } + + ///// + ///// Finishes reading a spawned object, and instantiates the object. + ///// + //private NetworkObject ReadSpawnedObject(PooledReader reader, int objectId, ObjectSpawnType ost) + //{ + // //Parent. + // SpawnParentType spt = (SpawnParentType)reader.ReadByte(); + // Transform parentTransform = null; + // if (spt == SpawnParentType.NetworkObject) + // { + // NetworkObject n = reader.ReadNetworkObject(); + // if (n != null) + // parentTransform = n.transform; + // } + // else if (spt == SpawnParentType.NetworkBehaviour) + // { + // NetworkBehaviour n = reader.ReadNetworkBehaviour(); + // if (n != null) + // parentTransform = n.transform; + // } + + // short prefabId = reader.ReadInt16(); + // NetworkObject result = null; + + // if (prefabId == -1) + // { + // /* Purge reader of expected values. + // * Use networkmanager transform, it doesn't really matter + // * since values are discarded anyway. */ + // ReadTransformProperties(reader, base.NetworkManager.transform, out _, out _, out _); + // if (NetworkManager.CanLog(LoggingType.Error)) + // Debug.LogError($"Spawned object has an invalid prefabId. Make sure all objects which are being spawned over the network are within SpawnableObjects on the NetworkManager."); + // } + // else + // { + // NetworkObject prefab = NetworkManager.SpawnablePrefabs.GetObject(false, prefabId); + // ReadTransformProperties(reader, prefab.transform, out Vector3 pos, out Quaternion rot, out Vector3 scale); + + // //Only instantiate if not host. + // if (!base.NetworkManager.IsHost) + // { + // result = MonoBehaviour.Instantiate(prefab); + // Transform t = result.transform; + // t.SetParent(parentTransform, true); + // t.SetLocalPositionRotationAndScale(pos, rot, scale); + // //Only need to set IsGlobal also if not host. + // result.SetIsGlobal((ost == ObjectSpawnType.InstantiatedGlobal)); + // } + // //If host then find server instantiated object. + // else + // { + // NetworkManager.ServerManager.Objects.Spawned.TryGetValueIL2CPP(objectId, out result); + // } + // } + + // return result; + //} + + /// + /// Reads transform properties and applies them to a transform. + /// + private void ReadTransformProperties(PooledReader reader, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) + { + //Read changed. + ChangedTransformProperties ctp = (ChangedTransformProperties)reader.ReadByte(); + //Position. + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalPosition)) + localPosition = reader.ReadVector3(); + else + localPosition = null; + //Rotation. + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalRotation)) + localRotation = reader.ReadQuaternion(base.NetworkManager.ServerManager.SpawnPacking.Rotation); + else + localRotation = null; + //Scale. + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalScale)) + localScale = reader.ReadVector3(); + else + localScale = null; + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs.meta new file mode 100644 index 0000000..014b78e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da027fa27b0c0994ebfa317968862970 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs new file mode 100644 index 0000000..ddd82f9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs @@ -0,0 +1,548 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Object; +using FishNet.Object; +using FishNet.Object.Helping; +using FishNet.Serializing; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Scripting; + +namespace FishNet.Managing.Client +{ + + /// + /// Information about cached network objects. + /// + internal class ClientObjectCache + { + #region Types. + public enum CacheSearchType + { + Any = 0, + Spawning = 1, + Despawning = 2 + } + #endregion + + #region Internal. + /// + /// Objets which are being spawned during iteration. + /// + internal Dictionary SpawningObjects = new Dictionary(); + #endregion + + #region Private. + /// + /// Cached objects buffer. Contains spawns and despawns. + /// + private ListCache _cachedObjects = new ListCache(); + /// + /// Object spawns that are nested, but the parent object isn't spawned yet. + /// + private ListCache _pendingNestedSpawns = new ListCache(); + /// + /// NetworkObjects which have been spawned already during the current iteration. + /// + private HashSet _iteratedSpawns = new HashSet(); + /// + /// ClientObjects reference. + /// + private ClientObjects _clientObjects; + /// + /// NetworkManager for this cache. + /// + private NetworkManager _networkManager; + #endregion + + public ClientObjectCache(ClientObjects cobs, NetworkManager networkManager) + { + _clientObjects = cobs; + _networkManager = networkManager; + } + + /// + /// Returns a NetworkObject found in spawned cache using objectId. + /// + /// + /// + public NetworkObject GetInCached(int objectId, CacheSearchType searchType) + { + int count = _cachedObjects.Written; + List collection = _cachedObjects.Collection; + for (int i = 0; i < count; i++) + { + CachedNetworkObject cnob = collection[i]; + if (cnob.NetworkObject.ObjectId == objectId) + { + //Any condition always returns. + if (searchType == CacheSearchType.Any) + return cnob.NetworkObject; + + bool spawning = (searchType == CacheSearchType.Spawning); + bool spawnAction = (cnob.Action == CachedNetworkObject.ActionType.Spawn); + if (spawning == spawnAction) + return cnob.NetworkObject; + else + return null; + } + } + + //Fall through. + return null; + } + + /// + /// Initializes for a spawned NetworkObject. + /// + /// + /// + /// + public void AddSpawn(NetworkManager manager, int objectId, int ownerId, ObjectSpawnType ost, byte componentIndex, int rootObjectId, int? parentObjectId, byte? parentComponentIndex + , short? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment rpcLinks, ArraySegment syncValues) + { + CachedNetworkObject cnob = _cachedObjects.AddReference(); + cnob.InitializeSpawn(manager, objectId, ownerId, ost, componentIndex, rootObjectId, parentObjectId, parentComponentIndex + , prefabId, localPosition, localRotation, localScale, sceneId, rpcLinks, syncValues); + } + + /// + /// Initializes for a despawned NetworkObject. + /// + /// + public void AddDespawn(NetworkObject nob, bool disableOnDespawn) + { + CachedNetworkObject cnob = _cachedObjects.AddReference(); + cnob.InitializeDespawn(nob, disableOnDespawn); + } + + /// + /// Iterates any written objects. + /// + public void Iterate() + { + int written = _cachedObjects.Written; + if (written == 0) + return; + + try + { + //Indexes which have already been processed. + HashSet processedIndexes = new HashSet(); + List collection = _cachedObjects.Collection; + bool despawnConflict = false; + /* The next iteration will set rpclinks, + * synctypes, and so on. */ + for (int i = 0; i < written; i++) + { + /* An index may already be processed if it was pushed ahead. + * This can occur if a nested object spawn exists but the root + * object has not spawned yet. In this situation the root spawn is + * found and performed first. */ + if (processedIndexes.Contains(i)) + continue; + CachedNetworkObject cnob = collection[i]; + bool spawn = (cnob.Action == CachedNetworkObject.ActionType.Spawn); + + /* See if nested, and if so check if root is already spawned. + * If parent is not spawned then find it and process the parent first. */ + if (spawn) + { + /* When an object is nested or has a parent it is + * dependent upon either the root of nested, or the parent, + * being spawned to setup properly. + * + * When either of these are true check spawned objects first + * to see if the objects exist. If not check if they are appearing + * later in the cache. Root or parent objects can appear later + * in the cache depending on the order of which observers are rebuilt. + * While it is possible to have the server ensure spawns always send + * root/parents first, that's a giant can of worms that's not worth getting into. + * Not only are there many scenarios to cover, but it also puts more work + * on the server. It's more effective to have the client handle the sorting. */ + + //Nested. + if (cnob.IsNested || cnob.HasParent) + { + bool nested = cnob.IsNested; + //It's not possible to be nested and have a parent. Set the Id to look for based on if nested or parented. + int targetObjectId = (nested) ? cnob.RootObjectId : cnob.ParentObjectId.Value; + NetworkObject nob = GetSpawnedObject(targetObjectId); + //If not spawned yet. + if (nob == null) + { + bool found = false; + for (int z = (i + 1); z < written; z++) + { + CachedNetworkObject zCnob = collection[z]; + if (zCnob.ObjectId == targetObjectId) + { + found = true; + if (cnob.Action != CachedNetworkObject.ActionType.Spawn) + { + if (_networkManager.CanLog(LoggingType.Error)) + { + string errMsg = (nested) + ? $"ObjectId {targetObjectId} was found for a nested spawn, but ActionType is not spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned." + : $"ObjectId {targetObjectId} was found for a parented spawn, but ActionType is not spawn. ObjectId {cnob.ObjectId} will not be spawned."; + Debug.LogError(errMsg); + } + break; + } + else + { + ProcessObject(zCnob, true, z); + break; + } + } + } + //Root nob could not be found. + if (!found && _networkManager.CanLog(LoggingType.Error)) + { + string errMsg = (nested) + ? $"ObjectId {targetObjectId} could not be found for a nested spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned." + : $"ObjectId {targetObjectId} was found for a parented spawn. ObjectId {cnob.ObjectId} will not be spawned."; + Debug.LogError(errMsg); + } + } + } + } + + ProcessObject(cnob, spawn, i); + } + + void ProcessObject(CachedNetworkObject cnob, bool spawn, int index) + { + processedIndexes.Add(index); + + if (spawn) + { + if (cnob.IsSceneObject) + cnob.NetworkObject = _clientObjects.GetSceneNetworkObject(cnob); + else if (cnob.IsNested) + cnob.NetworkObject = _clientObjects.GetNestedNetworkObject(cnob); + else + cnob.NetworkObject = _clientObjects.GetInstantiatedNetworkObject(cnob); + } + else + { + if (cnob.NetworkObject == null && _networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"NetworkObject for ObjectId of {cnob.ObjectId} was found null. Unable to despawn object."); + } + NetworkObject nob = cnob.NetworkObject; + //No need to error here, the other Gets above would have. + if (nob == null) + return; + + if (spawn) + { + //If not also server then object also has to be preinitialized. + if (!_networkManager.IsServer) + { + int ownerId = cnob.OwnerId; + //If local client is owner then use localconnection reference. + NetworkConnection localConnection = _networkManager.ClientManager.Connection; + NetworkConnection owner; + //If owner is self. + if (ownerId == localConnection.ClientId) + { + owner = localConnection; + } + else + { + /* If owner cannot be found then share owners + * is disabled */ + if (!_networkManager.ClientManager.Clients.TryGetValueIL2CPP(ownerId, out owner)) + owner = NetworkManager.EmptyConnection; + } + nob.PreinitializeInternal(_networkManager, cnob.ObjectId, owner, false); + } + + _clientObjects.AddToSpawned(cnob.NetworkObject, false); + SpawningObjects.Add(cnob.ObjectId, cnob.NetworkObject); + + IterateSpawn(cnob); + _iteratedSpawns.Add(cnob.NetworkObject); + } + else + { + /* If spawned already this iteration then the nob + * must be initialized so that the start/stop cycles + * complete normally. Otherwise, the despawn callbacks will + * fire immediately while the start callbacks will run after all + * spawns have been iterated. + * The downside to this is that synctypes + * for spawns later in this iteration will not be initialized + * yet, and if the nob being spawned/despawned references + * those synctypes the values will be default. + * + * The alternative is to delay the despawning until after + * all spawns are iterated, but that will break the order + * reliability. This is unfortunately a lose/lose situation so + * the best we can do is let the user know the risk. */ + if (_iteratedSpawns.Contains(cnob.NetworkObject)) + { + if (_networkManager.CanLog(LoggingType.Common)) + Debug.Log($"NetworkObject {cnob.NetworkObject.name} is being despawned on the same tick it's spawned." + + $" When this occurs SyncTypes will not be set on other objects during the time of this despawn." + + $" In result, if NetworkObject {cnob.NetworkObject.name} is referencing a SyncType of another object being spawned this tick, the returned values will be default."); + + despawnConflict = true; + cnob.NetworkObject.gameObject.SetActive(true); + cnob.NetworkObject.Initialize(false); + } + //Now being initialized, despawn the object. + IterateDespawn(cnob); + } + } + + /* Lastly activate the objects after all data + * has been synchronized. This will execute callbacks, + * and any synctype hooks after the callbacks. */ + for (int i = 0; i < written; i++) + { + CachedNetworkObject cnob = collection[i]; + if (cnob.Action == CachedNetworkObject.ActionType.Spawn) + { + /* Apply syncTypes. It's very important to do this after all + * spawns have been processed and added to the manager.Objects collection. + * Otherwise, the synctype may reference an object spawning the same tick + * and the result would be null due to said object not being in spawned. */ + foreach (NetworkBehaviour nb in cnob.NetworkObject.NetworkBehaviours) + { + PooledReader reader = cnob.SyncValuesReader; + //SyncVars. + int length = reader.ReadInt32(); + nb.OnSyncType(reader, length, false); + //SyncObjects + length = reader.ReadInt32(); + nb.OnSyncType(reader, length, true); + } + + /* Only continue with the initialization if it wasn't initialized + * early to prevent a despawn conflict. */ + bool canInitialize = (!despawnConflict || !_iteratedSpawns.Contains(cnob.NetworkObject)); + if (canInitialize) + { + cnob.NetworkObject.gameObject.SetActive(true); + cnob.NetworkObject.Initialize(false); + } + } + } + } + finally + { + //Once all have been iterated reset. + Reset(); + } + } + + /// + /// Initializes an object on clients and spawns the NetworkObject. + /// + /// + private void IterateSpawn(CachedNetworkObject cnob) + { + /* All nob spawns have been added to spawned before + * they are processed. This ensures they will be found if + * anything is referencing them before/after initialization. */ + /* However, they have to be added again here should an ItereteDespawn + * had removed them. This can occur if an object is set to be spawned, + * thus added to spawned before iterations, then a despawn runs which + * removes it from spawn. */ + _clientObjects.AddToSpawned(cnob.NetworkObject, false); + + List rpcLinkIndexes = new List(); + //Apply rpcLinks. + foreach (NetworkBehaviour nb in cnob.NetworkObject.NetworkBehaviours) + { + PooledReader reader = cnob.RpcLinkReader; + int length = reader.ReadInt32(); + + int readerStart = reader.Position; + while (reader.Position - readerStart < length) + { + //Index of RpcLink. + ushort linkIndex = reader.ReadUInt16(); + RpcLink link = new RpcLink( + cnob.NetworkObject.ObjectId, nb.ComponentIndex, + //RpcHash. + reader.ReadUInt16(), + //ObserverRpc. + (RpcType)reader.ReadByte()); + //Add to links. + _clientObjects.SetRpcLink(linkIndex, link); + + rpcLinkIndexes.Add(linkIndex); + } + } + cnob.NetworkObject.SetRpcLinkIndexes(rpcLinkIndexes); + } + + /// + /// Deinitializes an object on clients and despawns the NetworkObject. + /// + /// + private void IterateDespawn(CachedNetworkObject cnob) + { + bool disableOnDespawn = (cnob.Action == CachedNetworkObject.ActionType.DespawnAndDestroy); + _clientObjects.Despawn(cnob.NetworkObject, disableOnDespawn, false); + } + + + /// + /// Returns a NetworkObject found in spawn cache, or Spawned. + /// + /// + internal NetworkObject GetSpawnedObject(int objectId) + { + NetworkObject result; + //If not found in Spawning then check Spawned. + if (!SpawningObjects.TryGetValue(objectId, out result)) + { + Dictionary spawned = (_networkManager.IsHost) ? + _networkManager.ServerManager.Objects.Spawned + : _networkManager.ClientManager.Objects.Spawned; + bool r = spawned.TryGetValue(objectId, out result); + //if (!r && objectId == 0) + //{ + // Debug.Log("IsHost? " + _networkManager.IsHost); + // foreach (var item in spawned) + // { + // Debug.Log(item.Key + ", " + item.Value.name); + // } + //} + + + } + + return result; + } + + + /// + /// Resets cache. + /// + public void Reset() + { + _cachedObjects.Reset(); + _iteratedSpawns.Clear(); + SpawningObjects.Clear(); + } + } + + /// + /// A cached network object which exist in world but has not been Initialized yet. + /// + [Preserve] + internal class CachedNetworkObject + { + #region Types. + public enum ActionType + { + Unset = 0, + Spawn = 1, + DespawnAndDisable = 2, + DespawnAndDestroy = 3 + } + #endregion + + /// + /// True if cached object is nested. + /// + public bool IsNested => (ComponentIndex > 0); + /// + /// True if a scene object. + /// + public bool IsSceneObject => (SceneId > 0); + /// + /// True if this object has a parent. + /// + public bool HasParent => (ParentObjectId != null); + /// + /// True if the parent object is a NetworkBehaviour. + /// + public bool ParentIsNetworkBehaviour => (HasParent && (ParentComponentIndex != null)); + + public int ObjectId; + public int OwnerId; + public ObjectSpawnType ObjectSpawnType; + public byte ComponentIndex; + public int RootObjectId; + public int? ParentObjectId; + public byte? ParentComponentIndex; + public short? PrefabId; + public Vector3? LocalPosition; + public Quaternion? LocalRotation; + public Vector3? LocalScale; + public ulong SceneId; + public ArraySegment RpcLinks; + public ArraySegment SyncValues; + + + + /// + /// True if spawning. + /// + public ActionType Action { get; private set; } + /// + /// Cached NetworkObject. + /// +#pragma warning disable 0649 + public NetworkObject NetworkObject; + /// + /// Reader containing rpc links for the network object. + /// + public PooledReader RpcLinkReader { get; private set; } + /// + /// Reader containing sync values for the network object. + /// + public PooledReader SyncValuesReader { get; private set; } +#pragma warning restore 0649 + + public void InitializeSpawn(NetworkManager manager, int objectId, int ownerId, ObjectSpawnType objectSpawnType, byte componentIndex, int rootObjectId, int? parentObjectId, byte? parentComponentIndex + , short? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment rpcLinks, ArraySegment syncValues) + { + Action = ActionType.Spawn; + ObjectId = objectId; + OwnerId = ownerId; + ObjectSpawnType = objectSpawnType; + ComponentIndex = componentIndex; + RootObjectId = rootObjectId; + ParentObjectId = parentObjectId; + ParentComponentIndex = parentComponentIndex; + PrefabId = prefabId; + LocalPosition = localPosition; + LocalRotation = localRotation; + LocalScale = localScale; + SceneId = sceneId; + RpcLinks = rpcLinks; + SyncValues = syncValues; + + RpcLinkReader = ReaderPool.GetReader(rpcLinks, manager); + SyncValuesReader = ReaderPool.GetReader(syncValues, manager); + } + + /// + /// Initializes for a despawned NetworkObject. + /// + /// + public void InitializeDespawn(NetworkObject nob, bool disableOnDespawn) + { + Action = (disableOnDespawn) ? ActionType.DespawnAndDestroy : ActionType.DespawnAndDisable; + NetworkObject = nob; + } + + ~CachedNetworkObject() + { + if (RpcLinkReader != null) + RpcLinkReader.Dispose(); + if (SyncValuesReader != null) + SyncValuesReader.Dispose(); + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs.meta new file mode 100644 index 0000000..5481a01 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54cb2af8ab4557d479acb7fed98bd0c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Debugging.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging.meta new file mode 100644 index 0000000..63f6644 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae208c57eb1f4414896575607893b48d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs new file mode 100644 index 0000000..777b5ef --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace FishNet.Managing.Debugging +{ + /// + /// A container for debugging. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/DebugManager")] + public class DebugManager : MonoBehaviour + { + public bool ObserverRpcLinks = true; + public bool TargetRpcLinks = true; + public bool ReplicateRpcLinks = true; + public bool ReconcileRpcLinks = true; + public bool ServerRpcLinks = true; + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs.meta new file mode 100644 index 0000000..b36061b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d0962ead4b02a34aae248fccce671ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs new file mode 100644 index 0000000..9eed7d6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs @@ -0,0 +1,77 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace FishNet.Managing.Debugging +{ + + internal class ParseLogger + { + /// + /// Contains the last several non-split packets to arrive. This is used for debugging. + /// + private Queue _incomingPacketIds = new Queue(); + /// + /// Maximum number of packets allowed to be queued. + /// + private const int PACKET_COUNT = 5; + + /// + /// Resets data. + /// + internal void Reset() + { + _incomingPacketIds.Clear(); + } + + /// + /// Adds a packet to data. + /// + /// + internal void AddPacket(PacketId pId) + { + _incomingPacketIds.Enqueue(pId); + if (_incomingPacketIds.Count > PACKET_COUNT) + _incomingPacketIds.Dequeue(); + } + + /// + /// Prints current data. + /// + internal void Print(NetworkManager nm) + { + if (nm == null) + { + if (!NetworkManager.StaticCanLog(LoggingType.Error)) + return; + } + else + { + if (!nm.CanLog(LoggingType.Error)) + return; + } + + StringBuilder sb = new StringBuilder(); + foreach (PacketId item in _incomingPacketIds) + sb.Insert(0, $"{item.ToString()}{Environment.NewLine}"); + + NetworkObject lastNob = Reader.LastNetworkObject; + string nobData = (lastNob == null) ? "Unset" : $"Id {lastNob.ObjectId} on gameObject {lastNob.name}"; + NetworkBehaviour lastNb = Reader.LastNetworkBehaviour; + string nbData = (lastNb == null) ? "Unset" : lastNb.GetType().Name; + + Debug.LogError($"The last {_incomingPacketIds.Count} packets to arrive are: {Environment.NewLine}{sb.ToString()}"); + Debug.LogError($"The last parsed NetworkObject is {nobData}, and NetworkBehaviour {nbData}."); + + Reset(); + } + } + +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs.meta new file mode 100644 index 0000000..0b7d4f2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afc241e869d97a44f8339510586dce73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Editor.meta new file mode 100644 index 0000000..7f31d5b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30f99c38769dfc548b3b57c6866f6a44 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs new file mode 100644 index 0000000..c56967c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs @@ -0,0 +1,72 @@ +#if UNITY_EDITOR +using FishNet.Managing.Object; +using UnityEditor; +using UnityEngine; + +namespace FishNet.Managing.Editing +{ + [CustomEditor(typeof(NetworkManager))] + public class NetworkManagerEditor : Editor + { + private SerializedProperty _logging; + private SerializedProperty _refreshDefaultPrefabs; + private SerializedProperty _runInBackground; + private SerializedProperty _dontDestroyOnLoad; + private SerializedProperty _persistence; + private SerializedProperty _spawnablePrefabs; + private SerializedProperty _incomingIterationOrder; + private SerializedProperty _outgoingIterationOrder; + + private void OnEnable() + { + _logging = serializedObject.FindProperty("_logging"); + _refreshDefaultPrefabs = serializedObject.FindProperty("_refreshDefaultPrefabs"); + _runInBackground = serializedObject.FindProperty("_runInBackground"); + _dontDestroyOnLoad = serializedObject.FindProperty("_dontDestroyOnLoad"); + _persistence = serializedObject.FindProperty("_persistence"); + _spawnablePrefabs = serializedObject.FindProperty("_spawnablePrefabs"); + _incomingIterationOrder = serializedObject.FindProperty("_incomingIterationOrder"); + _outgoingIterationOrder = serializedObject.FindProperty("_outgoingIterationOrder"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + NetworkManager networkManager = (NetworkManager)target; + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(networkManager), typeof(NetworkManager), false); + GUI.enabled = true; + + //EditorGUILayout.BeginVertical(GUI.skin.box); + //EditorGUILayout.EndVertical(); + + + EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_runInBackground); + EditorGUILayout.PropertyField(_dontDestroyOnLoad); + EditorGUILayout.PropertyField(_persistence); + EditorGUILayout.Space(); + EditorGUI.indentLevel--; + + EditorGUILayout.LabelField("Logging", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_logging); + EditorGUILayout.Space(); + EditorGUI.indentLevel--; + + EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_spawnablePrefabs); + EditorGUILayout.PropertyField(_refreshDefaultPrefabs); + + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs.meta new file mode 100644 index 0000000..587918d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e8e16b3e97106a4980b954c56d7bbc5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Logging.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Logging.meta new file mode 100644 index 0000000..8796da6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Logging.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 756fcf2bc72a3214baf43099a0be9799 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs new file mode 100644 index 0000000..e6ccdaf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs @@ -0,0 +1,127 @@ +using FishNet.Documenting; +using System; +using UnityEngine; + +namespace FishNet.Managing.Logging +{ + + /// + /// Configuration ScriptableObject specifying which data to log. Used in conjuction with NetworkManager. + /// + [CreateAssetMenu(fileName = "New LoggingConfiguration", menuName = "FishNet/Logging/Logging Configuration")] + public class LoggingConfiguration : ScriptableObject + { + + #region Serialized. + /// + /// True to use logging features. False to disable all logging. + /// + [Tooltip("True to use logging features. False to disable all logging.")] + [SerializeField] + private bool _loggingEnabled = true; + /// + /// Type of logging to use for development builds and editor. + /// + [Tooltip("Type of logging to use for development builds and editor.")] + [SerializeField] + private LoggingType _developmentLogging = LoggingType.Common; + /// + /// Type of logging to use for GUI builds. + /// + [Tooltip("Type of logging to use for GUI builds.")] + [SerializeField] + private LoggingType _guiLogging = LoggingType.Warning; + /// + /// Type of logging to use for headless builds. + /// + [Tooltip("Type of logging to use for headless builds.")] + [SerializeField] + private LoggingType _headlessLogging = LoggingType.Error; + #endregion + + #region Private. + /// + /// True when initialized. + /// + private bool _initialized; + /// + /// Highest type which can be logged. + /// + private LoggingType _highestLoggingType = LoggingType.Off; + #endregion + + [APIExclude] + public void LoggingConstructor(bool loggingEnabled, LoggingType development, LoggingType gui, LoggingType headless) + { + _loggingEnabled = loggingEnabled; + _developmentLogging = development; + _guiLogging = gui; + _headlessLogging = headless; + } + + /// + /// Initializes script for use. + /// + /// + internal void InitializeOnceInternal() + { + byte currentHighest = (byte)LoggingType.Off; +#if UNITY_SERVER //if headless. + currentHighest = Math.Max(currentHighest, (byte)_headlessLogging); +#endif +#if UNITY_EDITOR || DEVELOPMENT_BUILD //if editor or development. + currentHighest = Math.Max(currentHighest, (byte)_developmentLogging); +#endif +#if !UNITY_EDITOR && !UNITY_SERVER //if a build. + currentHighest = Math.Max(currentHighest, (byte)_guiLogging); +#endif + _highestLoggingType = (LoggingType)currentHighest; + _initialized = true; + } + + /// + /// True if can log for loggingType. + /// + /// Type of logging being filtered. + /// + public bool CanLog(LoggingType loggingType) + { + if (!_loggingEnabled) + return false; + + if (!_initialized) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (Application.isPlaying) + Debug.LogError("CanLog called before being initialized."); + else + return true; +#endif + return false; + } + + return ((byte)loggingType <= (byte)_highestLoggingType); + } + + /// + /// Returns if logging can be written to disk. + /// + /// + internal bool CanWrite() + { + return false; + //return _writeLogs; + } + + /// + /// Clones this logging configuration. + /// + /// + internal LoggingConfiguration Clone() + { + LoggingConfiguration copy = ScriptableObject.CreateInstance(); + copy.LoggingConstructor(_loggingEnabled, _developmentLogging, _guiLogging, _headlessLogging); + return copy; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs.meta new file mode 100644 index 0000000..109c326 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 925fc096350b81f4f82f4fe4ac0c4dda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs new file mode 100644 index 0000000..e5a82e1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs @@ -0,0 +1,25 @@ +namespace FishNet.Managing.Logging +{ + /// + /// Type of logging being filtered. + /// + public enum LoggingType : byte + { + /// + /// Disable logging. + /// + Off = 0, + /// + /// Only log errors. + /// + Error = 1, + /// + /// Log warnings and errors. + /// + Warning = 2, + /// + /// Log all common activities, warnings, and errors. + /// + Common = 3 + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs.meta new file mode 100644 index 0000000..96f2758 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8bf0a7ab3f60fe44984fcfd16d8fe7b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs new file mode 100644 index 0000000..94b7a23 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs @@ -0,0 +1,124 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using UnityEngine; + +namespace FishNet.Managing +{ + public partial class NetworkManager : MonoBehaviour + { + #region Serialized. + /// + /// Logging configuration to use. When empty default logging settings will be used. + /// + [Tooltip("Logging configuration to use. When empty default logging settings will be used.")] + [SerializeField] + private LoggingConfiguration _logging; + #endregion + + #region Const. + private const string ERROR_LOGGING_PREFIX = "Error - "; + private const string WARNING_LOGGING_PREFIX = "Warning - "; + private const string COMMON_LOGGING_PREFIX = "Log - "; + #endregion + + /// + /// Initializes logging settings. + /// + private void InitializeLogging() + { + if (_logging == null) + _logging = ScriptableObject.CreateInstance(); + else + _logging = _logging.Clone(); + + _logging.InitializeOnceInternal(); + } + + + /// + /// True if can log for loggingType. + /// + /// + /// + [APIExclude] + public static bool StaticCanLog(LoggingType loggingType) + { + NetworkManager nm = InstanceFinder.NetworkManager; + if (nm == null || !nm.CanLog(loggingType)) + return false; + else + return true; + } + + /// + /// True if can log for loggingType. + /// + /// Type of logging being filtered. + /// + public bool CanLog(LoggingType loggingType) + { + if (_logging == null) + return true; + else + return _logging.CanLog(loggingType); + } + + /// + /// Performs a common log, should logging settings permit it. + /// + /// + public void Log(string txt) + { + if (CanLog(LoggingType.Common)) + { + Debug.Log(txt); + WriteLog(LoggingType.Common, txt); + } + } + + /// + /// Performs a warning log, should logging settings permit it. + /// + /// + public void LogWarning(string txt) + { + if (CanLog(LoggingType.Warning)) + { + Debug.LogWarning(txt); + WriteLog(LoggingType.Warning, txt); + } + } + + /// + /// Performs an error log, should logging settings permit it. + /// + /// + public void LogError(string txt) + { + if (CanLog(LoggingType.Error)) + { + Debug.LogError(txt); + WriteLog(LoggingType.Error, txt); + } + } + + /// + /// Writes log to file. + /// + /// + private void WriteLog(LoggingType loggingType, string txt) + { + string prefix; + if (loggingType == LoggingType.Common) + prefix = COMMON_LOGGING_PREFIX; + else if (loggingType == LoggingType.Warning) + prefix = WARNING_LOGGING_PREFIX; + else if (loggingType == LoggingType.Error) + prefix = ERROR_LOGGING_PREFIX; + else + prefix = string.Empty; + + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs.meta new file mode 100644 index 0000000..aef818b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4200d74f31ee8144fb606ce88ad1b747 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs new file mode 100644 index 0000000..7ae40b2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs @@ -0,0 +1,32 @@ +using FishNet.Component.ColliderRollback; +using UnityEngine; + +namespace FishNet.Managing +{ + public sealed partial class NetworkManager : MonoBehaviour + { + + #region Public. + /// + /// RollbackManager for this NetworkManager. + /// + public RollbackManager RollbackManager { get; private set; } + #endregion + + + /// + /// Adds RollbackManager. + /// + private void AddRollbackManager() + { + if (gameObject.TryGetComponent(out RollbackManager result)) + RollbackManager = result; + else + RollbackManager = gameObject.AddComponent(); + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs.meta new file mode 100644 index 0000000..e25b92c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb7fdb186794b674788273f3b211ec5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs new file mode 100644 index 0000000..8d6b849 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs @@ -0,0 +1,55 @@ +using FishNet.Managing.Object; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Managing +{ + public partial class NetworkManager : MonoBehaviour + { + #region Serialized. + /// + /// + /// + [Tooltip("Collection to use for spawnable objects.")] + [SerializeField] + private PrefabObjects _spawnablePrefabs; + /// + /// Collection to use for spawnable objects. + /// + public PrefabObjects SpawnablePrefabs { get => _spawnablePrefabs; set => _spawnablePrefabs = value; } + #endregion + + + /// + /// Gets the index a prefab uses. Can be used in conjuction with GetPrefab. + /// + /// + /// True if to get from the server collection. + /// Returns index if found, and -1 if not found. + public int GetPrefabIndex(GameObject prefab, bool asServer) + { + int count = SpawnablePrefabs.GetObjectCount(); + for (int i = 0; i < count; i++) + { + GameObject go = SpawnablePrefabs.GetObject(asServer, i).gameObject; + if (go == prefab) + return i; + } + + //Fall through, not found. + return -1; + } + + /// + /// Gets the NetworkObject prefab for index. Can be used in conjuction with GetPrefabIndex. + /// + /// True if to get from the server collection. + /// + /// + public NetworkObject GetPrefab(int index, bool asServer) + { + return SpawnablePrefabs.GetObject(asServer, index); + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs.meta new file mode 100644 index 0000000..eddffd8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5761633dda73e7447a3a41b87354d06e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs new file mode 100644 index 0000000..2d220a1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs @@ -0,0 +1,538 @@ +#if UNITY_EDITOR +using FishNet.Editing; +#endif +using FishNet.Connection; +using FishNet.Managing.Client; +using FishNet.Managing.Server; +using FishNet.Managing.Timing; +using FishNet.Managing.Transporting; +using UnityEngine; +using FishNet.Managing.Scened; +using FishNet.Authenticating; +using FishNet.Object; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using System.Collections.Generic; +using System; +using FishNet.Managing.Observing; +using System.Linq; +using FishNet.Managing.Debugging; +using FishNet.Managing.Object; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using FishNet.Managing.Statistic; +#if UNITY_EDITOR +using FishNet.Editing.PrefabCollectionGenerator; +#endif + +namespace FishNet.Managing +{ + /// + /// Acts as a container for all things related to your networking session. + /// + [DefaultExecutionOrder(short.MinValue)] + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/NetworkManager")] + public sealed partial class NetworkManager : MonoBehaviour + { + #region Types. + /// + /// Which socket to iterate data on first when as host. + /// + public enum HostIterationOrder + { + ServerFirst, + ClientFirst + } + /// + /// How to persist with multiple NetworkManagers. + /// + public enum PersistenceType + { + /// + /// Destroy any new NetworkManagers. + /// + DestroyNewest, + /// + /// Destroy previous NetworkManager when a new NetworkManager occurs. + /// + DestroyOldest, + /// + /// Allow multiple NetworkManagers, do not destroy any automatically. + /// + AllowMultiple + } + + #endregion + + #region Public. + /// + /// True if this instance of the NetworkManager is initialized. + /// + public bool Initialized { get; private set; } + /// + /// + /// + private static List _instances = new List(); + /// + /// Currently initialized NetworkManagers. + /// + public static IReadOnlyCollection Instances + { + get + { + /* Remove null instances of NetworkManager. + * This shouldn't happen because instances are removed + * OnDestroy but none the less something is causing + * it. */ + for (int i = 0; i < _instances.Count; i++) + { + if (_instances[i] == null) + { + _instances.RemoveAt(i); + i--; + } + } + return _instances; + } + } + + /// + /// True if server is active. + /// + public bool IsServer => ServerManager.Started; + /// + /// True if only the server is active. + /// + public bool IsServerOnly => (IsServer && !IsClient); + /// + /// True if the client is active and authenticated. + /// + public bool IsClient => (ClientManager.Started && ClientManager.Connection.Authenticated); + /// + /// True if only the client is active and authenticated. + /// + public bool IsClientOnly => (!IsServer && IsClient); + /// + /// True if client and server are active. + /// + public bool IsHost => (IsServer && IsClient); + /// + /// True if client nor server are active. + /// + public bool IsOffline => (!IsServer && !IsClient); + /// + /// ServerManager for this NetworkManager. + /// + public ServerManager ServerManager { get; private set; } + /// + /// ClientManager for this NetworkManager. + /// + public ClientManager ClientManager { get; private set; } + /// + /// TransportManager for this NetworkManager. + /// + public TransportManager TransportManager { get; private set; } + /// + /// TimeManager for this NetworkManager. + /// + public TimeManager TimeManager { get; private set; } + /// + /// SceneManager for this NetworkManager. + /// + public SceneManager SceneManager { get; private set; } + /// + /// ObserverManager for this NetworkManager. + /// + public ObserverManager ObserverManager { get; private set; } + /// + /// Authenticator for this NetworkManager. May be null if no Authenticator is used. + /// + public Authenticator Authenticator { get; private set; } + /// + /// DebugManager for this NetworkManager. + /// + public DebugManager DebugManager { get; private set; } + /// + /// StatisticsManager for this NetworkManager. + /// + public StatisticsManager StatisticsManager { get; private set; } + /// + /// An empty connection reference. Used when a connection cannot be found to prevent object creation. + /// + [APIExclude] + public static NetworkConnection EmptyConnection { get; private set; } = new NetworkConnection(); + #endregion + + #region Internal. + /// + /// Starting index for RpcLinks. + /// + internal static ushort StartingRpcLinkIndex; + #endregion + + #region Serialized. + /// + /// True to refresh the DefaultPrefabObjects collection whenever the editor enters play mode. This is an attempt to alleviate the DefaultPrefabObjects scriptable object not refreshing when using multiple editor applications such as ParrelSync. + /// + [Tooltip("True to refresh the DefaultPrefabObjects collection whenever the editor enters play mode. This is an attempt to alleviate the DefaultPrefabObjects scriptable object not refreshing when using multiple editor applications such as ParrelSync.")] + [SerializeField] + private bool _refreshDefaultPrefabs = false; + /// + /// True to have your application run while in the background. + /// + [Tooltip("True to have your application run while in the background.")] + [SerializeField] + private bool _runInBackground = true; + /// + /// True to make this instance DontDestroyOnLoad. This is typical if you only want one NetworkManager. + /// + [Tooltip("True to make this instance DontDestroyOnLoad. This is typical if you only want one NetworkManager.")] + [SerializeField] + private bool _dontDestroyOnLoad = true; + /// + /// How to persist when other NetworkManagers are introduced. + /// + [Tooltip("How to persist when other NetworkManagers are introduced.")] + [SerializeField] + private PersistenceType _persistence = PersistenceType.DestroyNewest; + #endregion + + #region Private. + /// + /// True if this NetworkManager can persist after Awake checks. + /// + private bool _canPersist; + #endregion + + #region Const. + /// + /// Maximum framerate allowed. + /// + internal const ushort MAXIMUM_FRAMERATE = 500; + #endregion + + + private void Awake() + { + InitializeLogging(); + if (!ValidateSpawnablePrefabs(true)) + return; + + if (StartingRpcLinkIndex == 0) + StartingRpcLinkIndex = (ushort)(EnumFN.GetHighestValue() + 1); + + bool isDefaultPrefabs = (SpawnablePrefabs != null && SpawnablePrefabs is DefaultPrefabObjects); +#if UNITY_EDITOR + /* If first instance then force + * default prefabs to repopulate. + * This is only done in editor because + * cloning tools sometimes don't synchronize + * scriptable object changes, which is what + * the default prefabs is. */ + if (_refreshDefaultPrefabs && _instances.Count == 0 && isDefaultPrefabs) + { + Generator.IgnorePostProcess = true; + Debug.Log("DefaultPrefabCollection is being refreshed."); + Generator.GenerateFull(); + Generator.IgnorePostProcess = false; + } +#endif + //If default prefabs then also make a new instance and sort them. + if (isDefaultPrefabs) + { + DefaultPrefabObjects originalDpo = (DefaultPrefabObjects)SpawnablePrefabs; + //If not editor then a new instance must be made and sorted. + DefaultPrefabObjects instancedDpo = ScriptableObject.CreateInstance(); + instancedDpo.AddObjects(originalDpo.Prefabs.ToList(), false); + instancedDpo.Sort(); + SpawnablePrefabs = instancedDpo; + } + + _canPersist = CanInitialize(); + if (!_canPersist) + return; + + if (TryGetComponent(out _)) + { + if (CanLog(LoggingType.Error)) + Debug.LogError($"NetworkObject component found on the NetworkManager object {gameObject.name}. This is not allowed and will cause problems. Remove the NetworkObject component from this object."); + } + + SpawnablePrefabs.InitializePrefabRange(0); + SetDontDestroyOnLoad(); + SetRunInBackground(); + AddDebugManager(); + AddTransportManager(); + AddServerAndClientManagers(); + AddTimeManager(); + AddSceneManager(); + AddObserverManager(); + AddRollbackManager(); + AddStatisticsManager(); + InitializeComponents(); + + _instances.Add(this); + Initialized = true; + } + + private void Start() + { + ServerManager.StartForHeadless(); + } + + private void OnDestroy() + { + _instances.Remove(this); + } + + /// + /// Initializes components. To be called after all components are added. + /// + private void InitializeComponents() + { + TimeManager.InitializeOnceInternal(this); + TimeManager.OnLateUpdate += TimeManager_OnLateUpdate; + SceneManager.InitializeOnceInternal(this); + TransportManager.InitializeOnceInternal(this); + ServerManager.InitializeOnceInternal(this); + ClientManager.InitializeOnceInternal(this); + ObserverManager.InitializeOnceInternal(this); + RollbackManager.InitializeOnceInternal(this); + StatisticsManager.InitializeOnceInternal(this); + } + + /// + /// Updates the frame rate based on server and client status. + /// + internal void UpdateFramerate() + { + bool clientStarted = ClientManager.Started; + bool serverStarted = ServerManager.Started; + + int frameRate = 0; + //If both client and server are started then use whichever framerate is higher. + if (clientStarted && serverStarted) + frameRate = Math.Max(ServerManager.FrameRate, ClientManager.FrameRate); + else if (clientStarted) + frameRate = ClientManager.FrameRate; + else if (serverStarted) + frameRate = ServerManager.FrameRate; + + /* Make sure framerate isn't set to max on server. + * If it is then default to tick rate. If framerate is + * less than tickrate then also set to tickrate. */ +#if UNITY_SERVER + ushort minimumServerFramerate = (ushort)(TimeManager.TickRate + 1); + if (frameRate == MAXIMUM_FRAMERATE) + frameRate = minimumServerFramerate; + else if (frameRate < TimeManager.TickRate) + frameRate = minimumServerFramerate; +#endif + //If there is a framerate to set. + if (frameRate > 0) + Application.targetFrameRate = frameRate; + } + + /// + /// Called when MonoBehaviours call LateUpdate. + /// + private void TimeManager_OnLateUpdate() + { + /* Some reason runinbackground becomes unset + * or the setting goes ignored some times when it's set + * in awake. Rather than try to fix or care why Unity + * does this just set it in LateUpdate(or Update). */ + SetRunInBackground(); + } + + + /// + /// Returns if this NetworkManager can initialize. + /// + /// + private bool CanInitialize() + { + /* If allow multiple then any number of + * NetworkManagers are allowed. Don't + * automatically destroy any. */ + if (_persistence == PersistenceType.AllowMultiple) + return true; + + List instances = Instances.ToList(); + //This is the first instance, it may initialize. + if (instances.Count == 0) + return true; + + //First instance of NM. + NetworkManager firstInstance = instances[0]; + + //If to destroy the newest. + if (_persistence == PersistenceType.DestroyNewest) + { + if (CanLog(LoggingType.Common)) + Debug.Log($"NetworkManager on object {gameObject.name} is being destroyed due to persistence type {_persistence}. A NetworkManager instance already exist on {firstInstance.name}."); + Destroy(gameObject); + //This one is being destroyed because its the newest. + return false; + } + //If to destroy the oldest. + else if (_persistence == PersistenceType.DestroyOldest) + { + if (CanLog(LoggingType.Common)) + Debug.Log($"NetworkManager on object {firstInstance.name} is being destroyed due to persistence type {_persistence}. A NetworkManager instance has been created on {gameObject.name}."); + Destroy(firstInstance.gameObject); + //This being the new one will persist, allow initialization. + return true; + } + //Unhandled. + else + { + if (CanLog(LoggingType.Error)) + Debug.Log($"Persistance type of {_persistence} is unhandled on {gameObject.name}. Initialization will not proceed."); + + return false; + } + } + + /// + /// Validates SpawnablePrefabs field and returns if validated successfully. + /// + /// + private bool ValidateSpawnablePrefabs(bool print) + { + //If null and object is in a scene. + if (SpawnablePrefabs == null && !string.IsNullOrEmpty(gameObject.scene.name)) + { + //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."); + return false; + } + + return true; + } + + /// + /// Sets DontDestroyOnLoad if configured to. + /// + private void SetDontDestroyOnLoad() + { + if (_dontDestroyOnLoad) + DontDestroyOnLoad(this); + } + + /// + /// Sets Application.runInBackground to runInBackground. + /// + private void SetRunInBackground() + { + Application.runInBackground = _runInBackground; + } + + + /// + /// Adds DebugManager. + /// + private void AddDebugManager() + { + if (gameObject.TryGetComponent(out DebugManager result)) + DebugManager = result; + else + DebugManager = gameObject.AddComponent(); + } + + /// + /// Adds TransportManager. + /// + private void AddTransportManager() + { + if (gameObject.TryGetComponent(out TransportManager result)) + TransportManager = result; + else + TransportManager = gameObject.AddComponent(); + } + + /// + /// Adds TimeManager. + /// + private void AddTimeManager() + { + if (gameObject.TryGetComponent(out TimeManager result)) + TimeManager = result; + else + TimeManager = gameObject.AddComponent(); + } + + + /// + /// Adds SceneManager. + /// + private void AddSceneManager() + { + if (gameObject.TryGetComponent(out SceneManager result)) + SceneManager = result; + else + SceneManager = gameObject.AddComponent(); + } + + /// + /// Adds ObserverManager. + /// + private void AddObserverManager() + { + if (gameObject.TryGetComponent(out ObserverManager result)) + ObserverManager = result; + else + ObserverManager = gameObject.AddComponent(); + } + + /// + /// Adds StatisticsManager + /// + private void AddStatisticsManager() + { + if (gameObject.TryGetComponent(out StatisticsManager result)) + StatisticsManager = result; + else + StatisticsManager = gameObject.AddComponent(); + } + + /// + /// Adds and assigns NetworkServer and NetworkClient if they are not already setup. + /// + private void AddServerAndClientManagers() + { + //Add servermanager. + if (gameObject.TryGetComponent(out ServerManager sm)) + ServerManager = sm; + else + ServerManager = gameObject.AddComponent(); + + //Add clientmanager. + if (gameObject.TryGetComponent(out ClientManager cm)) + ClientManager = cm; + else + ClientManager = gameObject.AddComponent(); + } + + #region Editor. +#if UNITY_EDITOR + private void OnValidate() + { + if (SpawnablePrefabs == null) + Reset(); + } + private void Reset() + { + ValidateSpawnablePrefabs(true); + } + +#endif + + #endregion + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs.meta new file mode 100644 index 0000000..1f1685d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/NetworkManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2c95dfde7d73b54dbbdc23155d35d36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object.meta new file mode 100644 index 0000000..6f25714 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba48f298f92e0684db6b68c8d3fc2672 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs new file mode 100644 index 0000000..b0e3096 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs @@ -0,0 +1,16 @@ +using FishNet.Object; + +namespace FishNet.Managing.Object +{ + + /// + /// When using dual prefabs, defines which prefab to spawn for server, and which for clients. + /// + [System.Serializable] + public struct DualPrefab + { + public NetworkObject Server; + public NetworkObject Client; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs.meta new file mode 100644 index 0000000..0011412 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76840b2b810d8fc45aeccef03122763c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs new file mode 100644 index 0000000..a20a010 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs @@ -0,0 +1,380 @@ +using FishNet.Component.Observing; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Object +{ + public abstract class ManagedObjects + { + #region Public. + /// + /// NetworkObjects which are currently active. + /// + public Dictionary Spawned = new Dictionary(); + #endregion + + #region Protected. + /// + /// Returns the next ObjectId to use. + /// + protected internal virtual int GetNextNetworkObjectId() { return -1; } + /// + /// NetworkManager handling this. + /// + protected NetworkManager NetworkManager = null; + /// + /// Objects in currently loaded scenes. These objects can be active or inactive. + /// Key is the objectId while value is the object. Key is not the same as NetworkObject.ObjectId. + /// + protected Dictionary SceneObjects = new Dictionary(); + #endregion + + /// + /// Subscribes to SceneManager.SceneLoaded event. + /// + /// + internal void SubscribeToSceneLoaded(bool subscribe) + { + if (subscribe) + SceneManager.sceneLoaded += SceneManager_sceneLoaded; + else + SceneManager.sceneLoaded -= SceneManager_sceneLoaded; + } + + /// + /// Called when a scene is loaded. + /// + /// + /// + protected internal virtual void SceneManager_sceneLoaded(Scene s, LoadSceneMode arg1) { } + + /// + /// Called when a NetworkObject runs Deactivate. + /// + /// + internal virtual void NetworkObjectUnexpectedlyDestroyed(NetworkObject nob) + { + if (nob == null) + return; + + RemoveFromSpawned(nob, true); + } + + /// + /// Removes a NetworkedObject from spawned. + /// + /// + private void RemoveFromSpawned(NetworkObject nob, bool unexpectedlyDestroyed) + { + Spawned.Remove(nob.ObjectId); + //Do the same with SceneObjects. + if (unexpectedlyDestroyed && nob.IsSceneObject) + RemoveFromSceneObjects(nob); + } + + /// + /// Despawns a NetworkObject. + /// + internal virtual void Despawn(NetworkObject nob, bool disableOnDespawn, bool asServer) + { + disableOnDespawn = false; //tmp until finished. + + if (nob == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot despawn a null NetworkObject."); + return; + } + + //True if should be destroyed, false if deactivated. + bool destroy = false; + /* Only modify object state if asServer, + * or !asServer and not host. This is so clients, when acting as + * host, don't destroy objects they lost observation of. */ + + //Nested objects are NEVER destroyed. + if (nob.IsNested) + disableOnDespawn = true; + + //Only check potential destroys when not destruction is choosen over disabling. + if (!disableOnDespawn) + { + //If as server. + if (asServer) + { + //Scene object. + if (!nob.IsSceneObject) + { + /* If client-host has visibility + * then disable and wait for client-host to get destroy + * message. Otherwise destroy immediately. */ + if (nob.Observers.Contains(NetworkManager.ClientManager.Connection)) + NetworkManager.ServerManager.Objects.AddToPending(nob); + else + destroy = true; + } + } + //Not as server. + else + { + bool isServer = NetworkManager.IsServer; + //Only check to destroy if not a scene object. + if (!nob.IsSceneObject) + { + /* If was removed from pending then also destroy. + * Pending objects are ones that exist on the server + * side only to await destruction from client side. + * Objects can also be destroyed if server is not + * active. */ + destroy = (!isServer || NetworkManager.ServerManager.Objects.RemoveFromPending(nob.ObjectId)); + } + } + } + + //Deinitialize to invoke callbacks. + nob.Deinitialize(asServer); + //Remove from match condition only if server. + if (asServer) + MatchCondition.RemoveFromMatchWithoutRebuild(nob, NetworkManager); + //Remove from spawned collection. + RemoveFromSpawned(nob, false); + + //If to destroy. + if (destroy) + { + MonoBehaviour.Destroy(nob.gameObject); + } + //If to potentially disable. + else + { + //If as server. + if (asServer) + { + //If not clientHost then the object can be disabled. + if (!NetworkManager.IsClient) + nob.gameObject.SetActive(false); + } + //Not as server. + else + { + //If the server is not active then the object can be disabled. + if (!NetworkManager.IsServer) + { + nob.gameObject.SetActive(false); + } + //If also server then checks must be done. + else + { + /* Object is still spawned on the server side. This means + * the clientHost likely lost visibility. When this is the case + * update clientHost renderers. */ + if (NetworkManager.ServerManager.Objects.Spawned.ContainsKey(nob.ObjectId)) + nob.SetRenderersVisible(false); + /* No longer spawned on the server, can + * deactivate on the client. */ + else + nob.gameObject.SetActive(false); + } + } + + /* Also despawn child objects. + * This only must be done when not destroying + * as destroying would result in the despawn being + * forced. + * + * Only run if asServer as well. The server will send + * individual despawns for each child. */ + if (asServer) + { + foreach (NetworkObject childNob in nob.ChildNetworkObjects) + { + if (childNob != null && !childNob.IsDeinitializing) + Despawn(childNob, disableOnDespawn, asServer); + } + } + } + + } + + + /// + /// Updates NetworkBehaviours on nob. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void UpdateNetworkBehaviours(NetworkObject nob, bool asServer) + { + //Would have already been done on server side. + if (!asServer && NetworkManager.IsServer) + return; + + InitializePrefab(nob, -1); + } + + /// + /// Initializes a prefab, not to be mistaken for initializing a spawned object. + /// + /// Prefab to initialize. + /// Index within spawnable prefabs. + public static void InitializePrefab(NetworkObject prefab, int index) + { + if (prefab == null) + return; + /* Only set the Id if not -1. + * A value of -1 would indicate it's a scene + * object. */ + if (index != -1) + prefab.PrefabId = (short)index; + + byte componentIndex = 0; + prefab.UpdateNetworkBehaviours(null, ref componentIndex); + } + + /// + /// Despawns Spawned NetworkObjects. Scene objects will be disabled, others will be destroyed. + /// + protected virtual void DespawnSpawnedWithoutSynchronization(bool asServer) + { + foreach (NetworkObject nob in Spawned.Values) + DespawnWithoutSynchronization(nob, asServer); + + Spawned.Clear(); + } + + /// + /// Despawns a network object. + /// + /// + protected virtual void DespawnWithoutSynchronization(NetworkObject nob, bool asServer) + { + //Null can occur when running as host and server already despawns such as wehen stopping. + if (nob == null) + return; + + nob.Deinitialize(asServer); + /* Only run if asServer, or not + * asServer and server isn't running. This + * prevents objects from affecting the server + * as host* when being modified client side. */ + if (asServer || (!asServer && !NetworkManager.IsServer)) + { + if (nob.IsSceneObject) + nob.gameObject.SetActive(false); + else + MonoBehaviour.Destroy(nob.gameObject); + } + } + + /// + /// Adds a NetworkObject to Spawned. + /// + /// + internal void AddToSpawned(NetworkObject nob, bool asServer) + { + Spawned[nob.ObjectId] = nob; + + //If being added as client and is also server. + if (!asServer && NetworkManager.IsServer) + nob.SetRenderersVisible(true); + } + + /// + /// Adds a NetworkObject to SceneObjects. + /// + /// + protected internal void AddToSceneObjects(NetworkObject nob) + { + SceneObjects[nob.SceneId] = nob; + } + + /// + /// Removes a NetworkObject from SceneObjects. + /// + /// + protected internal void RemoveFromSceneObjects(NetworkObject nob) + { + SceneObjects.Remove(nob.SceneId); + } + + /// + /// Finds a NetworkObject within Spawned. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal NetworkObject GetSpawnedNetworkObject(int objectId) + { + NetworkObject r; + if (!Spawned.TryGetValueIL2CPP(objectId, out r)) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Spawned NetworkObject not found for ObjectId {objectId}."); + } + + return r; + } + + /// + /// Tries to skip data length for a packet. + /// + /// + /// + /// + protected internal void SkipDataLength(ushort packetId, PooledReader reader, int dataLength, int rpcLinkObjectId = -1) + { + /* -1 means length wasn't set, which would suggest a reliable packet. + * Object should never be missing for reliable packets since spawns + * and despawns are reliable in order. */ + if (dataLength == (int)MissingObjectPacketLength.Reliable) + { + string msg; + bool isRpcLink = (packetId >= NetworkManager.StartingRpcLinkIndex); + if (isRpcLink) + { + msg = (rpcLinkObjectId == -1) ? + $"RPCLink of Id {(PacketId)packetId} could not be found. Remaining data will be purged." : + $"ObjectId {rpcLinkObjectId} for RPCLink {(PacketId)packetId} could not be found."; + } + else + { + msg = $"NetworkBehaviour could not be found for packetId {(PacketId)packetId}. Remaining data will be purged."; + } + + /* Default logging for server is errors only. Use error on client and warning + * on servers to reduce chances of allocation attacks. */ +#if DEVELOPMENT_BUILD || UNITY_EDITOR || !UNITY_SERVER + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError(msg); +#else + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning(msg); +#endif + reader.Skip(reader.Remaining); + } + /* If length is known then is unreliable packet. It's possible + * this packetId arrived before or after the object was spawned/destroyed. + * Skip past the data for this packet and use rest in reader. With non-linked + * RPCs length is sent before object information. */ + else if (dataLength >= 0) + { + reader.Skip(Math.Min(dataLength, reader.Remaining)); + } + /* -2 indicates the length is very long. Don't even try saving + * the packet, user shouldn't be sending this much data over unreliable. */ + else if (dataLength == (int)MissingObjectPacketLength.PurgeRemaiming) + { + reader.Skip(reader.Remaining); + } + } + + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs.meta new file mode 100644 index 0000000..345e662 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1363007244792145846afddc31ac12c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs new file mode 100644 index 0000000..901239e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs @@ -0,0 +1,12 @@ +namespace FishNet.Managing.Object +{ + internal enum ObjectSpawnType : byte + { + Unset = 0, + Scene = 1, + Instantiated = 2, + InstantiatedGlobal = 3, + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs.meta new file mode 100644 index 0000000..39d74c8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed15edf5a1a100d45b05f6adace574cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects.meta new file mode 100644 index 0000000..d227d92 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 681483aaaf105014b93c3c89c7f43fda +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs new file mode 100644 index 0000000..08df7b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs @@ -0,0 +1,104 @@ +using FishNet.Documenting; +using FishNet.Object.Helping; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_EDITOR +using FishNet.Editing; +using UnityEditor; +#endif +using FishNet.Object; + +namespace FishNet.Managing.Object +{ + + [APIExclude] + //[CreateAssetMenu(fileName = "New DefaultPrefabObjects", menuName = "FishNet/Spawnable Prefabs/Default Prefab Objects")] + public class DefaultPrefabObjects : SinglePrefabObjects + { + /// + /// Sets asset path hashes for prefabs starting at index, or if missing. + /// Returns true if one or more NetworkObjects were updated. + internal bool SetAssetPathHashes(int index) + { +#if UNITY_EDITOR + bool dirtied = false; + int count = base.GetObjectCount(); + + if (count == 0) + return false; + if (index < 0 || index >= count) + { + Debug.LogError($"Index {index} is out of range when trying to set asset path hashes. Collection length is {count}. Defaulf prefabs may need to be rebuilt."); + return false; + } + + for (int i = 0; i < count; i++) + { + NetworkObject n = base.Prefabs[i]; + if (i < index) + continue; + + string pathAndName = $"{AssetDatabase.GetAssetPath(n.gameObject)}{n.gameObject.name}"; + ulong hashcode = Hashing.GetStableHash64(pathAndName); + //Already set. + if (n.AssetPathHash == hashcode) + continue; + + n.SetAssetPathHash(hashcode); + EditorUtility.SetDirty(n); + dirtied = true; + } + + return dirtied; +#else + return false; +#endif + } + + /// + /// Sorts prefabs by name and path hashcode. + /// + internal void Sort() + { + if (base.GetObjectCount() == 0) + return; + + Dictionary hashcodesAndNobs = new Dictionary(); + List hashcodes = new List(); + + bool error = false; + foreach (NetworkObject n in base.Prefabs) + { + hashcodes.Add(n.AssetPathHash); + //If hashcode is 0 something is wrong + if (n.AssetPathHash == 0) + { + error = true; + Debug.LogError($"AssetPathHash is not set for GameObject {n.name}."); + + } + hashcodesAndNobs.Add(n.AssetPathHash, n); + } + //An error occured, no reason to continue. + if (error) + { + Debug.LogError($"One or more NetworkObject prefabs did not have their AssetPathHash set. This usually occurs when a prefab cannot be saved. Check the specified prefabs for missing scripts or serialization errors and correct them, then use Fish-Networking -> Refresh Default Prefabs."); + return; + } + + //Once all hashes have been made re-add them to prefabs sorted. + hashcodes.Sort(); + //Build to a new list using sorted hashcodes. + List sortedNobs = new List(); + foreach (ulong hc in hashcodes) + sortedNobs.Add(hashcodesAndNobs[hc]); + + base.Clear(); + base.AddObjects(sortedNobs, false); + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs.meta new file mode 100644 index 0000000..1258c30 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ad70174b079c2f4ebc7931d3dd1af6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs new file mode 100644 index 0000000..2cc3730 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs @@ -0,0 +1,144 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Object +{ + + //document + [APIExclude] + [CreateAssetMenu(fileName = "New DualPrefabObjects", menuName = "FishNet/Spawnable Prefabs/Dual Prefab Objects")] + public class DualPrefabObjects : PrefabObjects + { + /// + /// + /// + [Tooltip("Prefabs which may be spawned.")] + [SerializeField] + private List _prefabs = new List(); + /// + /// Prefabs which may be spawned. + /// + public IReadOnlyCollection Prefabs => _prefabs; + + public override void Clear() + { + _prefabs.Clear(); + } + public override int GetObjectCount() + { + return _prefabs.Count; + } + + public override NetworkObject GetObject(bool asServer, int id) + { + if (id < 0 || id >= _prefabs.Count) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"PrefabId {id} is out of range."); + return null; + } + else + { + DualPrefab dp = _prefabs[id]; + NetworkObject nob = (asServer) ? dp.Server : dp.Client; + if (nob == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + { + string lookupSide = (asServer) ? "server" : "client"; + Debug.LogError($"Prefab for {lookupSide} on id {id} is null "); + } + } + + return nob; + } + } + + public override void RemoveNull() + { + for (int i = 0; i < _prefabs.Count; i++) + { + if (_prefabs[i].Server == null || _prefabs[i].Client == null) + { + _prefabs.RemoveAt(i); + i--; + } + } + + if (Application.isPlaying) + InitializePrefabRange(0); + } + + public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false) + { + AddObjects(new DualPrefab[] { dualPrefab }, checkForDuplicates); + } + + public override void AddObjects(List dualPrefabs, bool checkForDuplicates = false) + { + AddObjects(dualPrefabs.ToArray(), checkForDuplicates); + } + + public override void AddObjects(DualPrefab[] dualPrefabs, bool checkForDuplicates = false) + { + if (!checkForDuplicates) + { + _prefabs.AddRange(dualPrefabs); + } + else + { + foreach (DualPrefab dp in dualPrefabs) + AddUniqueNetworkObjects(dp); + } + + if (Application.isPlaying) + InitializePrefabRange(0); + } + + private void AddUniqueNetworkObjects(DualPrefab dp) + { + for (int i = 0; i < _prefabs.Count; i++) + { + if (_prefabs[i].Server == dp.Server && _prefabs[i].Client == dp.Client) + return; + } + + _prefabs.Add(dp); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void InitializePrefabRange(int startIndex) + { + for (int i = startIndex; i < _prefabs.Count; i++) + { + ManagedObjects.InitializePrefab(_prefabs[i].Server, i); + ManagedObjects.InitializePrefab(_prefabs[i].Client, i); + } + } + + + #region Unused. + public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); + } + + public override void AddObjects(List networkObjects, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); + } + + public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); + } + #endregion + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs.meta new file mode 100644 index 0000000..4acd585 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4b890523e001c74a9a2bf0d6340e5f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs new file mode 100644 index 0000000..fcc9abb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs @@ -0,0 +1,24 @@ +using FishNet.Documenting; +using FishNet.Object; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Managing.Object +{ + //document + [APIExclude] + public abstract class PrefabObjects : ScriptableObject + { + public abstract void Clear(); + public abstract int GetObjectCount(); + public abstract NetworkObject GetObject(bool asServer, int id); + public abstract void RemoveNull(); + public abstract void AddObject(NetworkObject networkObject, bool checkForDuplicates = false); + public abstract void AddObjects(List networkObjects, bool checkForDuplicates = false); + public abstract void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false); + public abstract void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false); + public abstract void AddObjects(List dualPrefab, bool checkForDuplicates = false); + public abstract void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false); + public abstract void InitializePrefabRange(int startIndex); + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs.meta new file mode 100644 index 0000000..4b4ef77 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c5a7beb0d6ee75a4fb1f058eb3e2640a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs new file mode 100644 index 0000000..34619dc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs @@ -0,0 +1,136 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Object +{ + //document + [APIExclude] + [CreateAssetMenu(fileName = "New SinglePrefabObjects", menuName = "FishNet/Spawnable Prefabs/Single Prefab Objects")] + public class SinglePrefabObjects : PrefabObjects + { + /// + /// + /// + [Tooltip("Prefabs which may be spawned.")] + [SerializeField] + private List _prefabs = new List(); + /// + /// Prefabs which may be spawned. + /// + public IReadOnlyList Prefabs => _prefabs; + + public override void Clear() + { + _prefabs.Clear(); + } + public override int GetObjectCount() + { + return _prefabs.Count; + } + public override NetworkObject GetObject(bool asServer, int id) + { + if (id < 0 || id >= _prefabs.Count) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"PrefabId {id} is out of range."); + return null; + } + else + { + NetworkObject nob = _prefabs[id]; + if (nob == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Prefab on id {id} is null."); + } + + return nob; + } + } + + public override void RemoveNull() + { + for (int i = 0; i < _prefabs.Count; i++) + { + if (_prefabs[i] == null) + { + _prefabs.RemoveAt(i); + i--; + } + } + + if (Application.isPlaying) + InitializePrefabRange(0); + } + + public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false) + { + if (!checkForDuplicates) + _prefabs.Add(networkObject); + else + AddUniqueNetworkObject(networkObject); + + if (Application.isPlaying) + InitializePrefabRange(0); + } + + public override void AddObjects(List networkObjects, bool checkForDuplicates = false) + { + if (!checkForDuplicates) + { + _prefabs.AddRange(networkObjects); + } + else + { + foreach (NetworkObject nob in networkObjects) + AddUniqueNetworkObject(nob); + } + + if (Application.isPlaying) + InitializePrefabRange(0); + } + public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false) + { + AddObjects(networkObjects.ToList(), checkForDuplicates); + } + + private void AddUniqueNetworkObject(NetworkObject nob) + { + if (!_prefabs.Contains(nob)) + _prefabs.Add(nob); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void InitializePrefabRange(int startIndex) + { + for (int i = startIndex; i < _prefabs.Count; i++) + ManagedObjects.InitializePrefab(_prefabs[i], i); + } + + + #region Unused. + public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); + } + + public override void AddObjects(List dualPrefab, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); + } + + public override void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); + } + #endregion + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs.meta new file mode 100644 index 0000000..0cf790b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4489d77032a81ef42b0067acf2737d4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs new file mode 100644 index 0000000..ff3a421 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs @@ -0,0 +1,10 @@ +namespace FishNet.Managing.Object +{ + public enum SpawnParentType : byte + { + Unset = 0, + NetworkObject = 1, + NetworkBehaviour = 2 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs.meta new file mode 100644 index 0000000..d346b30 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cbace351ced9ff94eb294dbb2e1d6a75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs new file mode 100644 index 0000000..3978696 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs @@ -0,0 +1,167 @@ +using FishNet.Connection; //remove on 2023/01/01 move to correct folder. +using FishNet.Object; +using FishNet.Observing; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; + +namespace FishNet.Managing.Observing +{ + + /// + /// Additional options for managing the observer system. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/ObserverManager")] + public sealed class ObserverManager : MonoBehaviour + { + #region Serialized. + /// + /// + /// + [Tooltip("True to update visibility for clientHost based on if they are an observer or not.")] + [FormerlySerializedAs("_setHostVisibility")] + [SerializeField] + private bool _updateHostVisibility = true; + /// + /// True to update visibility for clientHost based on if they are an observer or not. + /// + public bool UpdateHostVisibility + { + get => _updateHostVisibility; + private set => _updateHostVisibility = value; + } + /// + /// + /// + [Tooltip("Default observer conditions for networked objects.")] + [SerializeField] + private List _defaultConditions = new List(); + /// + /// NetworkManager on object. + /// + private NetworkManager _networkManager; + #endregion + + /// + /// Initializes this script for use. + /// + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + _networkManager = manager; + } + + /// + /// Sets a new value for UpdateHostVisibility. + /// + /// New value. + /// Which objects to update. + public void SetUpdateHostVisibility(bool value, HostVisibilityUpdateTypes updateType) + { + //Unchanged. + if (value == UpdateHostVisibility) + return; + + /* Update even if server state is not known. + * The setting should be updated so when the server + * does start spawned objects have latest setting. */ + if (HostVisibilityUpdateContains(updateType, HostVisibilityUpdateTypes.Manager)) + UpdateHostVisibility = value; + + /* If to update spawned as well then update all networkobservers + * with the setting and also update renderers. */ + if (_networkManager.IsServer && HostVisibilityUpdateContains(updateType, HostVisibilityUpdateTypes.Spawned)) + { + NetworkConnection clientConn = _networkManager.ClientManager.Connection; + foreach (NetworkObject n in _networkManager.ServerManager.Objects.Spawned.Values) + { + if (n.NetworkObserver != null) + n.NetworkObserver.SetUpdateHostVisibility(value); + + //Only check to update renderers if clientHost. If not client then clientConn won't be active. + if (clientConn.IsActive) + n.SetRenderersVisible(n.Observers.Contains(clientConn), true); + } + } + + bool HostVisibilityUpdateContains(HostVisibilityUpdateTypes whole, HostVisibilityUpdateTypes part) + { + return (whole & part) == part; + } + } + + /// + /// Adds default observer conditions to nob and returns the NetworkObserver used. + /// + internal NetworkObserver AddDefaultConditions(NetworkObject nob, ref NetworkObserver obs) + { + bool isGlobal = (nob.IsGlobal && !nob.IsSceneObject); + bool nullObs = (obs == null); + /* NetworkObserver is null and there are no + * conditions to add. Nothing will change by adding + * the NetworkObserver component so exit early. */ + if (nullObs && _defaultConditions.Count == 0) + return obs; + + //If NetworkObject does not have a NetworkObserver component. + if (nullObs) + { + /* Global nobs do not need a NetworkObserver. + * Ultimately, a global NetworkObject is one without + * any conditions. */ + if (isGlobal) + return null; + //If there are no conditions then there's nothing to add. + if (_defaultConditions.Count == 0) + return null; + /* If here then there not a global networkobject and there are conditions to use. + * Since the NetworkObserver is being added fresh, set OverrideType to UseManager + * so that the NetworkObserver is populated with the manager conditions. */ + obs = nob.gameObject.AddComponent(); + obs.OverrideType = NetworkObserver.ConditionOverrideType.UseManager; + } + //NetworkObject has a NetworkObserver already on it. + else + { + //If global the NetworkObserver has to be cleared and set to ignore manager. + if (isGlobal) + { + obs.ObserverConditionsInternal.Clear(); + obs.OverrideType = NetworkObserver.ConditionOverrideType.IgnoreManager; + } + } + + //If ignoring manager then use whatever is already configured. + if (obs.OverrideType == NetworkObserver.ConditionOverrideType.IgnoreManager) + { + //Do nothing. + } + //If using manager then replace all with conditions. + else if (obs.OverrideType == NetworkObserver.ConditionOverrideType.UseManager) + { + obs.ObserverConditionsInternal.Clear(); + AddMissing(obs); + } + //Adding only new. + else if (obs.OverrideType == NetworkObserver.ConditionOverrideType.AddMissing) + { + AddMissing(obs); + } + + void AddMissing(NetworkObserver networkObserver) + { + int count = _defaultConditions.Count; + for (int i = 0; i < count; i++) + { + ObserverCondition oc = _defaultConditions[i]; + if (!networkObserver.ObserverConditionsInternal.Contains(oc)) + networkObserver.ObserverConditionsInternal.Add(oc); + } + } + + return obs; + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs.meta new file mode 100644 index 0000000..ed04656 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/ObserverManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d331f979d46e8e4a9fc90070c596d44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened.meta new file mode 100644 index 0000000..3e495f2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 212ba5e93fab23e45a461067dc0bf611 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast.meta new file mode 100644 index 0000000..0704a09 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8eb071c832ae3664c9b1701b52872513 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs new file mode 100644 index 0000000..5ce7c3b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs @@ -0,0 +1,38 @@ +using FishNet.Broadcast; +using FishNet.Documenting; + +namespace FishNet.Managing.Scened +{ + + /// + /// Sent when there are starting scenes for the client to load. + /// + public struct EmptyStartScenesBroadcast : IBroadcast { } + /// + /// Sent to clients to load networked scenes. + /// + [APIExclude] + public struct LoadScenesBroadcast : IBroadcast + { + public LoadQueueData QueueData; + } + + /// + /// Sent to clients to unload networked scenes. + /// + [APIExclude] + public struct UnloadScenesBroadcast : IBroadcast + { + public UnloadQueueData QueueData; + } + + /// + /// Sent to server to indicate which scenes a client has loaded. + /// + [APIExclude] + public struct ClientScenesLoadedBroadcast : IBroadcast + { + public SceneLookupData[] SceneLookupDatas; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs.meta new file mode 100644 index 0000000..1c271ef --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 698a94b4f8664ac4ab108deae0ba3b7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs new file mode 100644 index 0000000..6a8e475 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using UnityEngine; +using UnitySceneManager = UnityEngine.SceneManagement.SceneManager; +using UnityScene = UnityEngine.SceneManagement.Scene; +using System.Collections; + +namespace FishNet.Managing.Scened +{ + + public class DefaultSceneProcessor : SceneProcessorBase + { + #region Private. + /// + /// Currently active loading AsyncOperations. + /// + private List _loadingAsyncOperations = new List(); + /// + /// A collection of scenes used both for loading and unloading. + /// + private List _scenes = new List(); + /// + /// Current AsyncOperation being processed. + /// + private AsyncOperation _currentAsyncOperation; + #endregion + + /// + /// Called when scene loading has begun. + /// + public override void LoadStart(LoadQueueData queueData) + { + base.LoadStart(queueData); + ResetValues(); + } + + public override void LoadEnd(LoadQueueData queueData) + { + base.LoadEnd(queueData); + ResetValues(); + } + + /// + /// Resets values for a fresh load or unload. + /// + private void ResetValues() + { + _currentAsyncOperation = null; + _loadingAsyncOperations.Clear(); + } + + /// + /// Called when scene unloading has begun within an unload operation. + /// + /// + public override void UnloadStart(UnloadQueueData queueData) + { + base.UnloadStart(queueData); + _scenes.Clear(); + } + + /// + /// Begin loading a scene using an async method. + /// + /// Scene name to load. + public override void BeginLoadAsync(string sceneName, UnityEngine.SceneManagement.LoadSceneParameters parameters) + { + AsyncOperation ao = UnitySceneManager.LoadSceneAsync(sceneName, parameters); + _loadingAsyncOperations.Add(ao); + + _currentAsyncOperation = ao; + _currentAsyncOperation.allowSceneActivation = false; + } + + /// + /// Begin unloading a scene using an async method. + /// + /// Scene name to unload. + public override void BeginUnloadAsync(UnityScene scene) + { + _currentAsyncOperation = UnitySceneManager.UnloadSceneAsync(scene); + } + + /// + /// Returns if a scene load or unload percent is done. + /// + /// + public override bool IsPercentComplete() + { + return (GetPercentComplete() >= 0.9f); + } + + /// + /// Returns the progress on the current scene load or unload. + /// + /// + public override float GetPercentComplete() + { + return (_currentAsyncOperation == null) ? 1f : _currentAsyncOperation.progress; + } + + /// + /// Adds a loaded scene. + /// + /// Scene loaded. + public override void AddLoadedScene(UnityScene scene) + { + base.AddLoadedScene(scene); + _scenes.Add(scene); + } + + /// + /// Returns scenes which were loaded during a load operation. + /// + public override List GetLoadedScenes() + { + return _scenes; + } + + /// + /// Activates scenes which were loaded. + /// + public override void ActivateLoadedScenes() + { + foreach (AsyncOperation ao in _loadingAsyncOperations) + ao.allowSceneActivation = true; + } + + /// + /// Returns if all asynchronized tasks are considered IsDone. + /// + /// + public override IEnumerator AsyncsIsDone() + { + bool notDone; + do + { + notDone = false; + foreach (AsyncOperation ao in _loadingAsyncOperations) + { + + if (!ao.isDone) + { + notDone = true; + break; + } + } + yield return null; + } while (notDone); + + yield break; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs.meta new file mode 100644 index 0000000..086a4ba --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c6eacaa60569d947b383df03fff1ea3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events.meta new file mode 100644 index 0000000..8c02699 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09823f70d9231d34f91d88d11b937758 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs new file mode 100644 index 0000000..440613c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs @@ -0,0 +1,34 @@ +using FishNet.Connection; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + /// + /// Data container about a scene presence change for a client. + /// + public struct ClientPresenceChangeEventArgs + { + + /// + /// Scene on the server which the client's presence has changed. + /// + public Scene Scene; + /// + /// Connection to client. + /// + public NetworkConnection Connection; + /// + /// True if the client was added to the scene, false is removed. + /// + public bool Added; + + internal ClientPresenceChangeEventArgs(Scene scene, NetworkConnection conn, bool added) + { + Scene = scene; + Connection = conn; + Added = added; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs.meta new file mode 100644 index 0000000..e250e89 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa91039d4ab1c6445af72881af122b0a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs new file mode 100644 index 0000000..304fcd5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + /// + /// Data container about a scene load start. + /// + public struct SceneLoadStartEventArgs + { + /// + /// Queue data used by the current scene action. + /// + public readonly LoadQueueData QueueData; + + internal SceneLoadStartEventArgs(LoadQueueData lqd) + { + QueueData = lqd; + } + } + + + /// + /// Data container about a scene load percent change. + /// + public struct SceneLoadPercentEventArgs + { + /// + /// Queue data used by the current scene action. + /// + public readonly LoadQueueData QueueData; + /// + /// Percentage of change completion. 1f is equal to 100% complete. + /// + public readonly float Percent; + + internal SceneLoadPercentEventArgs(LoadQueueData lqd, float percent) + { + QueueData = lqd; + Percent = percent; + } + } + + + /// + /// Data container about a scene load end. + /// + public struct SceneLoadEndEventArgs + { + /// + /// Queue data used by the current scene action. + /// + public readonly LoadQueueData QueueData; + /// + /// Scenes which were loaded. + /// + public readonly Scene[] LoadedScenes; + /// + /// Scenes which were skipped because they were already loaded. + /// + public readonly string[] SkippedSceneNames; + /// + /// Scenes which were unloaded. + /// + public readonly string[] UnloadedSceneNames; + + internal SceneLoadEndEventArgs(LoadQueueData lqd, string[] skipped, Scene[] loaded, string[] unloadedSceneNames) + { + QueueData = lqd; + SkippedSceneNames = skipped; + LoadedScenes = loaded; + UnloadedSceneNames = unloadedSceneNames; + } + + + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs.meta new file mode 100644 index 0000000..58c3671 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86278568f8087de49b0908f148501993 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs new file mode 100644 index 0000000..3183ae4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs @@ -0,0 +1,42 @@ +namespace FishNet.Managing.Scened +{ + + /// + /// Data container about a scene unload start. + /// + public struct SceneUnloadStartEventArgs + { + /// + /// Queue data used by the current scene action. + /// + public readonly UnloadQueueData QueueData; + + internal SceneUnloadStartEventArgs(UnloadQueueData sqd) + { + QueueData = sqd; + } + } + + /// + /// Data container about a scene unload end. + /// + public struct SceneUnloadEndEventArgs + { + /// + /// Queue data used by the current scene action. + /// + public readonly UnloadQueueData QueueData; + /// + /// Handles of scenes which were successfully unloaded. + /// + public int[] UnloadedSceneHandles; + + internal SceneUnloadEndEventArgs(UnloadQueueData sqd, int[] unloadedHandles) + { + QueueData = sqd; + UnloadedSceneHandles = unloadedHandles; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs.meta new file mode 100644 index 0000000..da3c534 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c24765fea85b564aa331b529f324f92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas.meta new file mode 100644 index 0000000..ad45a3a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: beefc84827a4af141aa1b326fca9084f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs new file mode 100644 index 0000000..6ac16c0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs @@ -0,0 +1,33 @@ +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + /// + /// Settings to apply when loading a scene. + /// + public class LoadOptions + { + /// + /// True if to automatically unload the loaded scenes when they are no longer being used by clients. This field only applies to scenes loaded for connections, not globally loaded scenes. + /// + [System.NonSerialized] + public bool AutomaticallyUnload = true; + /// + /// False if to only load scenes which are not yet loaded. When true a scene may load multiple times; this is known as scene stacking. Only the server is able to stack scenes; clients will load a single instance. Global scenes cannot be stacked. + /// + [System.NonSerialized] + public bool AllowStacking; + /// + /// LocalPhysics mode to use when loading this scene. Generally this will only be used when applying scene stacking. Only used by the server. + /// https://docs.unity3d.com/ScriptReference/SceneManagement.LocalPhysicsMode.html + /// + [System.NonSerialized] + public LocalPhysicsMode LocalPhysics = LocalPhysicsMode.None; + /// + /// True if scenes should be loaded using addressables. This field only exists for optional use so the user may know if their queue data is using addressables. + /// + public bool Addressables; + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs.meta new file mode 100644 index 0000000..3ca0ef9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1614453d3786b2a4eb18b69297da7dc9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs new file mode 100644 index 0000000..0c62f63 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs @@ -0,0 +1,19 @@ +namespace FishNet.Managing.Scened +{ + /// + /// Additional user-crafted data which can be included in scene load callbacks. + /// + public class LoadParams + { + /// + /// Objects which are included in callbacks on the server when loading a scene. Can be useful for including unique information about the scene, such as match id. These are not sent to clients; use ClientParams for this. + /// + [System.NonSerialized] + public object[] ServerParams = new object[0]; + /// + /// Bytes which are sent to clients during scene loads. Can contain any information. + /// + public byte[] ClientParams = new byte[0]; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs.meta new file mode 100644 index 0000000..ce62050 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8b395f67f61b4e45830a70289a1901d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs new file mode 100644 index 0000000..61a7fc9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs @@ -0,0 +1,51 @@ +using FishNet.Connection; +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +namespace FishNet.Managing.Scened +{ + + + /// + /// Data generated when loading a scene. + /// + public class LoadQueueData + { + /// + /// Clients which receive this SceneQueueData. If Networked, all clients do. If Connections, only the specified Connections do. + /// + [System.NonSerialized] + public SceneScopeType ScopeType; + /// + /// Connections to load scenes for. Only valid on the server and when ScopeType is Connections. + /// + [System.NonSerialized] + public NetworkConnection[] Connections = new NetworkConnection[0]; + /// + /// SceneLoadData to use. + /// + public SceneLoadData SceneLoadData = null; + /// + /// Current global scenes. + /// + public string[] GlobalScenes = new string[0]; + /// + /// True if to iterate this queue data as server. + /// + [System.NonSerialized] + public readonly bool AsServer; + + internal LoadQueueData() { } + internal LoadQueueData(SceneScopeType scopeType, NetworkConnection[] conns, SceneLoadData sceneLoadData, string[] globalScenes, bool asServer) + { + ScopeType = scopeType; + Connections = conns; + SceneLoadData = sceneLoadData; + GlobalScenes = globalScenes; + AsServer = asServer; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs.meta new file mode 100644 index 0000000..d58489f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fb4183af628f754b800dfdbb1ba9bf0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs new file mode 100644 index 0000000..96a3800 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs @@ -0,0 +1,25 @@ + +namespace FishNet.Managing.Scened +{ + /// + /// How to replace scenes when loading. + /// + public enum ReplaceOption : byte + { + /// + /// Replace all scenes, online and offline. + /// + All, + /// + /// Only replace scenes loaded using the SceneManager. + /// + OnlineOnly, + /// + /// Do not replace any scenes, additional scenes will be loaded as additive. + /// + None + } + + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs.meta new file mode 100644 index 0000000..c1ab805 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb8e2c0fe3b9d3344a05810936861555 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs new file mode 100644 index 0000000..4cc60da --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs @@ -0,0 +1,180 @@ +using FishNet.Object; +using FishNet.Serializing.Helping; +using System.Collections.Generic; +using System.IO; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + /// + /// Data about which scenes to load. + /// + public class SceneLoadData + { + /// + /// SceneLookupData for each scene to load. + /// + public SceneLookupData[] SceneLookupDatas = new SceneLookupData[0]; + /// + /// NetworkObjects to move to the new scenes. Objects will be moved to the first scene. + /// + public NetworkObject[] MovedNetworkObjects = new NetworkObject[0]; + /// + /// How to replace current scenes with new ones. When replacing scenes the first scene loaded will be set as the active scene, and the rest additive. + /// + public ReplaceOption ReplaceScenes = ReplaceOption.None; + /// + /// Parameters which may be set and will be included in load callbacks. + /// + public LoadParams Params = new LoadParams(); + /// + /// Additional options to use for loaded scenes. + /// + public LoadOptions Options = new LoadOptions(); + + public SceneLoadData() { } + /// + /// + /// + /// Scene to load. + public SceneLoadData(Scene scene) : this(new Scene[] { scene }, null) { } + /// + /// + /// + /// Scene to load by name. + public SceneLoadData(string sceneName) : this(new string[] { sceneName }, null) { } + /// + /// + /// + /// Scene to load by handle. + public SceneLoadData(int sceneHandle) : this(new int[] { sceneHandle }, null) { } + /// + /// + /// + /// Scene to load by handle. + /// Scene to load by name. + public SceneLoadData(int sceneHandle, string sceneName) : this(new SceneLookupData(sceneHandle, sceneName)) { } + /// + /// + /// + /// Scene to load by SceneLookupData. + public SceneLoadData(SceneLookupData sceneLookupData) : this(new SceneLookupData[] { sceneLookupData }) { } + /// + /// + /// + /// Scenes to load. + public SceneLoadData(List scenes) : this(scenes.ToArray(), null) { } + /// + /// + /// + /// Scenes to load by name. + public SceneLoadData(List sceneNames) : this(sceneNames.ToArray(), null) { } + /// + /// + /// + /// Scenes to load by handle. + public SceneLoadData(List sceneHandles) : this(sceneHandles.ToArray(), null) { } + /// + /// + /// + /// Scenes to load. + public SceneLoadData(Scene[] scenes) : this(scenes, null) { } + /// + /// + /// + /// Scenes to load by name. + public SceneLoadData(string[] sceneNames) : this(sceneNames, null) { } + /// + /// + /// + /// Scenes to load by handle. + public SceneLoadData(int[] sceneHandles) : this(sceneHandles, null) { } + /// + /// + /// + /// Scenes to load by SceneLookupDatas. + public SceneLoadData(SceneLookupData[] sceneLookupDatas) : this(sceneLookupDatas, null) { } + + /// + /// + /// + /// Scene to load. + /// NetworkObjects to move to the first specified scene. + public SceneLoadData(Scene scene, NetworkObject[] movedNetworkObjects) + { + SceneLookupData data = SceneLookupData.CreateData(scene); + Construct(new SceneLookupData[] { data }, movedNetworkObjects); + } + /// + /// + /// + /// Scenes to load. + /// NetworkObjects to move to the first specified scene. + public SceneLoadData(Scene[] scenes, NetworkObject[] movedNetworkObjects) + { + SceneLookupData[] datas = SceneLookupData.CreateData(scenes); + Construct(datas, movedNetworkObjects); + } + /// + /// + /// + /// Scenes to load by Name. + /// NetworkObjects to move to the first specified scene. + public SceneLoadData(string[] sceneNames, NetworkObject[] movedNetworkObjects) + { + SceneLookupData[] datas = SceneLookupData.CreateData(sceneNames); + Construct(datas, movedNetworkObjects); + } + /// + /// + /// + /// Scenes to load by handle. + /// NetworkObjects to move to the first specified scene. + public SceneLoadData(int[] sceneHandles, NetworkObject[] movedNetworkObjects) + { + SceneLookupData[] datas = SceneLookupData.CreateData(sceneHandles); + Construct(datas, movedNetworkObjects); + } + /// + /// + /// + /// Scenes to load by SceneLookupDatas. + /// NetworkObjects to move to the first specified scene. + public SceneLoadData(SceneLookupData[] sceneLookupDatas, NetworkObject[] movedNetworkObjects) + { + Construct(sceneLookupDatas, movedNetworkObjects); + } + + /// + /// Called at the end of every constructor. + /// + private void Construct(SceneLookupData[] datas, NetworkObject[] movedNetworkObjects) + { + SceneLookupDatas = datas; + if (movedNetworkObjects == null) + movedNetworkObjects = new NetworkObject[0]; + MovedNetworkObjects = movedNetworkObjects; + } + + /// + /// Returns if any data is invalid, such as null entries. + /// + /// + internal bool DataInvalid() + { + //Null values. + if (Params == null || MovedNetworkObjects == null || SceneLookupDatas == null || + Options == null) + return true; + //No lookups. + if (SceneLookupDatas.Length == 0) + return true; + + return false; + } + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs.meta new file mode 100644 index 0000000..e6bb59a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ecd4065158ab62047a074c594f245d90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs new file mode 100644 index 0000000..91087e0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs @@ -0,0 +1,18 @@ +namespace FishNet.Managing.Scened +{ + /// + /// Type of scopes for a scene load or unload. + /// + public enum SceneScopeType : byte + { + /// + /// Scene action occured for all clients. + /// + Global = 0, + /// + /// Scene action occurred for specified clients. + /// + Connections = 1 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs.meta new file mode 100644 index 0000000..9baf271 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2be621eb04519a14eb2297a666b1bc2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs new file mode 100644 index 0000000..c1a9719 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + + /// + /// Data about which scenes to unload. + /// + public class SceneUnloadData + { + /// + /// SceneLookupData for each scene to load. + /// + public SceneLookupData[] SceneLookupDatas = new SceneLookupData[0]; + /// + /// Parameters which may be set and will be included in load callbacks. + /// + public UnloadParams Params = new UnloadParams(); + /// + /// Additional options to use for loaded scenes. + /// + public UnloadOptions Options = new UnloadOptions(); + + /// + /// + /// + public SceneUnloadData() { } + /// + /// + /// + /// Scene to unload. + public SceneUnloadData(Scene scene) : this(new Scene[] { scene }) { } + /// + /// + /// + /// Scene to unload by name. + public SceneUnloadData(string sceneName) : this(new string[] { sceneName }) { } + /// + /// + /// + /// Scene to unload by handle. + public SceneUnloadData(int sceneHandle) : this(new int[] { sceneHandle }) { } + /// + /// + /// + /// Scenes to unload. + public SceneUnloadData(List scenes) : this(scenes.ToArray()) { } + /// + /// + /// + /// Scenes to unload by names. + public SceneUnloadData(List sceneNames) : this(sceneNames.ToArray()) { } + /// + /// + /// + /// Scenes to unload by handles. + public SceneUnloadData(List sceneHandles) : this(sceneHandles.ToArray()) { } + /// + /// + /// + /// Scenes to unload. + public SceneUnloadData(Scene[] scenes) + { + SceneLookupDatas = SceneLookupData.CreateData(scenes); + } + /// + /// + /// + /// Scenes to unload by names. + public SceneUnloadData(string[] sceneNames) + { + SceneLookupDatas = SceneLookupData.CreateData(sceneNames); + } + /// + /// + /// + /// Scenes to unload by handles. + public SceneUnloadData(int[] sceneHandles) + { + SceneLookupDatas = SceneLookupData.CreateData(sceneHandles); + } + /// + /// + /// + /// Scenes to unload by SceneLookupDatas. + public SceneUnloadData(SceneLookupData[] sceneLookupDatas) + { + SceneLookupDatas = sceneLookupDatas; + } + + + /// + /// Returns if any data is invalid, such as null entries. + /// + /// + internal bool DataInvalid() + { + //Null values. + if (Params == null || SceneLookupDatas == null || + Options == null) + return true; + //No lookups. + if (SceneLookupDatas.Length == 0) + return true; + + return false; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs.meta new file mode 100644 index 0000000..a4a3d0d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77cbfeea232e4ab44a4315b003ce6742 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs new file mode 100644 index 0000000..8224759 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs @@ -0,0 +1,36 @@ + +namespace FishNet.Managing.Scened +{ + /// + /// Settings to apply when loading a scene. + /// + public class UnloadOptions + { + /// + /// Conditions to unloading a scene on the server. + /// + public enum ServerUnloadMode + { + /// + /// Unloads the scene if no more connections are within it. + /// + UnloadUnused = 0, + /// + /// Unloads scenes for connections but keeps scene loaded on server even if no connections are within it. + /// + KeepUnused = 1, + } + + /// + /// How to unload scenes on the server. UnloadUnused will unload scenes which have no more clients in them. KeepUnused will not unload a scene even when empty. ForceUnload will unload a scene regardless of if clients are still connected to it. + /// + [System.NonSerialized] + public ServerUnloadMode Mode = ServerUnloadMode.UnloadUnused; + /// + /// True if scenes should be loaded using addressables. This field only exists for optional use so the user may know if their queue data is using addressables. + /// + public bool Addressables; + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs.meta new file mode 100644 index 0000000..68dcbd5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3de31d76de313bc49aefba61135fdffc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs new file mode 100644 index 0000000..ca23c63 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs @@ -0,0 +1,19 @@ +namespace FishNet.Managing.Scened +{ + /// + /// Additional user-crafted data which can be included in scene unload callbacks. + /// + public class UnloadParams + { + /// + /// Objects which are included in callbacks on the server when unloading a scene. Can be useful for including unique information about the scene, such as match id. These are not sent to clients; use ClientParams for this. + /// + [System.NonSerialized] + public object[] ServerParams = new object[0]; + /// + /// Bytes which are sent to clients during scene unloads. Can contain any information. + /// + public byte[] ClientParams = new byte[0]; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs.meta new file mode 100644 index 0000000..90ef393 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3bba3fbbe6ffbae4bb18d50c8c9b3b30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs new file mode 100644 index 0000000..a91953c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs @@ -0,0 +1,53 @@ +using FishNet.Connection; +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +namespace FishNet.Managing.Scened +{ + + /// + /// Data generated when unloading a scene. + /// + public class UnloadQueueData + { + /// + /// Clients which receive this SceneQueueData. If Networked, all clients do. If Connections, only the specified Connections do. + /// + [System.NonSerialized] + public readonly SceneScopeType ScopeType; + /// + /// Connections to unload scenes for. Only valid on the server and when ScopeType is Connections. + /// + [System.NonSerialized] + public NetworkConnection[] Connections; + /// + /// SceneUnloadData to use. + /// + public SceneUnloadData SceneUnloadData = null; + /// + /// Current global scenes. + /// + public string[] GlobalScenes = new string[0]; + /// + /// True if to iterate this queue data as server. + /// + [System.NonSerialized] + public readonly bool AsServer; + + internal UnloadQueueData() { } + internal UnloadQueueData(SceneScopeType scopeType, NetworkConnection[] conns, SceneUnloadData sceneUnloadData, string[] globalScenes, bool asServer) + { + ScopeType = scopeType; + Connections = conns; + SceneUnloadData = sceneUnloadData; + GlobalScenes = globalScenes; + AsServer = asServer; + } + + + } + + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs.meta new file mode 100644 index 0000000..782ce32 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea9c20d60381ea74f974fb87a7e78297 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs new file mode 100644 index 0000000..c7004c3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs @@ -0,0 +1,324 @@ +using FishNet.Managing.Logging; +using FishNet.Serializing.Helping; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Scened +{ + /// + /// Extensions for SceneLookupData. + /// + internal static class SceneLookupDataExtensions + { + /// + /// Returns Names from SceneLookupData. + /// + /// + /// + public static string[] GetNames(this SceneLookupData[] datas) + { + string[] names = new string[datas.Length]; + for (int i = 0; i < datas.Length; i++) + names[i] = datas[i].Name; + + return names; + } + } + + /// + /// Data container for looking up, loading, or unloading a scene. + /// + public class SceneLookupData + { + /// + /// Handle of the scene. If value is 0, then handle is not used. + /// + public int Handle; + /// + /// Name of the scene. + /// + public string Name = string.Empty; + /// + /// Returns the scene name without a directory path should one exist. + /// + public string NameOnly => System.IO.Path.GetFileNameWithoutExtension(Name); + + #region Const + /// + /// String to display when scene data is invalid. + /// + private const string INVALID_SCENE = "One or more scene information entries contain invalid data and have been skipped."; + #endregion + + /// + /// + /// + public SceneLookupData() { } + /// + /// + /// + /// Scene to generate from. + public SceneLookupData(Scene scene) + { + Handle = scene.handle; + Name = scene.name; + } + /// + /// + /// + /// Scene name to generate from. + public SceneLookupData(string name) + { + Name = name; + } + /// + /// + /// + /// Scene handle to generate from. + public SceneLookupData(int handle) + { + Handle = handle; + } + /// + /// + /// + /// Scene handle to generate from. + /// Name to generate from if handle is 0. + public SceneLookupData(int handle, string name) + { + Handle = handle; + Name = name; + } + + #region Comparers. + public static bool operator ==(SceneLookupData sldA, SceneLookupData sldB) + { + //One is null while the other is not. + if ((sldA is null) != (sldB is null)) + return false; + + /*If here both are either null or have value. */ + if (!(sldA is null)) + return sldA.Equals(sldB); + else if (!(sldB is null)) + return sldB.Equals(sldA); + + //Fall through indicates both are null. + return true; + } + + public static bool operator !=(SceneLookupData sldA, SceneLookupData sldB) + { + //One is null while the other is not. + if ((sldA is null) != (sldB is null)) + return true; + + /*If here both are either null or have value. */ + if (!(sldA is null)) + return !sldA.Equals(sldB); + else if (!(sldB is null)) + return !sldB.Equals(sldA); + + //Fall through indicates both are null. + return true; + } + + public bool Equals(SceneLookupData sld) + { + //Comparing instanced against null. + if (sld is null) + return false; + + //True if both handles are empty. + bool bothHandlesEmpty = ( + (this.Handle == 0) && + (sld.Handle == 0) + ); + + //If both have handles and they match. + if (!bothHandlesEmpty && sld.Handle == this.Handle) + return true; + //If neither have handles and name matches. + else if (bothHandlesEmpty && sld.Name == this.Name) + return true; + + //Fall through. + return false; + } + + public override int GetHashCode() + { + int hashCode = 2053068273; + hashCode = hashCode * -1521134295 + Handle.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); + return hashCode; + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + public override string ToString() + { + return base.ToString(); + } + #endregion + + #region CreateData. + /// + /// Returns a new SceneLookupData. + /// + /// Scene to create from. + /// + public static SceneLookupData CreateData(Scene scene) => new SceneLookupData(scene); + /// + /// Returns a new SceneLookupData. + /// + /// Scene name to create from. + /// + public static SceneLookupData CreateData(string name) => new SceneLookupData(name); + /// + /// Returns a new SceneLookupData. + /// + /// Scene handle to create from. + /// + public static SceneLookupData CreateData(int handle) => new SceneLookupData(handle); + /// + /// Returns a SceneLookupData collection. + /// + /// Scenes to create from. + /// + public static SceneLookupData[] CreateData(List scenes) => CreateData(scenes.ToArray()); + /// + /// Returns a SceneLookupData collection. + /// + /// Scene names to create from. + /// + public static SceneLookupData[] CreateData(List names) => CreateData(names.ToArray()); + /// + /// Returns a SceneLookupData collection. + /// + /// Scene handles to create from. + /// + public static SceneLookupData[] CreateData(List handles) => CreateData(handles.ToArray()); + /// + /// Returns a SceneLookupData collection. + /// + /// Scenes to create from. + /// + public static SceneLookupData[] CreateData(Scene[] scenes) + { + bool invalidFound = false; + List result = new List(); + foreach (Scene item in scenes) + { + if (!item.IsValid()) + { + invalidFound = true; + continue; + } + + result.Add(CreateData(item)); + } + + if (invalidFound) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning(INVALID_SCENE); + } + return result.ToArray(); + } + /// + /// Returns a SceneLookupData collection. + /// + /// Scene names to create from. + /// + public static SceneLookupData[] CreateData(string[] names) + { + bool invalidFound = false; + List result = new List(); + foreach (string item in names) + { + if (string.IsNullOrEmpty(item)) + { + invalidFound = true; + continue; + } + + string nameOnly = System.IO.Path.GetFileNameWithoutExtension(item); + result.Add(CreateData(nameOnly)); + } + + if (invalidFound) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning(INVALID_SCENE); + } + return result.ToArray(); + } + /// + /// Returns a SceneLookupData collection. + /// + /// Scene handles to create from. + /// + public static SceneLookupData[] CreateData(int[] handles) + { + bool invalidFound = false; + List result = new List(); + foreach (int item in handles) + { + if (item == 0) + { + invalidFound = true; + continue; + } + + result.Add(CreateData(item)); + } + + if (invalidFound) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning(INVALID_SCENE); + } + return result.ToArray(); + } + #endregion + + /// + /// Returns the first scene found using Handle or Name, preferring Handle. + /// + /// + /// True if scene was found by handle. Handle is always checked first. + public Scene GetScene(out bool foundByHandle) + { + foundByHandle = false; + + if (Handle == 0 && string.IsNullOrEmpty(Name)) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning("Scene handle and name is unset; scene cannot be returned."); + return default; + } + + Scene result = default; + + //Lookup my handle. + if (Handle != 0) + { + result = SceneManager.GetScene(Handle); + if (result.handle != 0) + foundByHandle = true; + } + + //If couldnt find handle try by string. + if (!foundByHandle) + result = SceneManager.GetScene(NameOnly); + + return result; + } + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs.meta new file mode 100644 index 0000000..2f035f7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df1ac9b164e75da46bc52f4dd4fe30ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs new file mode 100644 index 0000000..30cd2a7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs @@ -0,0 +1,2054 @@ +using FishNet.Connection; +using FishNet.Managing.Client; +using FishNet.Managing.Logging; +using FishNet.Managing.Server; +using FishNet.Object; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnitySceneManager = UnityEngine.SceneManagement.SceneManager; + +namespace FishNet.Managing.Scened +{ + /// + /// Handles loading, unloading, and scene visibility for clients. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/SceneManager")] + public sealed class SceneManager : MonoBehaviour + { + #region Types. + internal enum LightProbeUpdateType + { + Asynchronous = 0, + BlockThread = 1, + Off = 2, + } + #endregion + + #region Public. + /// + /// Called after the active scene has been set, immediately after scene loads. This will occur before NetworkBehaviour callbacks run for the scene's objects. + /// + public event Action OnActiveSceneSet; + /// + /// Called when a client loads initial scenes after connecting. Boolean will be true if asServer. + /// + public event Action OnClientLoadedStartScenes; + /// + /// Called when a scene change queue has begun. This will only call if a scene has succesfully begun to load or unload. The queue may process any number of scene events. For example: if a scene is told to unload while a load is still in progress, then the unload will be placed in the queue. + /// + public event Action OnQueueStart; + /// + /// Called when the scene queue is emptied. + /// + public event Action OnQueueEnd; + /// + /// Called when a scene load starts. + /// + public event Action OnLoadStart; + /// + /// Called when completion percentage changes while loading a scene. Value is between 0f and 1f, while 1f is 100% done. Can be used for custom progress bars when loading scenes. + /// + public event Action OnLoadPercentChange; + /// + /// Called when a scene load ends. + /// + public event Action OnLoadEnd; + /// + /// Called when a scene unload starts. + /// + public event Action OnUnloadStart; + /// + /// Called when a scene unload ends. + /// + public event Action OnUnloadEnd; + /// + /// Called when a client presence changes within a scene, before the server rebuilds observers. + /// + public event Action OnClientPresenceChangeStart; + /// + /// Called when a client presence changes within a scene, after the server rebuilds observers. + /// + public event Action OnClientPresenceChangeEnd; + /// + /// Connections within each scene. + /// + public Dictionary> SceneConnections { get; private set; } = new Dictionary>(); + #endregion + + #region Internal. + /// + /// Called after the active scene has been set, immediately after scene loads. + /// + internal event Action OnActiveSceneSetInternal; + #endregion + + #region Serialized. + /// + /// Script to handle addressables loading and unloading. This field may be blank if addressables are not being used. + /// + [Tooltip("Script to handle addressables loading and unloading. This field may be blank if addressables are not being used.")] + [SerializeField] + private SceneProcessorBase _sceneProcessor; + /// + /// How to update light probes after loading or unloading scenes. + /// + [Tooltip("How to update light probes after loading or unloading scenes.")] + [SerializeField] + private LightProbeUpdateType _lightProbeUpdating = LightProbeUpdateType.Asynchronous; + /// + /// True to move objects visible to clientHost that are within an unloading scene. This ensures the objects are despawned on the client side rather than when the scene is destroyed. + /// + [Tooltip("True to move objects visible to clientHost that are within an unloading scene. This ensures the objects are despawned on the client side rather than when the scene is destroyed.")] + [SerializeField] + private bool _moveClientHostObjects = true; + /// + /// True to automatically set active scenes when loading and unloading scenes. + /// + [Tooltip("True to automatically set active scenes when loading and unloading scenes.")] + [SerializeField] + private bool _setActiveScene = true; + #endregion + + #region Private. + /// + /// NetworkManager for this script. + /// + private NetworkManager _networkManager; + /// + /// ServerManager for this script. + /// + private ServerManager _serverManager => _networkManager.ServerManager; + /// + /// ClientManager for this script. + /// + private ClientManager _clientManager => _networkManager.ClientManager; + /// + /// Scenes which are currently loaded as networked scenes. All players should have networked scenes loaded. + /// + private string[] _globalScenes = new string[0]; + /// + /// Lastest SceneLoadData for a global load. + /// + private SceneLoadData _globalSceneLoadData = new SceneLoadData(); + /// + /// Scenes to load or unload, in order. + /// + private List _queuedOperations = new List(); + /// + /// Scenes which must be manually unloaded, even when emptied. + /// + private HashSet _manualUnloadScenes = new HashSet(); + /// + /// Scene containing moved objects when changing single scene. On client this will contain all objects moved until the server destroys them. + /// The network only sends spawn messages once per-client, per server side scene load. If a scene load is performed only for specific connections + /// then the server is not resetting their single scene, but rather the single scene for those connections only. Because of this, any objects + /// which are to be moved will not receive a second respawn message, as they are never destroyed on server, only on client. + /// While on server only this scene contains objects being moved temporarily, before being moved to the new scene. + /// + private Scene _movedObjectsScene; + /// + /// Scene containing objects awaiting to be destroyed by the client-host. + /// This is required when unloading scenes where the client-host has visibility. + /// Otherwise the objects would become destroyed when the scene unloads on the server + /// which would cause missing networkobjects on clients when receiving despawn messages. + /// + private Scene _delayedDestroyScene; + /// + /// A scene to be set as the active scene where there are no global scenes. + /// This is used to prevent connection scenes and MovedObjectsScene from becoming the active scene. + /// + private Scene _fallbackActiveScene; + /// + /// Becomes true when when a scene first successfully begins to load or unload. Value is reset to false when the scene queue is emptied. + /// + private bool _sceneQueueStartInvoked; + /// + /// Objects being moved from MovedObjects scene to another. + /// + private List _movingObjects = new List(); + /// + /// How many scene load confirmations the server is expecting from a client. + /// Unloads do not need to be checked because server does not require confirmation for those. + /// This is used to prevent attacks. + /// + private Dictionary _pendingClientSceneChanges = new Dictionary(); + #endregion + + #region Consts. + /// + /// String to use when scene data used to load is invalid. + /// + private const string INVALID_SCENELOADDATA = "One or more datas in SceneLoadData are invalid.This generally occurs when calling this method without specifying any scenes or when data fields are null."; + /// + /// String to use when scene data used to unload is invalid. + /// + private const string INVALID_SCENEUNLOADDATA = "One or more datas in SceneLoadData are invalid.This generally occurs when calling this method without specifying any scenes or when data fields are null."; + #endregion + + #region Unity callbacks and initialization. + private void Awake() + { + UnitySceneManager.sceneUnloaded += SceneManager_SceneUnloaded; + if (_sceneProcessor == null) + _sceneProcessor = gameObject.AddComponent(); + _sceneProcessor.Initialize(this); + } + + private void Start() + { + //No need to unregister since managers are on the same object. + _networkManager.ServerManager.OnRemoteConnectionState += ServerManager_OnRemoteConnectionState; + _networkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState; + _clientManager.RegisterBroadcast(OnLoadScenes); + _clientManager.RegisterBroadcast(OnUnloadScenes); + _serverManager.RegisterBroadcast(OnClientLoadedScenes); + + _clientManager.RegisterBroadcast(OnClientEmptyStartScenes); + _serverManager.RegisterBroadcast(OnServerEmptyStartScenes); + } + + private void OnDestroy() + { + UnitySceneManager.sceneUnloaded -= SceneManager_SceneUnloaded; + } + + /// + /// Called when the server connection state changes. + /// + private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj) + { + //If no servers are started. + if (!_networkManager.ServerManager.AnyServerStarted()) + ResetValues(); + + } + /// + /// Resets as if first use. + /// + private void ResetValues() + { + SceneConnections.Clear(); + _globalScenes = new string[0]; + _globalSceneLoadData = new SceneLoadData(); + _queuedOperations.Clear(); + _manualUnloadScenes.Clear(); + _sceneQueueStartInvoked = false; + _movingObjects.Clear(); + } + + /// + /// Called when a connection state changes for a remote client. + /// + private void ServerManager_OnRemoteConnectionState(NetworkConnection arg1, RemoteConnectionStateArgs arg2) + { + if (arg2.ConnectionState == RemoteConnectionState.Stopped) + ClientDisconnected(arg1); + } + + /// + /// Initializes this script for use. + /// + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + _networkManager = manager; + } + + /// + /// Received when a scene is unloaded. + /// + /// + private void SceneManager_SceneUnloaded(Scene scene) + { + if (!_networkManager.IsServer) + return; + + /* Remove any unloaded scenes from local variables. This shouldn't + * be needed if the user properly utilizes this scene manager, + * but just incase, we don't want a memory leak. */ + SceneConnections.Remove(scene); + _manualUnloadScenes.Remove(scene); + RemoveFromGlobalScenes(scene); + } + #endregion + + #region Initial synchronizing. + /// + /// Invokes OnClientLoadedStartScenes if connection just loaded start scenes. + /// + /// + private void TryInvokeLoadedStartScenes(NetworkConnection connection, bool asServer) + { + if (connection.SetLoadedStartScenes(asServer)) + OnClientLoadedStartScenes?.Invoke(connection, asServer); + } + + /// + /// Called when authenitcator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. This invokes before OnClientAuthenticated so FishNet may run operations on authenticated clients before user code does. + /// + /// + internal void OnClientAuthenticated(NetworkConnection connection) + { + AddPendingLoad(connection); + + //No global scenes to load. + if (_globalScenes.Length == 0) + { + EmptyStartScenesBroadcast msg = new EmptyStartScenesBroadcast(); + connection.Broadcast(msg); + } + else + { + SceneLoadData sld = new SceneLoadData(_globalScenes); + sld.Params = _globalSceneLoadData.Params; + sld.Options = _globalSceneLoadData.Options; + sld.ReplaceScenes = _globalSceneLoadData.ReplaceScenes; + + LoadQueueData qd = new LoadQueueData(SceneScopeType.Global, new NetworkConnection[0], sld, _globalScenes, false); + //Send message to load the networked scenes. + LoadScenesBroadcast msg = new LoadScenesBroadcast() + { + QueueData = qd + }; + + connection.Broadcast(msg, true); + } + } + + /// + /// Received on client when the server has no start scenes. + /// + private void OnClientEmptyStartScenes(EmptyStartScenesBroadcast msg) + { + _clientManager.Broadcast(msg); + } + /// + /// Received on server when client confirms there are no start scenes. + /// + private void OnServerEmptyStartScenes(NetworkConnection conn, EmptyStartScenesBroadcast msg) + { + //Already received, shouldn't be happening again. + if (conn.LoadedStartScenes) + { + if (_networkManager.CanLog(LoggingType.Common)) + Debug.LogError($"Received multiple EmptyStartSceneBroadcast from connectionId {conn.ClientId}. Connection will be kicked immediately."); + _networkManager.TransportManager.Transport.StopConnection(conn.ClientId, true); + } + else + { + OnClientLoadedScenes(conn, new ClientScenesLoadedBroadcast()); + } + } + #endregion + + #region Player disconnect. + /// + /// Received when a player disconnects from the server. + /// + /// //finish. + private void ClientDisconnected(NetworkConnection conn) + { + _pendingClientSceneChanges.Remove(conn); + /* Remove connection from all scenes. While doing so check + * if scene should be unloaded provided there are no more clients + * in the scene, and it's set to automatically unload. This situation is a bit + * unique since a client disconnect happens outside the manager, so there + * isn't much code we can re-use to perform this operation. */ + List scenesToUnload = new List(); + //Current active scene. + Scene activeScene = UnitySceneManager.GetActiveScene(); + foreach (KeyValuePair> item in SceneConnections) + { + Scene scene = item.Key; + HashSet hs = item.Value; + + bool removed = hs.Remove(conn); + /* If no more observers for scene, not a global scene, and not to be manually unloaded + * then remove scene from SceneConnections and unload it. */ + if (removed && hs.Count == 0 && + !IsGlobalScene(scene) && !_manualUnloadScenes.Contains(scene) && + (scene != activeScene)) + scenesToUnload.Add(scene); + } + + //If scenes should be unloaded. + if (scenesToUnload.Count > 0) + { + foreach (Scene s in scenesToUnload) + SceneConnections.Remove(s); + SceneUnloadData sud = new SceneUnloadData(SceneLookupData.CreateData(scenesToUnload)); + UnloadConnectionScenes(new NetworkConnection[0], sud); + } + } + #endregion + + #region Server received messages. + /// + /// Received on server when a client loads scenes. + /// + /// + /// + private void OnClientLoadedScenes(NetworkConnection conn, ClientScenesLoadedBroadcast msg) + { + int pendingLoads; + _pendingClientSceneChanges.TryGetValueIL2CPP(conn, out pendingLoads); + + //There's no loads or unloads pending, kick client. + if (pendingLoads == 0) + { + if (_networkManager.CanLog(LoggingType.Common)) + Debug.LogError($"Received excessive ClientScenesLoadedBroadcast from connectionId {conn.ClientId}. Connection will be kicked immediately."); + _networkManager.TransportManager.Transport.StopConnection(conn.ClientId, true); + + return; + } + //If there is a load pending then update pending count. + else + { + pendingLoads--; + if (pendingLoads == 0) + _pendingClientSceneChanges.Remove(conn); + else + _pendingClientSceneChanges[conn] = pendingLoads; + } + + if (!Comparers.IsDefault(msg)) + { + foreach (SceneLookupData item in msg.SceneLookupDatas) + { + Scene s = item.GetScene(out _); + if (s.IsValid()) + AddConnectionToScene(conn, s); + } + } + + TryInvokeLoadedStartScenes(conn, true); + } + #endregion + + #region Events. + /// + /// Checks if OnQueueStart should invoke, and if so invokes. + /// + private void TryInvokeOnQueueStart() + { + if (_sceneQueueStartInvoked) + return; + + _sceneQueueStartInvoked = true; + OnQueueStart?.Invoke(); + } + /// + /// Checks if OnQueueEnd should invoke, and if so invokes. + /// + private void TryInvokeOnQueueEnd() + { + if (!_sceneQueueStartInvoked) + return; + + _sceneQueueStartInvoked = false; + OnQueueEnd?.Invoke(); + } + /// + /// Invokes that a scene load has started. Only called when valid scenes will be loaded. + /// + /// + private void InvokeOnSceneLoadStart(LoadQueueData qd) + { + TryInvokeOnQueueStart(); + OnLoadStart?.Invoke(new SceneLoadStartEventArgs(qd)); + } + /// + /// Invokes that a scene load has ended. Only called after a valid scene has loaded. + /// + /// + private void InvokeOnSceneLoadEnd(LoadQueueData qd, List requestedLoadScenes, List loadedScenes, string[] unloadedSceneNames) + { + //Make new list to not destroy original data. + List skippedScenes = requestedLoadScenes.ToList(); + //Remove loaded scenes from requested scenes. + for (int i = 0; i < loadedScenes.Count; i++) + skippedScenes.Remove(loadedScenes[i].name); + + SceneLoadEndEventArgs args = new SceneLoadEndEventArgs(qd, skippedScenes.ToArray(), loadedScenes.ToArray(), unloadedSceneNames); + OnLoadEnd?.Invoke(args); + } + /// + /// Invokes that a scene unload has started. Only called when valid scenes will be unloaded. + /// + /// + private void InvokeOnSceneUnloadStart(UnloadQueueData sqd) + { + TryInvokeOnQueueStart(); + OnUnloadStart?.Invoke(new SceneUnloadStartEventArgs(sqd)); + } + /// + /// Invokes that a scene unload has ended. Only called after a valid scene has unloaded. + /// + /// + private void InvokeOnSceneUnloadEnd(UnloadQueueData sqd, List unloadedScenes) + { + int[] handles = new int[unloadedScenes.Count]; + OnUnloadEnd?.Invoke(new SceneUnloadEndEventArgs(sqd, handles)); + } + /// + /// Invokes when completion percentage changes while unloading or unloading a scene. Value is between 0f and 1f, while 1f is 100% done. + /// + /// + private void InvokeOnScenePercentChange(LoadQueueData qd, float value) + { + value = Mathf.Clamp(value, 0f, 1f); + SceneLoadPercentEventArgs slp = new SceneLoadPercentEventArgs(qd, value); + OnLoadPercentChange?.Invoke(slp); + } + #endregion + + #region Scene queue processing. + /// + /// Queues a load or unload operation and starts queue if needed. + /// + /// + private void QueueOperation(object data) + { + //Add to scene queue data. + _queuedOperations.Add(data); + /* If only one entry then scene operations are not currently in progress. + * Should there be more than one entry then scene operations are already + * occuring. The coroutine will automatically load in order. */ + + if (_queuedOperations.Count == 1) + StartCoroutine(__ProcessSceneQueue()); + } + /// + /// Processes queued scene operations. + /// + /// + /// + private IEnumerator __ProcessSceneQueue() + { + /* Queue start won't invoke unless a scene load or unload actually occurs. + * For example: if a scene is already loaded, and nothing needs to be loaded, + * queue start will not invoke. */ + + while (_queuedOperations.Count > 0) + { + //If a load scene. + if (_queuedOperations[0] is LoadQueueData) + yield return StartCoroutine(__LoadScenes()); + //If an unload scene. + else if (_queuedOperations[0] is UnloadQueueData) + yield return StartCoroutine(__UnloadScenes()); + + if (_queuedOperations.Count > 0) + _queuedOperations.RemoveAt(0); + } + + TryInvokeOnQueueEnd(); + } + #endregion + + #region LoadScenes + /// + /// Loads scenes on the server and for all clients. Future clients will automatically load these scenes. + /// + /// Data about which scenes to load. + public void LoadGlobalScenes(SceneLoadData sceneLoadData) + { + LoadGlobalScenesInternal(sceneLoadData, _globalScenes, true); + } + /// + /// Adds to load scene queue. + /// + /// + /// + private void LoadGlobalScenesInternal(SceneLoadData sceneLoadData, string[] globalScenes, bool asServer) + { + if (!CanExecute(asServer, true)) + return; + if (SceneDataInvalid(sceneLoadData, true)) + return; + + LoadQueueData lqd = new LoadQueueData(SceneScopeType.Global, new NetworkConnection[0], sceneLoadData, globalScenes, asServer); + QueueOperation(lqd); + } + + /// + /// Loads scenes on server and tells connections to load them as well. Other connections will not load this scene. + /// + /// Connections to load scenes for. + /// Data about which scenes to load. + public void LoadConnectionScenes(NetworkConnection conn, SceneLoadData sceneLoadData) + { + LoadConnectionScenes(new NetworkConnection[] { conn }, sceneLoadData); + } + /// + /// Loads scenes on server and tells connections to load them as well. Other connections will not load this scene. + /// + /// Connections to load scenes for. + /// Data about which scenes to load. + public void LoadConnectionScenes(NetworkConnection[] conns, SceneLoadData sceneLoadData) + { + LoadConnectionScenesInternal(conns, sceneLoadData, _globalScenes, true); + } + /// + /// Loads scenes on server without telling clients to load the scenes. + /// + /// Data about which scenes to load. + public void LoadConnectionScenes(SceneLoadData sceneLoadData) + { + LoadConnectionScenesInternal(new NetworkConnection[0], sceneLoadData, _globalScenes, true); + } + + /// + /// Adds to load scene queue. + /// + /// + /// + private void LoadConnectionScenesInternal(NetworkConnection[] conns, SceneLoadData sceneLoadData, string[] globalScenes, bool asServer) + { + if (!CanExecute(asServer, true)) + return; + if (SceneDataInvalid(sceneLoadData, true)) + return; + + LoadQueueData lqd = new LoadQueueData(SceneScopeType.Connections, conns, sceneLoadData, globalScenes, asServer); + QueueOperation(lqd); + } + + /// + /// Returns if a NetworkObject can be moved. + /// + /// + /// + private bool CanMoveNetworkObject(NetworkObject nob) + { + bool canLog = _networkManager.CanLog(LoggingType.Warning); + + //Null. + if (nob == null) + { + if (canLog) + Debug.LogWarning($"NetworkObject is null."); + return false; + } + //Not networked. + if (!nob.IsNetworked) + { + if (canLog) + Debug.LogWarning($"NetworkObject {nob.name} cannot be moved as it is not networked."); + return false; + } + + //Not spawned. + if (!nob.IsSpawned) + { + if (canLog) + Debug.LogWarning($"NetworkObject {nob.name} canot be moved as it is not spawned."); + return false; + } + //SceneObject. + if (nob.IsSceneObject) + { + if (canLog) + Debug.LogWarning($"NetworkObject {nob.name} cannot be moved as it is a scene object."); + return false; + } + //Not root. + if (nob.transform.parent != null) + { + if (canLog) + Debug.LogWarning($"NetworkObject {nob.name} cannot be moved because it is not the root object. Unity can only move root objects between scenes."); + return false; + } + + return true; + } + + /// + /// Loads a connection scene queue data. This behaves just like a networked scene load except it sends only to the specified connections, and it always loads as an additive scene on server. + /// + /// + private IEnumerator __LoadScenes() + { + LoadQueueData data = _queuedOperations[0] as LoadQueueData; + //True if running as server. + bool asServer = data.AsServer; + //True if running as client, while network server is active. + bool asHost = (!asServer && _networkManager.IsServer); + + //If connection went inactive. + if (!ConnectionActive(asServer)) + yield break; + + /* Scene sanity checks. */ + if (data.SceneLoadData.SceneLookupDatas.Length == 0) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"No scenes specified to load."); + yield break; + } + + //True if replacing scenes with specified ones. + ReplaceOption replaceScenes = data.SceneLoadData.ReplaceScenes; + + /* Immediately set new global scenes. If on client this is whatever + * server passes in. This should be set even if scope type + * is not global because clients might get a connection scene first. + */ + if (!asServer) + { + if (!asHost) + _globalScenes = data.GlobalScenes; + } + /* However, if server, then only update global scenes if scope + * is global. */ + else if (asServer && data.ScopeType == SceneScopeType.Global) + { + _globalSceneLoadData = data.SceneLoadData; + string[] names = data.SceneLoadData.SceneLookupDatas.GetNames(); + //If replacing. + if (replaceScenes != ReplaceOption.None) + { + _globalScenes = names; + } + //Add onto. + else + { + int index = _globalScenes.Length; + Array.Resize(ref _globalScenes, _globalScenes.Length + names.Length); + Array.Copy(names, 0, _globalScenes, index, names.Length); + } + + data.GlobalScenes = _globalScenes; + } + + + /* Scene queue data scenes. + * All scenes in the scene queue data whether they will be loaded or not. */ + List requestedLoadSceneNames = new List(); + List requestedLoadSceneHandles = new List(); + + /* Make a null filled array. This will be populated + * using loaded scenes, or already loaded (eg cannot be loaded) scenes. */ + SceneLookupData[] broadcastLookupDatas = new SceneLookupData[data.SceneLoadData.SceneLookupDatas.Length]; + + /* LoadableScenes and SceneReferenceDatas. + /* Will contain scenes which may be loaded. + * Scenes might not be added to loadableScenes + * if for example loadOnlyUnloaded is true and + * the scene is already loaded. */ + List loadableScenes = new List(); + for (int i = 0; i < data.SceneLoadData.SceneLookupDatas.Length; i++) + { + SceneLookupData sld = data.SceneLoadData.SceneLookupDatas[i]; + //Scene to load. + bool byHandle; + Scene s = sld.GetScene(out byHandle); + //If found then add it to requestedLoadScenes. + if (s.IsValid()) + { + requestedLoadSceneNames.Add(s.name); + if (byHandle) + requestedLoadSceneHandles.Add(s.handle); + } + + if (CanLoadScene(data, sld)) + { + //Don't load if as host, server side would have loaded already. + if (!asHost) + loadableScenes.Add(sld); + } + //Only the server needs to find scene handles to send to client. Client will send these back to the server. + else if (asServer) + { + /* If here then scene cannot be loaded, which + * can only happen if the scene already exists. + * Find the scene using sld and set to datas. */ + /* Set at the index of i. This way should the current + * SLD not be the first scene it won't fill the + * first slot in broadcastLookupDatas. This is important + * because the first slot is used for the single scene + * when using replace scenes. */ + broadcastLookupDatas[i] = new SceneLookupData(s); + } + } + + /* Move identities + * to holder scene to preserve them. + * Required if a single scene is specified. Cannot rely on + * loadSingleScene since it is only true if the single scene + * must be loaded, which may be false if it's already loaded on + * the server. */ + //Do not run if running as client, and server is active. This would have already run as server. + if (!asHost) + { + foreach (NetworkObject nob in data.SceneLoadData.MovedNetworkObjects) + { + //NetworkObject might be null if client lost observation of it. + if (nob != null && CanMoveNetworkObject(nob)) + UnitySceneManager.MoveGameObjectToScene(nob.gameObject, GetMovedObjectsScene()); + } + } + + /* Resetting SceneConnections. */ + /* If server and replacing scenes. + * It's important to run this AFTER moving MovedNetworkObjects + * so that they are no longer in the scenes they are leaving. Otherwise + * the scene condition would pick them up as still in the leaving scene. */ + if (asServer && (replaceScenes != ReplaceOption.None)) + { + //If global then remove all connections from all scenes. + if (data.ScopeType == SceneScopeType.Global) + { + Scene[] scenes = SceneConnections.Keys.ToArray(); + foreach (Scene s in scenes) + RemoveAllConnectionsFromScene(s); + } + //Connections. + else if (data.ScopeType == SceneScopeType.Connections) + { + RemoveConnectionsFromNonGlobalScenes(data.Connections); + } + } + + + /* Scene unloading if replacing scenes. + * + * Unload all scenes except MovedObjectsHolder. Also don't + * unload GlobalScenes if loading as connection. */ + List unloadableScenes = new List(); + //Do not run if running as client, and server is active. This would have already run as server. + if ((replaceScenes != ReplaceOption.None) && !asHost) + { + //Unload all other scenes. + for (int i = 0; i < UnitySceneManager.sceneCount; i++) + { + Scene s = UnitySceneManager.GetSceneAt(i); + //MovedObjectsScene will never be unloaded. + if (s == GetMovedObjectsScene()) + continue; + /* Scene is in one of the scenes being loaded. + * This can occur when trying to load additional clients + * into an existing scene. */ + if (requestedLoadSceneNames.Contains(s.name)) + continue; + //Same as above but using handles. + if (requestedLoadSceneHandles.Contains(s.handle)) + continue; + /* Cannot unload global scenes. If + * replace scenes was used for a global + * load then global scenes would have been reset + * before this. */ + if (IsGlobalScene(s)) + continue; + //If scene must be manually unloaded then it cannot be unloaded here. + if (_manualUnloadScenes.Contains(s)) + continue; + + HashSet conns; + if (SceneConnections.TryGetValueIL2CPP(s, out conns)) + { + //Still has clients in scene. + if (conns != null && conns.Count > 0) + continue; + } + //An offline scene. + else + { + //If not replacing all scenes then skip offline scenes. + if (replaceScenes != ReplaceOption.All) + continue; + } + + unloadableScenes.Add(s); + } + } + + /* Start event. */ + if (unloadableScenes.Count > 0 || loadableScenes.Count > 0) + { + InvokeOnSceneLoadStart(data); + _sceneProcessor.LoadStart(data); + } + //Unloaded scenes by name. Only used for information within callbacks. + string[] unloadedNames = new string[unloadableScenes.Count]; + for (int i = 0; i < unloadableScenes.Count; i++) + unloadedNames[i] = unloadableScenes[i].name; + /* Before unloading if !asServer and !asHost and replacing scenes + * then move all non scene networked objects to the moved + * objects holder. Otherwise network objects would get destroyed + * on the scene change and never respawned if server doesn't + * have a reason to update visibility. */ + if (!data.AsServer && !asHost && (replaceScenes != ReplaceOption.None)) + { + Scene s = GetMovedObjectsScene(); + foreach (NetworkObject nob in _networkManager.ClientManager.Objects.Spawned.Values) + { + if (!nob.IsSceneObject) + UnitySceneManager.MoveGameObjectToScene(nob.gameObject, s); + } + } + /* Unloading scenes. */ + _sceneProcessor.UnloadStart(data); + for (int i = 0; i < unloadableScenes.Count; i++) + { + MoveClientHostObjects(unloadableScenes[i], asServer); + //Unload one at a time. + _sceneProcessor.BeginUnloadAsync(unloadableScenes[i]); + while (!_sceneProcessor.IsPercentComplete()) + yield return null; + } + _sceneProcessor.UnloadEnd(data); + + //Scenes loaded. + List loadedScenes = new List(); + /* Scene loading. + /* Use additive to not thread lock server. */ + for (int i = 0; i < loadableScenes.Count; i++) + { + //Start load async and wait for it to finish. + LoadSceneParameters loadSceneParameters = new LoadSceneParameters() + { + loadSceneMode = LoadSceneMode.Additive, + localPhysicsMode = data.SceneLoadData.Options.LocalPhysics + }; + + /* How much percentage each scene load can be worth + * at maximum completion. EG: if there are two scenes + * 1f / 2f is 0.5f. */ + float maximumIndexWorth = (1f / (float)loadableScenes.Count); + + _sceneProcessor.BeginLoadAsync(loadableScenes[i].Name, loadSceneParameters); + while (!_sceneProcessor.IsPercentComplete()) + { + float percent = _sceneProcessor.GetPercentComplete(); + InvokePercentageChange(i, maximumIndexWorth, percent); + yield return null; + } + + //Invokes OnScenePercentChange with progress. + void InvokePercentageChange(int index, float maximumWorth, float currentScenePercent) + { + /* Total percent will be how much percentage is complete + * in total. Initialize it with a value based on how many + * scenes are already fully loaded. */ + float totalPercent = (index * maximumWorth); + //Add this scenes progress onto total percent. + totalPercent += Mathf.Lerp(0f, maximumWorth, currentScenePercent); + //Dispatch with total percent. + InvokeOnScenePercentChange(data, totalPercent); + } + + //Add to loaded scenes. + Scene loaded = UnitySceneManager.GetSceneAt(UnitySceneManager.sceneCount - 1); + loadedScenes.Add(loaded); + _sceneProcessor.AddLoadedScene(loaded); + } + //When all scenes are loaded invoke with 100% done. + InvokeOnScenePercentChange(data, 1f); + + + /* Add to ManuallyUnloadScenes. */ + if (data.AsServer && !data.SceneLoadData.Options.AutomaticallyUnload) + { + foreach (Scene s in loadedScenes) + _manualUnloadScenes.Add(s); + } + /* Move identities to first scene. */ + if (!asHost) + { + //Find the first valid scene to move objects to. + Scene firstValidScene = default; + //If to stack scenes. + if (data.SceneLoadData.Options.AllowStacking) + { + Scene firstScene = GetFirstLookupScene(data.SceneLoadData.SceneLookupDatas); + /* If the first lookup data contains a handle and the scene + * is found for that handle then use that as the moved to scene. + * Nobs always move to the first specified scene. */ + if (data.SceneLoadData.SceneLookupDatas[0].Handle != 0 && !string.IsNullOrEmpty(firstScene.name)) + { + firstValidScene = firstScene; + } + //If handle is not specified then used the last scene that has the same name as the first lookupData. + else + { + Scene lastSameSceneName = default; + for (int i = 0; i < UnitySceneManager.sceneCount; i++) + { + Scene s = UnitySceneManager.GetSceneAt(i); + if (s.name == firstScene.name) + lastSameSceneName = s; + } + + /* Shouldn't be possible since the scene will always exist either by + * just being loaded or already loaded. */ + if (string.IsNullOrEmpty(lastSameSceneName.name)) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Scene {data.SceneLoadData.SceneLookupDatas[0].Name} could not be found in loaded scenes."); + } + else + { + firstValidScene = lastSameSceneName; + } + } + } + //Not stacking. + else + { + firstValidScene = GetFirstLookupScene(data.SceneLoadData.SceneLookupDatas); + //If not found by look then try firstloaded. + if (string.IsNullOrEmpty(firstValidScene.name)) + firstValidScene = GetFirstLoadedScene(); + } + + //Gets first scene loaded this method call. + Scene GetFirstLoadedScene() + { + if (loadedScenes.Count > 0) + return loadedScenes[0]; + else + return default; + } + //Gets first found scene in datas. + Scene GetFirstLookupScene(SceneLookupData[] datas) + { + foreach (SceneLookupData sld in datas) + { + Scene result = sld.GetScene(out _); + if (!string.IsNullOrEmpty(result.name)) + return result; + } + + return default; + } + + //If firstValidScene is still invalid then throw. + if (string.IsNullOrEmpty(firstValidScene.name)) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Unable to move objects to a new scene because new scene lookup has failed."); + } + //Move objects. + else + { + Scene s = GetMovedObjectsScene(); + s.GetRootGameObjects(_movingObjects); + + foreach (GameObject go in _movingObjects) + UnitySceneManager.MoveGameObjectToScene(go, firstValidScene); + } + } + + _sceneProcessor.ActivateLoadedScenes(); + //Wait until everything is loaded (done). + yield return _sceneProcessor.AsyncsIsDone(); + _sceneProcessor.LoadEnd(data); + + /* Wait until loadedScenes are all marked as done. + * This is an extra precautionary step because on some devices + * the AsyncIsDone returns true before scenes are actually loaded. */ + bool allScenesLoaded = true; + do + { + foreach (Scene s in loadedScenes) + { + if (!s.isLoaded) + { + allScenesLoaded = false; + break; + } + } + yield return null; + } while (!allScenesLoaded); + + SetActiveScene(); + + //Only the server needs to find scene handles to send to client. Client will send these back to the server. + if (asServer) + { + //Populate broadcastLookupDatas with any loaded scenes. + foreach (Scene s in loadedScenes) + { + SetInFirstNullIndex(s); + + //Sets scene in the first null index of broadcastLookupDatas. + void SetInFirstNullIndex(Scene scene) + { + for (int i = 0; i < broadcastLookupDatas.Length; i++) + { + if (broadcastLookupDatas[i] == null) + { + broadcastLookupDatas[i] = new SceneLookupData(scene); + return; + } + } + + //If here there are no null entries. + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Cannot add scene to broadcastLookupDatas, collection is full."); + } + } + } + + /* If running as server and server is + * active then send scene changes to client. + * Making sure server is still active should it maybe + * have dropped during scene loading. */ + if (data.AsServer && _networkManager.IsServer) + { + //Tell clients to load same scenes. + LoadScenesBroadcast msg = new LoadScenesBroadcast() + { + QueueData = data + }; + //Replace scene lookup datas with ones intended to broadcast to client. + msg.QueueData.SceneLoadData.SceneLookupDatas = broadcastLookupDatas; + //If networked scope then send to all. + if (data.ScopeType == SceneScopeType.Global) + { + NetworkConnection[] conns = _serverManager.Clients.Values.ToArray(); + AddPendingLoad(conns); + _serverManager.Broadcast(msg, true); + } + //If connections scope then only send to connections. + else if (data.ScopeType == SceneScopeType.Connections) + { + AddPendingLoad(data.Connections); + for (int i = 0; i < data.Connections.Length; i++) + { + if (data.Connections[i].Authenticated) + data.Connections[i].Broadcast(msg, true); + } + } + } + /* If running as client then send a message + * to the server to tell them the scene was loaded. + * This allows the server to add the client + * to the scene for checkers. */ + else if (!data.AsServer && _networkManager.IsClient) + { + ClientScenesLoadedBroadcast msg = new ClientScenesLoadedBroadcast() + { + SceneLookupDatas = data.SceneLoadData.SceneLookupDatas + }; + _clientManager.Broadcast(msg); + } + + InvokeOnSceneLoadEnd(data, requestedLoadSceneNames, loadedScenes, unloadedNames); + } + + /// + /// Received on client when connection scenes must be loaded. + /// + /// + /// + private void OnLoadScenes(LoadScenesBroadcast msg) + { + //Null data is sent by the server when there are no start scenes to load. + if (msg.QueueData == null) + { + TryInvokeLoadedStartScenes(_clientManager.Connection, false); + return; + } + + LoadQueueData qd = msg.QueueData; + if (qd.ScopeType == SceneScopeType.Global) + LoadGlobalScenesInternal(qd.SceneLoadData, qd.GlobalScenes, false); + else + LoadConnectionScenesInternal(new NetworkConnection[0], qd.SceneLoadData, qd.GlobalScenes, false); + } + #endregion + + #region UnloadScenes. + /// + /// Unloads scenes on the server and for all clients. + /// + /// Data about which scenes to unload. + public void UnloadGlobalScenes(SceneUnloadData sceneUnloadData) + { + if (!CanExecute(true, true)) + return; + + UnloadGlobalScenesInternal(sceneUnloadData, _globalScenes, true); + } + /// + /// + /// + /// + /// + /// + /// + private void UnloadGlobalScenesInternal(SceneUnloadData sceneUnloadData, string[] globalScenes, bool asServer) + { + UnloadQueueData uqd = new UnloadQueueData(SceneScopeType.Global, new NetworkConnection[0], sceneUnloadData, globalScenes, asServer); + QueueOperation(uqd); + } + + + /// + /// Unloads scenes on server and tells a connection to unload them as well. Other connections will not unload this scene. + /// + /// Connection to unload scenes for. + /// Data about which scenes to unload. + public void UnloadConnectionScenes(NetworkConnection connection, SceneUnloadData sceneUnloadData) + { + UnloadConnectionScenes(new NetworkConnection[] { connection }, sceneUnloadData); + } + /// + /// Unloads scenes on server and tells connections to unload them as well. Other connections will not unload this scene. + /// + /// Connections to unload scenes for. + /// Data about which scenes to unload. + public void UnloadConnectionScenes(NetworkConnection[] connections, SceneUnloadData sceneUnloadData) + { + UnloadConnectionScenesInternal(connections, sceneUnloadData, _globalScenes, true); + } + + /// + /// Unloads scenes on server without telling any connections to unload them. + /// + /// Data about which scenes to unload. + public void UnloadConnectionScenes(SceneUnloadData sceneUnloadData) + { + UnloadConnectionScenesInternal(new NetworkConnection[0], sceneUnloadData, _globalScenes, true); + } + /// + /// Unloads scenes for connections. + /// + /// + /// + /// + /// + private void UnloadConnectionScenesInternal(NetworkConnection[] connections, SceneUnloadData sceneUnloadData, string[] globalScenes, bool asServer) + { + if (!CanExecute(asServer, true)) + return; + if (SceneDataInvalid(sceneUnloadData, true)) + return; + + UnloadQueueData uqd = new UnloadQueueData(SceneScopeType.Connections, connections, sceneUnloadData, globalScenes, asServer); + QueueOperation(uqd); + } + /// + /// Loads scenes within QueuedSceneLoads. + /// + /// + private IEnumerator __UnloadScenes() + { + UnloadQueueData data = _queuedOperations[0] as UnloadQueueData; + + //If connection went inactive. + if (!ConnectionActive(data.AsServer)) + yield break; + + /* Some actions should not run as client if server is also active. + * This is to keep things from running twice. */ + bool asClientHost = (!data.AsServer && _networkManager.IsServer); + ///True if running asServer. + bool asServer = data.AsServer; + + //Get scenes to unload. + Scene[] scenes = GetScenes(data.SceneUnloadData.SceneLookupDatas); + /* No scenes found. Only run this if not asHost. + * While asHost scenes will possibly not exist because + * server side has already unloaded them. But rest of + * the unload should continue. */ + if (scenes.Length == 0 && !asClientHost) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"No scenes were found to unload."); + yield break; + } + + /* Remove from global scenes + * if server and scope is global. + * All passed in scenes should be removed from global + * regardless of if they're valid or not. If they are invalid, + * then they shouldn't be in global to begin with. */ + if (asServer && data.ScopeType == SceneScopeType.Global) + { + RemoveFromGlobalScenes(data.SceneUnloadData.SceneLookupDatas); + //Update queue data. + data.GlobalScenes = _globalScenes; + } + + /* Remove connections. */ + if (asServer) + { + foreach (Scene s in scenes) + { + //If global then remove all connections. + if (data.ScopeType == SceneScopeType.Global) + RemoveAllConnectionsFromScene(s); + //Connections. + else if (data.ScopeType == SceneScopeType.Connections) + RemoveConnectionsFromScene(data.Connections, s); + } + } + + + /* This will contain all scenes which can be unloaded. + * The collection will be modified through various checks. */ + List unloadableScenes = scenes.ToList(); + /* If asServer and KeepUnused then clear all unloadables. + * The clients will still unload the scenes. */ + if ((asServer || asClientHost) && data.SceneUnloadData.Options.Mode == UnloadOptions.ServerUnloadMode.KeepUnused) + unloadableScenes.Clear(); + /* Check to remove global scenes unloadableScenes. + * This will need to be done if scenes are being unloaded + * for connections. Global scenes cannot be unloaded as + * connection. */ + if (data.ScopeType == SceneScopeType.Connections) + RemoveGlobalScenes(unloadableScenes); + //If set to unload unused only. + if (data.SceneUnloadData.Options.Mode == UnloadOptions.ServerUnloadMode.UnloadUnused) + RemoveOccupiedScenes(unloadableScenes); + + //If there are scenes to unload. + if (unloadableScenes.Count > 0) + { + InvokeOnSceneUnloadStart(data); + _sceneProcessor.UnloadStart(data); + + //Begin unloading. + foreach (Scene s in unloadableScenes) + { + MoveClientHostObjects(s, asServer); + /* Remove from manualUnloadedScenes. + * Scene may not be in this collection + * but removing is one call vs checking + * then removing. */ + _manualUnloadScenes.Remove(s); + + _sceneProcessor.BeginUnloadAsync(s); + while (!_sceneProcessor.IsPercentComplete()) + yield return null; + } + + _sceneProcessor.UnloadEnd(data); + } + + /* Must yield after sceneProcessor handles things. + * This is a Unity bug of sorts. I'm not entirely sure what + * is happening, but without the yield it seems as though + * the processor logic doesn't complete. This doesn't make much + * sense given unity is supposed to be single threaded. Must be + * something to do with the coroutine. */ + yield return null; + SetActiveScene(); + + /* If running as server then make sure server + * is still active after the unloads. If so + * send out unloads to clients. */ + if (asServer && ConnectionActive(true)) + { + //Tell clients to unload same scenes. + UnloadScenesBroadcast msg = new UnloadScenesBroadcast() + { + QueueData = data + }; + //Global. + if (data.ScopeType == SceneScopeType.Global) + { + _serverManager.Broadcast(msg, true); + } + //Connections. + else if (data.ScopeType == SceneScopeType.Connections) + { + if (data.Connections != null) + { + for (int i = 0; i < data.Connections.Length; i++) + { + if (data.Connections[i] != null) + data.Connections[i].Broadcast(msg, true); + } + } + } + } + + InvokeOnSceneUnloadEnd(data, unloadableScenes); + } + + + /// + /// Received on clients when networked scenes must be unloaded. + /// + /// + /// + private void OnUnloadScenes(UnloadScenesBroadcast msg) + { + UnloadQueueData qd = msg.QueueData; + if (qd.ScopeType == SceneScopeType.Global) + UnloadGlobalScenesInternal(qd.SceneUnloadData, qd.GlobalScenes, false); + else + UnloadConnectionScenesInternal(new NetworkConnection[0], qd.SceneUnloadData, qd.GlobalScenes, false); + } + #endregion + + /// + /// Move objects visible to clientHost that are within an unloading scene.This ensures the objects are despawned on the client side rather than when the scene is destroyed. + /// + /// + private void MoveClientHostObjects(Scene scene, bool asServer) + { + if (!_moveClientHostObjects) + return; + /* The asServer isn't really needed. I could only call + * this method when asServer is true. But for the sake + * of preventing user-error (me being the user this time) + * I've included it into the parameters. */ + if (!asServer) + return; + //Don't need to perform if not host. + if (!_networkManager.IsClient) + return; + + NetworkConnection clientConn = _networkManager.ClientManager.Connection; + /* It would be nice to see if the client wasn't even in the scene + * here using SceneConnections but it's possible that the scene had been + * wiped from SceneConnections earlier depending on how scenes are + * loaded or unloaded. Instead we must iterate through spawned objects. */ + + ListCache movingNobs = ListCaches.GetNetworkObjectCache(); + /* Rather than a get all networkobjects in scene + * let's iterate the spawned objects instead. I imagine + * in most scenarios iterating spawned would be faster. + * That's a long one! */ + foreach (NetworkObject nob in _networkManager.ServerManager.Objects.Spawned.Values) + { + //Not in the scene being destroyed. + if (nob.gameObject.scene != scene) + continue; + //ClientHost doesn't have visibility. + if (!nob.Observers.Contains(clientConn)) + continue; + //Cannot move if not root. + if (nob.transform.root != null) + continue; + + /* If here nob is in the same being + * destroyed and clientHost has visiblity. */ + movingNobs.AddValue(nob); + } + + int count = movingNobs.Written; + if (count > 0) + { + Scene moveScene = GetDelayedDestroyScene(); + List collection = movingNobs.Collection; + + for (int i = 0; i < count; i++) + { + NetworkObject nob = collection[i]; + /* Force as not a scene object + * so that it becomes destroyed + * rather than disabled. */ + nob.ClearRuntimeSceneObject(); + /* If the object is already being despawned then + *just disable and move it. Otherwise despawn it + * on the server then move it. */ + //Not deinitializing, despawn it then. + if (!nob.IsDeinitializing) + nob.Despawn(); + else + nob.gameObject.SetActive(false); + + UnitySceneManager.MoveGameObjectToScene(nob.gameObject, moveScene); + } + } + ListCaches.StoreCache(movingNobs); + } + + /// + /// Returns if a connection is in a scene using SceneConnections. + /// + /// + /// + /// + internal bool InSceneConnections(NetworkConnection conn, Scene scene) + { + if (!SceneConnections.TryGetValueIL2CPP(scene, out HashSet hs)) + return false; + else + return hs.Contains(conn); + } + + /// + /// Adds the owner of nob to the gameObjects scene if there are no global scenes. + /// + public void AddOwnerToDefaultScene(NetworkObject nob) + { + //No owner. + if (!nob.Owner.IsValid) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObject {nob.name} does not have an owner."); + return; + } + //Won't add to default if there are globals. + if (_globalScenes != null && _globalScenes.Length > 0) + return; + + AddConnectionToScene(nob.Owner, nob.gameObject.scene); + } + + /// + /// Adds a connection to a scene. This will always be called one connection at a time because connections are only added after they invidually validate loading the scene. + /// + /// + /// + private void AddConnectionToScene(NetworkConnection conn, Scene scene) + { + HashSet hs; + //Scene doesn't have any connections yet. + bool inSceneConnections = SceneConnections.TryGetValueIL2CPP(scene, out hs); + if (!inSceneConnections) + hs = new HashSet(); + + bool added = hs.Add(conn); + if (added) + { + conn.AddToScene(scene); + + //If not yet added to scene connections. + if (!inSceneConnections) + SceneConnections[scene] = hs; + + NetworkConnection[] arrayConn = new NetworkConnection[] { conn }; + InvokeClientPresenceChange(scene, arrayConn, true, true); + RebuildObservers(arrayConn.ToArray()); + InvokeClientPresenceChange(scene, arrayConn, true, false); + + /* Also need to rebuild all networkobjects + * for connection so other players can + * see them. */ + RebuildObservers(conn.Objects.ToArray()); + } + } + + + /// + /// Removes connections from any scene which is not global. + /// + /// + /// + private void RemoveConnectionsFromNonGlobalScenes(NetworkConnection[] conns) + { + List removedScenes = new List(); + + foreach (KeyValuePair> item in SceneConnections) + { + Scene scene = item.Key; + //Cannot remove from globla scenes. + if (IsGlobalScene(scene)) + continue; + + HashSet hs = item.Value; + List connectionsRemoved = new List(); + //Remove every connection from the scene. + foreach (NetworkConnection c in conns) + { + bool removed = hs.Remove(c); + if (removed) + { + c.RemoveFromScene(scene); + connectionsRemoved.Add(c); + } + } + + //If hashset is empty then remove scene from SceneConnections. + if (hs.Count == 0) + removedScenes.Add(scene); + + if (connectionsRemoved.Count > 0) + { + NetworkConnection[] connectionsRemovedArray = connectionsRemoved.ToArray(); + InvokeClientPresenceChange(scene, connectionsRemovedArray, false, true); + RebuildObservers(connectionsRemovedArray); + InvokeClientPresenceChange(scene, connectionsRemovedArray, false, false); + } + } + + foreach (Scene s in removedScenes) + SceneConnections.Remove(s); + + /* Also rebuild observers for objects owned by connection. + * This ensures other connections will lose visibility if + * they no longer share a scene. */ + foreach (NetworkConnection c in conns) + RebuildObservers(c.Objects.ToArray()); + } + + + /// + /// Removes connections from specified scenes. + /// + /// + /// + private void RemoveConnectionsFromScene(NetworkConnection[] conns, Scene scene) + { + HashSet hs; + //No hashset for scene, so no connections are in scene. + if (!SceneConnections.TryGetValueIL2CPP(scene, out hs)) + return; + + List connectionsRemoved = new List(); + //Remove every connection from the scene. + foreach (NetworkConnection c in conns) + { + bool removed = hs.Remove(c); + if (removed) + { + c.RemoveFromScene(scene); + connectionsRemoved.Add(c); + } + } + + //If hashset is empty then remove scene from SceneConnections. + if (hs.Count == 0) + SceneConnections.Remove(scene); + + if (connectionsRemoved.Count > 0) + { + NetworkConnection[] connectionsRemovedArray = connectionsRemoved.ToArray(); + InvokeClientPresenceChange(scene, connectionsRemovedArray, false, true); + RebuildObservers(connectionsRemovedArray); + InvokeClientPresenceChange(scene, connectionsRemovedArray, false, false); + } + + /* Also rebuild observers for objects owned by connection. + * This ensures other connections will lose visibility if + * they no longer share a scene. */ + foreach (NetworkConnection c in conns) + RebuildObservers(c.Objects.ToArray()); + } + + /// + /// Removes all connections from a scene. + /// + /// + private void RemoveAllConnectionsFromScene(Scene scene) + { + HashSet hs; + //No hashset for scene, so no connections are in scene. + if (!SceneConnections.TryGetValueIL2CPP(scene, out hs)) + return; + + //On each connection remove them from specified scene. + foreach (NetworkConnection c in hs) + c.RemoveFromScene(scene); + //Make hashset into list for presence change. + NetworkConnection[] connectionsRemoved = hs.ToArray(); + + //Clear hashset and remove entry from sceneconnections. + hs.Clear(); + SceneConnections.Remove(scene); + + if (connectionsRemoved.Length > 0) + { + InvokeClientPresenceChange(scene, connectionsRemoved, false, true); + RebuildObservers(connectionsRemoved); + InvokeClientPresenceChange(scene, connectionsRemoved, false, false); + } + + /* Also rebuild observers for objects owned by connection. + * This ensures other connections will lose visibility if + * they no longer share a scene. */ + foreach (NetworkConnection c in connectionsRemoved) + RebuildObservers(c.Objects.ToArray()); + } + + #region Can Load/Unload Scene. + /// + /// Returns if a scene can be loaded locally. + /// + /// + private bool CanLoadScene(LoadQueueData qd, SceneLookupData sld) + { + bool foundByHandle; + Scene s = sld.GetScene(out foundByHandle); + //Try to find if scene is already loaded. + bool alreadyLoaded = !string.IsNullOrEmpty(s.name); + + if (alreadyLoaded) + { + //Only servers can load the same scene multiple times for stacking. + if (!qd.AsServer) + return false; + //If can only load scenes which aren't loaded yet and scene is already loaded. + if (!qd.SceneLoadData.Options.AllowStacking) + return false; + /* Found by handle, this means the user is trying to specify + * exactly which scene to load into. When a handle is specified + * new instances will not be created, so a new scene cannot + * be loaded. */ + if (alreadyLoaded && foundByHandle) + return false; + } + + //Fall through. + return true; + } + #endregion + + #region Helpers. + /// + /// Rebuilds observers for networkObjects. + /// + /// + private void RebuildObservers(NetworkObject[] networkObjects) + { + foreach (NetworkObject nob in networkObjects) + { + if (nob != null && nob.IsSpawned) + _serverManager.Objects.RebuildObservers(nob); + } + } + /// + /// Rebuilds all NetworkObjects for connection. + /// + internal void RebuildObservers(NetworkConnection connection) + { + RebuildObservers(new NetworkConnection[] { connection }); + } + /// + /// Rebuilds all NetworkObjects for connections. + /// + internal void RebuildObservers(NetworkConnection[] connections) + { + foreach (NetworkConnection c in connections) + _serverManager.Objects.RebuildObservers(c); + } + /// + /// Invokes OnClientPresenceChange start or end. + /// + /// + /// + /// + /// + private void InvokeClientPresenceChange(Scene scene, NetworkConnection[] conns, bool added, bool start) + { + foreach (NetworkConnection c in conns) + { + ClientPresenceChangeEventArgs cpc = new ClientPresenceChangeEventArgs(scene, c, added); + if (start) + OnClientPresenceChangeStart?.Invoke(cpc); + else + OnClientPresenceChangeEnd?.Invoke(cpc); + } + } + #endregion + + #region GetScene. + /// + /// Gets scenes from SceneLookupData. + /// + /// + /// + private Scene[] GetScenes(SceneLookupData[] datas) + { + List result = new List(); + foreach (SceneLookupData sld in datas) + { + Scene s = sld.GetScene(out _); + if (!string.IsNullOrEmpty(s.name)) + result.Add(s); + } + + return result.ToArray(); + } + + /// + /// Returns a scene by name. + /// + /// + /// + public static Scene GetScene(string sceneName) + { + return UnityEngine.SceneManagement.SceneManager.GetSceneByName(sceneName); + } + /// + /// Returns a scene by handle. + /// + /// + /// + public static Scene GetScene(int sceneHandle) + { + int count = UnityEngine.SceneManagement.SceneManager.sceneCount; + for (int i = 0; i < count; i++) + { + Scene s = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i); + if (s.handle == sceneHandle) + return s; + } + + return new Scene(); + } + #endregion + + /// + /// Returns if GlobalScenes contains scene. + /// + /// + /// + private bool IsGlobalScene(Scene scene) + { + for (int i = 0; i < _globalScenes.Length; i++) + { + if (_globalScenes[i] == scene.name) + return true; + } + + return false; + } + + /// + /// Removes datas from GlobalScenes. + /// + /// + private void RemoveFromGlobalScenes(Scene scene) + { + RemoveFromGlobalScenes(new SceneLookupData[] { SceneLookupData.CreateData(scene) }); + } + /// + /// Removes datas from GlobalScenes. + /// + /// + private void RemoveFromGlobalScenes(SceneLookupData[] datas) + { + List newGlobalScenes = _globalScenes.ToList(); + int startCount = newGlobalScenes.Count; + //Remove scenes. + for (int i = 0; i < datas.Length; i++) + newGlobalScenes.Remove(datas[i].Name); + + //If any were removed remake globalscenes. + if (startCount != newGlobalScenes.Count) + _globalScenes = newGlobalScenes.ToArray(); + } + + /// + /// Removes GlobalScenes from scenes. + /// + /// + /// + private void RemoveGlobalScenes(List scenes) + { + for (int i = 0; i < scenes.Count; i++) + { + foreach (string gs in _globalScenes) + { + if (gs == scenes[i].name) + { + scenes.RemoveAt(i); + i--; + } + } + } + } + + /// + /// Removes occupied scenes from scenes. + /// + /// + private void RemoveOccupiedScenes(List scenes) + { + for (int i = 0; i < scenes.Count; i++) + { + if (SceneConnections.TryGetValueIL2CPP(scenes[i], out _)) + { + scenes.RemoveAt(i); + i--; + } + } + } + + /// + /// Adds a pending load for a connection. + /// + private void AddPendingLoad(NetworkConnection conn) + { + AddPendingLoad(new NetworkConnection[] { conn }); + } + /// + /// Adds a pending load for a connection. + /// + private void AddPendingLoad(NetworkConnection[] conns) + { + foreach (NetworkConnection c in conns) + { + /* Make sure connection is active. This should always be true + * but perhaps disconnect happened as scene was loading on server + * therefor it cannot be sent to the client. + * Also only authenticated clients can load scenes. */ + if (!c.IsActive || !c.Authenticated) + continue; + + if (_pendingClientSceneChanges.TryGetValue(c, out int result)) + _pendingClientSceneChanges[c] = (result + 1); + else + _pendingClientSceneChanges[c] = 1; + } + } + /// + /// Sets the first global scene as the active scene. + /// If a global scene is not available then FallbackActiveScene is used. + /// + private void SetActiveScene() + { + if (!_setActiveScene) + return; + + Scene s = default; + if (_globalScenes != null && _globalScenes.Length > 0) + s = GetScene(_globalScenes[0]); + + /* If scene isn't set from global then make + * sure currently active isn't the movedobjectscene. + * If it is, then use the fallback scene. */ + if (string.IsNullOrEmpty(s.name) && UnitySceneManager.GetActiveScene() == _movedObjectsScene) + s = GetFallbackActiveScene(); + + //If was changed then update active scene. + if (!string.IsNullOrEmpty(s.name)) + UnitySceneManager.SetActiveScene(s); + + OnActiveSceneSet?.Invoke(); + OnActiveSceneSetInternal?.Invoke(); + + //Also update light probes. + if (_lightProbeUpdating == LightProbeUpdateType.Asynchronous) + LightProbes.TetrahedralizeAsync(); + else if (_lightProbeUpdating == LightProbeUpdateType.BlockThread) + LightProbes.Tetrahedralize(); + } + + /// + /// Returns the FallbackActiveScene. + /// + /// + private Scene GetFallbackActiveScene() + { + if (string.IsNullOrEmpty(_fallbackActiveScene.name)) + _fallbackActiveScene = UnitySceneManager.CreateScene("FallbackActiveScene"); + + return _fallbackActiveScene; + } + + /// + /// Returns the MovedObejctsScene. + /// + /// + private Scene GetMovedObjectsScene() + { + //Create moved objects scene. It will probably be used eventually. If not, no harm either way. + if (string.IsNullOrEmpty(_movedObjectsScene.name)) + _movedObjectsScene = UnitySceneManager.CreateScene("MovedObjectsHolder"); + + return _movedObjectsScene; + } + + /// + /// Returns the DelayedDestroyScene. + /// + /// + private Scene GetDelayedDestroyScene() + { + //Create moved objects scene. It will probably be used eventually. If not, no harm either way. + if (string.IsNullOrEmpty(_delayedDestroyScene.name)) + _delayedDestroyScene = UnityEngine.SceneManagement.SceneManager.CreateScene("DelayedDestroy"); + + return _delayedDestroyScene; + } + + + #region Sanity checks. + /// + /// Returns if a SceneLoadData is valid. + /// + /// + /// + /// + private bool SceneDataInvalid(SceneLoadData data, bool error) + { + bool result = data.DataInvalid(); + + if (result && error) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError(INVALID_SCENELOADDATA); + } + + return result; + } + /// + /// Returns if a SceneLoadData is valid. + /// + /// + /// + /// + private bool SceneDataInvalid(SceneUnloadData data, bool error) + { + bool result = data.DataInvalid(); + if (result && error) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError(INVALID_SCENEUNLOADDATA); + } + + return result; + } + /// + /// Returns if connection is active for server or client in association with AsServer. + /// + /// + /// + private bool ConnectionActive(bool asServer) + { + return (asServer) ? _networkManager.IsServer : _networkManager.IsClient; + } + /// + /// Returns if a method can execute. + /// + /// + /// + /// + private bool CanExecute(bool asServer, bool warn) + { + bool result; + if (asServer) + { + result = _networkManager.IsServer; + if (!result && warn) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Method cannot be called as the server is not active."); + } + } + else + { + result = _networkManager.IsClient; + if (!result && warn) + { + if (_networkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Method cannot be called as the client is not active."); + } + } + + return result; + } + #endregion + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs.meta new file mode 100644 index 0000000..03dd624 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15895a51081447d46bda466e7e830c08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs new file mode 100644 index 0000000..a364c84 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs @@ -0,0 +1,93 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityScene = UnityEngine.SceneManagement.Scene; + +namespace FishNet.Managing.Scened +{ + + public abstract class SceneProcessorBase : MonoBehaviour + { + #region Protected. + /// + /// SceneManager for this processor. + /// + protected SceneManager SceneManager; + #endregion + + /// + /// Initializes this script for use. + /// + /// SceneManager which will be utilizing this class. + public virtual void Initialize(SceneManager manager) + { + SceneManager = manager; + } + /// + /// Called when scene loading has begun. + /// + public virtual void LoadStart(LoadQueueData queueData) { } + /// + /// Called when scene loading has ended. + /// + public virtual void LoadEnd(LoadQueueData queueData) { } + /// + /// Called when scene unloading has begun within a load operation. + /// + public virtual void UnloadStart(LoadQueueData queueData) { } + /// + /// Called when scene unloading has ended within a load operation. + /// + public virtual void UnloadEnd(LoadQueueData queueData) { } + /// + /// Called when scene unloading has begun within an unload operation. + /// + public virtual void UnloadStart(UnloadQueueData queueData) { } + /// + /// Called when scene unloading has ended within an unload operation. + /// + public virtual void UnloadEnd(UnloadQueueData queueData) { } + /// + /// Begin loading a scene using an async method. + /// + /// Scene name to load. + public abstract void BeginLoadAsync(string sceneName, LoadSceneParameters parameters); + /// + /// Begin unloading a scene using an async method. + /// + /// Scene name to unload. + public abstract void BeginUnloadAsync(Scene scene); + /// + /// Returns if a scene load or unload percent is done. + /// + /// + public abstract bool IsPercentComplete(); + /// + /// Returns the progress on the current scene load or unload. + /// + /// + public abstract float GetPercentComplete(); + /// + /// Adds a scene to loaded scenes. + /// + /// Scene loaded. + public virtual void AddLoadedScene(Scene scene) { } + /// + /// Returns scenes which were loaded during a load operation. + /// + public abstract List GetLoadedScenes(); + /// + /// Activates scenes which were loaded. + /// + public abstract void ActivateLoadedScenes(); + /// + /// Returns if all asynchronized tasks are considered IsDone. + /// + /// + public abstract IEnumerator AsyncsIsDone(); + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs.meta new file mode 100644 index 0000000..e952beb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de3f29952a63dc341a7542a1f898cb12 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs new file mode 100644 index 0000000..a0f3d84 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs @@ -0,0 +1,356 @@ + +//using FishNet.Managing.Scened.Data; +//using System; +//using UnityEngine; +//using UnityEngine.SceneManagement; + +//namespace FishNet.Managing.Scened +//{ + +// public static class SceneSpawner +// { + +// #region Prefab. +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(Scene scene, GameObject prefab) +// { +// return Instantiate(scene, prefab); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(Scene scene, GameObject prefab) +// { +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab) +// { +// return Instantiate(sceneReferenceData, prefab); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab) +// { +// Scene scene = SceneManager.ReturnScene(sceneReferenceData); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(int sceneHandle, GameObject prefab) +// { +// return Instantiate(sceneHandle, prefab, prefab.transform.position, prefab.transform.rotation, null); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(int sceneHandle, GameObject prefab) +// { +// Scene scene = SceneManager.ReturnScene(sceneHandle); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(string sceneName, GameObject prefab) +// { +// return Instantiate(sceneName, prefab); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(string sceneName, GameObject prefab) +// { +// Scene scene = SceneManager.ReturnScene(sceneName); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, null, true); +// } +// #endregion + + + + +// #region Prefab, Parent, WorldSpace +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(Scene scene, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// return Instantiate(scene, prefab, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(Scene scene, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// return Instantiate(sceneReferenceData, prefab, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// Scene scene = SceneManager.ReturnScene(sceneReferenceData); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(int sceneHandle, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// return Instantiate(sceneHandle, prefab, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(int sceneHandle, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// Scene scene = SceneManager.ReturnScene(sceneHandle); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(string sceneName, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// return Instantiate(sceneName, prefab, parent, instantiateInWorldSpace); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(string sceneName, GameObject prefab, Transform parent, bool instantiateInWorldSpace = true) +// { +// Scene scene = SceneManager.ReturnScene(sceneName); +// return Instantiate(scene, prefab, prefab.transform.position, prefab.transform.rotation, parent, instantiateInWorldSpace); +// } +// #endregion + + + + +// #region Prefab, Position, Rotation. +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(Scene scene, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// return Instantiate(scene, prefab, position, rotation); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(Scene scene, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// return Instantiate(scene, prefab, position, rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// return Instantiate(sceneReferenceData, prefab, position, rotation); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// Scene scene = SceneManager.ReturnScene(sceneReferenceData); +// return Instantiate(scene, prefab, position, rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(int sceneHandle, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// return Instantiate(sceneHandle, prefab, position, rotation); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(int sceneHandle, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// Scene scene = SceneManager.ReturnScene(sceneHandle); +// return Instantiate(scene, prefab, position, rotation, null, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(string sceneName, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// return Instantiate(sceneName, prefab, position, rotation); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(string sceneName, GameObject prefab, Vector3 position, Quaternion rotation) +// { +// Scene scene = SceneManager.ReturnScene(sceneName); +// return Instantiate(scene, prefab, position, rotation, null, true); +// } +// #endregion + + + + +// #region Prefab, Position, Rotation, Parent. +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(Scene scene, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// return Instantiate(scene, prefab, position, rotation, parent); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(Scene scene, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// return Instantiate(scene, prefab, position, rotation, parent, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// return Instantiate(sceneReferenceData, prefab, position, rotation, parent); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(SceneReferenceData sceneReferenceData, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// Scene scene = SceneManager.ReturnScene(sceneReferenceData); +// return Instantiate(scene, prefab, position, rotation, parent, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(int sceneHandle, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// return Instantiate(sceneHandle, prefab, position, rotation, parent); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(int sceneHandle, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// Scene scene = SceneManager.ReturnScene(sceneHandle); +// return Instantiate(scene, prefab, position, rotation, parent, true); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static GameObject Instantiate(string sceneName, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// return Instantiate(sceneName, prefab, position, rotation, parent); +// } +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// public static T Instantiate(string sceneName, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent) +// { +// Scene scene = SceneManager.ReturnScene(sceneName); +// return Instantiate(scene, prefab, position, rotation, parent, true); +// } +// #endregion + + +// #region Instantiator. +// /// +// /// Instantiates a prefab and moves it to a scene. +// /// +// /// Instantiated prefab or script. +// private static T Instantiate(Scene scene, GameObject prefab, Vector3 position, Quaternion rotation, Transform parent, bool instantiateInWorldSpace) +// { +// if (string.IsNullOrEmpty(scene.name)) +// { +// Debug.LogWarning("Scene does not exist. Prefab cannot be instantiated."); +// return default(T); +// } + +// GameObject result = MonoBehaviour.Instantiate(prefab, position, rotation); +// if (result != null) +// { +// //Move to new scene first. +// UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(result, scene); + +// //Set parent and spaces. +// if (parent != null) +// { +// result.transform.SetParent(parent); +// //If to not instantiate in world space then update pos/rot to localspace. +// if (!instantiateInWorldSpace) +// { +// result.transform.localPosition = position; +// result.transform.localRotation = rotation; +// } +// } + +// //If was a gameobject then return as GO. +// if (typeof(T) == typeof(GameObject)) +// return (T)Convert.ChangeType(result, typeof(GameObject)); +// //Otherwise use getcomponent on the type. +// else +// return result.GetComponent(); +// } +// //Couldn't be instantiated, return default of T. +// else +// { +// return default(T); +// } + +// } +// #endregion + + +// } + + + + +//} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs.meta new file mode 100644 index 0000000..94dd0f6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 405b031a6ef64b346ae8c5ccbf07d8e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server.meta new file mode 100644 index 0000000..da71fec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 993fee93506dc1a409dfc0d0cb89354d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs new file mode 100644 index 0000000..6472def --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs @@ -0,0 +1,22 @@ + +using FishNet.Broadcast; +using FishNet.Utility.Performance; +using System.Collections.Generic; + +namespace FishNet.Managing.Server +{ + + public struct ClientConnectionChangeBroadcast : IBroadcast + { + public bool Connected; + public int Id; + } + + public struct ConnectedClientsBroadcast : IBroadcast + { + public ListCache ListCache; + public List Ids; + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs.meta new file mode 100644 index 0000000..9b30fbf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a16b83a545be8f8488795783a0fc8648 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor.meta new file mode 100644 index 0000000..10e9aa6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eef52ab3fdb83f04592a1de5ccb741f5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs new file mode 100644 index 0000000..1ff9a51 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs @@ -0,0 +1,61 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Managing.Server.Editing +{ + + + [CustomEditor(typeof(ServerManager), true)] + [CanEditMultipleObjects] + public class ServerManagerEditor : Editor + { + private SerializedProperty _authenticator; + private SerializedProperty _spawnPacking; + private SerializedProperty _changeFrameRate; + private SerializedProperty _frameRate; + private SerializedProperty _shareIds; + private SerializedProperty _startOnHeadless; + private SerializedProperty _limitClientMTU; + + protected virtual void OnEnable() + { + _authenticator = serializedObject.FindProperty("_authenticator"); + _spawnPacking = serializedObject.FindProperty("SpawnPacking"); + _changeFrameRate = serializedObject.FindProperty("_changeFrameRate"); + _frameRate = serializedObject.FindProperty("_frameRate"); + _shareIds = serializedObject.FindProperty("_shareIds"); + _startOnHeadless = serializedObject.FindProperty("_startOnHeadless"); + _limitClientMTU = serializedObject.FindProperty("_limitClientMTU"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((ServerManager)target), typeof(ServerManager), false); + GUI.enabled = true; + + + EditorGUILayout.PropertyField(_authenticator); + EditorGUILayout.PropertyField(_spawnPacking); + EditorGUILayout.PropertyField(_changeFrameRate); + if (_changeFrameRate.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_frameRate); + EditorGUI.indentLevel--; + } + EditorGUILayout.PropertyField(_shareIds); + EditorGUILayout.PropertyField(_startOnHeadless); + EditorGUILayout.PropertyField(_limitClientMTU); + + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs.meta new file mode 100644 index 0000000..953fe5a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da6ea97e6b868974e8ac139fe545e986 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object.meta new file mode 100644 index 0000000..f453896 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 272e053307699c84d9787bfd86d3529a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs new file mode 100644 index 0000000..e819b08 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs @@ -0,0 +1,468 @@ +using FishNet.Connection; +using FishNet.Managing.Object; +using FishNet.Managing.Transporting; +using FishNet.Object; +using FishNet.Observing; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Performance; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Server +{ + public partial class ServerObjects : ManagedObjects + { + #region Private. + /// + /// Cache filled with objects which observers are being updated. + /// This is primarily used to invoke events after all observers are updated, rather than as each is updated. + /// + private List _observerChangedObjectsCache = new List(100); + /// + /// NetworkObservers which require regularly iteration. + /// + private List _timedNetworkObservers = new List(); + /// + /// Index in TimedNetworkObservers to start on next cycle. + /// + private int _nextTimedObserversIndex; + #endregion + + /// + /// Called when MonoBehaviours call Update. + /// + private void Observers_OnUpdate() + { + UpdateTimedObservers(); + } + + /// + /// Progressively updates NetworkObservers with timed conditions. + /// + private void UpdateTimedObservers() + { + if (!base.NetworkManager.IsServer) + return; + //No point in updating if the timemanager isn't going to tick this frame. + if (!base.NetworkManager.TimeManager.FrameTicked) + return; + int observersCount = _timedNetworkObservers.Count; + if (observersCount == 0) + return; + + ServerManager serverManager = base.NetworkManager.ServerManager; + TransportManager transportManager = NetworkManager.TransportManager; + /* Try to iterate all timed observers every half a second. + * This value will increase as there's more observers. */ + int completionTicks = Mathf.Max(1, (base.NetworkManager.TimeManager.TickRate * 2)); + /* Multiply required ticks based on connection count and nob count. This will + * reduce how quickly observers update slightly but will drastically + * improve performance. */ + float tickMultiplier = 1f + (float)( + (serverManager.Clients.Count * 0.005f) + + (serverManager.Objects.Spawned.Count * 0.0005f) + ); + /* Add an additional iteration to prevent + * 0 iterations */ + int iterations = (observersCount / (int)(completionTicks * tickMultiplier)) + 1; + if (iterations > observersCount) + iterations = observersCount; + + + PooledWriter everyoneWriter = WriterPool.GetWriter(); + PooledWriter ownerWriter = WriterPool.GetWriter(); + + //Index to perform a check on. + int observerIndex = 0; + foreach (NetworkConnection conn in serverManager.Clients.Values) + { + + int cacheIndex = 0; + using (PooledWriter largeWriter = WriterPool.GetWriter()) + { + //Reset index to start on for every connection. + observerIndex = 0; + /* Run the number of calculated iterations. + * This is spaced out over frames to prevent + * fps spikes. */ + for (int i = 0; i < iterations; i++) + { + observerIndex = _nextTimedObserversIndex + i; + /* Compare actual collection size not cached value. + * This is incase collection is modified during runtime. */ + if (observerIndex >= _timedNetworkObservers.Count) + observerIndex -= _timedNetworkObservers.Count; + + /* If still out of bounds something whack is going on. + * Reset index and exit method. Let it sort itself out + * next iteration. */ + if (observerIndex < 0 || observerIndex >= _timedNetworkObservers.Count) + { + _nextTimedObserversIndex = 0; + break; + } + + NetworkObject nob = _timedNetworkObservers[observerIndex]; + ObserverStateChange osc = nob.RebuildObservers(conn, true); + if (osc == ObserverStateChange.Added) + { + everyoneWriter.Reset(); + ownerWriter.Reset(); + WriteSpawn(nob, conn, ref everyoneWriter, ref ownerWriter); + CacheObserverChange(nob, ref cacheIndex); + } + else if (osc == ObserverStateChange.Removed) + { + everyoneWriter.Reset(); + WriteDespawn(nob, nob.DisableOnDespawn, ref everyoneWriter); + } + else + { + continue; + } + /* Only use ownerWriter if an add, and if owner. Owner + * doesn't matter if not being added because no owner specific + * information would be included. */ + PooledWriter writerToUse = (osc == ObserverStateChange.Added && nob.Owner == conn) ? + ownerWriter : everyoneWriter; + + largeWriter.WriteArraySegment(writerToUse.GetArraySegment()); + } + + if (largeWriter.Length > 0) + { + transportManager.SendToClient( + (byte)Channel.Reliable, + largeWriter.GetArraySegment(), conn); + } + + //Invoke spawn callbacks on nobs. + for (int i = 0; i < cacheIndex; i++) + _observerChangedObjectsCache[i].InvokePostOnServerStart(conn); + } + } + + everyoneWriter.Dispose(); + ownerWriter.Dispose(); + _nextTimedObserversIndex = (observerIndex + 1); + } + + /// + /// Indicates that a networkObserver component should be updated regularly. This is done automatically. + /// + /// NetworkObject to be updated. + public void AddTimedNetworkObserver(NetworkObject networkObject) + { + _timedNetworkObservers.Add(networkObject); + } + + /// + /// Indicates that a networkObserver component no longer needs to be updated regularly. This is done automatically. + /// + /// NetworkObject to be updated. + public void RemoveTimedNetworkObserver(NetworkObject networkObject) + { + _timedNetworkObservers.Remove(networkObject); + } + + /// + /// Caches an observer change. + /// + /// + private void CacheObserverChange(NetworkObject nob, ref int cacheIndex) + { + /* If this spawn would exceed cache size then + * add instead of set value. */ + if (_observerChangedObjectsCache.Count <= cacheIndex) + _observerChangedObjectsCache.Add(nob); + else + _observerChangedObjectsCache[cacheIndex] = nob; + + cacheIndex++; + } + + /// + /// Removes a connection from observers without synchronizing changes. + /// + /// + private void RemoveFromObserversWithoutSynchronization(NetworkConnection connection) + { + int cacheIndex = 0; + + foreach (NetworkObject nob in Spawned.Values) + { + if (nob.RemoveObserver(connection)) + CacheObserverChange(nob, ref cacheIndex); + } + + //Invoke despawn callbacks on nobs. + for (int i = 0; i < cacheIndex; i++) + _observerChangedObjectsCache[i].InvokeOnServerDespawn(connection); + } + + /// + /// Rebuilds observers on all NetworkObjects for all connections. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers() + { + ListCache nobCache = ListCaches.GetNetworkObjectCache(); + foreach (NetworkObject nob in Spawned.Values) + nobCache.AddValue(nob); + ListCache connCache = ListCaches.GetNetworkConnectionCache(); + foreach (NetworkConnection conn in base.NetworkManager.ServerManager.Clients.Values) + connCache.AddValue(conn); + + RebuildObservers(nobCache, connCache); + ListCaches.StoreCache(nobCache); + ListCaches.StoreCache(connCache); + } + + /// + /// Rebuilds observers on NetworkObjects. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(NetworkObject[] nobs) + { + int count = nobs.Length; + for (int i = 0; i < count; i++) + RebuildObservers(nobs[i]); + } + + /// + /// Rebuilds observers on NetworkObjects. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(List nobs) + { + int count = nobs.Count; + for (int i = 0; i < count; i++) + RebuildObservers(nobs[i]); + } + + /// + /// Rebuilds observers on NetworkObjects. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(ListCache nobs) + { + int count = nobs.Written; + List collection = nobs.Collection; + for (int i = 0; i < count; i++) + RebuildObservers(collection[i]); + } + /// + /// Rebuilds observers on NetworkObjects for connections. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(ListCache nobs, ListCache conns) + { + int count = nobs.Written; + List collection = nobs.Collection; + for (int i = 0; i < count; i++) + RebuildObservers(collection[i], conns); + } + /// + /// Rebuilds observers on all objects for a connections. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(ListCache connections) + { + int count = connections.Written; + List collection = connections.Collection; + for (int i = 0; i < count; i++) + RebuildObservers(collection[i]); + } + /// + /// Rebuilds observers on all objects for connections. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(NetworkConnection[] connections) + { + int count = connections.Length; + for (int i = 0; i < count; i++) + RebuildObservers(connections[i]); + } + /// + /// Rebuilds observers on all objects for connections. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(List connections) + { + int count = connections.Count; + for (int i = 0; i < count; i++) + RebuildObservers(connections[i]); + } + + /// + /// Rebuilds observers on all NetworkObjects for a connection. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(NetworkConnection connection) + { + RebuildObservers(Spawned.Values, connection); + } + + /// + /// Rebuilds observers for a connection on NetworkObjects. + /// + public void RebuildObservers(IEnumerable nobs, NetworkConnection connection) + { + PooledWriter everyoneWriter = WriterPool.GetWriter(); + PooledWriter ownerWriter = WriterPool.GetWriter(); + + int observerCacheIndex = 0; + using (PooledWriter largeWriter = WriterPool.GetWriter()) + { + observerCacheIndex = 0; + foreach (NetworkObject n in nobs) + { + //If observer state changed then write changes. + ObserverStateChange osc = n.RebuildObservers(connection, false); + if (osc == ObserverStateChange.Added) + { + everyoneWriter.Reset(); + ownerWriter.Reset(); + WriteSpawn(n, connection, ref everyoneWriter, ref ownerWriter); + CacheObserverChange(n, ref observerCacheIndex); + } + else if (osc == ObserverStateChange.Removed) + { + everyoneWriter.Reset(); + WriteDespawn(n, n.DisableOnDespawn, ref everyoneWriter); + } + else + { + continue; + } + /* Only use ownerWriter if an add, and if owner. Owner //cleanup see if rebuild timed and this can be joined or reuse methods. + * doesn't matter if not being added because no owner specific + * information would be included. */ + PooledWriter writerToUse = (osc == ObserverStateChange.Added && n.Owner == connection) ? + ownerWriter : everyoneWriter; + + largeWriter.WriteArraySegment(writerToUse.GetArraySegment()); + } + + if (largeWriter.Length > 0) + { + NetworkManager.TransportManager.SendToClient( + (byte)Channel.Reliable, + largeWriter.GetArraySegment(), connection); + } + } + + //Dispose of writers created in this method. + everyoneWriter.Dispose(); + ownerWriter.Dispose(); + + //Invoke spawn callbacks on nobs. + for (int i = 0; i < observerCacheIndex; i++) + _observerChangedObjectsCache[i].InvokePostOnServerStart(connection); + } + + /// + /// Rebuilds observers for connections on a NetworkObject. + /// + private void RebuildObservers(NetworkObject nob, ListCache conns) + { + PooledWriter everyoneWriter = WriterPool.GetWriter(); + PooledWriter ownerWriter = WriterPool.GetWriter(); + + int written = conns.Written; + for (int i = 0; i < written; i++) + { + NetworkConnection conn = conns.Collection[i]; + + everyoneWriter.Reset(); + ownerWriter.Reset(); + //If observer state changed then write changes. + ObserverStateChange osc = nob.RebuildObservers(conn, false); + if (osc == ObserverStateChange.Added) + WriteSpawn(nob, conn, ref everyoneWriter, ref ownerWriter); + else if (osc == ObserverStateChange.Removed) + WriteDespawn(nob, nob.DisableOnDespawn, ref everyoneWriter); + else + continue; + + /* Only use ownerWriter if an add, and if owner. Owner + * doesn't matter if not being added because no owner specific + * information would be included. */ + PooledWriter writerToUse = (osc == ObserverStateChange.Added && nob.Owner == conn) ? + ownerWriter : everyoneWriter; + + if (writerToUse.Length > 0) + { + NetworkManager.TransportManager.SendToClient( + (byte)Channel.Reliable, + writerToUse.GetArraySegment(), conn); + + //If a spawn is being sent. + if (osc == ObserverStateChange.Added) + nob.InvokePostOnServerStart(conn); + } + + } + + //Dispose of writers created in this method. + everyoneWriter.Dispose(); + ownerWriter.Dispose(); + } + + + /// + /// Rebuilds observers for all connections for a NetworkObject. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void RebuildObservers(NetworkObject nob) + { + ListCache cache = ListCaches.GetNetworkConnectionCache(); + foreach (NetworkConnection item in NetworkManager.ServerManager.Clients.Values) + cache.AddValue(item); + + RebuildObservers(nob, cache); + ListCaches.StoreCache(cache); + } + /// + /// Rebuilds observers for a connection on NetworkObject. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void RebuildObservers(NetworkObject nob, NetworkConnection conn) + { + ListCache cache = ListCaches.GetNetworkConnectionCache(); + cache.AddValue(conn); + + RebuildObservers(nob, cache); + ListCaches.StoreCache(cache); + } + /// + /// Rebuilds observers for connections on NetworkObject. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(NetworkObject networkObject, NetworkConnection[] connections) + { + ListCache cache = ListCaches.GetNetworkConnectionCache(); + cache.AddValues(connections); + RebuildObservers(networkObject, cache); + ListCaches.StoreCache(cache); + } + + /// + /// Rebuilds observers for connections on NetworkObject. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RebuildObservers(NetworkObject networkObject, List connections) + { + ListCache cache = ListCaches.GetNetworkConnectionCache(); + cache.AddValues(connections); + RebuildObservers(networkObject, cache); + ListCaches.StoreCache(cache); + } + + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs.meta new file mode 100644 index 0000000..d184e37 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02d93fa4a653dd64da0bb338b82f4740 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs new file mode 100644 index 0000000..0b3e199 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs @@ -0,0 +1,45 @@ +using FishNet.Connection; +using FishNet.Managing.Object; +using FishNet.Managing.Utility; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using System.Runtime.CompilerServices; + +namespace FishNet.Managing.Server +{ + public partial class ServerObjects : ManagedObjects + { + + /// + /// Parses a ReplicateRpc. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseReplicateRpc(PooledReader reader, NetworkConnection conn, Channel channel) + { + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.ServerRpc, reader, channel); + + if (nb != null) + nb.OnReplicateRpc(null, reader, conn, channel); + else + SkipDataLength((ushort)PacketId.ServerRpc, reader, dataLength); + } + + /// + /// Parses a ServerRpc. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ParseServerRpc(PooledReader reader, NetworkConnection conn, Channel channel) + { + NetworkBehaviour nb = reader.ReadNetworkBehaviour(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.ServerRpc, reader, channel); + + if (nb != null) + nb.OnServerRpc(reader, conn, channel); + else + SkipDataLength((ushort)PacketId.ServerRpc, reader, dataLength); + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs.meta new file mode 100644 index 0000000..d684ec7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3cb6cef520a4ff44bb8c4814e566c5ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs new file mode 100644 index 0000000..eea62a6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs @@ -0,0 +1,764 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Object; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Server +{ + /// + /// Handles objects and information about objects for the server. See ManagedObjects for inherited options. + /// + public partial class ServerObjects : ManagedObjects + { + #region Public. + /// + /// Called right before client objects are destroyed when a client disconnects. + /// + public event Action OnPreDestroyClientObjects; + #endregion + + #region Private. + /// + /// Cached ObjectIds which may be used when exceeding available ObjectIds. + /// + private Queue _objectIdCache = new Queue(); + /// + /// NetworkBehaviours which have dirty SyncVars. + /// + private List _dirtySyncVarBehaviours = new List(20); + /// + /// NetworkBehaviours which have dirty SyncObjects. + /// + private List _dirtySyncObjectBehaviours = new List(20); + /// + /// Objects which need to be destroyed next tick. + /// This is needed when running as host so host client will get any final messages for the object before they're destroyed. + /// + private Dictionary _pendingDestroy = new Dictionary(); + /// + /// Scenes which were loaded that need to be setup. + /// + private List<(int, Scene)> _loadedScenes = new List<(int frame, Scene scene)>(); + /// + /// Cache of spawning objects, used for recursively spawning nested NetworkObjects. + /// + private ListCache _spawnCache = new ListCache(); + /// + /// True if one or more scenes are currently loading through the SceneManager. + /// + private bool _scenesLoading; + #endregion + + internal ServerObjects(NetworkManager networkManager) + { + base.NetworkManager = networkManager; + networkManager.SceneManager.OnLoadStart += SceneManager_OnLoadStart; + networkManager.SceneManager.OnActiveSceneSetInternal += SceneManager_OnActiveSceneSet; + networkManager.TimeManager.OnUpdate += TimeManager_OnUpdate; + } + + /// + /// Called when MonoBehaviours call Update. + /// + private void TimeManager_OnUpdate() + { + if (!base.NetworkManager.IsServer) + { + _scenesLoading = false; + _loadedScenes.Clear(); + return; + } + + if (!_scenesLoading) + IterateLoadedScenes(false); + Observers_OnUpdate(); + } + + #region Checking dirty SyncTypes. + /// + /// Iterates NetworkBehaviours with dirty SyncTypes. + /// + internal void WriteDirtySyncTypes() + { + /* Tells networkbehaviours to check their + * dirty synctypes. */ + IterateCollection(_dirtySyncVarBehaviours, false); + IterateCollection(_dirtySyncObjectBehaviours, true); + + void IterateCollection(List collection, bool isSyncObject) + { + for (int i = 0; i < collection.Count; i++) + { + bool dirtyCleared = collection[i].WriteDirtySyncTypes(isSyncObject); + if (dirtyCleared) + { + collection.RemoveAt(i); + i--; + } + } + } + } + /// + /// Sets that a NetworkBehaviour has a dirty syncVars. + /// + /// + internal void SetDirtySyncType(NetworkBehaviour nb, bool isSyncObject) + { + if (isSyncObject) + _dirtySyncObjectBehaviours.Add(nb); + else + _dirtySyncVarBehaviours.Add(nb); + } + #endregion + + #region Connection Handling. + /// + /// Called when the connection state changes for the local server. + /// + /// + internal void OnServerConnectionState(ServerConnectionStateArgs args) + { + + //If server just connected. + if (args.ConnectionState == LocalConnectionState.Started) + { + /* If there's no servers started besides the one + * that just started then build Ids and setup scene objects. */ + if (base.NetworkManager.ServerManager.OneServerStarted()) + { + BuildObjectIdCache(); + SetupSceneObjects(); + } + } + //Server in anything but started state. + else + { + //If no servers are started then reset. + if (!base.NetworkManager.ServerManager.AnyServerStarted()) + { + base.DespawnSpawnedWithoutSynchronization(true); + base.SceneObjects.Clear(); + _objectIdCache.Clear(); + base.NetworkManager.ServerManager.Clients.Clear(); + } + } + } + + /// + /// Called when a client disconnects. + /// + /// + internal void ClientDisconnected(NetworkConnection connection) + { + RemoveFromObserversWithoutSynchronization(connection); + + OnPreDestroyClientObjects?.Invoke(connection); + + /* A cache is made because the Objects + * collection would end up modified during + * iteration from removing ownership and despawning. */ + ListCache cache = ListCaches.GetNetworkObjectCache(); + foreach (NetworkObject nob in connection.Objects) + cache.AddValue(nob); + + int written = cache.Written; + List collection = cache.Collection; + for (int i = 0; i < written; i++) + { + /* Objects may already be deinitializing when a client disconnects + * because the root object could have been despawned first, and in result + * all child objects would have been recursively despawned. + * + * EG: object is: + * A (nob) + * B (nob) + * + * Both A and B are owned by the client so they will both be + * in collection. Should A despawn first B will recursively despawn + * from it. Then once that finishes and the next index of collection + * is run, which would B, the object B would have already been deinitialized. */ + if (!collection[i].IsDeinitializing) + base.NetworkManager.ServerManager.Despawn(collection[i]); + } + + ListCaches.StoreCache(cache); + } + #endregion + + #region ObjectIds. + /// + /// Builds the ObjectId cache with all possible Ids. + /// + private void BuildObjectIdCache() + { + _objectIdCache.Clear(); + + /* Shuffle Ids to make it more difficult + * for clients to track spawned object + * count. */ + List shuffledCache = new List(); + for (int i = 0; i < short.MaxValue; i++) + shuffledCache.Add(i); + /* Only shuffle when NOT in editor and not + * development build. + * Debugging could be easier when Ids are ordered. */ +#if !UNITY_EDITOR && !DEVELOPMENT_BUILD + shuffledCache.Shuffle(); +#endif + //Add shuffled to objectIdCache. + //Build Id cache. + int cacheCount = shuffledCache.Count; + for (int i = 0; i < cacheCount; i++) + _objectIdCache.Enqueue(shuffledCache[i]); + } + /// + /// Caches a NetworkObject ObjectId. + /// + /// + private void CacheObjectId(NetworkObject nob) + { + if (nob.ObjectId >= 0) + _objectIdCache.Enqueue(nob.ObjectId); + } + + /// + /// Gets the next ObjectId to use for NetworkObjects. + /// + /// + protected internal override int GetNextNetworkObjectId() + { + //Either something went wrong or user actually managed to spawn ~32K networked objects. + if (_objectIdCache.Count == 0) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"No more available ObjectIds. How the heck did you manage to have {short.MaxValue} objects spawned at once?"); + return -1; + } + else + { + return _objectIdCache.Dequeue(); + } + } + #endregion + + #region Initializing Objects In Scenes. + /// + /// Called when a scene load starts. + /// + private void SceneManager_OnLoadStart(Scened.SceneLoadStartEventArgs obj) + { + _scenesLoading = true; + } + /// + /// Called after the active scene has been scene, immediately after scene loads. + /// + private void SceneManager_OnActiveSceneSet() + { + _scenesLoading = false; + IterateLoadedScenes(true); + } + /// + /// Iterates loaded scenes and sets them up. + /// + /// True to ignore the frame restriction when iterating. + internal void IterateLoadedScenes(bool ignoreFrameRestriction) + { + //Not started, clear loaded scenes. + if (!NetworkManager.ServerManager.Started) + _loadedScenes.Clear(); + + for (int i = 0; i < _loadedScenes.Count; i++) + { + (int frame, Scene scene) value = _loadedScenes[i]; + if (ignoreFrameRestriction || (Time.frameCount > value.frame)) + { + SetupSceneObjects(value.scene); + _loadedScenes.RemoveAt(i); + i--; + } + } + } + + /// + /// Called when a scene loads on the server. + /// + /// + /// + protected internal override void SceneManager_sceneLoaded(Scene s, LoadSceneMode arg1) + { + base.SceneManager_sceneLoaded(s, arg1); + + if (!NetworkManager.ServerManager.Started) + return; + //Add to loaded scenes so that they are setup next frame. + _loadedScenes.Add((Time.frameCount, s)); + } + + /// + /// Setup all NetworkObjects in scenes. Should only be called when server is active. + /// + protected internal void SetupSceneObjects() + { + for (int i = 0; i < SceneManager.sceneCount; i++) + SetupSceneObjects(SceneManager.GetSceneAt(i)); + + Scene ddolScene = DDOLFinder.GetDDOL().gameObject.scene; + if (ddolScene.isLoaded) + SetupSceneObjects(ddolScene); + } + + /// + /// Setup NetworkObjects in a scene. Should only be called when server is active. + /// + /// + private void SetupSceneObjects(Scene s) + { + ListCache nobs; + SceneFN.GetSceneNetworkObjects(s, false, out nobs); + + bool isHost = base.NetworkManager.IsHost; + + for (int i = 0; i < nobs.Written; i++) + { + NetworkObject nob = nobs.Collection[i]; + //Only setup if a scene object and not initialzied. + if (nob.IsNetworked && nob.IsSceneObject && nob.IsDeinitializing) + { + base.UpdateNetworkBehaviours(nob, true); + base.AddToSceneObjects(nob); + /* If was active in the editor (before hitting play), or currently active + * then PreInitialize without synchronizing to clients. There is no reason + * to synchronize to clients because the scene just loaded on server, + * which means clients are not yet in the scene. */ + if (nob.ActiveDuringEdit || nob.gameObject.activeInHierarchy) + { + //If not host then object doesn't need to be spawned until a client joins. + if (!isHost) + SetupWithoutSynchronization(nob); + //Otherwise spawn object so observers update for clientHost. + else + SpawnWithoutChecks(nob); + } + } + } + + ListCaches.StoreCache(nobs); + } + + /// + /// Performs setup on a NetworkObject without synchronizing the actions to clients. + /// + private void SetupWithoutSynchronization(NetworkObject nob, NetworkConnection ownerConnection = null) + { + if (nob.IsNetworked) + { + int objectId = GetNextNetworkObjectId(); + nob.PreinitializeInternal(NetworkManager, objectId, ownerConnection, true); + base.AddToSpawned(nob, true); + nob.gameObject.SetActive(true); + nob.Initialize(true); + } + } + #endregion + + #region Spawning. + /// + /// Spawns an object over the network. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Spawn(NetworkObject networkObject, NetworkConnection ownerConnection = null) + { + if (!NetworkManager.ServerManager.Started) + { + if (base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning("Cannot spawn object because the server is not active."); + return; + } + if (networkObject == null) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Specified networkObject is null."); + return; + } + if (!networkObject.gameObject.scene.IsValid()) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"{networkObject.name} is a prefab. You must instantiate the prefab first, then use Spawn on the instantiated copy."); + return; + } + if (ownerConnection != null && ownerConnection.IsActive && !ownerConnection.LoadedStartScenes) + { + if (base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"{networkObject.name} was spawned but it's recommended to not spawn objects for connections until they have loaded start scenes. You can be notified when a connection loads start scenes by using connection.OnLoadedStartScenes on the connection, or SceneManager.OnClientLoadStartScenes."); + } + if (networkObject.IsSpawned) + { + if (base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"{networkObject.name} is already spawned."); + return; + } + if (networkObject.ParentNetworkObject != null && !networkObject.ParentNetworkObject.IsSpawned) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"{networkObject.name} cannot be spawned because it has a parent NetworkObject {networkObject.ParentNetworkObject} which is not spawned."); + return; + } + + SpawnWithoutChecks(networkObject, ownerConnection); + } + + /// + /// Spawns networkObject without any checks. + /// + private void SpawnWithoutChecks(NetworkObject networkObject, NetworkConnection ownerConnection = null, bool recursive = false) + { + /* Setup locally without sending to clients. + * When observers are built for the network object + * during initialization spawn messages will + * be sent. */ + networkObject.SetIsNetworked(true); + if (!recursive) + _spawnCache.Reset(); + + _spawnCache.AddValue(networkObject); + SetupWithoutSynchronization(networkObject, ownerConnection); + + foreach (NetworkObject item in networkObject.ChildNetworkObjects) + { + /* Only spawn recursively if the nob state is unset. + * Unset indicates that the nob has not been */ + if (item.gameObject.activeInHierarchy || item.State == NetworkObjectState.Spawned) + SpawnWithoutChecks(item, ownerConnection, true); + } + + //Also rebuild observers for the object so it spawns for others. + RebuildObservers(_spawnCache); + + /* If also client then we need to make sure the object renderers have correct visibility. + * Set visibility based on if the observers contains the clientHost connection. */ + if (NetworkManager.IsClient) + { + int count = _spawnCache.Written; + List collection = _spawnCache.Collection; + for (int i = 0; i < count; i++) + collection[i].SetRenderersVisible(networkObject.Observers.Contains(NetworkManager.ClientManager.Connection)); + } + } + + /// + /// Writes a spawn into writers. + /// + /// + /// Connection spawn is being written for. + /// + /// + private void WriteSpawn(NetworkObject nob, NetworkConnection connection, ref PooledWriter everyoneWriter, ref PooledWriter ownerWriter) + { + /* Using a number of writers to prevent rebuilding the + * packets excessively for values that are owner only + * vs values that are everyone. To save performance the + * owner writer is only written to if owner is valid. + * This makes the code a little uglier but will scale + * significantly better with more connections. + * + * EG: + * with this technique networkBehaviours are iterated + * twice if there is an owner; once for data to send to everyone + * and again for data only going to owner. + * + * The alternative would be to iterate the networkbehaviours + * for every connection it's going to and filling a single + * writer with values based on if owner or not. This would + * result in significantly more iterations. */ + PooledWriter headerWriter = WriterPool.GetWriter(); + headerWriter.WritePacketId(PacketId.ObjectSpawn); + headerWriter.WriteNetworkObject(nob); + if (base.NetworkManager.ServerManager.ShareIds || connection == nob.Owner) + headerWriter.WriteNetworkConnection(nob.Owner); + else + headerWriter.WriteInt16(-1); + + bool nested = nob.IsNested; + bool sceneObject = nob.IsSceneObject; + //Write type of spawn. + ObjectSpawnType ost; + if (sceneObject) + ost = ObjectSpawnType.Scene; + else + ost = (nob.IsGlobal) ? ObjectSpawnType.InstantiatedGlobal : ObjectSpawnType.Instantiated; + headerWriter.WriteByte((byte)ost); + //ComponentIndex for the nob. 0 is root but more appropriately there's a IsNested boolean as shown above. + headerWriter.WriteByte(nob.ComponentIndex); + + /* When nested the parent nob needs to be written. */ + if (nested) + { + headerWriter.WriteNetworkObject(nob.ParentNetworkObject); + } + //No need to write scene/prefab id, or parent if nested. + else + { + /* Writing a scene object. */ + if (sceneObject) + { + //Write Guid. + headerWriter.WriteUInt64(nob.SceneId, AutoPackType.Unpacked); + } + /* Writing a spawned object. */ + else + { + //Check to write parent behaviour or nob. + NetworkBehaviour parentNb; + Transform t = nob.transform.parent; + if (t != null) + { + parentNb = t.GetComponent(); + /* Check for a NetworkObject if there is no NetworkBehaviour. + * There is a small chance the parent object will only contain + * a NetworkObject. */ + if (parentNb == null) + { + //If null check if there is a nob. + NetworkObject parentNob = t.GetComponent(); + //ParentNob is null or not spawned. + if (!ParentIsSpawned(parentNob)) + { + headerWriter.WriteByte((byte)SpawnParentType.Unset); + } + else + { + headerWriter.WriteByte((byte)SpawnParentType.NetworkObject); + headerWriter.WriteNetworkObject(parentNob); + } + } + //NetworkBehaviour found on parent. + else + { + //ParentNb is null or not spawned. + if (!ParentIsSpawned(parentNb.NetworkObject)) + { + headerWriter.WriteByte((byte)SpawnParentType.Unset); + } + else + { + headerWriter.WriteByte((byte)SpawnParentType.NetworkBehaviour); + headerWriter.WriteNetworkBehaviour(parentNb); + } + } + + //True if pNob is not null, and is spawned. + bool ParentIsSpawned(NetworkObject pNob) + { + bool isNull = (pNob == null); + if (isNull || !pNob.IsSpawned) + { + /* Only log if pNob exist. Otherwise this would print if the user + * was parenting any object, which may not be desirable as they could be + * simply doing it for organization reasons. */ + if (!isNull && base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Parent {t.name} is not spawned. {nob.name} will not have it's parent sent in the spawn message."); + return false; + } + + return true; + } + + } + //No parent. + else + { + headerWriter.WriteByte((byte)SpawnParentType.Unset); + } + + headerWriter.WriteInt16(nob.PrefabId); + } + } + + /* Write changed transform properties. */ + ChangedTransformProperties ctp; + //If a scene object then get it from scene properties. + if (sceneObject || nested) + ctp = nob.GetTransformChanges(nob.SerializedTransformProperties); + else + ctp = nob.GetTransformChanges(base.NetworkManager.SpawnablePrefabs.GetObject(true, nob.PrefabId).gameObject); + headerWriter.WriteByte((byte)ctp); + //If properties have changed. + if (ctp != ChangedTransformProperties.Unset) + { + //Write any changed properties. + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalPosition)) + headerWriter.WriteVector3(nob.transform.localPosition); + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalRotation)) + headerWriter.WriteQuaternion(nob.transform.localRotation, base.NetworkManager.ServerManager.SpawnPacking.Rotation); + if (Enums.TransformPropertiesContains(ctp, ChangedTransformProperties.LocalScale)) + headerWriter.WriteVector3(nob.transform.localScale); + } + + //Write headers first. + everyoneWriter.WriteBytes(headerWriter.GetBuffer(), 0, headerWriter.Length); + if (nob.Owner.IsValid) + ownerWriter.WriteBytes(headerWriter.GetBuffer(), 0, headerWriter.Length); + + /* Used to write latest data which must be sent to + * clients, such as SyncTypes and RpcLinks. */ + PooledWriter tempWriter = WriterPool.GetWriter(); + //Send RpcLinks first. + foreach (NetworkBehaviour nb in nob.NetworkBehaviours) + nb.WriteRpcLinks(tempWriter); + //Add to everyone/owner. + everyoneWriter.WriteBytesAndSize(tempWriter.GetBuffer(), 0, tempWriter.Length); + if (nob.Owner.IsValid) + ownerWriter.WriteBytesAndSize(tempWriter.GetBuffer(), 0, tempWriter.Length); + + //Add most recent sync type values. + /* SyncTypes have to be populated for owner and everyone. + * The data may be unique for owner if synctypes are set + * to only go to owner. */ + tempWriter.Reset(); + foreach (NetworkBehaviour nb in nob.NetworkBehaviours) + nb.WriteSyncTypesForSpawn(tempWriter, false); + everyoneWriter.WriteBytesAndSize(tempWriter.GetBuffer(), 0, tempWriter.Length); + //If owner is valid then populate owner writer as well. + if (nob.Owner.IsValid) + { + tempWriter.Reset(); + foreach (NetworkBehaviour nb in nob.NetworkBehaviours) + nb.WriteSyncTypesForSpawn(tempWriter, true); + ownerWriter.WriteBytesAndSize(tempWriter.GetBuffer(), 0, tempWriter.Length); + } + + //Dispose of writers created in this method. + headerWriter.Dispose(); + tempWriter.Dispose(); + } + #endregion + + #region Despawning. + internal void AddToPending(NetworkObject nob) + { + _pendingDestroy[nob.ObjectId] = nob; + } + /// + /// Tries to removes objectId from PendingDestroy and returns if successful. + /// + internal bool RemoveFromPending(int objectId) + { + return _pendingDestroy.Remove(objectId); + } + /// + /// Returns a NetworkObject in PendingDestroy. + /// + internal NetworkObject GetFromPending(int objectId) + { + NetworkObject nob; + _pendingDestroy.TryGetValue(objectId, out nob); + return nob; + } + /// + /// Destroys NetworkObjects pending for destruction. + /// + internal void DestroyPending() + { + foreach (NetworkObject item in _pendingDestroy.Values) + { + if (item != null) + MonoBehaviour.Destroy(item.gameObject); + } + + _pendingDestroy.Clear(); + } + + /// + /// Despawns an object over the network. + /// + internal override void Despawn(NetworkObject nob, bool disableOnDespawn, bool asServer) + { + if (nob.CanSpawnOrDespawn(true)) + { + FinalizeDespawn(nob, disableOnDespawn); + base.Despawn(nob, disableOnDespawn, true); + } + } + + /// + /// Called when a NetworkObject is destroyed without being deactivated first. + /// + /// + internal override void NetworkObjectUnexpectedlyDestroyed(NetworkObject nob) + { + FinalizeDespawn(nob, true); + base.NetworkObjectUnexpectedlyDestroyed(nob); + } + + /// + /// Finalizes the despawn process. By the time this is called the object is considered unaccessible. + /// + /// + private void FinalizeDespawn(NetworkObject nob, bool disableOnDespawn) + { + if (nob != null && nob.ObjectId != -1) + { + nob.WriteDirtySyncTypes(); + WriteDespawnAndSend(nob, disableOnDespawn); + CacheObjectId(nob); + } + } + + /// + /// Writes a despawn and sends it to clients. + /// + /// + private void WriteDespawnAndSend(NetworkObject nob, bool disableOnDespawn) + { + PooledWriter everyoneWriter = WriterPool.GetWriter(); + WriteDespawn(nob, disableOnDespawn, ref everyoneWriter); + + ArraySegment despawnSegment = everyoneWriter.GetArraySegment(); + + //Add observers to a list cache. + ListCache cache = ListCaches.GetNetworkConnectionCache(); + cache.Reset(); + cache.AddValues(nob.Observers); + int written = cache.Written; + for (int i = 0; i < written; i++) + { + //Invoke ondespawn and send despawn. + NetworkConnection conn = cache.Collection[i]; + nob.InvokeOnServerDespawn(conn); + NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, despawnSegment, conn); + //Remove from observers. + //nob.Observers.Remove(conn); + } + + everyoneWriter.Dispose(); + ListCaches.StoreCache(cache); + } + /// + /// Writes a despawn. + /// + /// + private void WriteDespawn(NetworkObject nob, bool disableOnDespawn, ref PooledWriter everyoneWriter) + { + everyoneWriter.WritePacketId(PacketId.ObjectDespawn); + everyoneWriter.WriteNetworkObject(nob); + everyoneWriter.WriteBoolean(disableOnDespawn); + } + + + + } + #endregion + + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs.meta new file mode 100644 index 0000000..ba10d54 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5e7f3005cbc7924f99819311c58651a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs new file mode 100644 index 0000000..f98cd2c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs @@ -0,0 +1,470 @@ +using FishNet.Broadcast; +using FishNet.Broadcast.Helping; +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Utility; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Server +{ + public sealed partial class ServerManager : MonoBehaviour + { + #region Private. + /// + /// Delegate to read received broadcasts. + /// + /// + /// + private delegate void ClientBroadcastDelegate(NetworkConnection connection, PooledReader reader); + /// + /// Delegates for each key. + /// + private readonly Dictionary> _broadcastHandlers = new Dictionary>(); + /// + /// Delegate targets for each key. + /// + private Dictionary> _handlerTargets = new Dictionary>(); + /// + /// Connections which can be broadcasted to after having excluded removed. + /// + private HashSet _connectionsWithoutExclusions = new HashSet(); + #endregion + + /// + /// Registers a method to call when a Broadcast arrives. + /// + /// Type of broadcast being registered. + /// Method to call. + /// True if the client must be authenticated for the method to call. + public void RegisterBroadcast(Action handler, bool requireAuthentication = true) where T : struct, IBroadcast + { + ushort key = BroadcastHelper.GetKey(); + + /* Create delegate and add for + * handler method. */ + HashSet handlers; + if (!_broadcastHandlers.TryGetValueIL2CPP(key, out handlers)) + { + handlers = new HashSet(); + _broadcastHandlers.Add(key, handlers); + } + ClientBroadcastDelegate del = CreateBroadcastDelegate(handler, requireAuthentication); + handlers.Add(del); + + /* Add hashcode of target for handler. + * This is so we can unregister the target later. */ + int handlerHashCode = handler.GetHashCode(); + HashSet<(int, ClientBroadcastDelegate)> targetHashCodes; + if (!_handlerTargets.TryGetValueIL2CPP(key, out targetHashCodes)) + { + targetHashCodes = new HashSet<(int, ClientBroadcastDelegate)>(); + _handlerTargets.Add(key, targetHashCodes); + } + + targetHashCodes.Add((handlerHashCode, del)); + } + + /// + /// Unregisters a method call from a Broadcast type. + /// + /// Type of broadcast being unregistered. + /// Method to unregister. + public void UnregisterBroadcast(Action handler) where T : struct, IBroadcast + { + ushort key = BroadcastHelper.GetKey(); + + /* If key is found for T then look for + * the appropriate handler to remove. */ + if (_broadcastHandlers.TryGetValueIL2CPP(key, out HashSet handlers)) + { + HashSet<(int, ClientBroadcastDelegate)> targetHashCodes; + if (_handlerTargets.TryGetValueIL2CPP(key, out targetHashCodes)) + { + int handlerHashCode = handler.GetHashCode(); + ClientBroadcastDelegate result = null; + foreach ((int targetHashCode, ClientBroadcastDelegate del) in targetHashCodes) + { + if (targetHashCode == handlerHashCode) + { + result = del; + targetHashCodes.Remove((targetHashCode, del)); + break; + } + } + //If no more in targetHashCodes then remove from handlerTarget. + if (targetHashCodes.Count == 0) + _handlerTargets.Remove(key); + + if (result != null) + handlers.Remove(result); + } + + //If no more in handlers then remove broadcastHandlers. + if (handlers.Count == 0) + _broadcastHandlers.Remove(key); + } + } + + /// + /// Creates a ClientBroadcastDelegate. + /// + /// + /// + /// + /// + private ClientBroadcastDelegate CreateBroadcastDelegate(Action handler, bool requireAuthentication) + { + void LogicContainer(NetworkConnection connection, PooledReader reader) + { + //If requires authentication and client isn't authenticated. + if (requireAuthentication && !connection.Authenticated) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"ConnectionId {connection.ClientId} sent broadcast {typeof(T).Name} which requires authentication, but client was not authenticated. Client has been disconnected."); + NetworkManager.TransportManager.Transport.StopConnection(connection.ClientId, true); + return; + } + + T broadcast = reader.Read(); + handler?.Invoke(connection, broadcast); + } + return LogicContainer; + } + + /// + /// Parses a received broadcast. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ParseBroadcast(PooledReader reader, NetworkConnection conn, Channel channel) + { + ushort key = reader.ReadUInt16(); + int dataLength = Packets.GetPacketLength((ushort)PacketId.Broadcast, reader, channel); + + //Try to invoke the handler for that message + if (_broadcastHandlers.TryGetValueIL2CPP(key, out HashSet handlers)) + { + int readerStartPosition = reader.Position; + /* //muchlater resetting the position could be better by instead reading once and passing in + * the object to invoke with. */ + bool rebuildHandlers = false; + //True if data is read at least once. Otherwise it's length will have to be purged. + bool dataRead = false; + foreach (ClientBroadcastDelegate handler in handlers) + { + if (handler.Target == null && NetworkManager.CanLog(LoggingType.Warning)) + { + Debug.LogWarning($"A Broadcast handler target is null. This can occur when a script is destroyed but does not unregister from a Broadcast."); + rebuildHandlers = true; + } + else + { + reader.Position = readerStartPosition; + handler.Invoke(conn, reader); + dataRead = true; + } + } + + //If rebuilding handlers... + if (rebuildHandlers) + { + List dels = handlers.ToList(); + handlers.Clear(); + for (int i = 0; i < dels.Count; i++) + { + if (dels[i].Target != null) + handlers.Add(dels[i]); + } + } + //Make sure data was read as well. + if (!dataRead) + reader.Skip(dataLength); + } + else + { + reader.Skip(dataLength); + } + } + + /// + /// Sends a broadcast to a connection. + /// + /// Type of broadcast to send. + /// Connection to send to. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the client must be authenticated for this broadcast to send. + /// Channel to send on. + public void Broadcast(NetworkConnection connection, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + if (requireAuthenticated && !connection.Authenticated) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because they are not authenticated."); + return; + } + + using (PooledWriter writer = WriterPool.GetWriter()) + { + Broadcasts.WriteBroadcast(writer, message, channel); + ArraySegment segment = writer.GetArraySegment(); + NetworkManager.TransportManager.SendToClient((byte)channel, segment, connection); + } + } + + + /// + /// Sends a broadcast to connections. + /// + /// Type of broadcast to send. + /// Connections to send to. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void Broadcast(HashSet connections, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + bool failedAuthentication = false; + using (PooledWriter writer = WriterPool.GetWriter()) + { + Broadcasts.WriteBroadcast(writer, message, channel); + ArraySegment segment = writer.GetArraySegment(); + + foreach (NetworkConnection conn in connections) + { + if (requireAuthenticated && !conn.Authenticated) + failedAuthentication = true; + else + NetworkManager.TransportManager.SendToClient((byte)channel, segment, conn); + } + } + + if (failedAuthentication) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"One or more broadcast did not send to a client because they were not authenticated."); + return; + } + } + + + /// + /// Sends a broadcast to connections except excluded. + /// + /// Type of broadcast to send. + /// Connections to send to. + /// Connection to exclude. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void BroadcastExcept(HashSet connections, NetworkConnection excludedConnection, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + //Fast exit if no exclusions. + if (excludedConnection == null || !excludedConnection.IsValid) + { + Broadcast(connections, message, requireAuthenticated, channel); + return; + } + + connections.Remove(excludedConnection); + Broadcast(connections, message, requireAuthenticated, channel); + } + + + /// + /// Sends a broadcast to connections except excluded. + /// + /// Type of broadcast to send. + /// Connections to send to. + /// Connections to exclude. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void BroadcastExcept(HashSet connections, HashSet excludedConnections, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + //Fast exit if no exclusions. + if (excludedConnections == null || excludedConnections.Count == 0) + { + Broadcast(connections, message, requireAuthenticated, channel); + return; + } + + /* I'm not sure if the hashset API such as intersect generates + * GC or not but I'm betting doing remove locally is faster, or + * just as fast. */ + foreach (NetworkConnection ec in excludedConnections) + connections.Remove(ec); + + Broadcast(connections,message, requireAuthenticated, channel); + } + + /// + /// Sends a broadcast to all connections except excluded. + /// + /// Type of broadcast to send. + /// Connection to exclude. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void BroadcastExcept(NetworkConnection excludedConnection, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + //Fast exit if there are no excluded. + if (excludedConnection == null || !excludedConnection.IsValid) + { + Broadcast(message, requireAuthenticated, channel); + return; + } + + _connectionsWithoutExclusions.Clear(); + /* It will be faster to fill the entire list then + * remove vs checking if each connection is contained within excluded. */ + foreach (NetworkConnection c in Clients.Values) + _connectionsWithoutExclusions.Add(c); + //Remove + _connectionsWithoutExclusions.Remove(excludedConnection); + + Broadcast(_connectionsWithoutExclusions, message, requireAuthenticated, channel); + } + + /// + /// Sends a broadcast to all connections except excluded. + /// + /// Type of broadcast to send. + /// Connections to send to. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void BroadcastExcept(HashSet excludedConnections, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + //Fast exit if there are no excluded. + if (excludedConnections == null || excludedConnections.Count == 0) + { + Broadcast(message, requireAuthenticated, channel); + return; + } + + _connectionsWithoutExclusions.Clear(); + /* It will be faster to fill the entire list then + * remove vs checking if each connection is contained within excluded. */ + foreach (NetworkConnection c in Clients.Values) + _connectionsWithoutExclusions.Add(c); + //Remove + foreach (NetworkConnection c in excludedConnections) + _connectionsWithoutExclusions.Remove(c); + + Broadcast(_connectionsWithoutExclusions, message, requireAuthenticated, channel); + } + + /// + /// Sends a broadcast to observers. + /// + /// Type of broadcast to send. + /// NetworkObject to use Observers from. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Broadcast(NetworkObject networkObject, T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (networkObject == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast because networkObject is null."); + return; + } + + Broadcast(networkObject.Observers, message, requireAuthenticated, channel); + } + + + /// + /// Sends a broadcast to all clients. + /// + /// Type of broadcast to send. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the clients must be authenticated for this broadcast to send. + /// Channel to send on. + public void Broadcast(T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (!Started) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast to client because server is not active."); + return; + } + + bool failedAuthentication = false; + using (PooledWriter writer = WriterPool.GetWriter()) + { + Broadcasts.WriteBroadcast(writer, message, channel); + ArraySegment segment = writer.GetArraySegment(); + + foreach (NetworkConnection conn in Clients.Values) + { + // + if (requireAuthenticated && !conn.Authenticated) + failedAuthentication = true; + else + NetworkManager.TransportManager.SendToClient((byte)channel, segment, conn); + } + } + + if (failedAuthentication) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"One or more broadcast did not send to a client because they were not authenticated."); + return; + } + } + + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs.meta new file mode 100644 index 0000000..e0fdef7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1cd9dcd58556e27449ce5cb0d70611cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs new file mode 100644 index 0000000..da9db3f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs @@ -0,0 +1,206 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Object; +using FishNet.Transporting; +using FishNet.Transporting.Multipass; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Server +{ + public sealed partial class ServerManager : MonoBehaviour + { + /// + /// Returns true if only one server is started. + /// + /// + internal bool OneServerStarted() + { + int startedCount = 0; + TransportManager tm = NetworkManager.TransportManager; + //If using multipass check all transports. + if (tm.Transport is Multipass mp) + { + + foreach (Transport t in mp.Transports) + { + //Another transport is started, no need to load start scenes again. + if (t.GetConnectionState(true) == LocalConnectionState.Started) + startedCount++; + } + } + //Not using multipass. + else + { + if (tm.Transport.GetConnectionState(true) == LocalConnectionState.Started) + startedCount = 1; + } + + return (startedCount == 1); + } + + /// + /// Returns true if any server socket is in the started state. + /// + /// When set the transport on this index will be ignored. This value is only used with Multipass. + /// + internal bool AnyServerStarted(int? excludedIndex = null) + { + TransportManager tm = NetworkManager.TransportManager; + //If using multipass check all transports. + if (tm.Transport is Multipass mp) + { + //Get transport which had state changed. + Transport excludedTransport = (excludedIndex == null) ? null : mp.GetTransport(excludedIndex.Value); + + foreach (Transport t in mp.Transports) + { + /* Skip t if is the transport that had it's state changed. + * We are looking for other transports already in started. */ + if (t == excludedTransport) + continue; + //Another transport is started, no need to load start scenes again. + if (t.GetConnectionState(true) == LocalConnectionState.Started) + return true; + } + } + //Not using multipass. + else + { + return (tm.Transport.GetConnectionState(true) == LocalConnectionState.Started); + } + + //Fall through, none started. + return false; + } + + /// + /// Spawns an object over the network. Can only be called on the server. + /// + /// GameObject instance to spawn. + /// Connection to give ownership to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Spawn(GameObject go, NetworkConnection ownerConnection = null) + { + if (!CanSpawnOrDespawn(true)) + return; + if (go == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"GameObject cannot be spawned because it is null."); + return; + } + + NetworkObject nob = go.GetComponent(); + Spawn(nob, ownerConnection); + } + + + /// + /// Spawns an object over the network. Can only be called on the server. + /// + /// MetworkObject instance to spawn. + /// Connection to give ownership to. + public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null) + { + if (!CanSpawnOrDespawn(true)) + return; + if (nob == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObject cannot be spawned because it is null."); + return; + } + + Objects.Spawn(nob, ownerConnection); + } + + + /// + /// Spawns an object over the network. Can only be called on the server. + /// + /// MetworkObject instance to spawn. + /// Connection to give ownership to. + /// True to synchronize the parent object in the spawn message. The parent must have a NetworkObject or NetworkBehaviour component for this to work. + [Obsolete("SynchronizeParent is now automatic, and no longer optional. Use Spawn(NetworkObject, NetworkConnection) instead.")] //Remove 2023/01/01. + public void Spawn(NetworkObject nob, NetworkConnection ownerConnection, bool synchronizeParent) + { + if (!CanSpawnOrDespawn(true)) + return; + if (nob == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObject cannot be spawned because it is null."); + return; + } + + Objects.Spawn(nob, ownerConnection); + } + + + /// + /// Returns if Spawn can be called. + /// + /// True to warn if not able to execute spawn or despawn. + /// + private bool CanSpawnOrDespawn(bool warn) + { + bool canLog = (warn && NetworkManager.CanLog(LoggingType.Warning)); + if (!Started) + { + if (canLog) + Debug.Log($"The server must be active to spawn or despawn networked objects."); + return false; + } + + return true; + } + + + /// + /// Despawns an object over the network. Can only be called on the server. + /// + /// GameObject instance to despawn. + /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Despawn(GameObject go, bool? disableOnDespawnOverride = null) + { + if (!CanSpawnOrDespawn(true)) + return; + + if (go == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"GameObject cannot be despawned because it is null."); + return; + } + + NetworkObject nob = go.GetComponent(); + Despawn(nob, disableOnDespawnOverride); + } + + /// + /// Despawns an object over the network. Can only be called on the server. + /// + /// NetworkObject instance to despawn. + /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. + public void Despawn(NetworkObject networkObject, bool? disableOnDespawnOverride = null) + { + if (!CanSpawnOrDespawn(true)) + return; + if (networkObject == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObject cannot be despawned because it is null."); + return; + } + + bool disableOnDespawn = (disableOnDespawnOverride == null) ? networkObject.DisableOnDespawn : disableOnDespawnOverride.Value; + Objects.Despawn(networkObject, disableOnDespawn, true); + } + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs.meta new file mode 100644 index 0000000..2ff8199 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2a07d9984be21648bc714ea03bd0d70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs new file mode 100644 index 0000000..f7dfe32 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs @@ -0,0 +1,78 @@ +using FishNet.Object; +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Managing.Server +{ + + public sealed partial class ServerManager : MonoBehaviour + { + + + #region Internal + /// + /// Current RPCLinks. + /// + internal Dictionary RpcLinks = new Dictionary(); + /// + /// RPCLink indexes which can be used. + /// + private Queue _availableRpcLinkIndexes = new Queue(); + #endregion + + /// + /// Initializes RPC Links for NetworkBehaviours. + /// + private void InitializeRpcLinks() + { + /* Brute force enum values. + * Linq Last/Max lookup throws for IL2CPP. */ + ushort highestValue = 0; + Array pidValues = Enum.GetValues(typeof(PacketId)); + foreach (PacketId pid in pidValues) + highestValue = Math.Max(highestValue, (ushort)pid); + + highestValue += 1; + for (ushort i = highestValue; i < ushort.MaxValue; i++) + _availableRpcLinkIndexes.Enqueue(i); + } + + /// + /// Sets the next RPC Link to use. + /// + /// True if a link was available and set. + internal bool GetRpcLink(out ushort value) + { + if (_availableRpcLinkIndexes.Count > 0) + { + value = _availableRpcLinkIndexes.Dequeue(); + return true; + } + else + { + value = 0; + return false; + } + } + + /// + /// Sets data to RpcLinks for linkIndex. + /// + internal void SetRpcLink(ushort linkIndex, RpcLink data) + { + RpcLinks[linkIndex] = data; + } + + /// + /// Returns RPCLinks to availableRpcLinkIndexes. + /// + internal void ReturnRpcLinks(Dictionary links) + { + foreach (ushort linkId in links.Keys) + _availableRpcLinkIndexes.Enqueue(linkId); + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs.meta new file mode 100644 index 0000000..00ff24f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9f0a4620d06f5c41b01f20af3f90634 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs new file mode 100644 index 0000000..34621ec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs @@ -0,0 +1,679 @@ +using FishNet.Authenticating; +using FishNet.Component.Observing; +using FishNet.Connection; +using FishNet.Managing.Debugging; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Serialization; + +namespace FishNet.Managing.Server +{ + /// + /// A container for server data and actions. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/ServerManager")] + public sealed partial class ServerManager : MonoBehaviour + { + #region Public. + /// + /// Called after the local server connection state changes. + /// + public event Action OnServerConnectionState; + /// + /// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. + /// + public event Action OnAuthenticationResult; + /// + /// Called when a remote client state changes with the server. + /// + public event Action OnRemoteConnectionState; + /// + /// True if the server connection has started. + /// + public bool Started { get; private set; } + /// + /// Handling and information for objects on the server. + /// + public ServerObjects Objects { get; private set; } + /// + /// Authenticated and non-authenticated connected clients. + /// + [HideInInspector] + public Dictionary Clients = new Dictionary(); + /// + /// NetworkManager for server. + /// + [HideInInspector] + public NetworkManager NetworkManager { get; private set; } + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("Authenticator for this ServerManager. May be null if not using authentication.")] + [SerializeField] + private Authenticator _authenticator; + /// + /// Authenticator for this ServerManager. May be null if not using authentication. + /// + public Authenticator Authenticator { get => _authenticator; set => _authenticator = value; } + /// + /// How to pack object spawns. + /// + [Tooltip("How to pack object spawns.")] + [SerializeField] + internal TransformPackingData SpawnPacking = new TransformPackingData() + { + Position = AutoPackType.Unpacked, + Rotation = AutoPackType.PackedLess, + Scale = AutoPackType.PackedLess + }; + /// + /// True to automatically set the frame rate when the client connects. + /// + [Tooltip("True to automatically set the frame rate when the client connects.")] + [SerializeField] + private bool _changeFrameRate = true; + /// + /// + /// + [Tooltip("Maximum frame rate the server may run at. When as host this value runs at whichever is higher between client and server.")] + [Range(1, NetworkManager.MAXIMUM_FRAMERATE)] + [SerializeField] + private ushort _frameRate = NetworkManager.MAXIMUM_FRAMERATE; + /// + /// Maximum frame rate the server may run at. When as host this value runs at whichever is higher between client and server. + /// + internal ushort FrameRate => (_changeFrameRate) ? _frameRate : (ushort)0; + /// + /// + /// + [Tooltip("True to share the Ids of clients and the objects they own with other clients. No sensitive information is shared.")] + [SerializeField] + private bool _shareIds = true; + /// + /// True to share the Ids of clients and the objects they own with other clients. No sensitive information is shared. + /// + internal bool ShareIds => _shareIds; + /// + /// True to automatically start the server connection when running as headless. + /// + [Tooltip("True to automatically start the server connection when running as headless.")] + [SerializeField] + private bool _startOnHeadless = true; + /// + /// + /// + [Tooltip("True to kick clients which send data larger than the MTU.")] + [SerializeField] + private bool _limitClientMTU = true; + /// + /// True to kick clients which send data larger than the MTU. + /// + internal bool LimitClientMTU => _limitClientMTU; + #endregion + + #region Private. + /// + /// Used to read splits. + /// + private SplitReader _splitReader = new SplitReader(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + /// + /// Logs data about parser to help debug. + /// + private ParseLogger _parseLogger = new ParseLogger(); +#endif + #endregion + + private void OnDestroy() + { + Objects?.SubscribeToSceneLoaded(false); + } + + /// + /// Initializes this script for use. + /// + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + NetworkManager = manager; + Objects = new ServerObjects(manager); + Objects.SubscribeToSceneLoaded(true); + InitializeRpcLinks(); + //Unsubscribe first incase already subscribed. + SubscribeToTransport(false); + SubscribeToTransport(true); + NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; + NetworkManager.SceneManager.OnClientLoadedStartScenes += SceneManager_OnClientLoadedStartScenes; + + if (_authenticator == null) + _authenticator = GetComponent(); + if (_authenticator != null) + { + _authenticator.InitializeOnce(manager); + _authenticator.OnAuthenticationResult += _authenticator_OnAuthenticationResult; + } + } + + /// + /// Starts the server if configured to for headless. + /// + internal void StartForHeadless() + { + if (_startOnHeadless) + { + //Wrapping logic in check instead of everything so _startOnHeadless doesnt warn as unused in editor. +#if UNITY_SERVER + StartConnection(); +#endif + } + } + + /// + /// Stops the local server connection. + /// + /// True to send a disconnect message to all clients first. + public bool StopConnection(bool sendDisconnectMessage) + { + if (sendDisconnectMessage) + SendDisconnectMessages(Clients.Values.ToList(), true); + + //Return stop connection result. + return NetworkManager.TransportManager.Transport.StopConnection(true); + } + + /// + /// Sends a disconnect messge to connectionIds. + /// This does not iterate outgoing automatically. + /// + /// + internal void SendDisconnectMessages(int[] connectionIds) + { + List conns = new List(); + foreach (int item in connectionIds) + { + if (Clients.TryGetValueIL2CPP(item, out NetworkConnection c)) + conns.Add(c); + } + + if (conns.Count > 0) + SendDisconnectMessages(conns, false); + } + /// + /// Sends a disconnect message to all clients and immediately iterates outgoing. + /// + private void SendDisconnectMessages(List conns, bool iterate) + { + PooledWriter writer = WriterPool.GetWriter(); + writer.WritePacketId(PacketId.Disconnect); + ArraySegment segment = writer.GetArraySegment(); + //Send segment to each client, authenticated or not. + foreach (NetworkConnection c in conns) + c.SendToClient((byte)Channel.Reliable, segment); + //Recycle writer. + writer.Dispose(); + + if (iterate) + NetworkManager.TransportManager.IterateOutgoing(true); + } + + /// + /// Starts the local server connection. + /// + public bool StartConnection() + { + return NetworkManager.TransportManager.Transport.StartConnection(true); + } + /// + /// Starts the local server using port. + /// + /// Port to start on. + /// + public bool StartConnection(ushort port) + { + Transport t = NetworkManager.TransportManager.Transport; + t.SetPort(port); + return t.StartConnection(true); + } + + /// + /// Called after the local client connection state changes. + /// + private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj) + { + /* If client is doing anything but started destroy pending. + * Pending is only used for host mode. */ + if (obj.ConnectionState != LocalConnectionState.Started) + Objects.DestroyPending(); + } + + /// + /// Called when a client loads initial scenes after connecting. + /// + private void SceneManager_OnClientLoadedStartScenes(NetworkConnection conn, bool asServer) + { + if (asServer) + { + Objects.RebuildObservers(conn); + /* If connection is host then renderers must be hidden + * for all objects not visible to the host. The observer system + * does handle this but only after an initial state is set. + * If the clientHost joins without observation of an object + * then the initial state will never be set. */ + if (conn.IsLocalClient) + { + foreach (NetworkObject nob in Objects.Spawned.Values) + { + if (!nob.Observers.Contains(conn)) + nob.SetRenderersVisible(false); + } + } + } + } + + /// + /// Changes subscription status to transport. + /// + /// + private void SubscribeToTransport(bool subscribe) + { + if (NetworkManager == null || NetworkManager.TransportManager == null || NetworkManager.TransportManager.Transport == null) + return; + + if (!subscribe) + { + NetworkManager.TransportManager.Transport.OnServerReceivedData -= Transport_OnServerReceivedData; + NetworkManager.TransportManager.Transport.OnServerConnectionState -= Transport_OnServerConnectionState; + NetworkManager.TransportManager.Transport.OnRemoteConnectionState -= Transport_OnRemoteConnectionState; + } + else + { + NetworkManager.TransportManager.Transport.OnServerReceivedData += Transport_OnServerReceivedData; + NetworkManager.TransportManager.Transport.OnServerConnectionState += Transport_OnServerConnectionState; + NetworkManager.TransportManager.Transport.OnRemoteConnectionState += Transport_OnRemoteConnectionState; + } + } + + /// + /// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. + /// Server listens for this event automatically. + /// + private void _authenticator_OnAuthenticationResult(NetworkConnection conn, bool authenticated) + { + if (!authenticated) + conn.Disconnect(false); + else + ClientAuthenticated(conn); + } + + /// + /// Called when a connection state changes for the local server. + /// + private void Transport_OnServerConnectionState(ServerConnectionStateArgs args) + { + /* Let the client manager know the server state is changing first. + * This gives the client an opportunity to clean-up or prepare + * before the server completes it's actions. */ + Started = AnyServerStarted(); + NetworkManager.ClientManager.Objects.OnServerConnectionState(args); + //If no servers are started then reset match conditions. + if (!Started) + MatchCondition.ClearMatchesWithoutRebuilding(); + + Objects.OnServerConnectionState(args); + + LocalConnectionState state = args.ConnectionState; + + if (NetworkManager.CanLog(LoggingType.Common)) + { + Transport t = NetworkManager.TransportManager.GetTransport(args.TransportIndex); + string tName = (t == null) ? "Unknown" : t.GetType().Name; + Debug.Log($"Local Server is {state.ToString().ToLower()} for {tName}."); + } + + NetworkManager.UpdateFramerate(); + OnServerConnectionState?.Invoke(args); + } + + /// + /// Called when a connection state changes for a remote client. + /// + private void Transport_OnRemoteConnectionState(RemoteConnectionStateArgs args) + { + //Sanity check to make sure transports are following proper types/ranges. + int id = args.ConnectionId; + int maxIdValue = short.MaxValue; + if (id < 0 || id > maxIdValue) + { + NetworkManager.TransportManager.Transport.StopConnection(args.ConnectionId, true); + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"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."); + return; + } + //Valid Id. + else + { + //If started then add to authenticated clients. + if (args.ConnectionState == RemoteConnectionState.Started) + { + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.Log($"Remote connection started for Id {id}."); + NetworkConnection conn = new NetworkConnection(NetworkManager, id); + 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. */ + if (Authenticator != null && !NetworkManager.TransportManager.IsLocalTransport(id)) + Authenticator.OnRemoteConnection(conn); + else + ClientAuthenticated(conn); + } + //If stopping. + else if (args.ConnectionState == RemoteConnectionState.Stopped) + { + /* If client's connection is found then clean + * them up from server. */ + if (Clients.TryGetValueIL2CPP(id, out NetworkConnection conn)) + { + conn.SetDisconnecting(true); + OnRemoteConnectionState?.Invoke(conn, args); + Clients.Remove(id); + MatchCondition.RemoveFromMatchWithoutRebuild(conn, NetworkManager); + Objects.ClientDisconnected(conn); + BroadcastClientConnectionChange(false, conn); + conn.Reset(); + + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.Log($"Remote connection stopped for Id {id}."); + } + } + } + } + + /// + /// Sends client their connectionId. + /// + /// + private void SendAuthenticated(NetworkConnection conn) + { + using (PooledWriter writer = WriterPool.GetWriter()) + { + writer.WritePacketId(PacketId.Authenticated); + writer.WriteNetworkConnection(conn); + NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, writer.GetArraySegment(), conn); + } + } + /// + /// Called when the server socket receives data. + /// + private void Transport_OnServerReceivedData(ServerReceivedDataArgs args) + { + ParseReceived(args); + } + + /// + /// Called when the server receives data. + /// + /// + private void ParseReceived(ServerReceivedDataArgs args) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _parseLogger.Reset(); +#endif + + //Not from a valid connection. + if (args.ConnectionId < 0) + return; + ArraySegment segment = args.Data; + NetworkManager.StatisticsManager.NetworkTraffic.LocalServerReceivedData((ulong)segment.Count); + if (segment.Count <= TransportManager.TICK_BYTES) + return; + + //FishNet internally splits packets so nothing should ever arrive over MTU. + int channelMtu = NetworkManager.TransportManager.Transport.GetMTU((byte)args.Channel); + //If over MTU kick client immediately. + if (segment.Count > channelMtu && !NetworkManager.TransportManager.IsLocalTransport(args.ConnectionId)) + { + ExceededMTUKick(); + return; + } + + PacketId packetId = PacketId.Unset; +#if !UNITY_EDITOR && !DEVELOPMENT_BUILD + try + { +#endif + using (PooledReader reader = ReaderPool.GetReader(segment, NetworkManager)) + { + NetworkManager.TimeManager.LastPacketTick = reader.ReadUInt32(AutoPackType.Unpacked); + /* This is a special condition where a message may arrive split. + * When this occurs buffer each packet until all packets are + * received. */ + if (reader.PeekPacketId() == PacketId.Split) + { + //Skip packetId. + reader.ReadPacketId(); + + int expectedMessages; + _splitReader.GetHeader(reader, out expectedMessages); + //If here split message can be written. + _splitReader.Write(NetworkManager.TimeManager.LastPacketTick, reader, expectedMessages); + + /* If fullMessage returns 0 count then the split + * has not written fully yet. Otherwise, if there is + * data within then reinitialize reader with the + * full message. */ + ArraySegment fullMessage = _splitReader.GetFullMessage(); + if (fullMessage.Count == 0) + return; + + /* If here then all data has been received. + * It's possible the client could have exceeded + * maximum MTU but not the maximum number of splits. + * This is because the length of each split + * is not written, so we don't know how much data of the + * final message actually belonged to the split vs + * unrelated data added afterwards. We're going to cut + * the client some slack in this situation for the sake + * of keeping things simple. */ + //Initialize reader with full message. + reader.Initialize(fullMessage, NetworkManager); + } + + //Parse reader. + while (reader.Remaining > 0) + { + packetId = reader.ReadPacketId(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _parseLogger.AddPacket(packetId); +#endif + NetworkConnection conn; + + /* Connection isn't available. This should never happen. + * Force an immediate disconnect. */ + if (!Clients.TryGetValueIL2CPP(args.ConnectionId, out conn)) + { + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.LogError($"ConnectionId {conn.ClientId} not found within Clients. Connection will be kicked immediately."); + NetworkManager.TransportManager.Transport.StopConnection(args.ConnectionId, true); + return; + } + /* 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.Authenticated && packetId != PacketId.Broadcast) + { + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.LogError($"ConnectionId {conn.ClientId} send a Broadcast without being authenticated. Connection will be kicked immediately."); + conn.Disconnect(true); + return; + } + + if (packetId == PacketId.Replicate) + { + Objects.ParseReplicateRpc(reader, conn, args.Channel); + } + else if (packetId == PacketId.ServerRpc) + { + Objects.ParseServerRpc(reader, conn, args.Channel); + } + else if (packetId == PacketId.Broadcast) + { + ParseBroadcast(reader, conn, args.Channel); + } + else if (packetId == PacketId.PingPong) + { + ParsePingPong(reader, conn); + } + else + { + if (NetworkManager.CanLog(LoggingType.Error)) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + Debug.LogError($"Server received an unhandled PacketId of {(ushort)packetId} from connectionId {args.ConnectionId}. Remaining data has been purged."); + _parseLogger.Print(NetworkManager); +#else + Debug.LogError($"Server received an unhandled PacketId of {(ushort)packetId} from connectionId {args.ConnectionId}. Connection will be kicked immediately."); + NetworkManager.TransportManager.Transport.StopConnection(args.ConnectionId, true); +#endif + } + return; + } + } + } +#if !UNITY_EDITOR && !DEVELOPMENT_BUILD + } + catch (Exception e) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Server encountered an error while parsing data for packetId {packetId} from connectionId {args.ConnectionId}. Connection will be kicked immediately. Message: {e.Message}."); + //Kick client immediately. + NetworkManager.TransportManager.Transport.StopConnection(args.ConnectionId, true); + } +#endif + + //Kicks connection for exceeding MTU. + void ExceededMTUKick() + { + NetworkManager.TransportManager.Transport.StopConnection(args.ConnectionId, true); + if (NetworkManager.CanLog(LoggingType.Common)) + Debug.Log($"ConnectionId {args.ConnectionId} sent a message larger than allowed amount. Connection will be kicked immediately."); + } + + } + + /// + /// Parses a received PingPong. + /// + /// + /// + private void ParsePingPong(PooledReader reader, NetworkConnection conn) + { + /* //security limit how often clients can send pings. + * have clients use a stopwatch rather than frame time + * for checks to ensure it's not possible to send + * excessively should their game stutter then catch back up. */ + uint clientTick = reader.ReadUInt32(AutoPackType.Unpacked); + if (conn.CanPingPong()) + NetworkManager.TimeManager.SendPong(conn, clientTick); + } + + + /// + /// Called when a remote client authenticates with the server. + /// + /// + private void ClientAuthenticated(NetworkConnection connection) + { + /* Immediately send connectionId to client. Some transports + * don't give clients their remoteId, therefor it has to be sent + * by the ServerManager. This packet is very simple and can be built + * on the spot. */ + connection.ConnectionAuthenticated(); + /* Send client Ids before telling the client + * they are authenticated. This is important because when the client becomes + * authenticated they set their LocalConnection using Clients field in ClientManager, + * which is set after getting Ids. */ + BroadcastClientConnectionChange(true, connection); + SendAuthenticated(connection); + + OnAuthenticationResult?.Invoke(connection, true); + NetworkManager.SceneManager.OnClientAuthenticated(connection); + } + + /// + /// Sends a client connection state change. + /// + /// + /// + private void BroadcastClientConnectionChange(bool connected, NetworkConnection conn) + { + //If sharing Ids then send all connected client Ids first if is a connected state. + if (ShareIds) + { + /* Send a broadcast to all authenticated clients with the clientId + * that just connected. The conn client will also get this. */ + ClientConnectionChangeBroadcast changeMsg = new ClientConnectionChangeBroadcast() + { + Connected = connected, + Id = conn.ClientId + }; + Broadcast(changeMsg); + + /* If state is connected then the conn client + * must also receive all currently connected client ids. */ + if (connected) + { + //Send already connected clients to the connection that just joined. + ListCache lc = ListCaches.IntCache; + lc.Reset(); + foreach (int key in Clients.Keys) + lc.AddValue(key); + + ConnectedClientsBroadcast allMsg = new ConnectedClientsBroadcast() + { + ListCache = lc + }; + conn.Broadcast(allMsg); + } + } + //If not sharing Ids then only send ConnectionChange to conn. + else + { + if (connected) + { + /* Send broadcast only to the client which just disconnected. + * Only send if connecting. If the client is disconnected there's no reason + * to send them a disconnect msg. */ + ClientConnectionChangeBroadcast changeMsg = new ClientConnectionChangeBroadcast() + { + Connected = connected, + Id = conn.ClientId + }; + Broadcast(conn, changeMsg, true, Channel.Reliable); + } + } + + } + + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs.meta new file mode 100644 index 0000000..9a70fbe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68828c85278210948b9d50a8db3aab74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic.meta new file mode 100644 index 0000000..5fdb9ab --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c554690fa24f652408df67e97c3a0e5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs new file mode 100644 index 0000000..9f9a5f2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs @@ -0,0 +1,21 @@ +namespace FishNet.Managing.Statistic +{ + + public struct NetworkTrafficArgs + { + /// + /// Number of bytes sent to the server. + /// + public readonly ulong ToServerBytes; + /// + /// Number of bytes sent by the server. + /// + public readonly ulong FromServerBytes; + + public NetworkTrafficArgs(ulong toServerBytes, ulong fromServerBytes) + { + ToServerBytes = toServerBytes; + FromServerBytes = fromServerBytes; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs.meta new file mode 100644 index 0000000..ff42599 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fb953771006e0541ba76e564a90c21d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs new file mode 100644 index 0000000..e1e517e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs @@ -0,0 +1,199 @@ + + +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Statistic +{ + [System.Serializable] + public class NetworkTraficStatistics + { + #region Public. + /// + /// Called when NetworkTraffic is updated for the client. + /// + public event Action OnClientNetworkTraffic; + /// + /// Called when NetworkTraffic is updated for the server. + /// + public event Action OnServerNetworkTraffic; + #endregion + + #region Serialized. + /// + /// How often to update traffic statistics. + /// + [Tooltip("How often to update traffic statistics.")] + [SerializeField] + [Range(0f, 10f)] + private float _updateInteval = 1f; + /// + /// + /// + [Tooltip("True to update client statistics.")] + [SerializeField] + private bool _updateClient; + /// + /// True to update client statistics. + /// + public bool UpdateClient + { + get => _updateClient; + private set => _updateClient = value; + } + /// + /// Sets UpdateClient value. + /// + /// + public void SetUpdateClient(bool update) + { + UpdateClient = update; + } + /// + /// + /// + [Tooltip("True to update server statistics.")] + [SerializeField] + private bool _updateServer; + /// + /// True to update client statistics. + /// + public bool UpdateServer + { + get => _updateServer; + private set => _updateServer = value; + } + /// + /// Sets UpdateServer value. + /// + /// + public void SetUpdateServer(bool update) + { + UpdateServer = update; + } + #endregion + + #region Private. + /// + /// NetworkManager for this statistics. + /// + private NetworkManager _networkManager; + /// + /// Bytes sent to the server from local client. + /// + private ulong _client_toServerBytes; + /// + /// Bytes received on the local client from the server. + /// + private ulong _client_fromServerBytes; + /// + /// Bytes sent to all clients from the local server. + /// + private ulong _server_toClientsBytes; + /// + /// Bytes received on the local server from all clients. + /// + private ulong _server_fromClientsBytes; + /// + /// Next time network traffic updates may invoke. + /// + private float _nextUpdateTime; + /// + /// Size suffixes as text. + /// + private static readonly string[] _sizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; + #endregion + + internal void InitializeOnceInternal(NetworkManager manager) + { + _networkManager = manager; + manager.TimeManager.OnPreTick += TimeManager_OnPreTick; + } + + /// + /// Called before the TimeManager ticks. + /// + private void TimeManager_OnPreTick() + { + if (Time.unscaledTime < _nextUpdateTime) + return; + _nextUpdateTime = Time.unscaledTime + _updateInteval; + + if (UpdateClient && _networkManager.IsClient) + OnClientNetworkTraffic?.Invoke(new NetworkTrafficArgs(_client_toServerBytes, _client_fromServerBytes)); + if (UpdateServer && _networkManager.IsServer) + OnServerNetworkTraffic?.Invoke(new NetworkTrafficArgs(_server_fromClientsBytes, _server_toClientsBytes)); + + _client_toServerBytes = 0; + _client_fromServerBytes = 0; + _server_toClientsBytes = 0; + _server_fromClientsBytes = 0; + } + + /// + /// Called when the local client sends data. + /// + internal void LocalClientSentData(ulong dataLength) + { + _client_toServerBytes = Math.Min(_client_toServerBytes + dataLength, ulong.MaxValue); + } + /// + /// Called when the local client receives data. + /// + public void LocalClientReceivedData(ulong dataLength) + { + _client_fromServerBytes = Math.Min(_client_fromServerBytes + dataLength, ulong.MaxValue); + } + + + /// + /// Called when the local client sends data. + /// + internal void LocalServerSentData(ulong dataLength) + { + _server_toClientsBytes = Math.Min(_server_toClientsBytes + dataLength, ulong.MaxValue); + } + /// + /// Called when the local client receives data. + /// + public void LocalServerReceivedData(ulong dataLength) + { + _server_fromClientsBytes = Math.Min(_server_fromClientsBytes + dataLength, ulong.MaxValue); + } + + + //Attribution: https://stackoverflow.com/questions/14488796/does-net-provide-an-easy-way-convert-bytes-to-kb-mb-gb-etc + /// + /// Formats passed in bytes value to the largest possible data type with 2 decimals. + /// + public static string FormatBytesToLargest(ulong bytes) + { + int decimalPlaces = 2; + if (bytes == 0) + return string.Format("{0:n" + decimalPlaces + "} bytes", 0); + + // mag is 0 for bytes, 1 for KB, 2, for MB, etc. + int mag = (int)Math.Log(bytes, 1024); + + // 1L << (mag * 10) == 2 ^ (10 * mag) + // [i.e. the number of bytes in the unit corresponding to mag] + decimal adjustedSize = (decimal)bytes / (1L << (mag * 10)); + + // make adjustment when the value is large enough that + // it would round up to 1000 or more + if (Math.Round(adjustedSize, decimalPlaces) >= 1000) + { + mag += 1; + adjustedSize /= 1024; + } + + //Don't show decimals for bytes. + if (mag == 0) + decimalPlaces = 0; + return string.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, _sizeSuffixes[mag]); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs.meta new file mode 100644 index 0000000..77c4fbc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cc04f6ae0339c94e9153396dce3f46e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs new file mode 100644 index 0000000..c862ab4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace FishNet.Managing.Statistic +{ + + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/StatisticsManager")] + public class StatisticsManager : MonoBehaviour + { + /// + /// Statistics for NetworkTraffic. + /// + public NetworkTraficStatistics NetworkTraffic = new NetworkTraficStatistics(); + + internal void InitializeOnceInternal(NetworkManager manager) + { + NetworkTraffic.InitializeOnceInternal(manager); + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs.meta new file mode 100644 index 0000000..f50fb2f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 756c28cd3141c4140ae776188ee26729 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing.meta new file mode 100644 index 0000000..35f0ef3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edf228892c89f3d4694213cba4a584fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor.meta new file mode 100644 index 0000000..f5e62ae --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 142c456200062324b95ea95078a9c38f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs new file mode 100644 index 0000000..8510308 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs @@ -0,0 +1,65 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Managing.Timing.Editing +{ + + + [CustomEditor(typeof(TimeManager), true)] + [CanEditMultipleObjects] + public class TimeManagerEditor : Editor + { + private SerializedProperty _tickRate; + private SerializedProperty _pingInterval; + private SerializedProperty _timingInterval; + private SerializedProperty _physicsMode; + private SerializedProperty _maximumBufferedInputs; + + protected virtual void OnEnable() + { + _tickRate = serializedObject.FindProperty("_tickRate"); + _pingInterval = serializedObject.FindProperty("_pingInterval"); + _timingInterval = serializedObject.FindProperty("_timingInterval"); + _physicsMode = serializedObject.FindProperty("_physicsMode"); + _maximumBufferedInputs = serializedObject.FindProperty("_maximumBufferedInputs"); + } + + public override void OnInspectorGUI() + { + + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((TimeManager)target), typeof(TimeManager), false); + GUI.enabled = true; + + //Timing. + EditorGUILayout.LabelField("Timing", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_tickRate); + EditorGUILayout.PropertyField(_pingInterval); + EditorGUILayout.PropertyField(_timingInterval); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + //Physics. + EditorGUILayout.LabelField("Physics", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + 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. + EditorGUILayout.LabelField("Prediction", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_maximumBufferedInputs); + EditorGUI.indentLevel--; + + serializedObject.ApplyModifiedProperties(); + } + } + +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs.meta new file mode 100644 index 0000000..cb15067 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12987a8c0302190489ecb55f6fbd494e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs new file mode 100644 index 0000000..4ceb011 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs @@ -0,0 +1,86 @@ +using FishNet.Documenting; +using System; +using UnityEngine; + +namespace FishNet.Managing.Timing +{ + + [APIExclude] + public class MovingAverage + { + #region Public. + /// + /// Average from samples favoring the most recent sample. + /// + public float Average { get; private set; } + #endregion + + /// + /// Next index to write a sample to. + /// + private int _writeIndex; + /// + /// Collected samples. + /// + private float[] _samples; + /// + /// Number of samples written. Will be at most samples size. + /// + private int _writtenSamples; + /// + /// Samples accumulated over queue. + /// + private float _sampleAccumulator; + + public MovingAverage(int sampleSize) + { + if (sampleSize < 0) + { + sampleSize = 0; + } + else if (sampleSize < 2) + { + if (NetworkManager.StaticCanLog(Logging.LoggingType.Warning)) + Debug.LogWarning("Using a sampleSize of less than 2 will always return the most recent value as Average."); + } + + _samples = new float[sampleSize]; + } + + + /// + /// Computes a new windowed average each time a new sample arrives + /// + /// + public void ComputeAverage(float newSample) + { + if (_samples.Length <= 1) + { + Average = newSample; + return; + } + + _sampleAccumulator += newSample; + _samples[_writeIndex] = newSample; + + //Increase writeIndex. + _writeIndex++; + _writtenSamples = Math.Max(_writtenSamples, _writeIndex); + if (_writeIndex >= _samples.Length) + _writeIndex = 0; + + Average = _sampleAccumulator / _writtenSamples; + + /* If samples are full then drop off + * the oldest sample. This will always be + * the one just after written. The entry isn't + * actually removed from the array but will + * be overwritten next sample. */ + if (_writtenSamples >= _samples.Length) + _sampleAccumulator -= _samples[_writeIndex]; + + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs.meta new file mode 100644 index 0000000..941fad9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03d05f88778c5c744810e48f251f2d3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs new file mode 100644 index 0000000..6a77670 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs @@ -0,0 +1,23 @@ +namespace FishNet.Managing.Timing +{ + /// + /// How to simulate physics. + /// + public enum PhysicsMode + { + /// + /// Unity performs physics every FixedUpdate. + /// + Unity = 0, + /// + /// TimeManager performs physics each tick. + /// + TimeManager = 1, + /// + /// Physics will be disabled. + /// + Disabled = 2 + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs.meta new file mode 100644 index 0000000..6b21845 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 502e9f31bebd41f4f9088a19eae53735 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs new file mode 100644 index 0000000..f940a70 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs @@ -0,0 +1,47 @@ +using FishNet.Serializing; +using FishNet.Utility.Extension; +using System; +using UnityEngine; + +namespace FishNet.Managing.Timing +{ + + public struct PreciseTick + { + /// + /// The current tick. + /// + public uint Tick; + /// + /// Percentage into the next tick. + /// + public double Percent; + + public PreciseTick(uint tick, double percent) + { + Tick = tick; + Percent = percent; + } + } + + public static class PreciseTickSerializer + { + public static void WritePreciseTick(this Writer writer, PreciseTick value) + { + writer.WriteUInt32(value.Tick, AutoPackType.Unpacked); + /* No reason percent should exist beyond these values, but better to be safe. + * There is also no double clamp in Unity so... */ + double percent = MathFN.ClampDouble(value.Percent, 0d, 1f); + byte percentByte = (byte)(percent * 100); + writer.WriteByte(percentByte); + } + + public static PreciseTick ReadPreciseTick(this Reader reader) + { + uint tick = reader.ReadUInt32(AutoPackType.Unpacked); + byte percentByte = reader.ReadByte(); + double percent = MathFN.ClampDouble((percentByte / 100f), 0d, 1d); + return new PreciseTick(tick, percent); + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs.meta new file mode 100644 index 0000000..4d9406a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a96dd6b21066a424199583b80746464f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs new file mode 100644 index 0000000..9fb79da --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEngine.SceneManagement; + +namespace FishNet.Managing.Timing +{ + internal sealed class SceneHandleEqualityComparer : EqualityComparer + { + public override bool Equals(Scene a, Scene b) + { + return (a.handle == b.handle); + } + + public override int GetHashCode(Scene obj) + { + return obj.handle; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs.meta new file mode 100644 index 0000000..0e09f91 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/SceneComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 161dbbe3995ff53479fc4e259f86549d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs new file mode 100644 index 0000000..a3800d3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs @@ -0,0 +1,23 @@ +namespace FishNet.Managing.Timing +{ + /// + /// How ticks are rounded when using time. + /// + public enum TickRounding + { + /// + /// Rounds up. + /// + RoundUp, + /// + /// Rounds down. + /// + RoundDown, + /// + /// Rounds to the nearest whole. + /// + RoundNearest + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs.meta new file mode 100644 index 0000000..02d1339 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d12f8894fc7343b4bbe332464dc4bce5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs new file mode 100644 index 0000000..0726324 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs @@ -0,0 +1,10 @@ +namespace FishNet.Managing.Timing +{ + public enum TickType : byte + { + Tick = 0, + LocalTick = 1, + LastPacketTick = 2 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs.meta new file mode 100644 index 0000000..cebcd6e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TickType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 489fba8b0da3c9b4b9ff4e7a46804473 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs new file mode 100644 index 0000000..1c1a8bb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs @@ -0,0 +1,1051 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using SystemStopwatch = System.Diagnostics.Stopwatch; +using UnityScene = UnityEngine.SceneManagement.Scene; + +namespace FishNet.Managing.Timing +{ + + /// + /// Provides data and actions for network time and tick based systems. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/TimeManager")] + public sealed partial class TimeManager : MonoBehaviour + { + //#region Types. + //public enum BufferPurgeType + //{ + // /// + // /// Run an additional input per tick when buffered inputs are higher than normal. + // /// This prevents clients from sending excessive inputs but may briefly disrupt clients synchronization if their timing is drastically off. + // /// Use this option for more secure prediction. + // /// + // Discard = 0, + // /// + // /// Run an additional input per tick when buffered inputs are higher than normal. + // /// This is useful for keeping the client synchronized with the server by processing inputs that would normally be discarded. + // /// However, by running extra buffered inputs the client has a better opportunity to cheat. + // /// + // Run = 1 + //} + //#endregion + + #region Public. + /// + /// Called before performing a reconcile on NetworkBehaviour. + /// + public event Action OnPreReconcile; + /// + /// Called after performing a reconcile on a NetworkBehaviour. + /// + public event Action OnPostReconcile; + /// + /// Called before physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + public event Action OnPreReplicateReplay; + /// + /// Called after physics is simulated when replaying a replicate method. + /// Contains the PhysicsScene and PhysicsScene2D which was simulated. + /// + public event Action OnPostReplicateReplay; + /// + /// Called right before a tick occurs, as well before data is read. + /// + public event Action OnPreTick; + /// + /// Called when a tick occurs. + /// + public event Action OnTick; + /// + /// When using TimeManager for physics timing, this is called immediately before physics simulation will occur for the tick. + /// While using Unity for physics timing, this is called during FixedUpdate. + /// This may be useful if you wish to run physics differently for stacked scenes. + /// + public event Action OnPhysicsSimulation; + /// + /// Called after a tick occurs; physics would have simulated if using PhysicsMode.TimeManager. + /// + public event Action OnPostTick; + /// + /// Called when MonoBehaviours call Update. + /// + public event Action OnUpdate; + /// + /// Called when MonoBehaviours call LateUpdate. + /// + public event Action OnLateUpdate; + /// + /// Called when MonoBehaviours call FixedUpdate. + /// + public event Action OnFixedUpdate; + /// + /// RoundTripTime in milliseconds. + /// + public long RoundTripTime { get; private set; } + /// + /// True if the number of frames per second are less than the number of expected ticks per second. + /// + internal bool LowFrameRate => ((Time.unscaledTime - _lastMultipleTicks) < 1f); + /// + /// Tick on the last received packet, be it from server or client. + /// + public uint LastPacketTick { get; internal set; } + /// + /// Current approximate network tick as it is on server. + /// When running as client only this is an approximation to what the server tick is. + /// The value of this field may increase and decrease as timing adjusts. + /// This value is reset upon disconnecting. + /// Tick can be used to get the server time by using TicksToTime(). + /// Use LocalTick for values that only increase. + /// + public uint Tick { get; internal set; } + /// + /// Percentage as 0-100 of how much into next tick the time is. + /// + [Obsolete("Use GetPreciseTick or GetTickPercent instead.")] //Remove on 2023/01/01 + public byte TickPercent + { + get + { + if (_networkManager == null) + return 0; + + double delta = (_networkManager.IsServer) ? TickDelta : _adjustedTickDelta; + double percent = (_elapsedTickTime / delta) * 100; + return (byte)Mathf.Clamp((float)percent, 0, 100); + } + } + /// + /// DeltaTime for TickRate. + /// + [HideInInspector] + public double TickDelta { get; private set; } + /// + /// True if the TimeManager will or has ticked this frame. + /// + public bool FrameTicked { get; private set; } + /// + /// How long the local server has been connected. + /// + public float ServerUptime { get; private set; } + /// + /// How long the local client has been connected. + /// + public float ClientUptime { get; private set; } + /// + /// + /// + private bool _isReplaying; + /// + /// Returns if any prediction is replaying. + /// + /// + public bool IsReplaying() => _isReplaying; + /// + /// Returns if scene is replaying. + /// + /// + /// + public bool IsReplaying(UnityScene scene) => _replayingScenes.Contains(scene); + /// + /// True if any predictions are replaying. + /// + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("How many times per second the server will simulate. This does not limit server frame rate.")] + [Range(1, 240)] + [SerializeField] + private ushort _tickRate = 30; + /// + /// How many times per second the server will simulate. This does not limit server frame rate. + /// + public ushort TickRate { get => _tickRate; private set => _tickRate = value; } + /// + /// + /// + [Tooltip("How often in seconds to a connections ping. This is also responsible for approximating server tick. This value does not affect prediction.")] + [Range(1, 15)] + [SerializeField] + private byte _pingInterval = 1; + /// + /// How often in seconds to a connections ping. This is also responsible for approximating server tick. This value does not affect prediction. + /// + internal byte PingInterval => _pingInterval; + /// + /// How often in seconds to update prediction timing. Lower values will result in marginally more accurate timings at the cost of bandwidth. + /// + [Tooltip("How often in seconds to update prediction timing. Lower values will result in marginally more accurate timings at the cost of bandwidth.")] + [Range(1, 15)] + [SerializeField] + private byte _timingInterval = 2; + /// + /// + /// + [Tooltip("How to perform physics.")] + [SerializeField] + private PhysicsMode _physicsMode = PhysicsMode.Unity; + /// + /// How to perform physics. + /// + public PhysicsMode PhysicsMode => _physicsMode; + /// + /// + /// + [Tooltip("Maximum number of buffered inputs which will be accepted from client before old inputs are discarded.")] + [Range(1, 100)] + [SerializeField] + private byte _maximumBufferedInputs = 15; + /// + /// Maximum number of buffered inputs which will be accepted from client before old inputs are discarded. + /// + public byte MaximumBufferedInputs => _maximumBufferedInputs; + #endregion + + #region Private. + /// + /// Scenes which are currently replaying prediction. + /// + private HashSet _replayingScenes = new HashSet(new SceneHandleEqualityComparer()); + /// + /// Ticks that have passed on client since the last time server sent an UpdateTicksBroadcast. + /// + private uint _clientTicks = 0; + /// + /// Last Tick the server sent out UpdateTicksBroadcast. + /// + private uint _lastUpdateTicks = 0; + /// + /// + /// + private uint _localTick; + /// + /// A tick that is not synchronized. This value will only increment. May be used for indexing or Ids with custom logic. + /// When called on the server Tick is returned, otherwise LocalTick is returned. + /// This value resets upon disconnecting. + /// + public uint LocalTick + { + get => (_networkManager.IsServer) ? Tick : _localTick; + private set => _localTick = value; + } + /// + /// Stopwatch used for pings. + /// + SystemStopwatch _pingStopwatch = new SystemStopwatch(); + /// + /// Ticks passed since last ping. + /// + private uint _pingTicks; + /// + /// MovingAverage instance used to calculate mean ping. + /// + private MovingAverage _pingAverage = new MovingAverage(5); + /// + /// Time elapsed after ticks. This is extra time beyond the simulation rate. + /// + private double _elapsedTickTime; + /// + /// NetworkManager used with this. + /// + private NetworkManager _networkManager; + /// + /// Internal deltaTime for clients. Controlled by the server. + /// + private double _adjustedTickDelta; + /// + /// Range which client timing may reside within. + /// + private double[] _clientTimingRange; + /// + /// Last frame an iteration occurred for incoming. + /// + private int _lastIncomingIterationFrame = -1; + /// + /// True if client received Pong since last ping. + /// + private bool _receivedPong = true; + /// + /// Last unscaledTime multiple ticks occurred in a single frame. + /// + private float _lastMultipleTicks; + /// + /// Number of TimeManagers open which are using manual physics. + /// + private static uint _manualPhysics; + #endregion + + #region Const. + /// + /// Maximum percentage timing may vary from SimulationInterval for clients. + /// + private const float CLIENT_TIMING_PERCENT_RANGE = 0.5f; + /// + /// Percentage of TickDelta client will adjust when needing to speed up. + /// + private const double CLIENT_SPEEDUP_PERCENT = 0.003d; + /// + /// Percentage of TickDelta client will adjust when needing to slow down. + /// + private const double CLIENT_SLOWDOWN_PERCENT = 0.005d; + /// + /// When steps to be sent to clients are equal to or higher than this value in either direction a reset steps will be sent. + /// + private const byte RESET_STEPS_THRESHOLD = 5; + /// + /// Playerprefs string to load and save user fixed time. + /// + private const string SAVED_FIXED_TIME_TEXT = "SavedFixedTimeFN"; + #endregion + private void OnEnable() + { + UnityEngine.SceneManagement.SceneManager.sceneUnloaded += SceneManager_sceneUnloaded; + } + +#if UNITY_EDITOR + private void OnDisable() + { + UnityEngine.SceneManagement.SceneManager.sceneUnloaded -= SceneManager_sceneUnloaded; + + //If closing/stopping. + if (ApplicationState.IsQuitting()) + { + _manualPhysics = 0; + UnsetSimulationSettings(); + } + else if (PhysicsMode == PhysicsMode.TimeManager) + { + _manualPhysics = Math.Max(0, _manualPhysics - 1); + } + } +#endif + + /// + /// Called when FixedUpdate ticks. This is called before any other script. + /// + internal void TickFixedUpdate() + { + OnFixedUpdate?.Invoke(); + /* Invoke onsimulation if using Unity time. + * Otherwise let the tick cycling part invoke. */ + if (PhysicsMode == PhysicsMode.Unity) + OnPhysicsSimulation?.Invoke(Time.fixedDeltaTime); + } + + /// + /// Called when Update ticks. This is called before any other script. + /// + internal void TickUpdate() + { + if (_networkManager.IsServer) + ServerUptime += Time.deltaTime; + if (_networkManager.IsClient) + ClientUptime += Time.deltaTime; + + IncreaseTick(); + OnUpdate?.Invoke(); + } + + /// + /// Called when LateUpdate ticks. This is called after all other scripts. + /// + internal void TickLateUpdate() + { + OnLateUpdate?.Invoke(); + } + + + /// + /// Initializes this script for use. + /// + internal void InitializeOnceInternal(NetworkManager networkManager) + { + _networkManager = networkManager; + SetInitialValues(); + _networkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState; + _networkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; + + AddNetworkLoops(); + } + + /// + /// Adds network loops to gameObject. + /// + private void AddNetworkLoops() + { + //Writer. + if (!gameObject.TryGetComponent(out _)) + gameObject.AddComponent(); + //Reader. + if (!gameObject.TryGetComponent(out _)) + gameObject.AddComponent(); + } + + + /// + /// Called when a scene unloads. + /// + /// + private void SceneManager_sceneUnloaded(UnityScene s) + { + _replayingScenes.Remove(s); + } + + + /// + /// Called after the local client connection state changes. + /// + private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj) + { + if (obj.ConnectionState != LocalConnectionState.Started) + { + _replayingScenes.Clear(); + _pingStopwatch.Stop(); + ClientUptime = 0f; + LocalTick = 0; + //Also reset Tick if not running as host. + if (!_networkManager.IsServer) + Tick = 0; + } + //Started. + else + { + _pingStopwatch.Restart(); + } + } + + /// + /// Called after the local server connection state changes. + /// + private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj) + { + //If no servers are running. + if (!_networkManager.ServerManager.AnyServerStarted()) + { + ServerUptime = 0f; + Tick = 0; + } + } + + /// + /// Invokes OnPre/PostReconcile events. + /// Internal use. + /// + [APIExclude] + [CodegenMakePublic] //To internal. + public void InvokeOnReconcile(NetworkBehaviour nb, bool before) + { + nb.IsReconciling = before; + if (before) + OnPreReconcile?.Invoke(nb); + else + OnPostReconcile?.Invoke(nb); + } + + /// + /// Invokes OnReplicateReplay. + /// Internal use. + /// + [APIExclude] + [CodegenMakePublic] //To internal. + public void InvokeOnReplicateReplay(UnityScene scene, PhysicsScene ps, PhysicsScene2D ps2d, bool before) + { + _isReplaying = before; + if (before) + { + _replayingScenes.Add(scene); + OnPreReplicateReplay?.Invoke(ps, ps2d); + } + else + { + _replayingScenes.Remove(scene); + OnPostReplicateReplay?.Invoke(ps, ps2d); + } + } + + /// + /// Sets values to use based on settings. + /// + private void SetInitialValues() + { + SetTickRate(TickRate); + InitializePhysicsMode(PhysicsMode); + } + + /// + /// Sets simulation settings to Unity defaults. + /// + private void UnsetSimulationSettings() + { + Physics.autoSimulation = true; +#if !UNITY_2020_2_OR_NEWER + Physics2D.autoSimulation = true; +#else + Physics2D.simulationMode = SimulationMode2D.FixedUpdate; +#endif + + float simulationTime = PlayerPrefs.GetFloat(SAVED_FIXED_TIME_TEXT, float.MinValue); + if (simulationTime != float.MinValue) + Time.fixedDeltaTime = simulationTime; + } + + /// + /// Initializes physics mode when starting. + /// + /// + private void InitializePhysicsMode(PhysicsMode mode) + { + //Disable. + if (mode == PhysicsMode.Disabled) + { + SetPhysicsMode(mode); + } + //Do not automatically simulate. + else if (mode == PhysicsMode.TimeManager) + { +#if UNITY_EDITOR + //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"); +#endif + Time.fixedDeltaTime = (float)TickDelta; + /* Only check this if network manager + * is not null. It would be null via + * OnValidate. */ + if (_networkManager != null) + { + //If at least one time manager is already running manual physics. + if (_manualPhysics > 0) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"There are multiple TimeManagers instantiated which are using manual physics. Manual physics with multiple TimeManagers is not supported."); + } + _manualPhysics++; + } + + SetPhysicsMode(mode); + } + //Automatically simulate. + else + { +#if UNITY_EDITOR + float savedTime = PlayerPrefs.GetFloat(SAVED_FIXED_TIME_TEXT, float.MinValue); + if (savedTime != float.MinValue && Time.fixedDeltaTime != savedTime) + { + Debug.LogWarning("Time.fixedDeltaTime has been set back to user values."); + Time.fixedDeltaTime = savedTime; + } + + PlayerPrefs.DeleteKey(SAVED_FIXED_TIME_TEXT); +#endif + SetPhysicsMode(mode); + } + } + + /// + /// Updates physics based on which physics mode to use. + /// + /// + public void SetPhysicsMode(PhysicsMode mode) + { + //Disable. + if (mode == PhysicsMode.Disabled || mode == PhysicsMode.TimeManager) + { + Physics.autoSimulation = false; +#if !UNITY_2020_2_OR_NEWER + Physics2D.autoSimulation = false; +#else + Physics2D.simulationMode = SimulationMode2D.Script; +#endif + } + //Automatically simulate. + else + { + Physics.autoSimulation = true; +#if !UNITY_2020_2_OR_NEWER + Physics2D.autoSimulation = true; +#else + Physics2D.simulationMode = SimulationMode2D.FixedUpdate; +#endif + } + } + + #region PingPong. + /// + /// Modifies client ping based on LocalTick and clientTIck. + /// + /// + internal void ModifyPing(uint clientTick) + { + uint tickDifference = (LocalTick - clientTick); + _pingAverage.ComputeAverage(tickDifference); + double averageInTime = (_pingAverage.Average * TickDelta * 1000); + RoundTripTime = (long)Math.Round(averageInTime); + _receivedPong = true; + } + + /// + /// Sends a ping to the server. + /// + private void TrySendPing(uint? tickOverride = null) + { + byte pingInterval = PingInterval; + + /* How often client may send ping is based on if + * the server responded to the last ping. + * A response may not be received if the server + * believes the client is pinging too fast, or if the + * client is having difficulties reaching the server. */ + long requiredTime = (pingInterval * 1000); + float multiplier = (_receivedPong) ? 1f : 1.5f; + + requiredTime = (long)(requiredTime * multiplier); + uint requiredTicks = TimeToTicks(pingInterval * multiplier); + + _pingTicks++; + /* We cannot just consider time because ticks might run slower + * from adjustments. We also cannot only consider ticks because + * they might run faster from adjustments. Therefor require both + * to have pass checks. */ + if (_pingTicks < requiredTicks || _pingStopwatch.ElapsedMilliseconds < requiredTime) + return; + + _pingTicks = 0; + _pingStopwatch.Restart(); + //Unset receivedPong, wait for new response. + _receivedPong = false; + + uint tick = (tickOverride == null) ? LocalTick : tickOverride.Value; + using (PooledWriter writer = WriterPool.GetWriter()) + { + writer.WriteUInt16((ushort)PacketId.PingPong); + writer.WriteUInt32(tick, AutoPackType.Unpacked); + _networkManager.TransportManager.SendToServer((byte)Channel.Unreliable, writer.GetArraySegment()); + } + } + + /// + /// Sends a pong to a client. + /// + internal void SendPong(NetworkConnection conn, uint clientTick) + { + if (!conn.IsActive || !conn.Authenticated) + return; + + using (PooledWriter writer = WriterPool.GetWriter()) + { + writer.WriteUInt16((ushort)PacketId.PingPong); + writer.WriteUInt32(clientTick, AutoPackType.Unpacked); + conn.SendToClient((byte)Channel.Unreliable, writer.GetArraySegment()); + } + } + #endregion + + /// + /// Increases the tick based on simulation rate. + /// + private void IncreaseTick() + { + bool isClient = _networkManager.IsClient; + + double timePerSimulation = (_networkManager.IsServer) ? TickDelta : _adjustedTickDelta; + double time = Time.unscaledDeltaTime; + _elapsedTickTime += time; + FrameTicked = (_elapsedTickTime >= timePerSimulation); + + //Multiple ticks will occur this frame. + if (_elapsedTickTime > (timePerSimulation * 2d)) + _lastMultipleTicks = Time.unscaledTime; + + while (_elapsedTickTime >= timePerSimulation) + { + _elapsedTickTime -= timePerSimulation; + + OnPreTick?.Invoke(); + /* This has to be called inside the loop because + * OnPreTick promises data hasn't been read yet. + * Therefor iterate must occur after OnPreTick. + * Iteration will only run once per frame. */ + TryIterateData(true); + + OnTick?.Invoke(); + + if (PhysicsMode == PhysicsMode.TimeManager) + { + float tick = (float)TickDelta; + OnPhysicsSimulation?.Invoke(tick); + Physics.Simulate(tick); + Physics2D.Simulate(tick); + } + + OnPostTick?.Invoke(); + + /* If isClient this is the + * last tick during this loop. */ + if (isClient && (_elapsedTickTime < timePerSimulation)) + TrySendPing(LocalTick + 1); + + if (_networkManager.IsServer) + SendTimingAdjustment(); + + //Send out data. + TryIterateData(false); + + if (_networkManager.IsClient) + _clientTicks++; + + Tick++; + LocalTick++; + } + + } + + + #region TicksToTime. + /// + /// Returns the percentage of how far the TimeManager is into the next tick. + /// + /// + public double GetTickPercent() + { + if (_networkManager == null) + return default; + + double delta = (_networkManager.IsServer) ? TickDelta : _adjustedTickDelta; + double percent = (_elapsedTickTime / delta) * 100d; + return percent; + } + /// + /// Returns a PreciseTick. + /// + /// Tick to set within the returned PreciseTick. + /// + public PreciseTick GetPreciseTick(uint tick) + { + if (_networkManager == null) + return default; + + double delta = (_networkManager.IsServer) ? TickDelta : _adjustedTickDelta; + double percent = (_elapsedTickTime / delta) * 100; + + return new PreciseTick(tick, percent); + } + /// + /// Returns a PreciseTick. + /// + /// Tick to use within PreciseTick. + /// + public PreciseTick GetPreciseTick(TickType tickType) + { + if (_networkManager == null) + return default; + + if (tickType == TickType.Tick) + { + return GetPreciseTick(Tick); + } + else if (tickType == TickType.LocalTick) + { + return GetPreciseTick(LocalTick); + } + else if (tickType == TickType.LastPacketTick) + { + return GetPreciseTick(LastPacketTick); + } + else + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"TickType {tickType.ToString()} is unhandled."); + return default; + } + } + + + /// + /// Converts current ticks to time. + /// + /// TickType to compare against. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double TicksToTime(TickType tickType = TickType.LocalTick) + { + if (tickType == TickType.LocalTick) + { + return TicksToTime(LocalTick); + } + else if (tickType == TickType.Tick) + { + return TicksToTime(Tick); + } + else if (tickType == TickType.LastPacketTick) + { + return TicksToTime(LastPacketTick); + } + else + { + if (_networkManager != null && _networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"TickType {tickType} is unhandled."); + return 0d; + } + } + + /// + /// Converts current ticks to time. + /// + /// True to use the LocalTick, false to use Tick. + /// + [Obsolete("Use TicksToTime(TickType) instead.")] + [MethodImpl(MethodImplOptions.AggressiveInlining)] //Remove on 2023/01/01 + public double TicksToTime(bool useLocalTick = true) + { + if (useLocalTick) + return TicksToTime(LocalTick); + else + return TicksToTime(Tick); + } + /// + /// Converts a number ticks to time. + /// + /// Ticks to convert. + /// + public double TicksToTime(uint ticks) + { + return (TickDelta * (double)ticks); + } + /// + /// Converts time passed from currentTick to previous. Value will be negative if previousTick is larger than currentTick. + /// + /// The current tick. + /// The previous tick. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double TicksToTime(uint currentTick, uint previousTick) + { + double multiplier; + double result; + if (currentTick >= previousTick) + { + multiplier = 1f; + result = TicksToTime(currentTick - previousTick); + } + else + { + multiplier = -1f; + result = TicksToTime(previousTick - currentTick); + } + + return (result * multiplier); + } + + /// + /// Gets time passed from Tick to preciseTick. + /// + /// PreciseTick value to compare against. + /// True to allow negative values. When false and value would be negative 0 is returned. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double TimePassed(PreciseTick preciseTick, bool allowNegative = false) + { + PreciseTick currentPt = GetPreciseTick(TickType.Tick); + + long tickDifference = (currentPt.Tick - preciseTick.Tick); + double percentDifference = (currentPt.Percent - preciseTick.Percent); + + /* If tickDifference is less than 0 or tickDifference and percentDifference are 0 or less + * then the result would be negative. */ + bool negativeValue = (tickDifference < 0 || (tickDifference <= 0 && percentDifference <= 0)); + + if (!allowNegative && negativeValue) + return 0d; + + double tickTime = TimePassed(preciseTick.Tick, true); + double percent = (percentDifference / 100); + double percentTime = (percent * TickDelta); + + return (tickTime + percentTime); + } + /// + /// Gets time passed from Tick to previousTick. + /// + /// The previous tick. + /// True to allow negative values. When false and value would be negative 0 is returned. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double TimePassed(uint previousTick, bool allowNegative = false) + { + uint currentTick = Tick; + //Difference will be positive. + if (currentTick >= previousTick) + { + return TicksToTime(currentTick - previousTick); + } + //Difference would be negative. + else + { + if (!allowNegative) + { + return 0d; + } + else + { + double difference = TicksToTime(previousTick - currentTick); + return (difference * -1d); + } + } + } + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + /// Converts time to ticks. + /// + /// Time to convert. + /// + public uint TimeToTicks(double time, TickRounding rounding = TickRounding.RoundNearest) + { + double result = (time / TickDelta); + + if (rounding == TickRounding.RoundNearest) + return (uint)Math.Round(result); + else if (rounding == TickRounding.RoundDown) + return (uint)Math.Floor(result); + else + return (uint)Math.Ceiling(result); + } + + /// + /// Tries to iterate incoming or outgoing data. + /// + /// True to iterate incoming. + private void TryIterateData(bool incoming) + { + if (incoming) + { + /* It's not possible for data to come in + * more than once per frame but there could + * be new data going out each tick, since + * movement is often based off the tick system. + * Because of this don't iterate incoming if + * it's the same frame but the outgoing + * may iterate multiple times per frame. */ + int frameCount = Time.frameCount; + if (frameCount == _lastIncomingIterationFrame) + return; + _lastIncomingIterationFrame = frameCount; + + _networkManager.TransportManager.IterateIncoming(true); + _networkManager.TransportManager.IterateIncoming(false); + } + else + { + _networkManager.TransportManager.IterateOutgoing(true); + _networkManager.TransportManager.IterateOutgoing(false); + } + } + + + #region Timing adjusting. + /// + /// Sends a TimingUpdate packet to clients. + /// + private void SendTimingAdjustment() + { + uint requiredTicks = TimeToTicks(_timingInterval); + uint tick = Tick; + if (tick - _lastUpdateTicks >= requiredTicks) + { + //Now send using a packetId. + PooledWriter writer = WriterPool.GetWriter(); + writer.WritePacketId(PacketId.TimingUpdate); + _networkManager.TransportManager.SendToClients((byte)Channel.Unreliable, writer.GetArraySegment()); + writer.Dispose(); + + _lastUpdateTicks = tick; + } + } + + /// + /// Called on client when server sends a timing update. + /// + /// + internal void ParseTimingUpdate() + { + //Don't adjust timing on server. + if (_networkManager.IsServer) + return; + + //Add half of rtt onto tick. + uint rttTicks = TimeToTicks((RoundTripTime / 2) / 1000f); + Tick = LastPacketTick + rttTicks; + + uint expected = (uint)(TickRate * _timingInterval); + long difference; + //If ticking too fast. + if (_clientTicks > expected) + difference = (long)(_clientTicks - expected); + //Not ticking fast enough. + else + difference = (long)((expected - _clientTicks) * -1); + + //If difference is unusually off then reset timings. + if (Mathf.Abs(difference) >= RESET_STEPS_THRESHOLD) + { + _adjustedTickDelta = TickDelta; + } + else + { + sbyte steps = (sbyte)Mathf.Clamp(difference, sbyte.MinValue, sbyte.MaxValue); + double percent = (steps < 0) ? CLIENT_SPEEDUP_PERCENT : CLIENT_SLOWDOWN_PERCENT; + double change = (steps * (percent * TickDelta)); + + _adjustedTickDelta = MathFN.ClampDouble(_adjustedTickDelta + change, _clientTimingRange[0], _clientTimingRange[1]); + } + + _clientTicks = 0; + } + #endregion + + /// + /// Sets the TickRate to use. This value is not synchronized, it must be set on client and server independently. + /// + /// New TickRate to use. + public void SetTickRate(ushort value) + { + TickRate = value; + TickDelta = (1d / TickRate); + _adjustedTickDelta = TickDelta; + _clientTimingRange = new double[] + { + TickDelta * (1f - CLIENT_TIMING_PERCENT_RANGE), + TickDelta * (1f + CLIENT_TIMING_PERCENT_RANGE) + }; + } + + #region UNITY_EDITOR + private void OnValidate() + { + SetInitialValues(); + } + #endregion + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs.meta new file mode 100644 index 0000000..5f8b64f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3fdaae44044276a49a52229c1597e33b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting.meta new file mode 100644 index 0000000..089da21 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dadeb2231e0f13b418e05dfc6c4321f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs new file mode 100644 index 0000000..0cfabbf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs @@ -0,0 +1,352 @@ +using FishNet.Transporting; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using UnityEngine; + +//Thanks to TiToMoskito originally creating this as a Transport. +//https://github.com/TiToMoskito/FishyLatency +namespace FishNet.Managing.Transporting +{ + [System.Serializable] + public class LatencySimulator + { + #region Types. + /// + /// A message affected by latency. + /// + private struct Message + { + public readonly int ConnectionId; + public readonly byte[] Data; + public readonly int Length; + public readonly float SendTime; + + public Message(int connectionId, ArraySegment segment, float latency) + { + this.ConnectionId = connectionId; + this.SendTime = (Time.unscaledTime + latency); + this.Length = segment.Count; + this.Data = ByteArrayPool.Retrieve(this.Length); + Buffer.BlockCopy(segment.Array, segment.Offset, this.Data, 0, this.Length); + } + + public ArraySegment GetSegment() + { + return new ArraySegment(Data, 0, Length); + } + } + #endregion + + #region Internal. + /// + /// True if latency can be simulated. + /// + internal bool CanSimulate => (GetEnabled() && (GetLatency() > 0 || GetPacketLost() > 0 || GetOutOfOrder() > 0)); + #endregion + + #region Serialized + [Header("Settings")] + /// + /// + /// + [Tooltip("True if latency simulator is enabled.")] + [SerializeField] + private bool _enabled; + /// + /// Gets the enabled value of simulator. + /// + public bool GetEnabled() => _enabled; + /// + /// Sets the enabled value of simulator. + /// + /// New value. + public void SetEnabled(bool value) + { + if (value == _enabled) + return; + + _enabled = value; + Reset(); + } + /// + /// + /// + [Tooltip("True to add latency on clientHost as well.")] + [SerializeField] + private bool _simulateHost = true; + /// + /// Milliseconds to add between packets. When acting as host this value will be doubled. Added latency will be a minimum of tick rate. + /// + [Tooltip("Milliseconds to add between packets. When acting as host this value will be doubled. Added latency will be a minimum of tick rate.")] + [Range(0, 60000)] + [SerializeField] + private long _latency = 0; + /// + /// Gets the latency value. + /// + /// + public long GetLatency() => _latency; + /// + /// Sets a new latency value. + /// + /// Latency as milliseconds. + public void SetLatency(long value) => _latency = value; + + [Header("Unreliable")] + /// + /// Percentage of unreliable packets which should arrive out of order. + /// + [Tooltip("Percentage of unreliable packets which should arrive out of order.")] + [Range(0f, 1f)] + [SerializeField] + private double _outOfOrder = 0; + /// + /// Out of order chance, 1f is a 100% chance to occur. + /// + /// + public double GetOutOfOrder() => _outOfOrder; + /// + /// Sets out of order chance. 1f is a 100% chance to occur. + /// + /// New Value. + public void SetOutOfOrder(double value) => _outOfOrder = value; + /// + /// Percentage of packets which should drop. + /// + [Tooltip("Percentage of packets which should drop.")] + [Range(0, 1)] + [SerializeField] + private double _packetLoss = 0; + /// + /// Gets packet loss chance. 1f is a 100% chance to occur. + /// + /// + public double GetPacketLost() => _packetLoss; + /// + /// Sets packet loss chance. 1f is a 100% chance to occur. + /// + /// New Value. + public void SetPacketLoss(double value) => _packetLoss = value; + #endregion + + #region Private + /// + /// Transport to send data on. + /// + private Transport _transport; + /// + /// Reliable messages to the server. + /// + private List _toServerReliable = new List(); + /// + /// Unreliable messages to the server. + /// + private List _toServerUnreliable = new List(); + /// + /// Reliable messages to clients. + /// + private List _toClientReliable = new List(); + /// + /// Unreliable messages to clients. + /// + private List _toClientUnreliable = new List(); + /// + /// NetworkManager for this instance. + /// + private NetworkManager _networkManager; + /// + /// Used to generate chances of latency. + /// + private readonly System.Random _random = new System.Random(); + #endregion + + #region Initialization and Unity + public void Initialize(NetworkManager manager, Transport transport) + { + _networkManager = manager; + _transport = transport; + } + #endregion + + /// + /// Stops both client and server. + /// + public void Reset() + { + bool enabled = GetEnabled(); + if (_transport != null && enabled) + { + IterateAndStore(_toServerReliable); + IterateAndStore(_toServerUnreliable); + IterateAndStore(_toClientReliable); + IterateAndStore(_toClientUnreliable); + } + + void IterateAndStore(List messages) + { + foreach (Message m in messages) + { + _transport.SendToServer((byte)Channel.Reliable, m.GetSegment()); + ByteArrayPool.Store(m.Data); + } + } + + _toServerReliable.Clear(); + _toServerUnreliable.Clear(); + _toClientReliable.Clear(); + _toClientUnreliable.Clear(); + } + + + #region Simulation + /// + /// Returns long latency as a float. + /// + /// + /// + private float GetLatencyAsFloat() + { + return (float)(_latency / 1000f); + } + + /// + /// Adds a packet for simulation. + /// + public void AddOutgoing(byte channelId, ArraySegment segment, bool toServer = true, int connectionId = -1) + { + /* If to not simulate for host see if this packet + * should be sent normally. */ + if (!_simulateHost && _networkManager != null && _networkManager.IsHost) + { + /* If going to the server and is host then + * it must be sent from clientHost. */ + if (toServer) + { + _transport.SendToServer(channelId, segment); + return; + } + //Not to server, see if going to clientHost. + else + { + //If connId is the same as clientHost id. + if (_networkManager.ClientManager.Connection.ClientId == connectionId) + { + _transport.SendToClient(channelId, segment, connectionId); + return; + } + } + } + + List collection; + Channel c = (Channel)channelId; + + if (toServer) + collection = (c == Channel.Reliable) ? _toServerReliable : _toServerUnreliable; + else + collection = (c == Channel.Reliable) ? _toClientReliable : _toClientUnreliable; + + float latency = GetLatencyAsFloat(); + //If dropping check to add extra latency if reliable, or discard if not. + if (DropPacket()) + { + if (c == Channel.Reliable) + { + latency += latency; //add extra for resend. + } + //If not reliable then return the segment array to pool. + else + { + return; + } + } + + Message msg = new Message(connectionId, segment, latency); + int count = collection.Count; + if (c == Channel.Unreliable && count > 0 && OutOfOrderPacket(c)) + collection.Insert(count - 1, msg); + else + collection.Add(msg); + } + + /// + /// Simulates pending outgoing packets. + /// + /// True if sending to the server. + public void IterateOutgoing(bool toServer) + { + if (_transport == null) + { + Reset(); + return; + } + + if (toServer) + { + IterateCollection(_toServerReliable, Channel.Reliable); + IterateCollection(_toServerUnreliable, Channel.Unreliable); + } + else + { + IterateCollection(_toClientReliable, Channel.Reliable); + IterateCollection(_toClientUnreliable, Channel.Unreliable); + } + + void IterateCollection(List collection, Channel channel) + { + byte cByte = (byte)channel; + float unscaledTime = Time.unscaledTime; + + int count = collection.Count; + int iterations = 0; + for (int i = 0; i < count; i++) + { + Message msg = collection[i]; + //Not enough time has passed. + if (unscaledTime < msg.SendTime) + break; + + if (toServer) + _transport.SendToServer(cByte, msg.GetSegment()); + else + _transport.SendToClient(cByte, msg.GetSegment(), msg.ConnectionId); + + iterations++; + } + + if (iterations > 0) + { + for (int i = 0; i < iterations; i++) + ByteArrayPool.Store(collection[i].Data); + collection.RemoveRange(0, iterations); + } + } + + _transport.IterateOutgoing(toServer); + } + + /// + /// Returns if a packet should drop. + /// + /// + private bool DropPacket() + { + return (_packetLoss > 0d && (_random.NextDouble() < _packetLoss)); + } + + /// + /// Returns if a packet should be out of order. + /// + /// + /// + private bool OutOfOrderPacket(Channel c) + { + if (c == Channel.Reliable) + return false; + + return (_outOfOrder > 0d && (_random.NextDouble() < _outOfOrder)); + } + #endregion + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs.meta new file mode 100644 index 0000000..7eb5b8b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82bfafe804acb534fbf04c88de6eeed1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs new file mode 100644 index 0000000..bd32a42 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs @@ -0,0 +1,87 @@ +using FishNet.Serializing; +using System; +using UnityEngine; + +namespace FishNet.Managing.Transporting +{ + + internal class SplitReader + { + #region Private. + /// + /// Tick split is for. + /// Tick must be a negative value so that it's impossible for the first tick to align. + /// + private long _tick = -1; + /// + /// Expected number of splits. + /// + private int _expectedMessages; + /// + /// Number of splits received so far. + /// + private ushort _receivedMessages; + /// + /// Writer containing split packet combined. + /// + private PooledWriter _writer = WriterPool.GetWriter(); + #endregion + + /// + /// Gets split header values. + /// + internal void GetHeader(PooledReader reader, out int expectedMessages) + { + expectedMessages = reader.ReadInt32(); + } + + /// + /// Combines split data. + /// + internal void Write(uint tick, PooledReader reader, int expectedMessages) + { + //New tick which means new split. + if (tick != _tick) + Reset(tick, expectedMessages); + + /* Empty remainder of reader into the writer. + * It does not matter if parts of the reader + * contain data added after the split because + * once the split is fully combined the data + * is parsed as though it came in as one message, + * which is how data is normally read. */ + ArraySegment data = reader.ReadArraySegment(reader.Remaining); + _writer.WriteArraySegment(data); + _receivedMessages++; + } + + /// + /// Returns if all split messages have been received. + /// + /// + internal ArraySegment GetFullMessage() + { + if (_receivedMessages < _expectedMessages) + { + return default(ArraySegment); + } + else + { + ArraySegment segment = _writer.GetArraySegment(); + Reset(); + return segment; + } + } + + private void Reset(uint tick = 0, int expectedMessages = 0) + { + _tick = tick; + _receivedMessages = 0; + _expectedMessages = expectedMessages; + _writer.Reset(); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs.meta new file mode 100644 index 0000000..3c123e3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1c06be1540b77842be35823aa54b19b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs new file mode 100644 index 0000000..d21d908 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs @@ -0,0 +1,65 @@ +using FishNet.Transporting; +using FishNet.Transporting.Multipass; +using UnityEngine; + +namespace FishNet.Managing.Transporting +{ + + /// + /// Communicates with the Transport to send and receive data. + /// + public sealed partial class TransportManager : MonoBehaviour + { + #region Public. + /// + /// Returns IsLocalTransport for the current transport. + /// + public bool IsLocalTransport(int connectionId) => (Transport == null) ? false : Transport.IsLocalTransport(connectionId); + #endregion + + + /// + /// Gets transport on index. + /// Commonly index will be 0 unless using Multipass. + /// + /// + public Transport GetTransport(int index) + { + //If using multipass try to find the correct transport. + if (Transport is Multipass mp) + { + return mp.GetTransport(index); + } + //Not using multipass. + else + { + return Transport; + } + } + + /// + /// Gets transport of type T. + /// + /// Returns the found transport which is of type T. Returns null if not found. + public Transport GetTransport() where T : Transport + { + //If using multipass try to find the correct transport. + if (Transport is Multipass mp) + { + if (typeof(T) == typeof(Multipass)) + return mp; + else + return mp.GetTransport(); + } + //Not using multipass. + else + { + if (Transport.GetType() == typeof(T)) + return Transport; + else + return null; + } + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs.meta new file mode 100644 index 0000000..21ee1b3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aac8eab4e511d7e4dbc81eb74aea7f23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs new file mode 100644 index 0000000..ad3028f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs @@ -0,0 +1,511 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Managing.Timing; +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Managing.Transporting +{ + + /// + /// Communicates with the Transport to send and receive data. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Manager/TransportManager")] + public sealed partial class TransportManager : MonoBehaviour + { + #region Types. + private struct DisconnectingClient + { + public uint Tick; + public NetworkConnection Connection; + + public DisconnectingClient(uint tick, NetworkConnection connection) + { + Tick = tick; + Connection = connection; + } + } + #endregion + + #region Public. + /// + /// Called before IterateOutgoing has started. + /// + internal event Action OnIterateOutgoingStart; + /// + /// Called after IterateOutgoing has completed. + /// + internal event Action OnIterateOutgoingEnd; + /// + /// Called before IterateIncoming has started. True for on server, false for on client. + /// + internal event Action OnIterateIncomingStart; + /// + /// Called after IterateIncoming has completed. True for on server, false for on client. + /// + internal event Action OnIterateIncomingEnd; + /// + /// The current Transport being used. + /// + [Tooltip("The current Transport being used.")] + public Transport Transport; + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("Latency simulation settings.")] + [SerializeField] + private LatencySimulator _latencySimulator = new LatencySimulator(); + /// + /// Latency simulation settings. + /// + public LatencySimulator LatencySimulator + { + get + { + //Shouldn't ever be null unless the user nullifies it. + if (_latencySimulator == null) + _latencySimulator = new LatencySimulator(); + return _latencySimulator; + } + } + #endregion + + #region Private. + /// + /// NetworkConnections on the server which have to send data to clients. + /// + private List _dirtyToClients = new List(); + /// + /// PacketBundles to send to the server. + /// + private List _toServerBundles = new List(); + /// + /// NetworkManager handling this TransportManager. + /// + private NetworkManager _networkManager; + /// + /// Clients which are pending disconnects. + /// + private List _disconnectingClients = new List(); + #endregion + + #region Consts. + /// + /// Number of bytes sent for PacketId. + /// + public const byte PACKET_ID_BYTES = 2; + /// + /// Number of bytes sent for ObjectId. + /// + public const byte OBJECT_ID_BYTES = 2; + /// + /// Number of bytes sent for ComponentIndex. + /// + public const byte COMPONENT_INDEX_BYTES = 1; + /// + /// Number of bytes sent for Tick. + /// + public const byte TICK_BYTES = 4; + /// + /// Number of bytes sent to indicate split count. + /// + private const byte SPLIT_COUNT_BYTES = 4; + /// + /// Number of bytes required for split data. + /// + public const byte SPLIT_INDICATOR_SIZE = (PACKET_ID_BYTES + SPLIT_COUNT_BYTES); + /// + /// Number of channels supported. + /// + public const byte CHANNEL_COUNT = 2; + #endregion + + /// + /// Initializes this script for use. + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + _networkManager = manager; + /* If transport isn't specified then add default + * transport. */ + if (Transport == null && !gameObject.TryGetComponent(out Transport)) + Transport = gameObject.AddComponent(); + + Transport.Initialize(_networkManager, 0); + InitializeToServerBundles(); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + _latencySimulator.Initialize(manager, Transport); +#endif + } + + /// + /// Sets a connection from server to client dirty. + /// + /// + internal void ServerDirty(NetworkConnection conn) + { + _dirtyToClients.Add(conn); + } + + /// + /// Initializes ToServerBundles for use. + /// + private void InitializeToServerBundles() + { + /* For ease of use FishNet will always have + * only two channels, reliable and unreliable. + * Even if the transport only supports reliable + * also setup for unreliable. */ + for (byte i = 0; i < CHANNEL_COUNT; i++) + { + int mtu = Transport.GetMTU(i); + _toServerBundles.Add(new PacketBundle(_networkManager, mtu)); + } + } + + /// + /// Sends data to a client. + /// + /// Channel to send on. + /// Data to send. + /// Connection to send to. Use null for all clients. + /// True to split large packets which exceed MTU and send them in order on the reliable channel. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SendToClient(byte channelId, ArraySegment segment, NetworkConnection connection, bool splitLargeMessages = true) + { + if (connection == null) + return; + + //Split is needed. + if (splitLargeMessages && SplitRequired(channelId, segment.Count, out int requiredMessages, out int maxMessageSize)) + SendSplitData(connection, ref segment, requiredMessages, maxMessageSize); + //Split not needed. + else + connection.SendToClient(channelId, segment); + } + + /// + /// Sends data to observers. + /// + /// + /// + /// + /// True to split large packets which exceed MTU and send them in order on the reliable channel. + internal void SendToClients(byte channelId, ArraySegment segment, HashSet observers, bool splitLargeIntoReliable = true) + { + foreach (NetworkConnection conn in observers) + SendToClient(channelId, segment, conn, splitLargeIntoReliable); + } + + /// + /// Sends data to all clients if networkObject has no observers, otherwise sends to observers. + /// + /// Channel to send on. + /// Data to send. + /// NetworkObject being used to send data. + /// True to split large packets which exceed MTU and send them in order on the reliable channel. + internal void SendToClients(byte channelId, ArraySegment segment, NetworkObject networkObject, bool excludeOwner = false, bool splitLargeMessages = true) + { + if (!excludeOwner) + { + SendToClients(channelId, segment, networkObject.Observers, splitLargeMessages); + } + else + { + foreach (NetworkConnection conn in networkObject.Observers) + { + if (conn != networkObject.Owner) + SendToClient(channelId, segment, conn, splitLargeMessages); + } + } + } + + /// + /// Sends data to all clients. + /// + /// Channel to send on. + /// Data to send. + /// True to split large packets which exceed MTU and send them in order on the reliable channel. + internal void SendToClients(byte channelId, ArraySegment segment, bool splitLargeMessages = true) + { + /* To ensure proper order everything must be tossed into each + * NetworkConnection rather than batch send. This is because there + * is no way to know if batch send must iterate before or + * after connection sends. By sending to each connection order + * is maintained. */ + foreach (NetworkConnection conn in _networkManager.ServerManager.Clients.Values) + SendToClient(channelId, segment, conn, splitLargeMessages); + } + + + /// + /// Sends data to the server. + /// + /// Channel to send on. + /// Data to send. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SendToServer(byte channelId, ArraySegment segment, bool splitMessages = true) + { + if (channelId >= _toServerBundles.Count) + channelId = (byte)Channel.Reliable; + + //Split is needed. + if (splitMessages && SplitRequired(channelId, segment.Count, out int requiredMessages, out int maxMessageSize)) + { + //Client is not allowed to send data sizes beyond MTU. + //if (_networkManager.ServerManager.LimitClientMTU) //todo uncomment and finish + //{ + // if (_networkManager.CanLog(LoggingType.Error)) + // Debug.LogError($"Local client attempted to send a packet size of {segment.Count} which would exceed the MTU, and settings do not allow this. To allow clients to send packets beyond MTU add a ServerManager component to your NetworkManager uncheck LimitClientMTU."); + + // _networkManager.ClientManager.StopConnection(); + // return; + //} + //If here split can be sent. + SendSplitData(null, ref segment, requiredMessages, maxMessageSize); + } + //Split not needed. + else + { + _toServerBundles[channelId].Write(segment); + } + } + + #region Splitting. + /// + /// True if data must be split. + /// + /// + /// + /// + private bool SplitRequired(byte channelId, int segmentSize, out int requiredMessages, out int maxMessageSize) + { + maxMessageSize = Transport.GetMTU(channelId) - (TransportManager.TICK_BYTES + SPLIT_INDICATOR_SIZE); + requiredMessages = Mathf.CeilToInt((float)segmentSize / maxMessageSize); + + return (requiredMessages > 1); + } + + /// + /// Splits data going to which is too large to fit within the transport MTU. + /// + /// Connection to send to. If null data will be sent to the server. + /// True if data was sent split. + private void SendSplitData(NetworkConnection conn, ref ArraySegment segment, int requiredMessages, int maxMessageSize) + { + if (requiredMessages <= 1) + { + if (_networkManager.CanLog(LoggingType.Error)) + Debug.LogError($"SendSplitData was called with {requiredMessages} required messages. This method should only be called if messages must be split into 2 pieces or more."); + return; + } + + byte channelId = (byte)Channel.Reliable; + PooledWriter headerWriter = WriterPool.GetWriter(); + headerWriter.WritePacketId(PacketId.Split); + headerWriter.WriteInt32(requiredMessages); + ArraySegment headerSegment = headerWriter.GetArraySegment(); + + int writeIndex = 0; + bool firstWrite = true; + //Send to connection until everything is written. + while (writeIndex < segment.Count) + { + bool wasFirst = firstWrite; + int headerReduction = 0; + if (firstWrite) + { + headerReduction = headerSegment.Count; + firstWrite = false; + } + int chunkSize = Mathf.Min(segment.Count - writeIndex - headerReduction, maxMessageSize); + //Make a new array segment for the chunk that is getting split. + ArraySegment splitSegment = new ArraySegment( + segment.Array, segment.Offset + writeIndex, chunkSize); + + //If connection is specified then it's going to a client. + if (conn != null) + { + conn.SendToClient(channelId, headerSegment, true); + conn.SendToClient(channelId, splitSegment); + } + //Otherwise it's going to the server. + else + { + _toServerBundles[channelId].Write(headerSegment, true); + _toServerBundles[channelId].Write(splitSegment, false); + } + + writeIndex += chunkSize; + } + + headerWriter.Dispose(); + } + #endregion + + + + /// + /// Processes data received by the socket. + /// + /// True to process data received on the server. + internal void IterateIncoming(bool server) + { + OnIterateIncomingStart?.Invoke(server); + Transport.IterateIncoming(server); + OnIterateIncomingEnd?.Invoke(server); + } + + /// + /// Processes data to be sent by the socket. + /// + /// True to process data received on the server. + internal void IterateOutgoing(bool toServer) + { + OnIterateOutgoingStart?.Invoke(); + int channelCount = CHANNEL_COUNT; + ulong sentBytes = 0; + bool latencySimulatorEnabled = LatencySimulator.CanSimulate; + + /* If sending to the client. */ + if (!toServer) + { + TimeManager tm = _networkManager.TimeManager; + uint localTick = tm.LocalTick; + //Write any dirty syncTypes. + _networkManager.ServerManager.Objects.WriteDirtySyncTypes(); + + //Run through all dirty connections to send data to. + for (int z = 0; z < _dirtyToClients.Count; z++) + { + NetworkConnection conn = _dirtyToClients[z]; + if (conn == null || !conn.IsValid) + continue; + + //Get packets for every channel. + for (byte channel = 0; channel < channelCount; channel++) + { + if (conn.GetPacketBundle(channel, out PacketBundle pb)) + { + for (int i = 0; i < pb.WrittenBuffers; i++) + { + //Length should always be more than 0 but check to be safe. + if (pb.GetBuffer(i, out ByteBuffer bb)) + { + ArraySegment segment = new ArraySegment(bb.Data, 0, bb.Length); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (latencySimulatorEnabled) + _latencySimulator.AddOutgoing(channel, segment, false, conn.ClientId); + else +#endif + Transport.SendToClient(channel, segment, conn.ClientId); + sentBytes += (ulong)segment.Count; + } + } + + pb.Reset(); + } + } + + /* When marked as disconnecting data will still be sent + * this iteration but the connection will be marked as invalid. + * This will prevent future data from going out/coming in. + * Also the connection will be added to a disconnecting collection + * so it will it disconnected briefly later to allow data from + * this tick to send. */ + if (conn.Disconnecting) + { + uint requiredTicks = tm.TimeToTicks(0.1d, TickRounding.RoundUp); + /* Require 100ms or 2 ticks to pass + * before disconnecting to allow for the + * higher chance of success that remaining + * data is sent. */ + requiredTicks = Math.Max(requiredTicks, 2); + _disconnectingClients.Add(new DisconnectingClient(requiredTicks + localTick, conn)); + } + + conn.ResetServerDirty(); + } + + //Iterate disconnects. + for (int i = 0; i < _disconnectingClients.Count; i++) + { + DisconnectingClient dc = _disconnectingClients[i]; + if (localTick >= dc.Tick) + { + _networkManager.TransportManager.Transport.StopConnection(dc.Connection.ClientId, true); + _disconnectingClients.RemoveAt(i); + i--; + } + } + + _networkManager.StatisticsManager.NetworkTraffic.LocalServerSentData(sentBytes); + _dirtyToClients.Clear(); + } + /* If sending to the server. */ + else + { + for (byte channel = 0; channel < channelCount; channel++) + { + if (PacketBundle.GetPacketBundle(channel, _toServerBundles, out PacketBundle pb)) + { + for (int i = 0; i < pb.WrittenBuffers; i++) + { + if (pb.GetBuffer(i, out ByteBuffer bb)) + { + ArraySegment segment = new ArraySegment(bb.Data, 0, bb.Length); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (latencySimulatorEnabled) + _latencySimulator.AddOutgoing(channel, segment); + else +#endif + Transport.SendToServer(channel, segment); + sentBytes += (ulong)segment.Count; + } + } + pb.Reset(); + } + } + + _networkManager.StatisticsManager.NetworkTraffic.LocalClientSentData(sentBytes); + } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (latencySimulatorEnabled) + _latencySimulator.IterateOutgoing(toServer); +#endif + + Transport.IterateOutgoing(toServer); + OnIterateOutgoingEnd?.Invoke(); + } + + #region Editor. +#if UNITY_EDITOR + private void OnValidate() + { + if (Transport == null) + Transport = GetComponent(); + + /* Update enabled state to force a reset if needed. + * This may be required if the user checked the enabled + * tick box at runtime. If enabled value didn't change + * then the Get will be the same as the Set and nothing + * will happen. */ + _latencySimulator.SetEnabled(_latencySimulator.GetEnabled()); + } +#endif + #endregion + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs.meta new file mode 100644 index 0000000..b3b9a63 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34e4a322dca349547989b14021da4e23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Utility.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Utility.meta new file mode 100644 index 0000000..bb492a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3be43175b2896f44194e0f4ef13a9ac5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs b/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs new file mode 100644 index 0000000..66dffbd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs @@ -0,0 +1,67 @@ +using FishNet.Object; +using FishNet.Serializing; +using FishNet.Transporting; +using UnityEngine; + +namespace FishNet.Managing.Utility +{ + + public class Packets + { + /// + /// Returns written data length for packet. + /// + internal static int GetPacketLength(ushort packetId, PooledReader reader, Channel channel) + { + /* Broadcast is a special circumstance where data + * will not be purged even if unreliable. + * This is because a broadcast receiver may not + * be set, which could be intentional. Because of this + * length is always sent to skip + * past the broadcast data. + * + * Reliables also need length read in the instance a client + * sends data to an object which server is despawning. Without + * parsing length the remainer data from client will be corrupt. */ + PacketId pid = (PacketId)packetId; + if (channel == Channel.Reliable || + pid == PacketId.Broadcast || + pid == PacketId.SyncVar + ) + { + return reader.ReadInt32(); + } + //Unreliable purges remaining. + else if (channel == Channel.Unreliable) + { + return (int)MissingObjectPacketLength.PurgeRemaiming; + } + /* Unhandled. This shouldn't be possible + * since both reliable and unreliable is checked. + * There are no other options. This is merely here + * for a sanity check. */ + else + { + LogError($"Operation is unhandled for packetId {(PacketId)packetId} on channel {channel}."); + return (int)MissingObjectPacketLength.PurgeRemaiming; + } + + //Logs an error message. + void LogError(string message) + { + bool canLog; + if (reader.NetworkManager != null) + canLog = reader.NetworkManager.CanLog(Logging.LoggingType.Error); + else + canLog = NetworkManager.StaticCanLog(Logging.LoggingType.Error); + + if (canLog) + Debug.LogError(message); + } + + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs.meta b/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs.meta new file mode 100644 index 0000000..a2a301b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Managing/Utility/Utility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: facab6859c82ccd49b2d1c6b80404726 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object.meta b/UnityProject/Assets/FishNet/Runtime/Object.meta new file mode 100644 index 0000000..194abf7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcd52ca5352336e44acf3536245b6205 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs b/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs new file mode 100644 index 0000000..51ccb64 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs @@ -0,0 +1,134 @@ +using FishNet.Managing.Logging; +using FishNet.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Object +{ + + /// + /// ServerRpc methods will send messages to the server. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ServerRpcAttribute : Attribute + { + /// + /// True to only allow the owning client to call this RPC. + /// + public bool RequireOwnership = true; + /// + /// True to also run the RPC logic locally. + /// + public bool RunLocally = false; + } + + /// + /// ObserversRpc methods will send messages to all observers. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ObserversRpcAttribute : Attribute + { + /// + /// True to also send data to the owner of object. + /// + public bool IncludeOwner = true; + /// + /// True to buffer the last value and send it to new players when the object is spawned for them. + /// RPC will be sent on the same channel as the original RPC, and immediately before the OnSpawnServer override. + /// + public bool BufferLast = false; + /// + /// True to also run the RPC logic locally. + /// + public bool RunLocally = false; + } + + /// + /// TargetRpc methods will send messages to a single client. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class TargetRpcAttribute : Attribute + { + /// + /// True to also run the RPC logic locally. + /// + public bool RunLocally = false; + } + + /// + /// Prevents a method from running if server is not active. + /// Can only be used inside a NetworkBehaviour + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ServerAttribute : Attribute + { + /// + /// Type of logging to use when the IsServer check fails. + /// + public LoggingType Logging = LoggingType.Warning; + } + + /// + /// Prevents this method from running if client is not active. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ClientAttribute : Attribute + { + /// + /// Type of logging to use when the IsClient check fails. + /// + public LoggingType Logging = LoggingType.Warning; + /// + /// True to only allow a client to run the method if they are owner of the object. + /// + public bool RequireOwnership = false; + } +} + + +namespace FishNet.Object.Synchronizing +{ + + /// + /// Synchronizes collections or objects from the server to clients. Can be used with custom SyncObjects. + /// Value must be changed on server. + /// + [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] + public class SyncObjectAttribute : PropertyAttribute + { + /// + /// How often values may update over the network. + /// + public float SendRate = 0.1f; + /// + /// Clients which may receive value updates. + /// + public ReadPermission ReadPermissions = ReadPermission.Observers; + } + + /// + /// Synchronizes a variable from server to clients automatically. + /// Value must be changed on server. + /// + [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] + public class SyncVarAttribute : PropertyAttribute + { + /// + /// How often values may update over the network. + /// + public float SendRate = 0.1f; + /// + /// Clients which may receive value updates. + /// + public ReadPermission ReadPermissions = ReadPermission.Observers; + /// + /// Channel to use. Unreliable SyncVars will use eventual consistency. + /// + public Channel Channel; + /// + /// Method which will be called on the server and clients when the value changes. + /// + public string OnChange; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs.meta new file mode 100644 index 0000000..9bf2107 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Attributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2c79ec60813585469c43b4539e3d0c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs b/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs new file mode 100644 index 0000000..f1246f9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs @@ -0,0 +1,35 @@ +using FishNet.Documenting; + +namespace FishNet.Object +{ + /// + /// Properties which have changed on a transform. + /// + [System.Flags] + [APIExclude] + internal enum ChangedTransformProperties : byte + { + Unset = 0, + LocalPosition = 2, + LocalRotation = 4, + LocalScale = 8 + } + + [APIExclude] + internal static partial class Enums + { + /// + /// Returns if whole contains part. + /// + /// + /// + /// + public static bool TransformPropertiesContains(ChangedTransformProperties whole, ChangedTransformProperties part) + { + return (whole & part) == part; + } + } + + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs.meta new file mode 100644 index 0000000..3357abe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1870202c019b99348aaedbe2029caf33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs b/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs new file mode 100644 index 0000000..62e903a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs @@ -0,0 +1,13 @@ +using FishNet.Connection; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] +namespace FishNet.Object.Delegating +{ + public delegate void ServerRpcDelegate(NetworkBehaviour obj, PooledReader reader, Channel channel, NetworkConnection sender); + public delegate void ClientRpcDelegate(NetworkBehaviour obj, PooledReader reader, Channel channel); + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs.meta new file mode 100644 index 0000000..67c5bde --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Delegates.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5dbd9cdda4843f34ab416273d80f83c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs b/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs new file mode 100644 index 0000000..19aed6a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs @@ -0,0 +1,13 @@ + +namespace FishNet.Object +{ + /// + /// This may be added at runtime to find objects without any network scripts, beneath a NetworkObject. + /// + public class EmptyNetworkBehaviour : NetworkBehaviour + { + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs.meta new file mode 100644 index 0000000..4c947e7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/EmptyNetworkBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a6a39c46bf52104ba8efe3100bce3f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping.meta b/UnityProject/Assets/FishNet/Runtime/Object/Helping.meta new file mode 100644 index 0000000..b4e5fab --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0684bc52d23dfb743a5d2fab1278d8f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs b/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs new file mode 100644 index 0000000..1f06b4e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs @@ -0,0 +1,153 @@ +namespace FishNet.Object.Helping +{ + + public static class Hashing + { + + private const uint FNV_offset_basis32 = 2166136261; + private const uint FNV_prime32 = 16777619; + private const ulong FNV_offset_basis64 = 14695981039346656037; + private const ulong FNV_prime64 = 1099511628211; + + + /// + /// non cryptographic stable hash code, + /// it will always return the same hash for the same + /// string. + /// + /// This is simply an implementation of FNV-1 32 bit xor folded to 16 bit + /// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + /// + /// The stable hash32. + /// Text. + internal static ushort GetStableHash16(this string txt) + { + uint hash32 = txt.GetStableHash32(); + + return (ushort)((hash32 >> 16) ^ hash32); + } + + + /// + /// non cryptographic stable hash code, + /// it will always return the same hash for the same + /// string. + /// + /// This is simply an implementation of FNV-1 32 bit + /// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + /// + /// The stable hash32. + /// Text. + public static uint GetStableHash32(this string txt) + { + unchecked + { + uint hash = FNV_offset_basis32; + for (int i = 0; i < txt.Length; i++) + { + uint ch = txt[i]; + hash = hash * FNV_prime32; + hash = hash ^ ch; + } + return hash; + } + } + + /// + /// non cryptographic stable hash code, + /// it will always return the same hash for the same + /// string. + /// + /// This is simply an implementation of FNV-1 64 bit + /// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + /// + /// The stable hash32. + /// Text. + internal static ulong GetStableHash64(this string txt) + { + unchecked + { + ulong hash = FNV_offset_basis64; + for (int i = 0; i < txt.Length; i++) + { + ulong ch = txt[i]; + hash = hash * FNV_prime64; + hash = hash ^ ch; + } + return hash; + } + } + + ///// + ///// non cryptographic stable hash code, + ///// it will always return the same hash for the same + ///// string. + ///// + ///// This is simply an implementation of FNV-1 32 bit xor folded to 16 bit + ///// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + ///// + ///// The stable hash32. + ///// Text. + //internal static ushort GetStableHash16(this byte[] bytes) + //{ + // uint hash32 = bytes.GetStableHash32(); + + // return (ushort)((hash32 >> 16) ^ hash32); + //} + + ///// + ///// non cryptographic stable hash code, + ///// it will always return the same hash for the same + ///// string. + ///// + ///// This is simply an implementation of FNV-1 32 bit + ///// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + ///// + ///// The stable hash32. + ///// Text. + //internal static uint GetStableHash32(this byte[] bytes) + //{ + // unchecked + // { + // uint hash = FNV_offset_basis32; + // for (int i = 0; i < bytes.Length; i++) + // { + // uint bt = bytes[i]; + // hash = hash * FNV_prime32; + // hash = hash ^ bt; + // } + // return hash; + // } + //} + + ///// + ///// non cryptographic stable hash code, + ///// it will always return the same hash for the same + ///// string. + ///// + ///// This is simply an implementation of FNV-1 64 bit + ///// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + ///// + ///// The stable hash32. + ///// Text. + //internal static ulong GetStableHash64(this byte[] bytes) + //{ + // unchecked + // { + // ulong hash = FNV_offset_basis64; + // for (int i = 0; i < bytes.Length; i++) + // { + // ulong bt = bytes[i]; + // hash = hash * FNV_prime64; + // hash = hash ^ bt; + // } + // return hash; + // } + //} + + + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs.meta new file mode 100644 index 0000000..327d971 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/Hashing.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c55dc5a22646764aa5dbfab2062669e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs new file mode 100644 index 0000000..53c2aea --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs @@ -0,0 +1,39 @@ +using FishNet.Object.Helping; + +namespace FishNet.Object +{ + + #region Types. + /// + /// Lookup data for a RPC Link. + /// + internal struct RpcLink + { + /// + /// ObjectId for link. + /// + public int ObjectId; + /// + /// NetworkBehaviour component index on ObjectId. + /// + public byte ComponentIndex; + /// + /// RpcHash for link. + /// + public uint RpcHash; + /// + /// Type of Rpc link is for. + /// + public RpcType RpcType; + + public RpcLink(int objectId, byte componentIndex, uint rpcHash, RpcType rpcType) + { + ObjectId = objectId; + ComponentIndex = componentIndex; + RpcHash = rpcHash; + RpcType = rpcType; + } + } + #endregion + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs.meta new file mode 100644 index 0000000..b76b723 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcLink.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05a91745dd829d043aadf391ac7b233e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs new file mode 100644 index 0000000..5bf072a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs @@ -0,0 +1,13 @@ +namespace FishNet.Object.Helping +{ + public enum RpcType : int + { + None = 0, + Server = 1, + Observers = 2, + Target = 4, + Replicate = 8, + Reconcile = 16 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs.meta new file mode 100644 index 0000000..7cb63bd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/RpcType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09f9e7236f988c64fad54645f4cc7f8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs b/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs new file mode 100644 index 0000000..32e781f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs @@ -0,0 +1,49 @@ + +namespace FishNet.Object.Helping +{ + + public static class CodegenHelper + { + /// + /// Returns if a NetworkObject is deinitializing. + /// + /// + /// + public static bool NetworkObject_Deinitializing(NetworkBehaviour nb) + { + if (nb == null) + return true; + + return nb.IsDeinitializing; + } + + /// + /// Returns if running as server. + /// + /// + /// + public static bool IsServer(NetworkBehaviour nb) + { + if (nb == null) + return false; + + return nb.IsServer; + } + + /// + /// Returns if running as client. + /// + /// + /// + public static bool IsClient(NetworkBehaviour nb) + { + if (nb == null) + return false; + + return nb.IsClient; + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs.meta new file mode 100644 index 0000000..70bef6e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Helping/StaticShortcuts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 149cde0042627604d810c2c7fc0f9176 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs new file mode 100644 index 0000000..bdc29c4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs @@ -0,0 +1,184 @@ +#if UNITY_2020_3_OR_NEWER +using FishNet.CodeAnalysis.Annotations; +#endif +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Object.Synchronizing.Internal; +using UnityEngine; + +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + #region Public. + /// + /// True if OnStartServer has been called. + /// + [APIExclude] + public bool OnStartServerCalled { get; private set; } + /// + /// True if OnStartClient has been called. + /// + [APIExclude] + public bool OnStartClientCalled { get; private set; } + #endregion + + #region Private. + /// + /// True if OnStartNetwork has been called. + /// + private bool _onStartNetworkCalled; + /// + /// True if OnStopNetwork has been called. + /// + private bool _onStopNetworkCalled; + #endregion + + /// + /// Invokes cached callbacks on SyncTypes which were held until OnStartXXXXX was called. + /// + /// + internal void InvokeSyncTypeCallbacks(bool asServer) + { + foreach (SyncBase item in _syncVars.Values) + item.OnStartCallback(asServer); + foreach (SyncBase item in _syncObjects.Values) + item.OnStartCallback(asServer); + } + /// + /// Invokes the OnStart/StopNetwork. + /// + /// + internal void InvokeOnNetwork(bool start) + { + if (start) + { + if (_onStartNetworkCalled) + return; + OnStartNetwork(); + } + else + { + if (_onStopNetworkCalled) + return; + OnStopNetwork(); + } + } + + /// + /// Called when the network has initialized this object. May be called for server or client but will only be called once. + /// When as host or server this method will run before OnStartServer. + /// When as client only the method will run before OnStartClient. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStartNetwork() + { + _onStartNetworkCalled = true; + _onStopNetworkCalled = false; + } + /// + /// Called when the network is deinitializing this object. May be called for server or client but will only be called once. + /// When as host or server this method will run after OnStopServer. + /// When as client only this method will run after OnStopClient. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStopNetwork() + { + _onStopNetworkCalled = true; + _onStartNetworkCalled = false; + } + + /// + /// Called on the server after initializing this object. + /// SyncTypes modified before or during this method will be sent to clients in the spawn message. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStartServer() + { + OnStartServerCalled = true; + } + /// + /// Called on the server before deinitializing this object. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStopServer() + { + OnStartServerCalled = false; + ReturnRpcLinks(); + } + /// + /// Called on the server after ownership has changed. + /// + /// Previous owner of this object. +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnOwnershipServer(NetworkConnection prevOwner) + { + //When switching ownership always clear replicate cache on server. + InternalClearReplicateCache(true); + } + /// + /// Called on the server after a spawn message for this object has been sent to clients. + /// Useful for sending remote calls or data to clients. + /// + /// Connection the object is being spawned for. +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnSpawnServer(NetworkConnection connection) { } + /// + /// Called on the server before a despawn message for this object has been sent to connection. + /// Useful for sending remote calls or actions to clients. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnDespawnServer(NetworkConnection connection) { } + /// + /// Called on the client after initializing this object. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStartClient() + { + OnStartClientCalled = true; + } + /// + /// Called on the client before deinitializing this object. + /// +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnStopClient() + { + OnStartClientCalled = false; + } + /// + /// Called on the client after gaining or losing ownership. + /// + /// Previous owner of this object. +#if UNITY_2020_3_OR_NEWER + [OverrideMustCallBase(BaseCallMustBeFirstStatement = true)] +#endif + public virtual void OnOwnershipClient(NetworkConnection prevOwner) + { + //If losing or gaining ownership then clear replicate cache. + if (IsOwner || prevOwner == LocalConnection) + InternalClearReplicateCache(false); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs.meta new file mode 100644 index 0000000..f5aabb3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Callbacks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9ddaf08801752b49bcfe720217df74a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs new file mode 100644 index 0000000..496e8ac --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs @@ -0,0 +1,22 @@ +using FishNet.Managing.Logging; +using UnityEngine; + +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + + /// + /// True if can log for loggingType. + /// + /// Type of logging being filtered. + /// + public bool CanLog(LoggingType loggingType) + { + return (NetworkManager == null) ? false : NetworkManager.CanLog(loggingType); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs.meta new file mode 100644 index 0000000..e446436 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Logging.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad4dd2795a9a00e4d814892ac1a67157 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs new file mode 100644 index 0000000..d627109 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs @@ -0,0 +1,277 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object.Prediction.Delegating; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Constant; +using FishNet.Utility.Extension; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + #region Public. + /// + /// + /// + private uint _lastReconcileTick; + /// + /// Gets the last tick this NetworkBehaviour reconciled with. + /// + public uint GetLastReconcileTick() => _lastReconcileTick; + /// + /// Sets the last tick this NetworkBehaviour reconciled with. + /// + [CodegenMakePublic] //Internal only. + protected internal void SetLastReconcileTick(uint value) + { + _lastReconcileTick = value; + } + /// + /// True if this object is reconciling. + /// + public bool IsReconciling { get; internal set; } + #endregion + + #region Private. + /// + /// Registered Replicate methods. + /// + private readonly Dictionary _replicateRpcDelegates = new Dictionary(); + /// + /// Registered Reconcile methods. + /// + private readonly Dictionary _reconcileRpcDelegates = new Dictionary(); + /// + /// True if initialized compnents for prediction. + /// + private bool _predictionInitialized; + /// + /// Rigidbody found on this object. This is used for prediction. + /// + private Rigidbody _predictionRigidbody; + /// + /// Rigidbody2D found on this object. This is used for prediction. + /// + private Rigidbody2D _predictionRigidbody2d; + /// + /// Last position for TransformMayChange. + /// + private Vector3 _lastMayChangePosition; + /// + /// Last rotation for TransformMayChange. + /// + private Quaternion _lastMayChangeRotation; + /// + /// Last scale for TransformMayChange. + /// + private Vector3 _lastMayChangeScale; + #endregion + + /// + /// Registers a RPC method. + /// Internal use. + /// + /// + /// + [APIExclude] //codegen this can be made protected internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal void RegisterReplicateRpc(uint hash, ReplicateRpcDelegate del) + { + _replicateRpcDelegates[hash] = del; + } + /// + /// Registers a RPC method. + /// Internal use. + /// + /// + /// + [APIExclude] //codegen this can be made protected internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal void RegisterReconcileRpc(uint hash, ReconcileRpcDelegate del) + { + _reconcileRpcDelegates[hash] = del; + } + + + /// + /// Called when a replicate is received. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnReplicateRpc(uint? methodHash, PooledReader reader, NetworkConnection sendingClient, Channel channel) + { + if (methodHash == null) + methodHash = ReadRpcHash(reader); + + if (sendingClient == null) + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"NetworkConnection is null. Replicate {methodHash.Value} on {gameObject.name}, behaviour {GetType().Name} will not complete. Remainder of packet may become corrupt."); + return; + } + + if (_replicateRpcDelegates.TryGetValueIL2CPP(methodHash.Value, out ReplicateRpcDelegate del)) + { + del.Invoke(this, reader, sendingClient); + } + else + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Replicate not found for hash {methodHash.Value} on {gameObject.name}, behaviour {GetType().Name}. Remainder of packet may become corrupt."); + } + } + + + /// + /// Called when a reconcile is received. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnReconcileRpc(uint? methodHash, PooledReader reader, Channel channel) + { + if (methodHash == null) + methodHash = ReadRpcHash(reader); + + if (_reconcileRpcDelegates.TryGetValueIL2CPP(methodHash.Value, out ReconcileRpcDelegate del)) + { + del.Invoke(this, reader); + } + else + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Reconcile not found for hash {methodHash.Value}. Remainder of packet may become corrupt."); + } + } + + /// + /// Clears cached replicates. This can be useful to call on server and client after teleporting. + /// + /// True to reset values for server, false to reset values for client. + public void ClearReplicateCache(bool asServer) { InternalClearReplicateCache(asServer); } + /// + /// Clears cached replicates. + /// For internal use only. + /// + /// + [APIExclude] + protected internal virtual void InternalClearReplicateCache(bool asServer) { } + + /// + /// Writes number of past inputs from buffer to writer and sends it to the server. + /// Internal use. + /// //codegen can be made internal, then public via codegen + [APIExclude] + public void SendReplicateRpc(uint hash, List replicateBuffer, int count) + { + if (!IsSpawnedWithWarning()) + return; + + int lastBufferIndex = (replicateBuffer.Count - 1); + //Nothing to send; should never be possible. + if (lastBufferIndex < 0) + return; + /* Where to start writing from. When passed + * into the writer values from this offset + * and forward will be written. */ + int offset = replicateBuffer.Count - count; + if (offset < 0) + offset = 0; + + Channel channel = Channel.Unreliable; + //Write history to methodWriter. + PooledWriter methodWriter = WriterPool.GetWriter(); + methodWriter.WriteList(replicateBuffer, offset); + + PooledWriter writer; + //if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) + //writer = CreateLinkedRpc(link, methodWriter, Channel.Unreliable); + //else //todo add support for -> server rpc links. + writer = CreateRpc(hash, methodWriter, PacketId.Replicate, channel); + NetworkManager.TransportManager.SendToServer((byte)channel, writer.GetArraySegment(), false); + + methodWriter.Dispose(); + writer.Dispose(); + } + + /// + /// Sends a RPC to target. + /// Internal use. + /// + [APIExclude] //codegen this can be made internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendReconcileRpc(uint hash, T reconcileData, Channel channel) + { + if (!IsSpawned) + return; + if (!Owner.IsActive) + return; + + PooledWriter methodWriter = WriterPool.GetWriter(); + methodWriter.Write(reconcileData); + + PooledWriter writer; +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (NetworkManager.DebugManager.ReconcileRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#else + if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#endif + writer = CreateLinkedRpc(link, methodWriter, channel); + else + writer = CreateRpc(hash, methodWriter, PacketId.Reconcile, channel); + + _networkObjectCache.NetworkManager.TransportManager.SendToClient((byte)channel, writer.GetArraySegment(), Owner); + + methodWriter.Dispose(); + writer.Dispose(); + } + + /// + /// Returns if there is a chance the transform may change after the tick. + /// + /// + protected internal bool TransformMayChange() + { + 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; + + 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; + } + + return changed; + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs.meta new file mode 100644 index 0000000..1d59a32 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 074dac4dd3f9f6a4d8c1eb1191334472 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs new file mode 100644 index 0000000..98a2b38 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs @@ -0,0 +1,183 @@ +#if UNITY_2020_3_OR_NEWER +using FishNet.CodeAnalysis.Annotations; +#endif +using FishNet.Component.ColliderRollback; +using FishNet.Connection; +using FishNet.Managing; +using FishNet.Managing.Client; +using FishNet.Managing.Logging; +using FishNet.Managing.Observing; +using FishNet.Managing.Scened; +using FishNet.Managing.Server; +using FishNet.Managing.Timing; +using FishNet.Managing.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + /// + /// True if the NetworkObject for this NetworkBehaviour is deinitializing. + /// + public bool IsDeinitializing => _networkObjectCache.IsDeinitializing; + [Obsolete("Use IsDeinitializing instead.")] + public bool Deinitializing => IsDeinitializing; //Remove on 2023/01/01. + /// + /// NetworkManager for this object. + /// + public NetworkManager NetworkManager => _networkObjectCache.NetworkManager; + /// + /// ServerManager for this object. + /// + public ServerManager ServerManager => _networkObjectCache.ServerManager; + /// + /// ClientManager for this object. + /// + public ClientManager ClientManager => _networkObjectCache.ClientManager; + /// + /// ObserverManager for this object. + /// + public ObserverManager ObserverManager => _networkObjectCache.ObserverManager; + /// + /// TransportManager for this object. + /// + public TransportManager TransportManager => _networkObjectCache.TransportManager; + /// + /// TimeManager for this object. + /// + public TimeManager TimeManager => _networkObjectCache.TimeManager; + /// + /// SceneManager for this object. + /// + public SceneManager SceneManager => _networkObjectCache.SceneManager; + /// + /// RollbackManager for this object. + /// + public RollbackManager RollbackManager => _networkObjectCache.RollbackManager; + /// + /// True if the client is active and authenticated. + /// + public bool IsClient => _networkObjectCache.IsClient; + /// + /// True if only the client is active and authenticated. + /// + public bool IsClientOnly => _networkObjectCache.IsClientOnly; + /// + /// True if server is active. + /// + public bool IsServer => _networkObjectCache.IsServer; + /// + /// True if only the server is active. + /// + public bool IsServerOnly => _networkObjectCache.IsServerOnly; + /// + /// True if client and server are active. + /// + public bool IsHost => _networkObjectCache.IsHost; + /// + /// True if client nor server are active. + /// + public bool IsOffline => _networkObjectCache.IsOffline; + /// + /// True if the local client is the owner of this object. + /// +#if UNITY_2020_3_OR_NEWER + [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "OnStartServer")] + [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Awake")] + [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Start")] +#endif + public bool IsOwner => _networkObjectCache.IsOwner; + /// + /// Owner of this object. + /// + public NetworkConnection Owner + { + get + { + //Ensures a null Owner is never returned. + if (_networkObjectCache == null) + return FishNet.Managing.NetworkManager.EmptyConnection; + + return _networkObjectCache.Owner; + } + } + /// + /// ClientId for this NetworkObject owner. + /// + public int OwnerId => _networkObjectCache.OwnerId; + /// + /// Unique Id for this _networkObjectCache. This does not represent the object owner. + /// + public int ObjectId => _networkObjectCache.ObjectId; + /// + /// The local connection of the client calling this method. + /// + public NetworkConnection LocalConnection => _networkObjectCache.LocalConnection; + /// + /// Returns if a connection is the owner of this object. + /// Internal use. + /// + /// + /// + public bool CompareOwner(NetworkConnection connection) + { + return (_networkObjectCache.Owner == connection); + } + /// + /// Despawns this _networkObjectCache. Can only be called on the server. + /// + /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. + public void Despawn(bool? disableOnDespawnOverride = null) + { + if (!IsNetworkObjectNull(true)) + _networkObjectCache.Despawn(disableOnDespawnOverride); + } + /// + /// Spawns an object over the network. Can only be called on the server. + /// + /// GameObject instance to spawn. + /// Connection to give ownership to. + public void Spawn(GameObject go, NetworkConnection ownerConnection = null) + { + if (IsNetworkObjectNull(true)) + return; + _networkObjectCache.Spawn(go, ownerConnection); + } + /// + /// Returns if NetworkObject is null. + /// + /// True to throw a warning if null. + /// + private bool IsNetworkObjectNull(bool warn) + { + bool isNull = (_networkObjectCache == null); + if (isNull && warn) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObject is null. This can occur if this object is not spawned, or initialized yet."); + } + + return isNull; + } + /// + /// Removes ownership from all clients. + /// + public void RemoveOwnership() + { + _networkObjectCache.GiveOwnership(null, true); + } + /// + /// Gives ownership to newOwner. + /// + /// + public void GiveOwnership(NetworkConnection newOwner) + { + _networkObjectCache.GiveOwnership(newOwner, true); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs.meta new file mode 100644 index 0000000..79aaf06 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7aef532208d06c4880973c51b1906f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs new file mode 100644 index 0000000..4e46275 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs @@ -0,0 +1,128 @@ +using FishNet.Managing.Server; +using FishNet.Object.Helping; +using FishNet.Serializing; +using FishNet.Transporting; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + #region Private. + /// + /// Link indexes for RPCs. + /// + private Dictionary _rpcLinks = new Dictionary(); + #endregion + + /// + /// Initializes RpcLinks. This will only call once even as host. + /// + private void InitializeOnceRpcLinks() + { + if (NetworkManager.IsServer) + { + /* Link only data from server to clients. While it is + * just as easy to link client to server it's usually + * not needed because server out data is more valuable + * than server in data. */ + /* Links will be stored in the NetworkBehaviour so that + * when the object is destroyed they can be added back + * into availableRpcLinks, within the ServerManager. */ + + ServerManager serverManager = NetworkManager.ServerManager; + //ObserverRpcs. + foreach (uint rpcHash in _observersRpcDelegates.Keys) + { + if (!MakeLink(rpcHash, RpcType.Observers)) + return; + } + //TargetRpcs. + foreach (uint rpcHash in _targetRpcDelegates.Keys) + { + if (!MakeLink(rpcHash, RpcType.Target)) + return; + } + //ReconcileRpcs. + foreach (uint rpcHash in _reconcileRpcDelegates.Keys) + { + if (!MakeLink(rpcHash, RpcType.Reconcile)) + return; + } + + /* Tries to make a link and returns if + * successful. When a link cannot be made the method + * should exit as no other links will be possible. */ + bool MakeLink(uint rpcHash, RpcType rpcType) + { + if (serverManager.GetRpcLink(out ushort linkIndex)) + { + _rpcLinks[rpcHash] = new RpcLinkType(linkIndex, rpcType); + return true; + } + else + { + return false; + } + } + } + } + + + /// + /// Creates a PooledWriter and writes the header for a rpc. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private PooledWriter CreateLinkedRpc(RpcLinkType link, PooledWriter methodWriter, Channel channel) + { + PooledWriter writer = WriterPool.GetWriter(); + writer.WriteUInt16(link.LinkIndex); + //Write length only if reliable. + if (channel == Channel.Reliable) + writer.WriteLength(methodWriter.Length); + //Data. + writer.WriteArraySegment(methodWriter.GetArraySegment()); + + return writer; + } + + /// + /// Returns RpcLinks the ServerManager. + /// + private void ReturnRpcLinks() + { + if (_rpcLinks.Count == 0) + return; + + ServerManager?.ReturnRpcLinks(_rpcLinks); + _rpcLinks.Clear(); + } + + /// + /// Writes rpcLinks to writer. + /// + internal void WriteRpcLinks(PooledWriter writer) + { + PooledWriter rpcLinkWriter = WriterPool.GetWriter(); + foreach (KeyValuePair item in _rpcLinks) + { + //RpcLink index. + rpcLinkWriter.WriteUInt16(item.Value.LinkIndex); + //Hash. + rpcLinkWriter.WriteUInt16((ushort)item.Key); + //True/false if observersRpc. + rpcLinkWriter.WriteByte((byte)item.Value.RpcType); + } + + writer.WriteBytesAndSize(rpcLinkWriter.GetBuffer(), 0, rpcLinkWriter.Length); + rpcLinkWriter.Dispose(); + } + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs.meta new file mode 100644 index 0000000..3f93ed0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCLinks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7136e9ee3f7eee44abab09285ab7b939 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs new file mode 100644 index 0000000..1ad18bf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs @@ -0,0 +1,426 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Object.Delegating; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object +{ + + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + #region Private. + /// + /// Registered ServerRpc methods. + /// + private readonly Dictionary _serverRpcDelegates = new Dictionary(); + /// + /// Registered ObserversRpc methods. + /// + private readonly Dictionary _observersRpcDelegates = new Dictionary(); + /// + /// Registered TargetRpc methods. + /// + private readonly Dictionary _targetRpcDelegates = new Dictionary(); + /// + /// Number of total RPC methods for scripts in the same inheritance tree for this instance. + /// + private uint _rpcMethodCount; + /// + /// Size of every rpcHash for this networkBehaviour. + /// + private byte _rpcHashSize = 1; + /// + /// RPCs buffered for new clients. + /// + private Dictionary _bufferedRpcs = new Dictionary(); + #endregion + + /// + /// Called when buffered RPCs should be sent. + /// + internal void SendBufferedRpcs(NetworkConnection conn) + { + TransportManager tm = _networkObjectCache.NetworkManager.TransportManager; + foreach ((PooledWriter writer, Channel ch) in _bufferedRpcs.Values) + tm.SendToClient((byte)ch, writer.GetArraySegment(), conn); + } + + /// + /// Registers a RPC method. + /// Internal use. + /// + /// + /// + [APIExclude] //codegen this can be made protected internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal void RegisterServerRpc(uint hash, ServerRpcDelegate del) + { + bool contains = _serverRpcDelegates.ContainsKey(hash); + _serverRpcDelegates[hash] = del; + if (!contains) + IncreaseRpcMethodCount(); + } + /// + /// Registers a RPC method. + /// Internal use. + /// + /// + /// + [APIExclude] //codegen this can be made protected internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal void RegisterObserversRpc(uint hash, ClientRpcDelegate del) + { + bool contains = _observersRpcDelegates.ContainsKey(hash); + _observersRpcDelegates[hash] = del; + if (!contains) + IncreaseRpcMethodCount(); + } + /// + /// Registers a RPC method. + /// Internal use. + /// + /// + /// + [APIExclude] //codegen this can be made protected internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal void RegisterTargetRpc(uint hash, ClientRpcDelegate del) + { + bool contains = _targetRpcDelegates.ContainsKey(hash); + _targetRpcDelegates[hash] = del; + if (!contains) + IncreaseRpcMethodCount(); + } + + /// + /// Increases rpcMethodCount and rpcHashSize. + /// + private void IncreaseRpcMethodCount() + { + _rpcMethodCount++; + if (_rpcMethodCount <= byte.MaxValue) + _rpcHashSize = 1; + else + _rpcHashSize = 2; + } + + /// + /// Clears all buffered RPCs for this NetworkBehaviour. + /// + public void ClearBuffedRpcs() + { + foreach ((PooledWriter writer, Channel _) in _bufferedRpcs.Values) + writer.Dispose(); + _bufferedRpcs.Clear(); + } + + /// + /// Reads a RPC hash. + /// + /// + /// + private uint ReadRpcHash(PooledReader reader) + { + if (_rpcHashSize == 1) + return reader.ReadByte(); + else + return reader.ReadUInt16(); + } + /// + /// Called when a ServerRpc is received. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnServerRpc(PooledReader reader, NetworkConnection sendingClient, Channel channel) + { + uint methodHash = ReadRpcHash(reader); + + if (sendingClient == null) + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"NetworkConnection is null. ServerRpc {methodHash} on object {gameObject.name} [id {ObjectId}] will not complete. Remainder of packet may become corrupt."); + return; + } + + if (_serverRpcDelegates.TryGetValueIL2CPP(methodHash, out ServerRpcDelegate data)) + { + data.Invoke(this, reader, channel, sendingClient); + } + else + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"ServerRpc not found for hash {methodHash} on object {gameObject.name} [id {ObjectId}]. Remainder of packet may become corrupt."); + } + } + + /// + /// Called when an ObserversRpc is received. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnObserversRpc(uint? methodHash, PooledReader reader, Channel channel) + { + if (methodHash == null) + methodHash = ReadRpcHash(reader); + + if (_observersRpcDelegates.TryGetValueIL2CPP(methodHash.Value, out ClientRpcDelegate del)) + { + del.Invoke(this, reader, channel); + } + else + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"ObserversRpc not found for hash {methodHash.Value} on object {gameObject.name} [id {ObjectId}] . Remainder of packet may become corrupt."); + } + } + + /// + /// Called when an TargetRpc is received. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnTargetRpc(uint? methodHash, PooledReader reader, Channel channel) + { + if (methodHash == null) + methodHash = ReadRpcHash(reader); + + if (_targetRpcDelegates.TryGetValueIL2CPP(methodHash.Value, out ClientRpcDelegate del)) + { + del.Invoke(this, reader, channel); + } + else + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"TargetRpc not found for hash {methodHash.Value} on object {gameObject.name} [id {ObjectId}] . Remainder of packet may become corrupt."); + } + } + + /// + /// Sends a RPC to server. + /// Internal use. + /// + /// + /// + /// + [APIExclude] //codegen this can be made internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendServerRpc(uint hash, PooledWriter methodWriter, Channel channel) + { + if (!IsSpawnedWithWarning()) + return; + + PooledWriter writer = CreateRpc(hash, methodWriter, PacketId.ServerRpc, channel); + _networkObjectCache.NetworkManager.TransportManager.SendToServer((byte)channel, writer.GetArraySegment()); + writer.Dispose(); + } + +// /// +// /// Sends a RPC to observers. +// /// Internal use. +// /// +// /// +// /// +// /// +// [APIExclude] //codegen this can be made internal then set public via codegen +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// protected internal bool InternalPrepareObserversRpc(uint hash, PooledWriter writer, Channel channel, bool buffered) +// { +// if (!IsSpawnedWithWarning()) +// return false; + +//#if UNITY_EDITOR || DEVELOPMENT_BUILD +// if (NetworkManager.DebugManager.ObserverRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +//#else +// if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +//#endif +// CreateLinkedRpcHeader(link, writer); +// else +// CreateRpcHeader(hash, writer, PacketId.ObserversRpc); + +// _networkObjectCache.NetworkManager.TransportManager.SendToClients((byte)channel, writer.GetArraySegment(), _networkObjectCache.Observers); + +// InternalBufferObserversRpc(hash, writer, channel); + +// return true; +// } + +// /// +// /// Buffers an ObserverRPC. +// /// +// protected internal void InternalBufferObserversRpc(uint hash, PooledWriter writer, Channel channel) +// { +// /* If buffered then dispose of any already buffered +// * writers and replace with new one. Writers should +// * automatically dispose when references are lost +// * anyway but better safe than sorry. */ +// if (_bufferedRpcs.TryGetValueIL2CPP(hash, out (PooledWriter pw, Channel ch) result)) +// result.pw.Dispose(); +// _bufferedRpcs[hash] = (writer, channel); +// } + + /// + /// Sends a RPC to observers. + /// Internal use. + /// + /// + /// + /// + [APIExclude] //codegen this can be made internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendObserversRpc(uint hash, PooledWriter methodWriter, Channel channel, bool buffered) + { + if (!IsSpawnedWithWarning()) + return; + + PooledWriter writer; +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (NetworkManager.DebugManager.ObserverRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#else + if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#endif + writer = CreateLinkedRpc(link, methodWriter, channel); + else + writer = CreateRpc(hash, methodWriter, PacketId.ObserversRpc, channel); + + _networkObjectCache.NetworkManager.TransportManager.SendToClients((byte)channel, writer.GetArraySegment(), _networkObjectCache.Observers); + /* If buffered then dispose of any already buffered + * writers and replace with new one. Writers should + * automatically dispose when references are lost + * anyway but better safe than sorry. */ + if (buffered) + { + if (_bufferedRpcs.TryGetValueIL2CPP(hash, out (PooledWriter pw, Channel ch) result)) + result.pw.Dispose(); + _bufferedRpcs[hash] = (writer, channel); + } + //If not buffered then dispose immediately. + else + { + writer.Dispose(); + } + } + + /// + /// Sends a RPC to target. + /// Internal use. + /// + /// + /// + /// + /// + [APIExclude] //codegen this can be made internal then set public via codegen + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendTargetRpc(uint hash, PooledWriter methodWriter, Channel channel, NetworkConnection target) + { + if (!IsSpawnedWithWarning()) + return; + + /* These checks could be codegened in to save a very very small amount of performance + * by performing them before the serializer is written, but the odds of these failing + * are very low and I'd rather keep the complexity out of codegen. */ + if (target == null) + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Action cannot be completed as no Target is specified."); + return; + } + else + { + /* If not using observers, sending to owner, + * or observers contains target. */ + //bool canSendTotarget = (!_networkObjectCache.UsingObservers || + // _networkObjectCache.OwnerId == target.ClientId || + // _networkObjectCache.Observers.Contains(target)); + bool canSendTotarget = _networkObjectCache.OwnerId == target.ClientId || _networkObjectCache.Observers.Contains(target); + + if (!canSendTotarget) + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Action cannot be completed as Target is not an observer for object {gameObject.name} [id {ObjectId}]."); + return; + } + } + + PooledWriter writer; + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (NetworkManager.DebugManager.TargetRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#else + if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) +#endif + writer = CreateLinkedRpc(link, methodWriter, channel); + else + writer = CreateRpc(hash, methodWriter, PacketId.TargetRpc, channel); + + _networkObjectCache.NetworkManager.TransportManager.SendToClient((byte)channel, writer.GetArraySegment(), target); + writer.Dispose(); + } + + + /// + /// Returns if spawned and throws a warning if not. + /// + /// + private bool IsSpawnedWithWarning() + { + bool result = this.IsSpawned; + if (!result) + { + if (_networkObjectCache.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Action cannot be completed as object {gameObject.name} [Id {ObjectId}] is not spawned."); + } + + return result; + } + + ///// + ///// Writes a full RPC and returns the writer. + ///// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //private void CreateRpcHeader(uint hash, PooledWriter writer, PacketId packetId) + //{ + // writer.WritePacketId(packetId); + // writer.WriteNetworkBehaviour(this); + // WriteRpcHash(hash, writer); + //} + + /// + /// Writes a full RPC and returns the writer. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private PooledWriter CreateRpc(uint hash, PooledWriter methodWriter, PacketId packetId, Channel channel) + { + //Writer containing full packet. + PooledWriter writer = WriterPool.GetWriter(); + writer.WritePacketId(packetId); + writer.WriteNetworkBehaviour(this); + //Only write length if reliable. + if (channel == Channel.Reliable) + writer.WriteLength(methodWriter.Length + _rpcHashSize); + //Hash and data. + WriteRpcHash(hash, writer); + writer.WriteArraySegment(methodWriter.GetArraySegment()); + return writer; + } + + /// + /// Writes rpcHash to writer. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteRpcHash(uint hash, PooledWriter writer) + { + if (_rpcHashSize == 1) + writer.WriteByte((byte)hash); + else + writer.WriteUInt16((byte)hash); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs.meta new file mode 100644 index 0000000..b468914 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 938eacb83fa7d0046bd769b31dac7e80 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs new file mode 100644 index 0000000..552a594 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs @@ -0,0 +1,419 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Utility.Extension; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Object +{ + + public abstract partial class NetworkBehaviour : MonoBehaviour + { + #region Types. + /// + /// Used to generate data sent from synctypes. + /// + private class SyncTypeWriter + { + /// + /// Clients which can be synchronized. + /// + public ReadPermission ReadPermission; + /// + /// Writers for each channel. + /// + public PooledWriter[] Writers { get; private set; } + + public SyncTypeWriter(ReadPermission readPermission) + { + ReadPermission = readPermission; + Writers = new PooledWriter[TransportManager.CHANNEL_COUNT]; + for (int i = 0; i < Writers.Length; i++) + Writers[i] = WriterPool.GetWriter(); + } + + /// + /// Resets Writers. + /// + public void Reset() + { + if (Writers == null) + return; + + for (int i = 0; i < Writers.Length; i++) + Writers[i].Reset(); + } + } + #endregion + + #region Private. + /// + /// Writers for syncTypes. A writer will exist for every ReadPermission type. + /// + private SyncTypeWriter[] _syncTypeWriters; + /// + /// SyncVars within this NetworkBehaviour. + /// + private Dictionary _syncVars = new Dictionary(); + /// + /// True if at least one syncVar is dirty. + /// + private bool _syncVarDirty; + /// + /// SyncVars within this NetworkBehaviour. + /// + private Dictionary _syncObjects = new Dictionary(); + /// + /// True if at least one syncObject is dirty. + /// + private bool _syncObjectDirty; + /// + /// All ReadPermission values. + /// + private static ReadPermission[] _readPermissions; + #endregion + + /// + /// Registers a SyncType. + /// + /// + /// + internal void RegisterSyncType(SyncBase sb, uint index) + { + if (sb.IsSyncObject) + _syncObjects.Add(index, sb); + else + _syncVars.Add(index, sb); + } + /// + /// Sets a SyncVar as dirty. + /// + /// True if dirtying a syncObject. + /// True if able to dirty SyncType. + internal bool DirtySyncType(bool isSyncObject) + { + if (!IsServer) + return false; + /* No reason to dirty if there are no observers. + * This can happen even if a client is going to see + * this object because the server side initializes + * before observers are built. */ + if (_networkObjectCache.Observers.Count == 0) + return false; + + bool alreadyDirtied = (isSyncObject) ? _syncObjectDirty : _syncVarDirty; + if (isSyncObject) + _syncObjectDirty = true; + else + _syncVarDirty = true; + + if (!alreadyDirtied) + _networkObjectCache.NetworkManager.ServerManager.Objects.SetDirtySyncType(this, isSyncObject); + + return true; + } + + /// + /// Initializes SyncTypes. This will only call once even as host. + /// + private void InitializeOnceSyncTypes() + { + if (_readPermissions == null) + { + System.Array arr = System.Enum.GetValues(typeof(ReadPermission)); + _readPermissions = new ReadPermission[arr.Length]; + + int count = 0; + foreach (ReadPermission rp in arr) + { + _readPermissions[count] = rp; + count++; + } + } + + //Build writers for observers and owner. + _syncTypeWriters = new SyncTypeWriter[_readPermissions.Length]; + for (int i = 0; i < _syncTypeWriters.Length; i++) + _syncTypeWriters[i] = new SyncTypeWriter(_readPermissions[i]); + + foreach (SyncBase sb in _syncVars.Values) + sb.PreInitialize(_networkObjectCache.NetworkManager); + foreach (SyncBase sb in _syncObjects.Values) + sb.PreInitialize(_networkObjectCache.NetworkManager); + } + + + /// + /// Reads a SyncVar. + /// + /// + internal void OnSyncType(PooledReader reader, int length, bool isSyncObject) + { + int readerStart = reader.Position; + while (reader.Position - readerStart < length) + { + byte index = reader.ReadByte(); + if (isSyncObject) + { + if (_syncObjects.TryGetValueIL2CPP(index, out SyncBase sb)) + { + sb.Read(reader); + } + else + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"SyncObject not found for index {index} on {transform.name}. Remainder of packet may become corrupt."); + } + } + else + { + if (_syncVars.ContainsKey(index)) + { + ReadSyncVar(reader, index); + } + else + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"SyncVar not found for index {index} on {transform.name}. Remainder of packet may become corrupt."); + } + } + } + } + + /// + /// Codegen overrides this method to read syncVars for each script which inherits NetworkBehaviour. + /// + /// + /// + [APIExclude] + internal virtual bool ReadSyncVar(PooledReader reader, uint index) { return false; } + + /// + /// Writers dirty SyncTypes if their write tick has been met. + /// + /// True if there are no pending dirty sync types. + internal bool WriteDirtySyncTypes(bool isSyncObject, bool ignoreInterval = false) + { + /* Can occur when a synctype is queued after + * the object is marked for destruction. This should not + * happen under most conditions since synctypes will be + * pushed through when despawn is called. */ + if (!IsSpawned) + { + Dictionary c1 = (isSyncObject) ? _syncObjects : _syncVars; + foreach (SyncBase sb in c1.Values) + sb.ResetDirty(); + + return true; + } + + /* If there is nothing dirty then return true, indicating no more + * pending dirty checks. */ + if (isSyncObject && (!_syncObjectDirty || _syncObjects.Count == 0)) + return true; + else if (!isSyncObject && (!_syncVarDirty || _syncVars.Count == 0)) + return true; + + /* True if writers have been reset for this check. + * For perf writers are only reset when data is to be written. */ + bool writersReset = false; + uint tick = _networkObjectCache.NetworkManager.TimeManager.Tick; + + //True if a syncvar is found to still be dirty. + bool dirtyFound = false; + //True if data has been written and is ready to send. + bool dataWritten = false; + Dictionary collection = (isSyncObject) ? _syncObjects : _syncVars; + + foreach (SyncBase sb in collection.Values) + { + if (!sb.IsDirty) + continue; + + dirtyFound = true; + if (ignoreInterval || sb.WriteTimeMet(tick)) + { + //If writers still need to be reset. + if (!writersReset) + { + writersReset = true; + //Reset writers. + for (int i = 0; i < _syncTypeWriters.Length; i++) + _syncTypeWriters[i].Reset(); + } + + //Find channel. + byte channel = (byte)sb.Channel; + sb.ResetDirty(); + //If ReadPermission is owner but no owner skip this syncvar write. + if (sb.Settings.ReadPermission == ReadPermission.OwnerOnly && !_networkObjectCache.Owner.IsValid) + continue; + + dataWritten = true; + //Find PooledWriter to use. + PooledWriter writer = null; + for (int i = 0; i < _syncTypeWriters.Length; i++) + { + if (_syncTypeWriters[i].ReadPermission == sb.Settings.ReadPermission) + { + /* Channel for syncVar is beyond available channels in transport. + * Use default reliable. */ + if (channel >= _syncTypeWriters[i].Writers.Length) + channel = (byte)Channel.Reliable; + + writer = _syncTypeWriters[i].Writers[channel]; + break; + } + } + + if (writer == null) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Writer couldn't be found for permissions {sb.Settings.ReadPermission} on channel {channel}."); + } + else + { + sb.WriteDelta(writer); + } + } + } + + //If no dirty were found. + if (!dirtyFound) + { + if (isSyncObject) + _syncObjectDirty = false; + else + _syncVarDirty = false; + return true; + } + //At least one sync type was dirty. + else if (dataWritten) + { + for (int i = 0; i < _syncTypeWriters.Length; i++) + { + for (byte channel = 0; channel < _syncTypeWriters[i].Writers.Length; channel++) + { + PooledWriter channelWriter = _syncTypeWriters[i].Writers[channel]; + //If there is data to send. + if (channelWriter.Length > 0) + { + using (PooledWriter headerWriter = WriterPool.GetWriter()) + { + //Write the packetId and NB information. + PacketId packetId = (isSyncObject) ? PacketId.SyncObject : PacketId.SyncVar; + headerWriter.WritePacketId(packetId); + PooledWriter dataWriter = WriterPool.GetWriter(); + dataWriter.WriteNetworkBehaviour(this); + + /* SyncVars need length written regardless because amount + * of data being sent per syncvar is unknown, and the packet may have + * additional data after the syncvars. Because of this we should only + * read up to syncvar length then assume the remainder is another packet. + * + * Reliable always has data written as well even if syncObject. This is so + * if an object does not exist for whatever reason the packet can be + * recovered by skipping the data. + * + * Realistically everything will be a syncvar or on the reliable channel unless + * the user makes a custom syncobject that utilizes unreliable. */ + if (!isSyncObject || (Channel)channel == Channel.Reliable) + dataWriter.WriteBytesAndSize(channelWriter.GetBuffer(), 0, channelWriter.Length); + else + dataWriter.WriteBytes(channelWriter.GetBuffer(), 0, channelWriter.Length); + + //Attach data onto packetWriter. + headerWriter.WriteArraySegment(dataWriter.GetArraySegment()); + dataWriter.Dispose(); + + //If sending to observers. + bool excludeOwnerPermission = (_syncTypeWriters[i].ReadPermission == ReadPermission.ExcludeOwner); + if (excludeOwnerPermission || _syncTypeWriters[i].ReadPermission == ReadPermission.Observers) + _networkObjectCache.NetworkManager.TransportManager.SendToClients((byte)channel, headerWriter.GetArraySegment(), _networkObjectCache, excludeOwnerPermission); + //Sending only to owner. + else + _networkObjectCache.NetworkManager.TransportManager.SendToClient(channel, headerWriter.GetArraySegment(), _networkObjectCache.Owner); + } + } + } + } + } + + /* Fall through. If here then sync types are still pending + * being written or were just written this frame. */ + return false; + } + + + /// + /// Resets all SyncTypes for this NetworkBehaviour. + /// + internal void ResetSyncTypes(bool asServer) + { + if (asServer || (!asServer && !IsServer)) + { + foreach (SyncBase item in _syncVars.Values) + item.Reset(); + foreach (SyncBase item in _syncObjects.Values) + item.Reset(); + } + } + + /// + /// Writers syncVars for a spawn message. + /// + /// + ///True to also include syncVars which are for owner only. + internal void WriteSyncTypesForSpawn(PooledWriter writer, bool forOwner) + { + WriteSyncType(_syncVars); + WriteSyncType(_syncObjects); + + void WriteSyncType(Dictionary collection) + { + using (PooledWriter syncTypeWriter = WriterPool.GetWriter()) + { + /* Since all values are being written everything is + * written in order so there's no reason to pass + * indexes. */ + foreach (SyncBase sb in collection.Values) + { + //If not for owner and syncvar is owner only. + if (!forOwner && sb.Settings.ReadPermission == ReadPermission.OwnerOnly) + { + //If there is an owner then skip. + if (_networkObjectCache.Owner.IsValid) + continue; + } + + sb.WriteFull(syncTypeWriter); + } + + writer.WriteBytesAndSize(syncTypeWriter.GetBuffer(), 0, syncTypeWriter.Length); + } + } + } + + + /// + /// Manually marks a SyncType as dirty, be it SyncVar or SyncObject. + /// + /// SyncType variable to dirty. + protected void DirtySyncType(object syncType) + { + /* This doesn't actually do anything. + * The codegen replaces calls to this method + * with a Dirty call for syncType. */ + } + + + } + + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs.meta new file mode 100644 index 0000000..2d0f47e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.SyncTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e56d5389eb07aa040b8a9ec8b0d7c597 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs new file mode 100644 index 0000000..bcbf514 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs @@ -0,0 +1,146 @@ +using FishNet.Documenting; +using FishNet.Serializing.Helping; +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; +using UnityEngine; + +[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] +namespace FishNet.Object +{ + /// + /// Scripts which inherit from NetworkBehaviour can be used to gain insight of, and perform actions on the network. + /// + public abstract partial class NetworkBehaviour : MonoBehaviour + { + /// + /// True if this NetworkBehaviour is initialized for the network. + /// + public bool IsSpawned => _networkObjectCache.IsSpawned; + /// + /// + /// + [SerializeField, HideInInspector] + private byte _componentIndexCache = byte.MaxValue; + /// + /// ComponentIndex for this NetworkBehaviour. + /// + public byte ComponentIndex + { + get => _componentIndexCache; + private set => _componentIndexCache = value; + } +#if UNITY_EDITOR + /// + /// NetworkObject automatically added or discovered during edit time. + /// + [SerializeField, HideInInspector] + private NetworkObject _addedNetworkObject; +#endif + /// + /// + /// + [SerializeField, HideInInspector] + private NetworkObject _networkObjectCache; + /// + /// NetworkObject this behaviour is for. + /// + public NetworkObject NetworkObject => _networkObjectCache; + + /// + /// Initializes this script. This will only run once even as host. + /// + /// + /// + internal void InitializeOnceInternal() + { + InitializeOnceSyncTypes(); + InitializeOnceRpcLinks(); + } + + + /// + /// Serializes information for network components. + /// + internal void SerializeComponents(NetworkObject nob, byte componentIndex) + { + _networkObjectCache = nob; + ComponentIndex = componentIndex; + } + + /// + /// Manually initializes network content for the NetworkBehaviour if the object it's on is disabled. + /// + internal void InitializeIfDisabled() + { + if (gameObject.activeInHierarchy) + return; + + NetworkInitializeIfDisabledInternal(); + } + /// + /// Long name is to prevent users from potentially creating their own method named the same. + /// + [CodegenMakePublic] //internal. + [APIExclude] + protected internal virtual void NetworkInitializeIfDisabledInternal() { } + #region Editor. + protected virtual void Reset() + { +#if UNITY_EDITOR + if (Application.isPlaying) + return; + + //NetworkObject nob = TryAddNetworkObject(); + TryAddNetworkObject(); + //nob.UpdateNetworkBehaviours(); +#endif + } + + protected virtual void OnValidate() + { +#if UNITY_EDITOR + if (Application.isPlaying) + return; + + TryAddNetworkObject(); + //NetworkObject nob = TryAddNetworkObject(); + ////If componentIndex has not been set. + //if (ComponentIndex == byte.MaxValue) + // nob.UpdateNetworkBehaviours(); +#endif + } + + /// + /// Tries to add the NetworkObject component. + /// + private NetworkObject TryAddNetworkObject() + { +#if UNITY_EDITOR + if (Application.isPlaying || _addedNetworkObject != null) + return _addedNetworkObject; + + /* Manually iterate up the chain because GetComponentInParent doesn't + * work when modifying prefabs in the inspector. Unity, you're starting + * to suck a lot right now. */ + NetworkObject result = null; + Transform climb = transform; + + while (climb != null) + { + if (climb.TryGetComponent(out result)) + break; + else + climb = climb.parent; + } + + _addedNetworkObject = (result != null) ? result : transform.root.gameObject.AddComponent(); + return _addedNetworkObject; +#else + return null; +#endif + } + #endregion + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs.meta new file mode 100644 index 0000000..6188375 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2230f9cdb1ffc9489b53875c963342d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs new file mode 100644 index 0000000..f78f9fe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs @@ -0,0 +1,32 @@ +using FishNet.Broadcast; +using FishNet.Managing.Logging; +using FishNet.Transporting; +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + + /// + /// Sends a broadcast to Observers on this NetworkObject. + /// + /// Type of broadcast to send. + /// Broadcast data being sent; for example: an instance of your broadcast type. + /// True if the client must be authenticated for this broadcast to send. + /// Channel to send on. + public void Broadcast(T message, bool requireAuthenticated = true, Channel channel = Channel.Reliable) where T : struct, IBroadcast + { + if (NetworkManager == null) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot send broadcast from {gameObject.name}, NetworkManager reference is null. This may occur if the object is not spawned or initialized."); + return; + } + + NetworkManager.ServerManager.Broadcast(Observers, message, requireAuthenticated, channel); + } + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs.meta new file mode 100644 index 0000000..4068fcb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Broadcast.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55d793117b52da549affcc9ec30b05c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs new file mode 100644 index 0000000..a54a189 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs @@ -0,0 +1,132 @@ +using FishNet.Connection; +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + /// + /// Called after all data is synchronized with this NetworkObject. + /// + private void InitializeCallbacks(bool asServer) + { + /* Note: When invoking OnOwnership here previous owner will + * always be an empty connection, since the object is just + * now initializing. */ + + if (!asServer) + ClientInitialized = true; + + //Set that client or server is active before callbacks. + SetActiveStatus(true, asServer); + + //Invoke OnStartNetwork. + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InvokeOnNetwork(true); + + //As server. + if (asServer) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnStartServer(); + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InvokeSyncTypeCallbacks(true); + + if (Owner.IsValid) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnOwnershipServer(FishNet.Managing.NetworkManager.EmptyConnection); + } + } + //As client. + else + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnStartClient(); + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InvokeSyncTypeCallbacks(false); + + if (IsOwner) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnOwnershipClient(FishNet.Managing.NetworkManager.EmptyConnection); + } + } + } + + /// + /// Invokes events to be called after OnServerStart. + /// This is made one method to save instruction calls. + /// + /// + internal void InvokePostOnServerStart(NetworkConnection conn) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].SendBufferedRpcs(conn); + + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnSpawnServer(conn); + } + + /// + /// Called on the server before it sends a despawn message to a client. + /// + /// Connection spawn was sent to. + internal void InvokeOnServerDespawn(NetworkConnection conn) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnDespawnServer(conn); + } + + /// + /// Invokes OnStop callbacks. + /// + /// + private void InvokeStopCallbacks(bool asServer) + { + if (asServer) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnStopServer(); + } + else + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnStopClient(); + } + + /* Invoke OnStopNetwork if server is calling + * or if client and not as server. */ + if (asServer || (!asServer && !IsServer)) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InvokeOnNetwork(false); + } + + if (asServer) + IsServer = false; + else + IsClient = false; + } + + /// + /// Invokes OnOwnership callbacks. + /// + /// + private void InvokeOwnership(NetworkConnection prevOwner, bool asServer) + { + if (asServer) + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnOwnershipServer(prevOwner); + } + else + { + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].OnOwnershipClient(prevOwner); + } + } + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs.meta new file mode 100644 index 0000000..21b4bb7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e9fbf0d6eb10e94d892dd4e817030bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs new file mode 100644 index 0000000..83e30a8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs @@ -0,0 +1,179 @@ +using FishNet.Connection; +using FishNet.Managing.Logging; +using FishNet.Observing; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + #region Public. + /// + /// Called when this NetworkObject losses all observers or gains observers while previously having none. + /// + public event Action OnObserversActive; + /// + /// NetworkObserver on this object. May be null if not using observers. + /// + [HideInInspector] + public NetworkObserver NetworkObserver = null; + /// + /// Clients which can see and get messages from this NetworkObject. + /// + public HashSet Observers = new HashSet(); + #endregion + + #region Private. + /// + /// True if NetworkObserver has been initialized. + /// + private bool _networkObserverInitiliazed = false; + /// + /// Found renderers on the NetworkObject and it's children. This is only used as clientHost to hide non-observers objects. + /// + [System.NonSerialized] + private Renderer[] _renderers; + /// + /// True if renderers have been looked up. + /// + private bool _renderersPopulated; + #endregion + + /// + /// Sets the renderer visibility for clientHost. + /// + /// True if renderers are to be visibile. + /// True to skip blocking checks. + public void SetRenderersVisible(bool visible, bool force = false) + { + if (!force) + { + if (NetworkObserver != null && !NetworkObserver.UpdateHostVisibility) + return; + } + + if (!_renderersPopulated) + { + _renderers = GetComponentsInChildren(true); + _renderersPopulated = true; + } + + Renderer[] rs = _renderers; + int count = rs.Length; + for (int i = 0; i < count; i++) + rs[i].enabled = visible; + } + + /// + /// Adds the default NetworkObserver conditions using the ObserverManager. + /// + private void AddDefaultNetworkObserverConditions() + { + if (_networkObserverInitiliazed) + return; + + NetworkObserver = GetComponent(); + NetworkManager.ObserverManager.AddDefaultConditions(this, ref NetworkObserver); + } + /// + /// Initializes NetworkObserver. This will only call once even as host. + /// + private void InitializeOnceObservers() + { + if (_networkObserverInitiliazed) + return; + + if (NetworkObserver != null) + NetworkObserver.PreInitialize(this); + + _networkObserverInitiliazed = true; + } + + /// + /// Removes a connection from observers for this object. + /// + /// + internal bool RemoveObserver(NetworkConnection connection) + { + int startCount = Observers.Count; + bool removed = Observers.Remove(connection); + if (removed) + TryInvokeOnObserversActive(startCount); + + return removed; + } + + /// + /// Adds the connection to observers if conditions are met. + /// + /// + /// True if added to Observers. + internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool timedOnly) + { + //If not a valid connection. + if (!connection.IsValid) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"An invalid connection was used when rebuilding observers."); + return ObserverStateChange.Unchanged; + } + //Valid not not active. + else if (!connection.IsActive) + { + /* Just remove from observers since connection isn't active + * and return unchanged because nothing should process + * given the connection isnt active. */ + Observers.Remove(connection); + return ObserverStateChange.Unchanged; + } + else if (IsDeinitializing) + { + /* If object is deinitializing it's either being despawned + * this frame or it's not spawned. If we've made it this far, + * it's most likely being despawned. */ + return ObserverStateChange.Unchanged; + } + + int startCount = Observers.Count; + //Not using observer system, this object is seen by everything. + if (NetworkObserver == null) + { + bool added = Observers.Add(connection); + if (added) + TryInvokeOnObserversActive(startCount); + + return (added) ? ObserverStateChange.Added : ObserverStateChange.Unchanged; + } + else + { + ObserverStateChange osc = NetworkObserver.RebuildObservers(connection, timedOnly); + if (osc == ObserverStateChange.Added) + Observers.Add(connection); + else if (osc == ObserverStateChange.Removed) + Observers.Remove(connection); + + if (osc != ObserverStateChange.Unchanged) + TryInvokeOnObserversActive(startCount); + + return osc; + } + + } + + /// + /// Invokes OnObserversActive if observers are now 0 but previously were not, or if was previously 0 but now has observers. + /// + /// + private void TryInvokeOnObserversActive(int startCount) + { + if ((Observers.Count > 0 && startCount == 0) || + Observers.Count == 0 && startCount > 0) + OnObserversActive?.Invoke(this); + } + + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs.meta new file mode 100644 index 0000000..2024e29 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.Observers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 816dbea70a70ab949a44f485155f0087 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs new file mode 100644 index 0000000..f2e92c2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs @@ -0,0 +1,254 @@ +using FishNet.Component.ColliderRollback; +using FishNet.Connection; +using FishNet.Managing; +using FishNet.Managing.Client; +using FishNet.Managing.Logging; +using FishNet.Managing.Observing; +using FishNet.Managing.Scened; +using FishNet.Managing.Server; +using FishNet.Managing.Timing; +using FishNet.Managing.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + #region Public. + /// + /// True if this object has been initialized on the client side. + /// This is set true right before client callbacks. + /// + public bool ClientInitialized { get; private set; } + /// + /// + /// + private bool _isClient; + /// + /// True if the client is active and authenticated. + /// + public bool IsClient + { + /* This needs to use a special check when + * player is acting as host. Clients won't + * set IsClient until they receive the spawn message + * but the user may expect this true after client + * gains observation but before client gets spawn. */ + get + { + if (IsServer) + return (NetworkManager == null) ? false : NetworkManager.IsClient; + else + return _isClient; + } + + private set => _isClient = value; + } + + /// + /// True if only the client is active and authenticated. + /// + public bool IsClientOnly => (IsClient && !IsServer); + /// + /// True if server is active. + /// + public bool IsServer { get; private set; } + /// + /// True if only the server is active. + /// + public bool IsServerOnly => (IsServer && !IsClient); + /// + /// True if client and server are active. + /// + public bool IsHost => (IsClient && IsServer); + /// + /// True if client nor server are active. + /// + public bool IsOffline => (!IsClient && !IsServer); + /// + /// True if the local client is the owner of this object. + /// + public bool IsOwner + { + get + { + /* ClientInitialized becomes true when this + * NetworkObject has been initialized on the client side. + * + * This value is used to prevent IsOwner from returning true + * when running as host. + * + * EG: server will set owner when it spawns the object. + * If IsOwner is checked before the object spawns on the + * client-host then it would also return true, since the + * Owner reference would be the same as what was set by server. + * This is however bad when the client hasn't initialized the object + * yet because it gives a false sense of initialization. + * + * Wait for client-host being initialized before potentially + * returning true. */ + + /* Removed this restriction because people may want to use + * base.IsOwner for initializing in OnNetworkStart. While this + * would return true for client only, it wouldn't for host. That + * would be bad. */ + //if (!ClientInitialized) + //return false; + + return Owner.IsLocalClient; + } + } + + /// + /// + /// + private NetworkConnection _owner; + /// + /// Owner of this object. + /// + public NetworkConnection Owner + { + get + { + //Ensures a null Owner is never returned. + if (_owner == null) + return FishNet.Managing.NetworkManager.EmptyConnection; + + return _owner; + } + private set { _owner = value; } + } + /// + /// ClientId for this NetworkObject owner. + /// + public int OwnerId => (!Owner.IsValid) ? -1 : Owner.ClientId; + /// + /// True if the object is initialized for the network. + /// + public bool IsSpawned => (!IsDeinitializing && ObjectId >= 0); + /// + /// The local connection of the client calling this method. + /// + public NetworkConnection LocalConnection => (NetworkManager == null) ? new NetworkConnection() : NetworkManager.ClientManager.Connection; + /// + /// NetworkManager for this object. + /// + public NetworkManager NetworkManager { get; private set; } + /// + /// ServerManager for this object. + /// + public ServerManager ServerManager { get; private set; } + /// + /// ClientManager for this object. + /// + public ClientManager ClientManager { get; private set; } + /// + /// ObserverManager for this object. + /// + public ObserverManager ObserverManager { get; private set; } + /// + /// TransportManager for this object. + /// + public TransportManager TransportManager { get; private set; } + /// + /// TimeManager for this object. + /// + public TimeManager TimeManager { get; private set; } + /// + /// SceneManager for this object. + /// + public SceneManager SceneManager { get; private set; } + /// + /// RollbackManager for this object. + /// + public RollbackManager RollbackManager { get; private set; } + #endregion + + /// + /// Returns a NetworkBehaviour on this NetworkObject. + /// + /// ComponentIndex of the NetworkBehaviour. + /// True to error if not found. + /// + public NetworkBehaviour GetNetworkBehaviour(byte componentIndex, bool error) + { + if (componentIndex >= NetworkBehaviours.Length) + { + if (error) + { + bool staticLog = (NetworkManager == null); + string errMsg = $"ComponentIndex of {componentIndex} is out of bounds on {gameObject.name} [id {ObjectId}]. This may occur if you have modified your gameObject/prefab without saving it, or the scene."; + + if (staticLog && NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError(errMsg); + else if (!staticLog && NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError(errMsg); + } + } + + return NetworkBehaviours[componentIndex]; + } + /// + /// Despawns this NetworkObject. Only call from the server. + /// + /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. + public void Despawn(bool? disableOnDespawnOverride = null) + { + NetworkObject nob = this; + NetworkManager.ServerManager.Despawn(nob, disableOnDespawnOverride); + } + /// + /// Spawns an object over the network. Only call from the server. + /// + public void Spawn(GameObject go, NetworkConnection ownerConnection = null) + { + if (!CanSpawnOrDespawn(true)) + return; + NetworkManager.ServerManager.Spawn(go, ownerConnection); + } + /// + /// Spawns an object over the network. Only call from the server. + /// + public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null) + { + if (!CanSpawnOrDespawn(true)) + return; + NetworkManager.ServerManager.Spawn(nob, ownerConnection); + } + + /// + /// Returns if Spawn or Despawn can be called. + /// + /// True to warn if not able to execute spawn or despawn. + /// + internal bool CanSpawnOrDespawn(bool warn) + { + bool canExecute = true; + + if (NetworkManager == null) + { + canExecute = false; + if (warn) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot despawn {gameObject.name}, NetworkManager reference is null. This may occur if the object is not spawned or initialized."); + } + } + else if (IsDeinitializing) + { + canExecute = false; + if (warn) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot despawn {gameObject.name}, it is already deinitializing."); + } + } + + return canExecute; + } + + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs.meta new file mode 100644 index 0000000..422ef3f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd30b4b61d50d01499c94a63a6eeb863 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs new file mode 100644 index 0000000..91535bf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs @@ -0,0 +1,208 @@ +using UnityEngine; +using System.Collections.Generic; +using System; +using FishNet.Object.Helping; +using System.Linq; +#if UNITY_EDITOR +using UnityEditor.Experimental.SceneManagement; +using UnityEditor.SceneManagement; +using UnityEditor; +#endif + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + #region Serialized. + + /// + /// + /// + [field: SerializeField, HideInInspector] + public short PrefabId { get; internal set; } = -1; +#pragma warning disable 414 //Disabled because Unity thinks tihs is unused when building. + /// + /// Hash to the scene which this object resides. + /// + [SerializeField, HideInInspector] + private uint _scenePathHash; +#pragma warning restore 414 + /// + /// Network Id for this scene object. + /// + [field: SerializeField, HideInInspector] + internal ulong SceneId { get; private set; } + /// + /// Hash for the path which this asset resides. This value is set during edit time. + /// + [field: SerializeField, HideInInspector] + public ulong AssetPathHash { get; private set; } + /// + /// Sets AssetPathhash value. + /// + /// Value to use. + public void SetAssetPathHash(ulong value) => AssetPathHash = value; + #endregion + +#if UNITY_EDITOR + /// + /// This is used to store NetworkObjects in the scene during edit time. + /// SceneIds are compared against this collection to ensure there are no duplicated. + /// + [SerializeField, HideInInspector] + private List _sceneNetworkObjects = new List(); +#endif + + /// + /// Removes SceneObject state. + /// This may only be called at runtime. + /// + internal void ClearRuntimeSceneObject() + { + if (!Application.isPlaying) + { + Debug.LogError($"ClearRuntimeSceneObject may only be called at runtime."); + return; + } + + SceneId = 0; + } + +#if UNITY_EDITOR + /// + /// Tries to generate a SceneId. + /// + internal void TryCreateSceneID() + { + if (Application.isPlaying) + return; + //Unity bug, sometimes this can be null depending on editor callback orders. + if (gameObject == null) + return; + //Not a scene object. + if (string.IsNullOrEmpty(gameObject.scene.name)) + { + SceneId = 0; + return; + } + + ulong startId = SceneId; + uint startPath = _scenePathHash; + + ulong sceneId = 0; + uint scenePathHash = 0; + //If prefab or part of a prefab, not a scene object. + if (PrefabUtility.IsPartOfPrefabAsset(this) || IsEditingInPrefabMode() || + //Not in a scene, another prefab check. + !gameObject.scene.IsValid() || + //Stored on disk, so is a prefab. Somehow prefabutility missed it. + EditorUtility.IsPersistent(this)) + { + //These are all failing conditions, don't do additional checks. + } + else + { + System.Random rnd = new System.Random(); + scenePathHash = gameObject.scene.path.ToLower().GetStableHash32(); + sceneId = SceneId; + //Not a valid sceneId or is a duplicate. + if (scenePathHash != _scenePathHash || SceneId == 0 || IsDuplicateSceneId(SceneId)) + { + /* If a scene has not been opened since an id has been + * generated then it will not be serialized in editor. The id + * would be correct in build but not if running in editor. + * Should conditions be true where scene is building without + * being opened then cancel build and request user to open and save + * scene. */ + if (BuildPipeline.isBuildingPlayer) + throw new InvalidOperationException($"Networked GameObject {gameObject.name} in scene {gameObject.scene.path} is missing a SceneId. Open the scene, select the Fish-Networking menu, and choose Rebuild SceneIds. If the problem persist ensures {gameObject.name} does not have any missing script references on it's prefab or in the scene. Also ensure that you have any prefab changes for the object applied."); + + ulong shiftedHash = (ulong)scenePathHash << 32; + ulong randomId = 0; + while (randomId == 0 || IsDuplicateSceneId(randomId)) + { + uint next = (uint)(rnd.Next(int.MinValue, int.MaxValue) + int.MaxValue); + /* Since the collection is lost when a scene loads the it's possible to + * have a sceneid from another scene. Because of this the scene path is + * inserted into the sceneid. */ + randomId = (next & 0xFFFFFFFF) | shiftedHash; + } + + sceneId = randomId; + } + + } + + bool idChanged = (sceneId != startId); + bool pathChanged = (startPath != scenePathHash); + //If either changed then dirty and set. + if (idChanged || pathChanged) + { + //Set dirty so changes will be saved. + EditorUtility.SetDirty(this); + /* Add to sceneIds collection. This must be done + * even if a new sceneId was not generated because + * the collection information is lost when the + * scene is existed. Essentially, it gets repopulated + * when the scene is re-opened. */ + SceneId = sceneId; + _scenePathHash = scenePathHash; + } + } + + private bool IsEditingInPrefabMode() + { + if (EditorUtility.IsPersistent(this)) + { + // if the game object is stored on disk, it is a prefab of some kind, despite not returning true for IsPartOfPrefabAsset =/ + return true; + } + else + { + // If the GameObject is not persistent let's determine which stage we are in first because getting Prefab info depends on it + StageHandle mainStage = StageUtility.GetMainStageHandle(); + StageHandle currentStage = StageUtility.GetStageHandle(gameObject); + if (currentStage != mainStage) + { + var prefabStage = PrefabStageUtility.GetPrefabStage(gameObject); + if (prefabStage != null) + { + return true; + } + } + } + return false; + + } + + /// + /// Returns if the Id used is a sceneId already belonging to another object. + /// + /// + /// + private bool IsDuplicateSceneId(ulong id) + { + //Find all nobs in scene. + _sceneNetworkObjects = GameObject.FindObjectsOfType().ToList(); + foreach (NetworkObject nob in _sceneNetworkObjects) + { + if (nob != null && nob != this && nob.SceneId == id) + return true; + } + //If here all checks pass. + return false; + } + + private void ReferenceIds_OnValidate() + { + TryCreateSceneID(); + } + private void ReferenceIds_Reset() + { + TryCreateSceneID(); + } +#endif + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs.meta new file mode 100644 index 0000000..8858eee --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.ReferenceIds.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be0a4b0a32b02f64495ba3b1d22f89c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs new file mode 100644 index 0000000..2d2269a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + + #region Private. + /// + /// RpcLinks being used within this NetworkObject. + /// + private List _rpcLinkIndexes; + #endregion + + /// + /// Sets rpcLinkIndexes to values. + /// + internal void SetRpcLinkIndexes(List values) + { + _rpcLinkIndexes = values; + } + + /// + /// Removes used link indexes from ClientObjects. + /// + internal void RemoveClientRpcLinkIndexes() + { + NetworkManager.ClientManager.Objects.RemoveLinkIndexes(_rpcLinkIndexes); + } + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs.meta new file mode 100644 index 0000000..d7142a8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.RpcLinks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b2f6927cf3ef254d91b89e5f99a92b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs new file mode 100644 index 0000000..9fa20f0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +namespace FishNet.Object +{ + public sealed partial class NetworkObject : MonoBehaviour + { + /// + /// Writers dirty SyncTypes for all Networkbehaviours if their write tick has been met. + /// + internal void WriteDirtySyncTypes() + { + NetworkBehaviour[] nbs = NetworkBehaviours; + int count = nbs.Length; + for (int i = 0; i < count; i++) + { + //There was a null check here before, shouldn't be needed so it was removed. + NetworkBehaviour nb = nbs[i]; + nb.WriteDirtySyncTypes(true, true); + nb.WriteDirtySyncTypes(false, true); + } + } + + /// + /// Resets SyncTypes for all NetworkBehaviours. + /// + internal void ResetSyncTypes(bool asServer) + { + NetworkBehaviour[] nbs = NetworkBehaviours; + int count = nbs.Length; + for (int i = 0; i < count; i++) + nbs[i].ResetSyncTypes(asServer); + } + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs.meta new file mode 100644 index 0000000..a50da6e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.SyncTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ffb07b7ea3c5b4419dc5f9941b2d204 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs new file mode 100644 index 0000000..4c250e9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs @@ -0,0 +1,763 @@ +using FishNet.Managing; +using FishNet.Connection; +using UnityEngine; +using FishNet.Serializing; +using FishNet.Transporting; +using FishNet.Managing.Logging; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using FishNet.Utility.Performance; +using System; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace FishNet.Object +{ + [DisallowMultipleComponent] + public sealed partial class NetworkObject : MonoBehaviour + { + #region Public. + [field: SerializeField, HideInInspector] + public bool IsNested { get; private set; } + /// + /// True if this NetworkObject was active during edit. Will be true if placed in scene during edit, and was in active state on run. + /// + [System.NonSerialized] + internal bool ActiveDuringEdit; + /// + /// Returns if this object was placed in the scene during edit-time. + /// + /// + public bool IsSceneObject => (SceneId > 0); + [Obsolete("Use IsSceneObject instead.")] //Remove on 2023/01/01 + public bool SceneObject => IsSceneObject; + /// + /// ComponentIndex for this NetworkBehaviour. + /// + [field: SerializeField, HideInInspector] + public byte ComponentIndex { get; private set; } + /// + /// Unique Id for this NetworkObject. This does not represent the object owner. + /// + public int ObjectId { get; private set; } + /// + /// True if this NetworkObject is deinitializing. Will also be true until Initialize is called. May be false until the object is cleaned up if object is destroyed without using Despawn. + /// + internal bool IsDeinitializing { get; private set; } = true; + /// + /// + /// + [field: SerializeField, HideInInspector] + private NetworkBehaviour[] _networkBehaviours; + /// + /// NetworkBehaviours within the root and children of this object. + /// + public NetworkBehaviour[] NetworkBehaviours + { + get => _networkBehaviours; + private set => _networkBehaviours = value; + } + /// + /// NetworkObject parenting this instance. The parent NetworkObject will be null if there was no parent during serialization. + /// + [field: SerializeField, HideInInspector] + public NetworkObject ParentNetworkObject { get; private set; } + /// NetworkObjects nested beneath this one. Recursive NetworkObjects may exist within each entry of this field. + /// + [field: SerializeField, HideInInspector] + public List ChildNetworkObjects { get; private set; } = new List(); + /// + /// + /// + [SerializeField, HideInInspector] + internal TransformProperties SerializedTransformProperties = new TransformProperties(); + /// + /// Current state of the NetworkObject. + /// + [System.NonSerialized] + internal NetworkObjectState State = NetworkObjectState.Unset; + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("True if the object will always initialize as a networked object. When false the object will not automatically initialize over the network. Using Spawn() on an object will always set that instance as networked.")] + [SerializeField] + private bool _isNetworked = true; + /// + /// True if the object will always initialize as a networked object. When false the object will not automatically initialize over the network. Using Spawn() on an object will always set that instance as networked. + /// + public bool IsNetworked + { + get => _isNetworked; + private set => _isNetworked = value; + } + /// + /// Sets IsNetworked value. This method must be called before Start. + /// + /// New IsNetworked value. + public void SetIsNetworked(bool value) + { + IsNetworked = value; + } + /// + /// + /// + [Tooltip("True to make this object global, and added to the DontDestroyOnLoad scene. This value may only be set for instantiated objects, and can be changed if done immediately after instantiating.")] + [SerializeField] + private bool _isGlobal; + /// + /// True to make this object global, and added to the DontDestroyOnLoad scene. This value may only be set for instantiated objects, and can be changed if done immediately after instantiating. + /// + public bool IsGlobal + { + get => _isGlobal; + private set => _isGlobal = value; + } + /// + /// Sets IsGlobal value. + /// + /// New global value. + public void SetIsGlobal(bool value) + { + if (IsNested) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning($"Object {gameObject.name} cannot change IsGlobal because it is nested. Only root objects may be set global."); + } + if (!IsDeinitializing) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning($"Object {gameObject.name} cannot change IsGlobal as it's already initialized. IsGlobal may only be changed immediately after instantiating."); + return; + } + if (IsSceneObject) + { + if (NetworkManager.StaticCanLog(LoggingType.Warning)) + Debug.LogWarning($"Object {gameObject.name} cannot have be global because it is a scene object. Only instantiated objects may be global."); + return; + } + + _networkObserverInitiliazed = false; + IsGlobal = value; + } + [Header("WIP! Not Functional")] + /// + /// + /// + [Tooltip("True to disable rather than destroy this NetworkObject when being despawned. Scene objects are never destroyed.")] + [SerializeField] + private bool _disableOnDespawn; + /// + /// True to disable rather than destroy this NetworkObject when being despawned. Scene objects are never destroyed. + /// + public bool DisableOnDespawn + { + get => _disableOnDespawn; + private set => _disableOnDespawn = value; + } + /// + /// Sets AllowDestroy value. + /// + /// + public void SetDisableOnDespawn(bool disableOnDespawn) + { + DisableOnDespawn = disableOnDespawn; + } + #endregion + + #region Private. + /// + /// True if disabled NetworkBehaviours have been initialized. + /// + private bool _disabledNetworkBehavioursInitialized; + #endregion + + + private void Awake() + { + SetChildDespawnedState(); + } + + private void Start() + { + TryStartDeactivation(); + ////Also deactivate children. + //foreach (NetworkObject nob in ChildNetworkObjects) + // nob.TryStartDeactivation(); + } + + /// + /// Initializes NetworkBehaviours if they are disabled. + /// + private void InitializeNetworkBehavioursIfDisabled() + { + if (_disabledNetworkBehavioursInitialized) + return; + _disabledNetworkBehavioursInitialized = true; + + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InitializeIfDisabled(); + } + + /// + /// Sets Despawned on child NetworkObjects if they are not enabled. + /// + private void SetChildDespawnedState() + { + NetworkObject nob; + for (int i = 0; i < ChildNetworkObjects.Count; i++) + { + nob = ChildNetworkObjects[i]; + if (!nob.gameObject.activeSelf) + nob.State = NetworkObjectState.Despawned; + } + } + + /// + /// Deactivates this NetworkObject during it's start cycle if conditions are met. + /// + internal void TryStartDeactivation() + { + if (!IsNetworked) + return; + + //Global. + if (IsGlobal && !IsSceneObject) + DontDestroyOnLoad(gameObject); + + if (NetworkManager == null || (!NetworkManager.IsClient && !NetworkManager.IsServer)) + { + //ActiveDuringEdit is only used for scene objects. + if (IsSceneObject) + ActiveDuringEdit = true; + gameObject.SetActive(false); + } + } + + private void OnDisable() + { + /* If deinitializing and an owner exist + * then remove object from owner. */ + if (IsDeinitializing && Owner.IsValid) + Owner.RemoveObject(this); + /* If not nested then check to despawn this OnDisable. + * A nob may become disabled without being despawned if it's + * beneath another deinitializing nob. This can be true even while + * not nested because users may move a nob under another at runtime. + * + * This object must also be activeSelf, meaning that it became disabled + * because a parent was. If not activeSelf then it's possible the + * user simply deactivated the object themselves. */ + else if (IsServer && !IsNested && gameObject.activeSelf) + { + bool canDespawn = false; + Transform nextParent = transform.parent; + while (nextParent != null) + { + if (nextParent.TryGetComponent(out NetworkObject pNob)) + { + //If nob is deinitialized then this one cannot exist. + if (pNob.IsDeinitializing) + { + canDespawn = true; + break; + } + } + nextParent = nextParent.parent; + } + + if (canDespawn) + Despawn(); + } + } + + private void OnDestroy() + { + //Does this need to be here? I'm thinking no, remove it and examine later. //todo + if (Owner.IsValid) + Owner.RemoveObject(this); + //Already being deinitialized by FishNet. + if (IsDeinitializing) + return; + + //Was destroyed without going through the proper methods. + if (NetworkManager.IsServer) + NetworkManager.ServerManager.Objects.NetworkObjectUnexpectedlyDestroyed(this); + if (NetworkManager.IsClient) + NetworkManager.ClientManager.Objects.NetworkObjectUnexpectedlyDestroyed(this); + + /* When destroyed unexpectedly it's + * impossible to know if this occurred on + * the server or client side, so send callbacks + * for both. */ + if (IsServer) + InvokeStopCallbacks(true); + if (IsClient) + InvokeStopCallbacks(false); + + /* If owner exist then remove object from owner. + * This has to be called here as well OnDisable because + * the OnDisable will only remove the object if + * deinitializing. This is because the object shouldn't + * be removed from owner if the object is simply being + * disabled, but not deinitialized. But in the scenario + * the object is unexpectedly destroyed, which is how we + * arrive here, the object needs to be removed from owner. */ + if (Owner.IsValid) + Owner.RemoveObject(this); + + Observers.Clear(); + IsDeinitializing = true; + + SetActiveStatus(false, true); + SetActiveStatus(false, false); + //Do not need to set state if being destroyed. + //Don't need to reset sync types if object is being destroyed. + } + + /// + /// Sets IsClient or IsServer to isActive. + /// + private void SetActiveStatus(bool isActive, bool server) + { + if (server) + IsServer = isActive; + else + IsClient = isActive; + } + /// + /// Initializes this script. This is only called once even when as host. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PreinitializeInternal(NetworkManager networkManager, int objectId, NetworkConnection owner, bool asServer) + { + State = NetworkObjectState.Spawned; + InitializeNetworkBehavioursIfDisabled(); + IsDeinitializing = false; + //QOL references. + NetworkManager = networkManager; + ServerManager = networkManager.ServerManager; + ClientManager = networkManager.ClientManager; + ObserverManager = networkManager.ObserverManager; + TransportManager = networkManager.TransportManager; + TimeManager = networkManager.TimeManager; + SceneManager = networkManager.SceneManager; + RollbackManager = networkManager.RollbackManager; + + SetOwner(owner); + ObjectId = objectId; + + /* This must be called at the beginning + * so that all conditions are handled by the observer + * manager prior to the preinitialize call on networkobserver. + * The method called is dependent on NetworkManager being set. */ + AddDefaultNetworkObserverConditions(); + + for (int i = 0; i < NetworkBehaviours.Length; i++) + NetworkBehaviours[i].InitializeOnceInternal(); + + /* NetworkObserver uses some information from + * NetworkBehaviour so it must be preinitialized + * after NetworkBehaviours are. */ + if (asServer) + InitializeOnceObservers(); + + //Add to connection objects if owner exist. + if (owner != null) + owner.AddObject(this); + } + + /// + /// Adds a NetworkBehaviour and serializes it's components. + /// + internal T AddAndSerialize() where T : NetworkBehaviour //runtimeNB make public. + { + int startingLength = NetworkBehaviours.Length; + T result = gameObject.AddComponent(); + //Add to network behaviours. + Array.Resize(ref _networkBehaviours, startingLength + 1); + _networkBehaviours[startingLength] = result; + //Serialize values and return. + result.SerializeComponents(this, (byte)startingLength); + return result; + } + + /// + /// Updates NetworkBehaviours and initializes them with serialized values. + /// + /// True if this call originated from a prefab collection, such as during it's initialization. + internal void UpdateNetworkBehaviours(NetworkObject parentNob, ref byte componentIndex) //runtimeNB make public. + { + /* This method can be called by the developer initializing prefabs, the prefab collection doing it automatically, + * or when the networkobject is modified or added to an object. + * + * Prefab collections generally contain all prefabs, meaning they will not only call this on the topmost + * networkobject but also each child, as the child would be it's own prefab in the collection. This assumes + * that is, the child is a nested prefab. + * + * Because of this potential a check must be done where if the componentIndex is 0 we must look + * for a networkobject above this one. If there is a networkObject above this one then we know the prefab + * is being initialized individually, not part of a recursive check. In this case exit early + * as the parent would have already resolved the needed information. */ + + //If first componentIndex make sure there's no more than maximum allowed nested nobs. + if (componentIndex == 0) + { + //Not possible for index to be 0 and nested. + if (IsNested) + return; + byte maxNobs = 255; + if (GetComponentsInChildren(true).Length > maxNobs) + { + Debug.LogError($"The number of child NetworkObjects on {gameObject.name} exceeds the maximum of {maxNobs}."); + return; + } + } + + Debug.Log("Setting componentIndex on " + gameObject.name + " to " + componentIndex + ". SceneId is " + this.SceneId); + ComponentIndex = componentIndex; + ParentNetworkObject = parentNob; + + //Transforms which can be searched for networkbehaviours. + ListCache transformCache = ListCaches.GetTransformCache(); + transformCache.Reset(); + ChildNetworkObjects.Clear(); + + transformCache.AddValue(transform); + for (int z = 0; z < transformCache.Written; z++) + { + Transform currentT = transformCache.Collection[z]; + for (int i = 0; i < currentT.childCount; i++) + { + Transform t = currentT.GetChild(i); + /* If contains a nob then do not add to transformsCache. + * Do add to ChildNetworkObjects so it can be initialized when + * parent is. */ + if (t.TryGetComponent(out NetworkObject childNob)) + { + /* Make sure both objects have the same value for + * IsSceneObject. It's possible the user instantiated + * an object and placed it beneath a scene object + * before the scene initialized. They may also + * add a scene object under an instantiated, even though + * this almost certainly will break things. */ + if (IsSceneObject == childNob.IsSceneObject) + ChildNetworkObjects.Add(childNob); + } + else + { + transformCache.AddValue(t); + } + } + } + + int written; + //Iterate all cached transforms and get networkbehaviours. + ListCache nbCache = ListCaches.GetNetworkBehaviourCache(); + nbCache.Reset(); + written = transformCache.Written; + List ts = transformCache.Collection; + // + for (int i = 0; i < written; i++) + nbCache.AddValues(ts[i].GetNetworkBehaviours()); + + //Copy to array. + written = nbCache.Written; + List nbs = nbCache.Collection; + NetworkBehaviours = new NetworkBehaviour[written]; + // + for (int i = 0; i < written; i++) + { + NetworkBehaviours[i] = nbs[i]; + NetworkBehaviours[i].SerializeComponents(this, (byte)i); + } + + ListCaches.StoreCache(transformCache); + ListCaches.StoreCache(nbCache); + + //Tell children nobs to update their NetworkBehaviours. + foreach (NetworkObject item in ChildNetworkObjects) + { + componentIndex++; + item.UpdateNetworkBehaviours(this, ref componentIndex); + } + } + + /// + /// Called after all data is synchronized with this NetworkObject. + /// + internal void Initialize(bool asServer) + { + InitializeCallbacks(asServer); + } + + /// + /// Called to prepare this object to be destroyed or disabled. + /// + internal void Deinitialize(bool asServer) + { + InvokeStopCallbacks(asServer); + if (asServer) + { + IsDeinitializing = true; + } + else + { + //Client only. + if (!NetworkManager.IsServer) + IsDeinitializing = true; + + RemoveClientRpcLinkIndexes(); + } + + ResetSyncTypes(asServer); + if (asServer) + Observers.Clear(); + + SetActiveStatus(false, asServer); + //State = NetworkObjectState.Despawned; + } + + ///// + ///// Disables this object and resets network values. + ///// + //internal void DisableNetworkObject() + //{ + // SetOwner(null, false); + // ObjectId = -1; + // Observers.Clear(); + // NetworkManager = null; + //} + + /// + /// Removes ownership from all clients. + /// + public void RemoveOwnership() + { + GiveOwnership(null, true); + } + /// + /// Gives ownership to newOwner. + /// + /// + public void GiveOwnership(NetworkConnection newOwner) + { + GiveOwnership(newOwner, true); + } + /// + /// Gives ownership to newOwner. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void GiveOwnership(NetworkConnection newOwner, bool asServer) + { + /* Additional asServer checks. */ + if (asServer) + { + if (!NetworkManager.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Ownership cannot be given for object {gameObject.name}. Only server may give ownership."); + return; + } + + //If the same owner don't bother sending a message, just ignore request. + if (newOwner == Owner && asServer) + return; + + if (newOwner != null && newOwner.IsActive && !newOwner.LoadedStartScenes) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Ownership has been transfered to ConnectionId {newOwner.ClientId} but this is not recommended until after they have loaded start scenes. You can be notified when a connection loads start scenes by using connection.OnLoadedStartScenes on the connection, or SceneManager.OnClientLoadStartScenes."); + } + } + + bool activeNewOwner = (newOwner != null && newOwner.IsActive); + + //Set prevOwner, disallowing null. + NetworkConnection prevOwner = Owner; + if (prevOwner == null) + prevOwner = NetworkManager.EmptyConnection; + + SetOwner(newOwner); + /* Only modify objects if asServer or not + * host. When host, server would + * have already modified objects + * collection so there is no need + * for client to as well. */ + if (asServer || !NetworkManager.IsHost) + { + if (activeNewOwner) + newOwner.AddObject(this); + if (prevOwner.IsValid) + prevOwner.RemoveObject(this); + } + //After changing owners invoke callbacks. + InvokeOwnership(prevOwner, asServer); + + //If asServer send updates to clients as needed. + if (asServer) + { + if (activeNewOwner) + ServerManager.Objects.RebuildObservers(this, newOwner); + + using (PooledWriter writer = WriterPool.GetWriter()) + { + writer.WritePacketId(PacketId.OwnershipChange); + writer.WriteNetworkObject(this); + writer.WriteNetworkConnection(Owner); + //If sharing then send to all observers. + if (NetworkManager.ServerManager.ShareIds) + { + NetworkManager.TransportManager.SendToClients((byte)Channel.Reliable, writer.GetArraySegment(), this); + } + //Only sending to old / new. + else + { + if (prevOwner.IsActive) + NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, writer.GetArraySegment(), prevOwner); + if (activeNewOwner) + NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, writer.GetArraySegment(), newOwner); + } + } + + if (prevOwner.IsActive) + ServerManager.Objects.RebuildObservers(prevOwner); + } + } + + /// + /// Sets the owner of this object. + /// + /// + /// + private void SetOwner(NetworkConnection owner) + { + Owner = owner; + } + + /// + /// Returns if this NetworkObject is a scene object, and has changed. + /// + /// + internal ChangedTransformProperties GetTransformChanges(TransformProperties stp) + { + ChangedTransformProperties ctp = ChangedTransformProperties.Unset; + if (transform.localPosition != stp.Position) + ctp |= ChangedTransformProperties.LocalPosition; + if (transform.localRotation != stp.Rotation) + ctp |= ChangedTransformProperties.LocalRotation; + if (transform.localScale != stp.LocalScale) + ctp |= ChangedTransformProperties.LocalScale; + + return ctp; + } + + /// + /// Returns if this NetworkObject is a scene object, and has changed. + /// + /// + internal ChangedTransformProperties GetTransformChanges(GameObject prefab) + { + Transform t = prefab.transform; + ChangedTransformProperties ctp = ChangedTransformProperties.Unset; + if (transform.position != t.position) + ctp |= ChangedTransformProperties.LocalPosition; + if (transform.rotation != t.rotation) + ctp |= ChangedTransformProperties.LocalRotation; + if (transform.localScale != t.localScale) + ctp |= ChangedTransformProperties.LocalScale; + + return ctp; + } + + #region Editor. +#if UNITY_EDITOR + + /// + /// Sets IsNested and returns the result. + /// + /// + private bool SetIsNestedThroughTraversal() + { + Transform parent = transform.parent; + //Iterate long as parent isn't null, and isnt self. + while (parent != null && parent != transform) + { + if (parent.TryGetComponent(out _)) + { + // Debug.Log("Found in parent"); + IsNested = true; + return IsNested; + } + + parent = parent.parent; + } + + //No NetworkObject found in parents, meaning this is not nested. + IsNested = false; + return IsNested; + + } + + private void OnValidate() + { + SetIsNestedThroughTraversal(); + SceneUpdateNetworkBehaviours(); + ReferenceIds_OnValidate(); + + if (IsGlobal && IsSceneObject) + Debug.LogWarning($"Object {gameObject.name} will have it's IsGlobal state ignored because it is a scene object. Instantiated copies will still be global. This warning is informative only."); + } + + private void Reset() + { + SetIsNestedThroughTraversal(); + SerializeTransformProperties(); + SceneUpdateNetworkBehaviours(); + ReferenceIds_Reset(); + } + + private void SceneUpdateNetworkBehaviours() + { + //In a scene. + if (!string.IsNullOrEmpty(gameObject.scene.name)) + { + if (IsNested) + return; + + byte componentIndex = 0; + UpdateNetworkBehaviours(null, ref componentIndex); + } + + } + + private void OnDrawGizmosSelected() + { + SerializeTransformProperties(); + } + + /// + /// Serializes TransformProperties to current transform properties. + /// + private void SerializeTransformProperties() + { + /* Use this method to set scene data since it doesn't need to exist outside + * the editor and because its updated regularly while selected. */ + //If a scene object. + if (!EditorApplication.isPlaying && !string.IsNullOrEmpty(gameObject.scene.name)) + { + SerializedTransformProperties = new TransformProperties( + transform.localPosition, transform.localRotation, transform.localScale); + } + } +#endif + #endregion + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs.meta new file mode 100644 index 0000000..228ed52 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26b716c41e9b56b4baafaf13a523ba2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs new file mode 100644 index 0000000..0b0b6d1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs @@ -0,0 +1,24 @@ + +namespace FishNet.Object +{ + /// + /// Current state of the NetworkObject. + /// + internal enum NetworkObjectState : byte + { + /// + /// State has not been set. This occurs when the object has never been spawned or despawned. + /// + Unset = 0, + /// + /// Object is currently spawned. + /// + Spawned = 1, + /// + /// Object is currently despawned. + /// + Despawned = 2, + } + +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs.meta new file mode 100644 index 0000000..1873ca3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/NetworkObjectState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 536f137f11dc6654eab9fbe94ca14cd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Prediction.meta b/UnityProject/Assets/FishNet/Runtime/Object/Prediction.meta new file mode 100644 index 0000000..a673566 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Prediction.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8bce6e27e176a2d4d91783beffe40ac2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs new file mode 100644 index 0000000..f3d355c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs @@ -0,0 +1,29 @@ +using System; + +namespace FishNet.Object.Prediction +{ + /// + /// Replicated methods are to be called from clients and will run the same data and logic on the server. + /// Only data used as method arguments will be serialized. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ReplicateAttribute : Attribute + { + /// + /// How many past datas to resend. + /// + public byte Resends = 5; + } + /// + /// Reconcile methods indicate how to reset your script or object after the server has replicated user data. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class ReconcileAttribute : Attribute + { + /// + /// How many times to resend reconcile. + /// + public byte Resends = 3; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs.meta new file mode 100644 index 0000000..fdd81b7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Attributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b082d36535ce0404d8438bc1b0499e53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs new file mode 100644 index 0000000..17399cc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs @@ -0,0 +1,15 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Serializing; +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] +namespace FishNet.Object.Prediction.Delegating +{ + [APIExclude] + public delegate void ReplicateRpcDelegate(NetworkBehaviour obj, PooledReader reader, NetworkConnection sender); + [APIExclude] + public delegate void ReconcileRpcDelegate(NetworkBehaviour obj, PooledReader reader); + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs.meta new file mode 100644 index 0000000..d3c53db --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Prediction/Delegates.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9904192dacd41a4ba7b29bc3199ec3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs b/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs new file mode 100644 index 0000000..84f89f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs @@ -0,0 +1,25 @@ +using FishNet.Object.Helping; + +namespace FishNet.Object +{ + + + internal struct RpcLinkType + { + /// + /// Index of link. + /// + public ushort LinkIndex; + /// + /// Type of Rpc link is for. + /// + public RpcType RpcType; + + public RpcLinkType(ushort linkIndex, RpcType rpcType) + { + LinkIndex = linkIndex; + RpcType = rpcType; + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs.meta new file mode 100644 index 0000000..3781ab0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/RpcLinkType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4fa68ca6a21d08f42980dcf68f984d53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing.meta new file mode 100644 index 0000000..fd7d57a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 340de3ebc97a18642be780cbfeda01dc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs new file mode 100644 index 0000000..71ed36b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs @@ -0,0 +1,19 @@ + +namespace FishNet.Object.Synchronizing +{ + /// + /// Custom SyncObjects must inherit from SyncBase and implement this interface. + /// + public interface ICustomSync + { + /// + /// Get the serialized type. + /// This must return the value type you are synchronizing, for example a struct or class. + /// If you are not synchronizing a particular value but instead of supported values such as int, bool, ect, then you may return null on this method. + /// + /// + object GetSerializedType(); + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs.meta new file mode 100644 index 0000000..7789232 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ICustomSync.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2024b0be0cd1cc744a442f3e2e6ba483 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs new file mode 100644 index 0000000..9356bbd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs @@ -0,0 +1,48 @@ +using FishNet.Managing; +using FishNet.Serializing; +using System; + +namespace FishNet.Object.Synchronizing.Internal +{ + /// + /// A sync object is an object that can synchronize it's state + /// between server and client, such as a SyncList + /// + public interface ISyncType + { + /// + /// true if there are changes since the last flush + /// + bool IsDirty { get; } + /// + /// Sets index for the SyncType. + /// + void SetRegistered(); + /// + /// PreInitializes this for use with the network. + /// + void PreInitialize(NetworkManager networkManager); + /// + /// Writes all changed values. + /// + /// + ///True to set the next time data may sync. + void WriteDelta(PooledWriter writer, bool resetSyncTick = true); + /// + /// Writers all values if not initial values. + /// + /// + void WriteFull(PooledWriter writer); + /// + /// Sets current values. + /// + /// + void Read(PooledReader reader); + /// + /// Resets the SyncObject so that it can be re-used + /// + void Reset(); + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs.meta new file mode 100644 index 0000000..e353a5a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ISyncObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d0e81c03149ecd4eba926bba2d0edbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs new file mode 100644 index 0000000..56e0d3d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs @@ -0,0 +1,11 @@ +namespace FishNet.Object +{ + + internal enum MissingObjectPacketLength : int + { + Reliable = -1, + PurgeRemaiming = -2, + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs.meta new file mode 100644 index 0000000..68a542f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/MissingObjectPacketLength.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d177496f9519e246b8e3ef199d83437 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs new file mode 100644 index 0000000..967d32c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs @@ -0,0 +1,21 @@ +namespace FishNet.Object.Synchronizing +{ + /// + /// Which clients may receive synchronization updates. + /// + public enum ReadPermission + { + /// + /// All observers will receive updates. + /// + Observers, + /// + /// Only owner will receive updates. + /// + OwnerOnly, + /// + /// Send to all observers except owner. + /// + ExcludeOwner + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs.meta new file mode 100644 index 0000000..e123b96 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/ReadPermissions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8050ef114e01f74409d8e29b821b6fc0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu.meta new file mode 100644 index 0000000..28aeb41 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c38d8297956cf34c9826ebe5fbadff6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs new file mode 100644 index 0000000..c1fe0e5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs @@ -0,0 +1,21 @@ +using FishNet.Documenting; + + +namespace FishNet.Object.Synchronizing.SecretMenu +{ + /// + /// Internal SyncVar extensions. + /// + [APIExclude] + public static class SyncVarExtensions + { + /// + /// Dirties SyncVars. + /// + /// + [APIExclude] + public static void Dirty(this object obj) { } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs.meta new file mode 100644 index 0000000..aa9b282 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SecretMenu/SyncVarExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1f982cd721eb344c88bab105d779127 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs new file mode 100644 index 0000000..e735fbd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs @@ -0,0 +1,53 @@ +using FishNet.Transporting; + +namespace FishNet.Object.Synchronizing.Internal +{ + public class Settings + { + /// + /// Defines the write permissions for this var + /// + public WritePermission WritePermission = WritePermission.ServerOnly; + /// + /// Clients which may receive updated values. + /// + public ReadPermission ReadPermission = ReadPermission.Observers; + /// + /// How often this variable may synchronize. + /// + public float SendTickRate = 0f; + /// + /// Channel to send values on. + /// + public Channel Channel = Channel.Reliable; + + /// + /// Constructs a new NetworkedVarSettings instance + /// + public Settings() + { + + } + + public Settings(WritePermission writePermission, ReadPermission readPermission, float sendTickrate, Channel channel) + { + WritePermission = writePermission; + ReadPermission = readPermission; + SendTickRate = sendTickrate; + Channel = channel; + } + + public Settings(float sendTickrate) + { + SendTickRate = sendTickrate; + } + + public Settings(ReadPermission readPermission, float sendTickrate, Channel channel) + { + ReadPermission = readPermission; + SendTickRate = sendTickrate; + Channel = channel; + } + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs.meta new file mode 100644 index 0000000..2492a21 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/Settings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24688925098da4d42be8dbfa66b88b82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs new file mode 100644 index 0000000..2f08959 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs @@ -0,0 +1,211 @@ +using FishNet.Managing; +using FishNet.Managing.Timing; +using FishNet.Serializing; +using FishNet.Transporting; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object.Synchronizing.Internal +{ + public class SyncBase : ISyncType + { + + #region Public. + /// + /// True if this SyncBase has been registered within it's containing class. + /// + public bool IsRegistered { get; private set; } + /// + /// True if a SyncObject, false if a SyncVar. + /// + public bool IsSyncObject { get; private set; } + /// + /// The settings for this SyncVar. + /// + public Settings Settings = new Settings(); + /// + /// How often updates may send. + /// + public float SendTickRate => Settings.SendTickRate; + /// + /// True if this SyncVar needs to send data. + /// + public bool IsDirty { get; private set; } + /// + /// NetworkManager this uses. + /// + public NetworkManager NetworkManager = null; + /// + /// NetworkBehaviour this SyncVar belongs to. + /// + public NetworkBehaviour NetworkBehaviour = null; + /// + /// Next time a SyncVar may send data/ + /// + public uint NextSyncTick = 0; + /// + /// Index within the sync collection. + /// + public uint SyncIndex { get; protected set; } = 0; + /// + /// Channel to send on. + /// + internal Channel Channel => _currentChannel; + #endregion + + #region Private. + /// + /// Sync interval converted to ticks. + /// + private uint _timeToTicks; + /// + /// Channel to use for next write. To ensure eventual consistency this eventually changes to reliable when Settings are unreliable. + /// + private Channel _currentChannel; + #endregion + + /// + /// Initializes this SyncBase. + /// + public void InitializeInstance(NetworkBehaviour nb, uint syncIndex, WritePermission writePermissions, ReadPermission readPermissions, float tickRate, Channel channel, bool isSyncObject) + { + NetworkBehaviour = nb; + SyncIndex = syncIndex; + _currentChannel = channel; + IsSyncObject = isSyncObject; + Settings = new Settings() + { + WritePermission = writePermissions, + ReadPermission = readPermissions, + SendTickRate = tickRate, + Channel = channel + }; + + NetworkBehaviour.RegisterSyncType(this, SyncIndex); + } + + /// + /// Sets the SyncIndex. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetRegistered() + { + Registered(); + } + + /// + /// Called when the SyncType has been registered, but not yet initialized over the network. + /// + protected virtual void Registered() + { + IsRegistered = true; + } + + /// + /// PreInitializes this for use with the network. + /// + public void PreInitialize(NetworkManager networkManager) + { + NetworkManager = networkManager; + _timeToTicks = NetworkManager.TimeManager.TimeToTicks(Settings.SendTickRate, TickRounding.RoundUp); + } + + /// + /// Called after OnStartXXXX has occurred. + /// + /// True if OnStartServer was called, false if OnStartClient. + protected internal virtual void OnStartCallback(bool asServer) { } + + /// + /// Dirties this Sync and the NetworkBehaviour. + /// + public bool Dirty() + { + /* Reset channel even if already dirty. + * This is because the value might have changed + * which will reset the eventual consistency state. */ + _currentChannel = Settings.Channel; + + /* Once dirty don't undirty until it's + * processed. This ensures that data + * is flushed. */ + bool canDirty = NetworkBehaviour.DirtySyncType(IsSyncObject); + IsDirty |= canDirty; + + return canDirty; + } + + /// + /// Sets IsDirty to false. + /// + internal void ResetDirty() + { + //If not a sync object and using unreliable channel. + if (!IsSyncObject && Settings.Channel == Channel.Unreliable) + { + //Check if dirty can be unset or if another tick must be run using reliable. + if (_currentChannel == Channel.Unreliable) + _currentChannel = Channel.Reliable; + //Already sent reliable, can undirty. Channel will reset next time this dirties. + else + IsDirty = false; + } + //If syncObject or using reliable unset dirty. + else + { + IsDirty = false; + } + } + /// + /// True if dirty and enough time has passed to write changes. + /// + /// + /// + internal bool WriteTimeMet(uint tick) + { + return (IsDirty && tick >= NextSyncTick); + } + /// + /// Writes current value. + /// + /// + /// True to set the next time data may sync. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + WriteHeader(writer, resetSyncTick); + } + /// + /// Writers the header for this SyncType. + /// + /// + /// + protected virtual void WriteHeader(PooledWriter writer, bool resetSyncTick = true) + { + if (resetSyncTick) + NextSyncTick = NetworkManager.TimeManager.Tick + _timeToTicks; + + writer.WriteByte((byte)SyncIndex); + } + /// + /// Writes current value if not initialized value. + /// + /// + public virtual void WriteFull(PooledWriter writer) { } + /// + /// Sets current value. + /// + /// + public virtual void Read(PooledReader reader) { } + /// + /// Resets to initialized values. + /// + public virtual void Reset() + { + NextSyncTick = 0; + ResetDirty(); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs.meta new file mode 100644 index 0000000..9fb0dec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a6f26e3f8016cc499b3fa99e7368fbc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs new file mode 100644 index 0000000..0a59261 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs @@ -0,0 +1,627 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using FishNet.Utility.Extension; +using JetBrains.Annotations; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object.Synchronizing +{ + + public class SyncIDictionary : SyncBase, IDictionary, IReadOnlyDictionary + { + + #region Types. + /// + /// Information needed to invoke a callback. + /// + private struct CachedOnChange + { + internal readonly SyncDictionaryOperation Operation; + internal readonly TKey Key; + internal readonly TValue Value; + + public CachedOnChange(SyncDictionaryOperation operation, TKey key, TValue value) + { + Operation = operation; + Key = key; + Value = value; + } + } + + /// + /// Information about how the collection has changed. + /// + private struct ChangeData + { + internal readonly SyncDictionaryOperation Operation; + internal readonly TKey Key; + internal readonly TValue Value; + + public ChangeData(SyncDictionaryOperation operation, TKey key, TValue value) + { + this.Operation = operation; + this.Key = key; + this.Value = value; + } + } + #endregion + + #region Public. + /// + /// Implementation from Dictionary. Not used. + /// + [APIExclude] + public bool IsReadOnly => false; + /// + /// Delegate signature for when SyncDictionary changes. + /// + /// Operation being completed, such as Add, Set, Remove. + /// Key being modified. + /// Value of operation. + /// True if callback is on the server side. False is on the client side. + [APIExclude] + public delegate void SyncDictionaryChanged(SyncDictionaryOperation op, TKey key, TValue value, bool asServer); + /// + /// Called when the SyncDictionary changes. + /// + public event SyncDictionaryChanged OnChange; + /// + /// Collection of objects. + /// + public readonly IDictionary Collection; + /// + /// Copy of objects on client portion when acting as a host. + /// + public readonly IDictionary ClientHostCollection = new Dictionary(); + /// + /// Number of objects in the collection. + /// + public int Count => Collection.Count; + /// + /// Keys within the collection. + /// + public ICollection Keys => Collection.Keys; + [APIExclude] + IEnumerable IReadOnlyDictionary.Keys => Collection.Keys; + /// + /// Values within the collection. + /// + public ICollection Values => Collection.Values; + [APIExclude] + IEnumerable IReadOnlyDictionary.Values => Collection.Values; + #endregion + + #region Private. + /// + /// Initial values for the dictionary. + /// + private IDictionary _initialValues = new Dictionary(); + /// + /// Changed data which will be sent next tick. + /// + private readonly List _changed = new List(); + /// + /// Server OnChange events waiting for start callbacks. + /// + private readonly List _serverOnChanges = new List(); + /// + /// Client OnChange events waiting for start callbacks. + /// + private readonly List _clientOnChanges = new List(); + /// + /// True if values have changed since initialization. + /// The only reasonable way to reset this during a Reset call is by duplicating the original list and setting all values to it on reset. + /// + private bool _valuesChanged; + /// + /// True to send all values in the next WriteDelta. + /// + private bool _sendAll; + #endregion + + [APIExclude] + public SyncIDictionary(IDictionary objects) + { + this.Collection = objects; + //Add to clienthostcollection. + foreach (KeyValuePair item in objects) + this.ClientHostCollection[item.Key] = item.Value; + } + + /// + /// Gets the collection being used within this SyncList. + /// + /// True if returning the server value, false if client value. The values will only differ when running as host. While asServer is true the most current values on server will be returned, and while false the latest values received by client will be returned. + /// The used collection. + public Dictionary GetCollection(bool asServer) + { + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + IDictionary collection = (asClientAndHost) ? ClientHostCollection : Collection; + return (collection as Dictionary); + } + + /// + /// Called when the SyncType has been registered, but not yet initialized over the network. + /// + protected override void Registered() + { + base.Registered(); + foreach (KeyValuePair item in Collection) + _initialValues[item.Key] = item.Value; + } + + /// + /// Adds an operation and invokes callback locally. + /// Internal use. + /// May be used for custom SyncObjects. + /// + /// + /// + /// + [APIExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddOperation(SyncDictionaryOperation operation, TKey key, TValue value) + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation {operation} as server when server is not active."); + return; + } + + /* Set as changed even if cannot dirty. + * Dirty is only set when there are observers, + * but even if there are not observers + * values must be marked as changed so when + * there are observers, new values are sent. */ + _valuesChanged = true; + + /* If unable to dirty then do not add to changed. + * A dirty may fail if the server is not started + * or if there's no observers. Changed doesn't need + * to be populated in this situations because clients + * will get the full collection on spawn. If we + * were to also add to changed clients would get the full + * collection as well the changed, which would double results. */ + if (base.Dirty()) + { + ChangeData change = new ChangeData(operation, key, value); + _changed.Add(change); + } + + bool asServer = true; + InvokeOnChange(operation, key, value, asServer); + } + + + /// + /// Called after OnStartXXXX has occurred. + /// + /// True if OnStartServer was called, false if OnStartClient. + protected internal override void OnStartCallback(bool asServer) + { + base.OnStartCallback(asServer); + List collection = (asServer) ? _serverOnChanges : _clientOnChanges; + + if (OnChange != null) + { + foreach (CachedOnChange item in collection) + OnChange.Invoke(item.Operation, item.Key, item.Value, asServer); + } + + collection.Clear(); + } + + + /// + /// Writes all changed values. + /// Internal use. + /// May be used for custom SyncObjects. + /// + /// + ///True to set the next time data may sync. + [APIExclude] + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + base.WriteDelta(writer, resetSyncTick); + + //If sending all then clear changed and write full. + if (_sendAll) + { + _sendAll = false; + _changed.Clear(); + WriteFull(writer); + } + else + { + //False for not full write. + writer.WriteBoolean(false); + writer.WriteUInt32((uint)_changed.Count); + + for (int i = 0; i < _changed.Count; i++) + { + ChangeData change = _changed[i]; + writer.WriteByte((byte)change.Operation); + + //Clear does not need to write anymore data so it is not included in checks. + if (change.Operation == SyncDictionaryOperation.Add || + change.Operation == SyncDictionaryOperation.Set) + { + writer.Write(change.Key); + writer.Write(change.Value); + } + else if (change.Operation == SyncDictionaryOperation.Remove) + { + writer.Write(change.Key); + } + } + + _changed.Clear(); + } + } + + + /// + /// Writers all values if not initial values. + /// Internal use. + /// May be used for custom SyncObjects. + /// + /// + [APIExclude] + public override void WriteFull(PooledWriter writer) + { + if (!_valuesChanged) + return; + + base.WriteHeader(writer, false); + //True for full write. + writer.WriteBoolean(true); + writer.WriteUInt32((uint)Collection.Count); + foreach (KeyValuePair item in Collection) + { + writer.WriteByte((byte)SyncDictionaryOperation.Add); + writer.Write(item.Key); + writer.Write(item.Value); + } + } + + + /// + /// Sets current values. + /// Internal use. + /// May be used for custom SyncObjects. + /// + /// + [APIExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Read(PooledReader reader) + { + bool asServer = false; + /* When !asServer don't make changes if server is running. + * This is because changes would have already been made on + * the server side and doing so again would result in duplicates + * and potentially overwrite data not yet sent. */ + bool asClientAndHost = (!asServer && base.NetworkBehaviour.IsServer); + IDictionary collection = (asClientAndHost) ? ClientHostCollection : Collection; + + //Clear collection since it's a full write. + bool fullWrite = reader.ReadBoolean(); + if (fullWrite) + collection.Clear(); + + int changes = (int)reader.ReadUInt32(); + for (int i = 0; i < changes; i++) + { + SyncDictionaryOperation operation = (SyncDictionaryOperation)reader.ReadByte(); + TKey key = default; + TValue value = default; + + /* Add, Set. + * Use the Set code for add and set, + * especially so collection doesn't throw + * if entry has already been added. */ + if (operation == SyncDictionaryOperation.Add || operation == SyncDictionaryOperation.Set) + { + key = reader.Read(); + value = reader.Read(); + collection[key] = value; + } + //Clear. + else if (operation == SyncDictionaryOperation.Clear) + { + collection.Clear(); + } + //Remove. + else if (operation == SyncDictionaryOperation.Remove) + { + key = reader.Read(); + collection.Remove(key); + } + + InvokeOnChange(operation, key, value, false); + } + + //If changes were made invoke complete after all have been read. + if (changes > 0) + InvokeOnChange(SyncDictionaryOperation.Complete, default, default, false); + } + + + /// + /// Invokes OnChanged callback. + /// + private void InvokeOnChange(SyncDictionaryOperation operation, TKey key, TValue value, bool asServer) + { + if (asServer) + { + if (base.NetworkBehaviour.OnStartServerCalled) + OnChange?.Invoke(operation, key, value, asServer); + else + _serverOnChanges.Add(new CachedOnChange(operation, key, value)); + } + else + { + if (base.NetworkBehaviour.OnStartClientCalled) + OnChange?.Invoke(operation, key, value, asServer); + else + _clientOnChanges.Add(new CachedOnChange(operation, key, value)); + } + } + + + /// + /// Resets to initialized values. + /// + [APIExclude] + public override void Reset() + { + base.Reset(); + _sendAll = false; + _changed.Clear(); + Collection.Clear(); + ClientHostCollection.Clear(); + _valuesChanged = false; + + foreach (KeyValuePair item in _initialValues) + { + Collection[item.Key] = item.Value; + ClientHostCollection[item.Key] = item.Value; + } + } + + + /// + /// Adds item. + /// + /// Item to add. + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + /// + /// Adds key and value. + /// + /// Key to add. + /// Value for key. + public void Add(TKey key, TValue value) + { + Add(key, value, true); + } + private void Add(TKey key, TValue value, bool asServer) + { + Collection.Add(key, value); + if (asServer) + AddOperation(SyncDictionaryOperation.Add, key, value); + } + + /// + /// Clears all values. + /// + public void Clear() + { + Clear(true); + } + private void Clear(bool asServer) + { + Collection.Clear(); + if (asServer) + AddOperation(SyncDictionaryOperation.Clear, default, default); + } + + + /// + /// Returns if key exist. + /// + /// Key to use. + /// True if found. + public bool ContainsKey(TKey key) + { + return Collection.ContainsKey(key); + } + /// + /// Returns if item exist. + /// + /// Item to use. + /// True if found. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(KeyValuePair item) + { + return TryGetValue(item.Key, out TValue value) && EqualityComparer.Default.Equals(value, item.Value); + } + + /// + /// Copies collection to an array. + /// + /// Array to copy to. + /// Offset of array data is copied to. + public void CopyTo([NotNull] KeyValuePair[] array, int offset) + { + if (offset <= -1 || offset >= array.Length) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Index is out of range."); + return; + } + + int remaining = array.Length - offset; + if (remaining < Count) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Array is not large enough to copy data. Array is of length {array.Length}, index is {offset}, and number of values to be copied is {Count.ToString()}."); + return; + } + + int i = offset; + foreach (KeyValuePair item in Collection) + { + array[i] = item; + i++; + } + } + + + /// + /// Removes a key. + /// + /// Key to remove. + /// True if removed. + public bool Remove(TKey key) + { + if (Collection.Remove(key)) + { + AddOperation(SyncDictionaryOperation.Remove, key, default); + return true; + } + + return false; + } + + + /// + /// Removes an item. + /// + /// Item to remove. + /// True if removed. + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + /// + /// Tries to get value from key. + /// + /// Key to use. + /// Variable to output to. + /// True if able to output value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(TKey key, out TValue value) + { + return Collection.TryGetValueIL2CPP(key, out value); + } + + /// + /// Gets or sets value for a key. + /// + /// Key to use. + /// Value when using as Get. + public TValue this[TKey key] + { + get => Collection[key]; + set + { + Collection[key] = value; + AddOperation(SyncDictionaryOperation.Set, key, value); + } + } + + /// + /// Dirties the entire collection forcing a full send. + /// + public void DirtyAll() + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + if (base.Dirty()) + _sendAll = true; + } + + /// + /// Dirties an entry by key. + /// + /// Key to dirty. + public void Dirty(TKey key) + { + if (Collection.TryGetValueIL2CPP(key, out TValue value)) + AddOperation(SyncDictionaryOperation.Set, key, value); + } + + /// + /// Dirties an entry by value. + /// This operation can be very expensive, will cause allocations, and may fail if your value cannot be compared. + /// + /// Value to dirty. + /// True if value was found and marked dirty. + public bool Dirty(TValue value, EqualityComparer comparer = null) + { + if (comparer == null) + comparer = EqualityComparer.Default; + + foreach (KeyValuePair item in Collection) + { + if (comparer.Equals(item.Value, value)) + { + AddOperation(SyncDictionaryOperation.Set, item.Key, value); + return true; + } + } + + //Not found. + return false; + } + + /// + /// Gets the IEnumerator for the collection. + /// + /// + public IEnumerator> GetEnumerator() => Collection.GetEnumerator(); + /// + /// Gets the IEnumerator for the collection. + /// + /// + IEnumerator IEnumerable.GetEnumerator() => Collection.GetEnumerator(); + + } + + [APIExclude] + public class SyncDictionary : SyncIDictionary + { + [APIExclude] + public SyncDictionary() : base(new Dictionary()) { } + [APIExclude] + public SyncDictionary(IEqualityComparer eq) : base(new Dictionary(eq)) { } + [APIExclude] + public new Dictionary.ValueCollection Values => ((Dictionary)Collection).Values; + [APIExclude] + public new Dictionary.KeyCollection Keys => ((Dictionary)Collection).Keys; + [APIExclude] + public new Dictionary.Enumerator GetEnumerator() => ((Dictionary)Collection).GetEnumerator(); + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs.meta new file mode 100644 index 0000000..10242a2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54751f912587a854cb61ff80a82087bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs new file mode 100644 index 0000000..7f9913f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs @@ -0,0 +1,31 @@ + +using FishNet.Documenting; + +namespace FishNet.Object.Synchronizing +{ + [APIExclude] + public enum SyncDictionaryOperation : byte + { + /// + /// A key and value have been added to the collection. + /// + Add, + /// + /// Collection has been cleared. + /// + Clear, + /// + /// A key was removed from the collection. + /// + Remove, + /// + /// A value has been set for a key in the collection. + /// + Set, + /// + /// All operations for the tick have been processed. + /// + Complete + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs.meta new file mode 100644 index 0000000..2b2b24c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionaryOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5d6ed9db47a8224fa9ed4d2ff54586f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs new file mode 100644 index 0000000..01017b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs @@ -0,0 +1,31 @@ + +using FishNet.Documenting; + +namespace FishNet.Object.Synchronizing +{ + [APIExclude] + public enum SyncHashSetOperation : byte + { + /// + /// An item is added to the collection. + /// + Add, + /// + /// An item is removed from the collection. + /// + Remove, + /// + /// Collection is cleared. + /// + Clear, + /// + /// All operations for the tick have been processed. This only occurs on clients as the server is unable to be aware of when the user is done modifying the list. + /// + Complete, + /// + /// An item has been updated within the collection. This is generally used when modifying data within a container. + /// + Update, + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs.meta new file mode 100644 index 0000000..2d909a8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashSetOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 914089f5707003340a68fd6cd718e4c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs new file mode 100644 index 0000000..6c46e73 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs @@ -0,0 +1,626 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Utility.Performance; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object.Synchronizing +{ + + public class SyncHashSet : SyncBase, ISet + { + #region Types. + /// + /// Information needed to invoke a callback. + /// + private struct CachedOnChange + { + internal readonly SyncHashSetOperation Operation; + internal readonly T Item; + + public CachedOnChange(SyncHashSetOperation operation, T item) + { + Operation = operation; + Item = item; + } + } + + /// + /// Information about how the collection has changed. + /// + private struct ChangeData + { + internal readonly SyncHashSetOperation Operation; + internal readonly T Item; + + public ChangeData(SyncHashSetOperation operation, T item) + { + Operation = operation; + + Item = item; + } + } + #endregion + + #region Public. + /// + /// Implementation from List. Not used. + /// + [APIExclude] + public bool IsReadOnly => false; + /// + /// Delegate signature for when SyncList changes. + /// + /// Type of change. + /// Item which was modified. + /// True if callback is occuring on the server. + [APIExclude] + public delegate void SyncHashSetChanged(SyncHashSetOperation op, T item, bool asServer); + /// + /// Called when the SyncList changes. + /// + public event SyncHashSetChanged OnChange; + /// + /// Collection of objects. + /// + public readonly ISet Collection; + /// + /// Copy of objects on client portion when acting as a host. + /// + public readonly ISet ClientHostCollection = new HashSet(); + /// + /// Number of objects in the collection. + /// + public int Count => Collection.Count; + #endregion + + #region Private. + /// + /// ListCache for comparing. + /// + private ListCache _listCache; + /// + /// Values upon initialization. + /// + private ISet _initialValues = new HashSet(); + /// + /// Comparer to see if entries change when calling public methods. + /// + private readonly IEqualityComparer _comparer; + /// + /// Changed data which will be sent next tick. + /// + private readonly List _changed = new List(); + /// + /// Server OnChange events waiting for start callbacks. + /// + private readonly List _serverOnChanges = new List(); + /// + /// Client OnChange events waiting for start callbacks. + /// + private readonly List _clientOnChanges = new List(); + /// + /// True if values have changed since initialization. + /// The only reasonable way to reset this during a Reset call is by duplicating the original list and setting all values to it on reset. + /// + private bool _valuesChanged; + /// + /// True to send all values in the next WriteDelta. + /// + private bool _sendAll; + #endregion + + [APIExclude] + public SyncHashSet() : this(new HashSet(), EqualityComparer.Default) { } + [APIExclude] + public SyncHashSet(IEqualityComparer comparer) : this(new HashSet(), (comparer == null) ? EqualityComparer.Default : comparer) { } + [APIExclude] + public SyncHashSet(ISet collection, IEqualityComparer comparer = null) + { + this._comparer = (comparer == null) ? EqualityComparer.Default : comparer; + this.Collection = collection; + //Add each in collection to clienthostcollection. + foreach (T item in collection) + ClientHostCollection.Add(item); + } + + /// + /// Called when the SyncType has been registered, but not yet initialized over the network. + /// + protected override void Registered() + { + base.Registered(); + foreach (T item in Collection) + _initialValues.Add(item); + } + + /// + /// Gets the collection being used within this SyncList. + /// + /// + public HashSet GetCollection(bool asServer) + { + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + ISet collection = (asClientAndHost) ? ClientHostCollection : Collection; + return (collection as HashSet); + } + + /// + /// Adds an operation and invokes locally. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddOperation(SyncHashSetOperation operation, T item) + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + /* Set as changed even if cannot dirty. + * Dirty is only set when there are observers, + * but even if there are not observers + * values must be marked as changed so when + * there are observers, new values are sent. */ + _valuesChanged = true; + + /* If unable to dirty then do not add to changed. + * A dirty may fail if the server is not started + * or if there's no observers. Changed doesn't need + * to be populated in this situations because clients + * will get the full collection on spawn. If we + * were to also add to changed clients would get the full + * collection as well the changed, which would double results. */ + if (base.Dirty()) + { + ChangeData change = new ChangeData(operation, item); + _changed.Add(change); + } + + bool asServer = true; + InvokeOnChange(operation, item, asServer); + } + + /// + /// Called after OnStartXXXX has occurred. + /// + /// True if OnStartServer was called, false if OnStartClient. + protected internal override void OnStartCallback(bool asServer) + { + base.OnStartCallback(asServer); + List collection = (asServer) ? _serverOnChanges : _clientOnChanges; + if (OnChange != null) + { + foreach (CachedOnChange item in collection) + OnChange.Invoke(item.Operation, item.Item, asServer); + } + + collection.Clear(); + } + + /// + /// Writes all changed values. + /// + /// + ///True to set the next time data may sync. + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + //If sending all then clear changed and write full. + if (_sendAll) + { + _sendAll = false; + _changed.Clear(); + WriteFull(writer); + } + else + { + base.WriteDelta(writer, resetSyncTick); + //False for not full write. + writer.WriteBoolean(false); + writer.WriteUInt32((uint)_changed.Count); + + for (int i = 0; i < _changed.Count; i++) + { + ChangeData change = _changed[i]; + writer.WriteByte((byte)change.Operation); + + //Clear does not need to write anymore data so it is not included in checks. + if (change.Operation == SyncHashSetOperation.Add || change.Operation == SyncHashSetOperation.Remove || change.Operation == SyncHashSetOperation.Update) + { + writer.Write(change.Item); + } + } + + _changed.Clear(); + } + } + + /// + /// Writes all values if not initial values. + /// + /// + public override void WriteFull(PooledWriter writer) + { + if (!_valuesChanged) + return; + + base.WriteHeader(writer, false); + //True for full write. + writer.WriteBoolean(true); + int count = Collection.Count; + writer.WriteUInt32((uint)count); + foreach (T item in Collection) + { + writer.WriteByte((byte)SyncHashSetOperation.Add); + writer.Write(item); + } + } + + /// + /// Sets current values. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [APIExclude] + public override void Read(PooledReader reader) + { + bool asServer = false; + /* When !asServer don't make changes if server is running. + * This is because changes would have already been made on + * the server side and doing so again would result in duplicates + * and potentially overwrite data not yet sent. */ + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + ISet collection = (asClientAndHost) ? ClientHostCollection : Collection; + + //Clear collection since it's a full write. + bool fullWrite = reader.ReadBoolean(); + if (fullWrite) + collection.Clear(); + + int changes = (int)reader.ReadUInt32(); + for (int i = 0; i < changes; i++) + { + SyncHashSetOperation operation = (SyncHashSetOperation)reader.ReadByte(); + T next = default; + + //Add. + if (operation == SyncHashSetOperation.Add) + { + next = reader.Read(); + collection.Add(next); + } + //Clear. + else if (operation == SyncHashSetOperation.Clear) + { + collection.Clear(); + } + //Remove. + else if (operation == SyncHashSetOperation.Remove) + { + next = reader.Read(); + collection.Remove(next); + } + //Updated. + else if (operation == SyncHashSetOperation.Update) + { + next = reader.Read(); + collection.Remove(next); + collection.Add(next); + } + + InvokeOnChange(operation, next, false); + } + + //If changes were made invoke complete after all have been read. + if (changes > 0) + InvokeOnChange(SyncHashSetOperation.Complete, default, false); + } + + /// + /// Invokes OnChanged callback. + /// + private void InvokeOnChange(SyncHashSetOperation operation, T item, bool asServer) + { + if (asServer) + { + if (base.NetworkBehaviour.OnStartServerCalled) + OnChange?.Invoke(operation, item, asServer); + else + _serverOnChanges.Add(new CachedOnChange(operation, item)); + } + else + { + if (base.NetworkBehaviour.OnStartClientCalled) + OnChange?.Invoke(operation, item, asServer); + else + _clientOnChanges.Add(new CachedOnChange(operation, item)); + } + } + + /// + /// Resets to initialized values. + /// + public override void Reset() + { + base.Reset(); + _sendAll = false; + _changed.Clear(); + Collection.Clear(); + ClientHostCollection.Clear(); + + foreach (T item in _initialValues) + { + Collection.Add(item); + ClientHostCollection.Add(item); + } + } + + /// + /// Adds value. + /// + /// + public bool Add(T item) + { + return Add(item, true); + } + private bool Add(T item, bool asServer) + { + bool result = Collection.Add(item); + //Only process if remove was successful. + if (result && asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Add(item); + AddOperation(SyncHashSetOperation.Add, item); + } + + return result; + } + /// + /// Adds a range of values. + /// + /// + public void AddRange(IEnumerable range) + { + foreach (T entry in range) + Add(entry, true); + } + + /// + /// Clears all values. + /// + public void Clear() + { + Clear(true); + } + private void Clear(bool asServer) + { + Collection.Clear(); + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Clear(); + AddOperation(SyncHashSetOperation.Clear, default); + } + } + + /// + /// Returns if value exist. + /// + /// + /// + public bool Contains(T item) + { + return Collection.Contains(item); + } + + /// + /// Removes a value. + /// + /// + /// + public bool Remove(T item) + { + return Remove(item, true); + } + private bool Remove(T item, bool asServer) + { + bool result = Collection.Remove(item); + //Only process if remove was successful. + if (result && asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Remove(item); + AddOperation(SyncHashSetOperation.Remove, item); + } + + return result; + } + + /// + /// Dirties the entire collection forcing a full send. + /// + public void DirtyAll() + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + if (base.Dirty()) + _sendAll = true; + } + + /// + /// Looks up obj in Collection and if found marks it's index as dirty. + /// This operation can be very expensive, will cause allocations, and may fail if your value cannot be compared. + /// + /// Object to lookup. + public void Dirty(T obj) + { + foreach (T item in Collection) + { + if (item.Equals(obj)) + { + AddOperation(SyncHashSetOperation.Update, obj); + return; + } + } + + //Not found. + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Could not find object within SyncHashSet, dirty will not be set."); + } + + /// + /// Returns Enumerator for collection. + /// + /// + public IEnumerator GetEnumerator() => Collection.GetEnumerator(); + [APIExclude] + IEnumerator IEnumerable.GetEnumerator() => Collection.GetEnumerator(); + [APIExclude] + IEnumerator IEnumerable.GetEnumerator() => Collection.GetEnumerator(); + + public void ExceptWith(IEnumerable other) + { + //Again, removing from self is a clear. + if (other == Collection) + { + Clear(); + } + else + { + foreach (T item in other) + Remove(item); + } + } + + public void IntersectWith(IEnumerable other) + { + ISet set; + if (other is ISet setA) + set = setA; + else + set = new HashSet(other); + + IntersectWith(set); + } + + private void IntersectWith(ISet other) + { + Intersect(Collection); + if (base.NetworkManager == null) + Intersect(ClientHostCollection); + + void Intersect(ISet collection) + { + if (_listCache == null) + _listCache = new ListCache(); + else + _listCache.Reset(); + + _listCache.AddValues(collection); + + int count = _listCache.Written; + for (int i = 0; i < count; i++) + { + T entry = _listCache.Collection[i]; + if (!other.Contains(entry)) + Remove(entry); + } + } + + } + + public bool IsProperSubsetOf(IEnumerable other) + { + return Collection.IsProperSubsetOf(other); + } + + public bool IsProperSupersetOf(IEnumerable other) + { + return Collection.IsProperSupersetOf(other); + } + + public bool IsSubsetOf(IEnumerable other) + { + return Collection.IsSubsetOf(other); + } + + public bool IsSupersetOf(IEnumerable other) + { + return Collection.IsSupersetOf(other); + } + + public bool Overlaps(IEnumerable other) + { + bool result = Collection.Overlaps(other); + return result; + } + + public bool SetEquals(IEnumerable other) + { + return Collection.SetEquals(other); + } + + public void SymmetricExceptWith(IEnumerable other) + { + //If calling except on self then that is the same as a clear. + if (other == Collection) + { + Clear(); + } + else + { + foreach (T item in other) + Remove(item); + } + } + + public void UnionWith(IEnumerable other) + { + if (other == Collection) + return; + + foreach (T item in other) + Add(item); + } + + /// + /// Adds an item. + /// + /// + void ICollection.Add(T item) + { + Add(item, true); + } + + /// + /// Copies values to an array. + /// + /// + /// + public void CopyTo(T[] array, int index) + { + Collection.CopyTo(array, index); + if (base.NetworkManager == null) + ClientHostCollection.CopyTo(array, index); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs.meta new file mode 100644 index 0000000..47a2d07 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncHashset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 624322b9d999d4b43a560134460955c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs new file mode 100644 index 0000000..18dac47 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs @@ -0,0 +1,731 @@ +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object.Synchronizing +{ + + public class SyncList : SyncBase, IList, IReadOnlyList + { + #region Types. + /// + /// Information needed to invoke a callback. + /// + private struct CachedOnChange + { + internal readonly SyncListOperation Operation; + internal readonly int Index; + internal readonly T Previous; + internal readonly T Next; + + public CachedOnChange(SyncListOperation operation, int index, T previous, T next) + { + Operation = operation; + Index = index; + Previous = previous; + Next = next; + } + } + + /// + /// Information about how the collection has changed. + /// + private struct ChangeData + { + internal readonly SyncListOperation Operation; + internal readonly int Index; + internal readonly T Item; + + public ChangeData(SyncListOperation operation, int index, T item) + { + Operation = operation; + Index = index; + Item = item; + } + } + + /// + /// Custom enumerator to prevent garbage collection. + /// + [APIExclude] + public struct Enumerator : IEnumerator + { + public T Current { get; private set; } + private readonly SyncList _list; + private int _index; + + public Enumerator(SyncList list) + { + this._list = list; + _index = -1; + Current = default; + } + + public bool MoveNext() + { + _index++; + if (_index >= _list.Count) + return false; + Current = _list[_index]; + return true; + } + + public void Reset() => _index = -1; + object IEnumerator.Current => Current; + public void Dispose() { } + } + #endregion + + #region Public. + /// + /// Implementation from List. Not used. + /// + [APIExclude] + public bool IsReadOnly => false; + /// + /// Delegate signature for when SyncList changes. + /// + /// + /// + /// + /// + [APIExclude] + public delegate void SyncListChanged(SyncListOperation op, int index, T oldItem, T newItem, bool asServer); + /// + /// Called when the SyncList changes. + /// + public event SyncListChanged OnChange; + /// + /// Collection of objects. + /// + public readonly IList Collection; + /// + /// Copy of objects on client portion when acting as a host. + /// + public readonly IList ClientHostCollection = new List(); + /// + /// Number of objects in the collection. + /// + public int Count => Collection.Count; + #endregion + + #region Private. + /// + /// Values upon initialization. + /// + private IList _initialValues = new List(); + /// + /// Comparer to see if entries change when calling public methods. + /// + private readonly IEqualityComparer _comparer; + /// + /// Changed data which will be sent next tick. + /// + private readonly List _changed = new List(); + /// + /// Server OnChange events waiting for start callbacks. + /// + private readonly List _serverOnChanges = new List(); + /// + /// Client OnChange events waiting for start callbacks. + /// + private readonly List _clientOnChanges = new List(); + /// + /// True if values have changed since initialization. + /// The only reasonable way to reset this during a Reset call is by duplicating the original list and setting all values to it on reset. + /// + private bool _valuesChanged; + /// + /// True to send all values in the next WriteDelta. + /// + private bool _sendAll; + #endregion + + [APIExclude] + public SyncList() : this(new List(), EqualityComparer.Default) { } + [APIExclude] + public SyncList(IEqualityComparer comparer) : this(new List(), (comparer == null) ? EqualityComparer.Default : comparer) { } + [APIExclude] + public SyncList(IList collection, IEqualityComparer comparer = null) + { + this._comparer = (comparer == null) ? EqualityComparer.Default : comparer; + this.Collection = collection; + //Add each in collection to clienthostcollection. + foreach (T item in collection) + this.ClientHostCollection.Add(item); + } + + /// + /// Called when the SyncType has been registered, but not yet initialized over the network. + /// + protected override void Registered() + { + base.Registered(); + foreach (T item in Collection) + _initialValues.Add(item); + } + + /// + /// Gets the collection being used within this SyncList. + /// + /// True if returning the server value, false if client value. The values will only differ when running as host. While asServer is true the most current values on server will be returned, and while false the latest values received by client will be returned. + /// + public List GetCollection(bool asServer) + { + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + IList collection = (asClientAndHost) ? ClientHostCollection : Collection; + return (collection as List); + } + + /// + /// Adds an operation and invokes locally. + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddOperation(SyncListOperation operation, int index, T prev, T next) + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + /* Set as changed even if cannot dirty. + * Dirty is only set when there are observers, + * but even if there are not observers + * values must be marked as changed so when + * there are observers, new values are sent. */ + _valuesChanged = true; + + /* If unable to dirty then do not add to changed. + * A dirty may fail if the server is not started + * or if there's no observers. Changed doesn't need + * to be populated in this situations because clients + * will get the full collection on spawn. If we + * were to also add to changed clients would get the full + * collection as well the changed, which would double results. */ + if (base.Dirty()) + { + ChangeData change = new ChangeData(operation, index, next); + _changed.Add(change); + } + bool asServer = true; + InvokeOnChange(operation, index, prev, next, asServer); + } + + /// + /// Called after OnStartXXXX has occurred. + /// + /// True if OnStartServer was called, false if OnStartClient. + protected internal override void OnStartCallback(bool asServer) + { + base.OnStartCallback(asServer); + List collection = (asServer) ? _serverOnChanges : _clientOnChanges; + + if (OnChange != null) + { + foreach (CachedOnChange item in collection) + OnChange.Invoke(item.Operation, item.Index, item.Previous, item.Next, asServer); + } + + collection.Clear(); + } + + /// + /// Writes all changed values. + /// + /// + ///True to set the next time data may sync. + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + //If sending all then clear changed and write full. + if (_sendAll) + { + _sendAll = false; + _changed.Clear(); + WriteFull(writer); + } + else + { + base.WriteDelta(writer, resetSyncTick); + //False for not full write. + writer.WriteBoolean(false); + writer.WriteUInt32((uint)_changed.Count); + + for (int i = 0; i < _changed.Count; i++) + { + ChangeData change = _changed[i]; + writer.WriteByte((byte)change.Operation); + + //Clear does not need to write anymore data so it is not included in checks. + if (change.Operation == SyncListOperation.Add) + { + writer.Write(change.Item); + } + else if (change.Operation == SyncListOperation.RemoveAt) + { + writer.WriteUInt32((uint)change.Index); + } + else if (change.Operation == SyncListOperation.Insert || change.Operation == SyncListOperation.Set) + { + writer.WriteUInt32((uint)change.Index); + writer.Write(change.Item); + } + } + + _changed.Clear(); + } + } + + /// + /// Writes all values if not initial values. + /// + /// + public override void WriteFull(PooledWriter writer) + { + if (!_valuesChanged) + return; + + base.WriteHeader(writer, false); + //True for full write. + writer.WriteBoolean(true); + writer.WriteUInt32((uint)Collection.Count); + for (int i = 0; i < Collection.Count; i++) + { + writer.WriteByte((byte)SyncListOperation.Add); + writer.Write(Collection[i]); + } + } + + /// + /// Sets current values. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [APIExclude] + public override void Read(PooledReader reader) + { + bool asServer = false; + /* When !asServer don't make changes if server is running. + * This is because changes would have already been made on + * the server side and doing so again would result in duplicates + * and potentially overwrite data not yet sent. */ + bool asClientAndHost = (!asServer && base.NetworkManager.IsServer); + IList collection = (asClientAndHost) ? ClientHostCollection : Collection; + + //Clear collection since it's a full write. + bool fullWrite = reader.ReadBoolean(); + if (fullWrite) + collection.Clear(); + + int changes = (int)reader.ReadUInt32(); + + for (int i = 0; i < changes; i++) + { + SyncListOperation operation = (SyncListOperation)reader.ReadByte(); + int index = -1; + T prev = default; + T next = default; + + //Add. + if (operation == SyncListOperation.Add) + { + next = reader.Read(); + index = collection.Count; + collection.Add(next); + } + //Clear. + else if (operation == SyncListOperation.Clear) + { + collection.Clear(); + } + //Insert. + else if (operation == SyncListOperation.Insert) + { + index = (int)reader.ReadUInt32(); + next = reader.Read(); + collection.Insert(index, next); + } + //RemoveAt. + else if (operation == SyncListOperation.RemoveAt) + { + index = (int)reader.ReadUInt32(); + prev = collection[index]; + collection.RemoveAt(index); + } + //Set + else if (operation == SyncListOperation.Set) + { + index = (int)reader.ReadUInt32(); + next = reader.Read(); + prev = collection[index]; + collection[index] = next; + } + + InvokeOnChange(operation, index, prev, next, false); + } + + //If changes were made invoke complete after all have been read. + if (changes > 0) + InvokeOnChange(SyncListOperation.Complete, -1, default, default, false); + } + + /// + /// Invokes OnChanged callback. + /// + private void InvokeOnChange(SyncListOperation operation, int index, T prev, T next, bool asServer) + { + if (asServer) + { + if (base.NetworkBehaviour.OnStartServerCalled) + OnChange?.Invoke(operation, index, prev, next, asServer); + else + _serverOnChanges.Add(new CachedOnChange(operation, index, prev, next)); + } + else + { + if (base.NetworkBehaviour.OnStartClientCalled) + OnChange?.Invoke(operation, index, prev, next, asServer); + else + _clientOnChanges.Add(new CachedOnChange(operation, index, prev, next)); + } + } + + /// + /// Resets to initialized values. + /// + public override void Reset() + { + base.Reset(); + _sendAll = false; + _changed.Clear(); + ClientHostCollection.Clear(); + Collection.Clear(); + + foreach (T item in _initialValues) + { + Collection.Add(item); + ClientHostCollection.Add(item); + } + } + + + /// + /// Adds value. + /// + /// + public void Add(T item) + { + Add(item, true); + } + private void Add(T item, bool asServer) + { + Collection.Add(item); + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Add(item); + AddOperation(SyncListOperation.Add, Collection.Count - 1, default, item); + } + } + /// + /// Adds a range of values. + /// + /// + public void AddRange(IEnumerable range) + { + foreach (T entry in range) + Add(entry, true); + } + + /// + /// Clears all values. + /// + public void Clear() + { + Clear(true); + } + private void Clear(bool asServer) + { + Collection.Clear(); + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Clear(); + AddOperation(SyncListOperation.Clear, -1, default, default); + } + } + + /// + /// Returns if value exist. + /// + /// + /// + public bool Contains(T item) + { + return (IndexOf(item) >= 0); + } + + /// + /// Copies values to an array. + /// + /// + /// + public void CopyTo(T[] array, int index) + { + Collection.CopyTo(array, index); + } + + /// + /// Gets the index of value. + /// + /// + /// + public int IndexOf(T item) + { + for (int i = 0; i < Collection.Count; ++i) + if (_comparer.Equals(item, Collection[i])) + return i; + return -1; + } + + /// + /// Finds index using match. + /// + /// + /// + public int FindIndex(Predicate match) + { + for (int i = 0; i < Collection.Count; ++i) + if (match(Collection[i])) + return i; + return -1; + } + + /// + /// Finds value using match. + /// + /// + /// + public T Find(Predicate match) + { + int i = FindIndex(match); + return (i != -1) ? Collection[i] : default; + } + + /// + /// Finds all values using match. + /// + /// + /// + public List FindAll(Predicate match) + { + List results = new List(); + for (int i = 0; i < Collection.Count; ++i) + if (match(Collection[i])) + results.Add(Collection[i]); + return results; + } + + /// + /// Inserts value at index. + /// + /// + /// + public void Insert(int index, T item) + { + Insert(index, item, true); + } + private void Insert(int index, T item, bool asServer) + { + Collection.Insert(index, item); + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.Insert(index, item); + AddOperation(SyncListOperation.Insert, index, default, item); + } + } + + /// + /// Inserts a range of values. + /// + /// + /// + public void InsertRange(int index, IEnumerable range) + { + foreach (T entry in range) + { + Insert(index, entry); + index++; + } + } + + /// + /// Removes a value. + /// + /// + /// + public bool Remove(T item) + { + int index = IndexOf(item); + bool result = index >= 0; + if (result) + RemoveAt(index); + + return result; + } + + /// + /// Removes value at index. + /// + /// + /// + public void RemoveAt(int index) + { + RemoveAt(index, true); + } + private void RemoveAt(int index, bool asServer) + { + T oldItem = Collection[index]; + Collection.RemoveAt(index); + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection.RemoveAt(index); + AddOperation(SyncListOperation.RemoveAt, index, oldItem, default); + } + } + + /// + /// Removes all values within the collection. + /// + /// + /// + public int RemoveAll(Predicate match) + { + List toRemove = new List(); + for (int i = 0; i < Collection.Count; ++i) + if (match(Collection[i])) + toRemove.Add(Collection[i]); + + foreach (T entry in toRemove) + Remove(entry); + + return toRemove.Count; + } + + /// + /// Gets or sets value at an index. + /// + /// + /// + public T this[int i] + { + get => Collection[i]; + set => Set(i, value, true, true); + } + + /// + /// Dirties the entire collection forcing a full send. + /// This will not invoke the callback on server. + /// + public void DirtyAll() + { + if (!base.IsRegistered) + return; + + if (base.NetworkManager != null && base.Settings.WritePermission == WritePermission.ServerOnly && !base.NetworkBehaviour.IsServer) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot complete operation as server when server is not active."); + return; + } + + if (base.Dirty()) + _sendAll = true; + } + + /// + /// Looks up obj in Collection and if found marks it's index as dirty. + /// While using this operation previous value will be the same as next. + /// This operation can be very expensive, and may fail if your value cannot be compared. + /// + /// Object to lookup. + public void Dirty(T obj) + { + int index = Collection.IndexOf(obj); + if (index != -1) + { + Dirty(index); + } + else + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Could not find object within SyncList, dirty will not be set."); + } + } + /// + /// Marks an index as dirty. + /// While using this operation previous value will be the same as next. + /// + /// + public void Dirty(int index) + { + bool asServer = true; + + T value = Collection[index]; + if (asServer) + AddOperation(SyncListOperation.Set, index, value, value); + } + /// + /// Sets value at index. + /// + /// + /// + public void Set(int index, T value, bool force = true) + { + Set(index, value, true, force); + } + private void Set(int index, T value, bool asServer, bool force) + { + bool sameValue = (!force && !_comparer.Equals(Collection[index], value)); + if (!sameValue) + { + T prev = Collection[index]; + Collection[index] = value; + if (asServer) + { + if (base.NetworkManager == null) + ClientHostCollection[index] = value; + AddOperation(SyncListOperation.Set, index, prev, value); + } + } + } + + + /// + /// Returns Enumerator for collection. + /// + /// + public Enumerator GetEnumerator() => new Enumerator(this); + [APIExclude] + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + [APIExclude] + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs.meta new file mode 100644 index 0000000..ba053ad --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f3a4c0d0a34e5142be66143d732c079 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs new file mode 100644 index 0000000..324ac62 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs @@ -0,0 +1,35 @@ + +using FishNet.Documenting; + +namespace FishNet.Object.Synchronizing +{ + [APIExclude] + public enum SyncListOperation : byte + { + /// + /// An item is added to the collection. + /// + Add, + /// + /// An item is inserted into the collection. + /// + Insert, + /// + /// An item is set in the collection. + /// + Set, + /// + /// An item is removed from the collection. + /// + RemoveAt, + /// + /// Collection is cleared. + /// + Clear, + /// + /// All operations for the tick have been processed. This only occurs on clients as the server is unable to be aware of when the user is done modifying the list. + /// + Complete + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs.meta new file mode 100644 index 0000000..a87c886 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncListOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4fa53fc807605df4997f0b63a6570bcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs new file mode 100644 index 0000000..ada21d9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs @@ -0,0 +1,286 @@ +using FishNet.Documenting; +using FishNet.Object.Helping; +using FishNet.Object.Synchronizing; +using FishNet.Object.Synchronizing.Internal; +using FishNet.Serializing; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace FishNet.Object.Synchronizing +{ + [APIExclude] + [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)] + public class SyncVar : SyncBase + { + #region Types. + /// + /// Information needed to invoke a callback. + /// + private struct CachedOnChange + { + internal readonly T Previous; + internal readonly T Next; + + public CachedOnChange(T previous, T next) + { + Previous = previous; + Next = next; + } + } + #endregion + + #region Public. + /// + /// Called when the SyncDictionary changes. + /// + public event Action OnChange; + #endregion + + #region Private. + /// + /// Server OnChange event waiting for start callbacks. + /// + private CachedOnChange? _serverOnChange; + /// + /// Client OnChange event waiting for start callbacks. + /// + private CachedOnChange? _clientOnChange; + /// + /// Value before the network is initialized on the containing object. + /// + private T _initialValue; + /// + /// Previous value on the client. + /// + private T _previousClientValue; + /// + /// Current value on the server, or client. + /// + private T _value; + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public SyncVar(NetworkBehaviour nb, uint syncIndex, WritePermission writePermission, ReadPermission readPermission, float sendRate, Channel channel, T value) + { + SetInitialValues(value); + base.InitializeInstance(nb, syncIndex, writePermission, readPermission, sendRate, channel, false); + } + + /// + /// Called when the SyncType has been registered, but not yet initialized over the network. + /// + protected override void Registered() + { + base.Registered(); + _initialValue = _value; + } + + /// + /// Sets initial values to next. + /// + /// + private void SetInitialValues(T next) + { + _initialValue = next; + UpdateValues(next); + } + /// + /// Sets current and previous values. + /// + /// + private void UpdateValues(T next) + { + _previousClientValue = next; + _value = next; + } + /// + /// Sets current value and marks the SyncVar dirty when able to. Returns if able to set value. + /// + /// True if SetValue was called in response to user code. False if from automated code. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetValue(T nextValue, bool calledByUser) + { + /* 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. */ + if (!base.IsRegistered) + return; + /* Don't include warning about setting values when not server. + * SyncVars have an option to exclude owner when synchronizing + * because the client may need to change values locally only. */ + + bool isServer = base.NetworkBehaviour.IsServer; + bool isClient = base.NetworkBehaviour.IsClient; + /* 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 + * but checks cannot be processed because they would otherwise + * stop setting the value. */ + bool skipChecks = (!isClient && !isServer); + + //Object is deinitializing. + if (!skipChecks && CodegenHelper.NetworkObject_Deinitializing(this.NetworkBehaviour)) + return; + + //If setting as server. + if (calledByUser) + { + /* If skipping checks there's no need to dirty. + * Value is expected to be set on server and client since + * it's being set before the object is initialized. Should + * this not be the case then the user made a mistake. */ + //If skipping checks also update + if (skipChecks) + { + T prev = _value; + UpdateValues(nextValue); + InvokeOnChange(prev, _value, calledByUser); + } + else + { + /* //writepermission if using owner write permissions + * make sure caller is owner. */ + if (Comparers.EqualityCompare(this._value, nextValue)) + return; + + T prev = _value; + _value = nextValue; + InvokeOnChange(prev, _value, calledByUser); + } + + TryDirty(); + } + //Not called by user. + else + { + + /* Previously clients were not allowed to set values + * but this has been changed because clients may want + * to update values locally while occasionally + * letting the syncvar adjust their side. */ + + T prev = _previousClientValue; + UpdateValues(nextValue); + InvokeOnChange(prev, _value, calledByUser); + TryDirty(); + } + + + /* Tries to dirty so update + * is sent over network. This needs to be called + * anytime the data changes because there is no way + * to know if the user set the value on both server + * and client or just one side. */ + void TryDirty() + { + //Cannot dirty when skipping checks. + if (skipChecks) + return; + + if (calledByUser) + base.Dirty(); + //writepermission Once client write permissions are added this needs to be updated. + //else if (!asServer && base.Settings.WritePermission == WritePermission.ServerOnly) + // base.Dirty(); + } + } + + /// + /// Invokes OnChanged callback. + /// + private void InvokeOnChange(T prev, T next, bool asServer) + { + if (asServer) + { + if (base.NetworkBehaviour.OnStartServerCalled) + OnChange?.Invoke(prev, next, asServer); + else + _serverOnChange = new CachedOnChange(prev, next); + } + else + { + if (base.NetworkBehaviour.OnStartClientCalled) + OnChange?.Invoke(prev, next, asServer); + else + _clientOnChange = new CachedOnChange(prev, next); + } + } + + + /// + /// Called after OnStartXXXX has occurred. + /// + /// True if OnStartServer was called, false if OnStartClient. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected internal override void OnStartCallback(bool asServer) + { + base.OnStartCallback(asServer); + + if (OnChange != null) + { + CachedOnChange? change = (asServer) ? _serverOnChange : _clientOnChange; + if (change != null) + InvokeOnChange(change.Value.Previous, change.Value.Next, asServer); + } + + if (asServer) + _serverOnChange = null; + else + _clientOnChange = null; + } + + /// + /// Writes current value. + /// + /// True to set the next time data may sync. + public override void WriteDelta(PooledWriter writer, bool resetSyncTick = true) + { + base.WriteDelta(writer, resetSyncTick); + writer.Write(_value); + } + + /// + /// Writes current value if not initialized value. + /// m> + public override void WriteFull(PooledWriter obj0) + { + if (Comparers.EqualityCompare(_initialValue, _value)) + return; + /* SyncVars only hold latest value, so just + * write current delta. */ + WriteDelta(obj0, false); + } + + //Read isn't used by SyncVar, it's done within the NB. + //public override void Read(PooledReader reader) { } + + /// + /// Gets current value. + /// + /// + /// + public T GetValue(bool calledByUser) => (calledByUser) ? _value : _previousClientValue; + + /// + /// Resets to initialized values. + /// + public override void Reset() + { + base.Reset(); + _value = _initialValue; + _previousClientValue = _initialValue; + } + } +} + + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs.meta new file mode 100644 index 0000000..5ae840f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f319403eec508734a93d723617ab1136 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs new file mode 100644 index 0000000..fbd2d15 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs @@ -0,0 +1,10 @@ +namespace FishNet.Object.Synchronizing +{ + /// + /// Which clients or server may write updates. + /// + public enum WritePermission + { + ServerOnly + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs.meta new file mode 100644 index 0000000..d1fb70b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/Synchronizing/WritePermissions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2696d0da2ff02e8499a8351a3021008f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs b/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs new file mode 100644 index 0000000..bbe05ee --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace FishNet.Object +{ + [System.Serializable] + public struct TransformProperties + { + public readonly Vector3 Position; + public readonly Quaternion Rotation; + public readonly Vector3 LocalScale; + + public TransformProperties(Vector3 position, Quaternion rotation, Vector3 localScale) + { + Position = position; + Rotation = rotation; + LocalScale = localScale; + } + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs.meta b/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs.meta new file mode 100644 index 0000000..ec7f7aa --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Object/TransformProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e4ce2bc25fe8364d8b443f5ac7591ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing.meta b/UnityProject/Assets/FishNet/Runtime/Observing.meta new file mode 100644 index 0000000..e4085bd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0cd196f74e1a994ebbc7a4cbd36eaf4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions.meta new file mode 100644 index 0000000..4b1cbbd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96ad2addbde8a81458e695b6797ae56e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs new file mode 100644 index 0000000..c1c5ee8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs @@ -0,0 +1,143 @@ +using FishNet.Connection; +using FishNet.Object; +using FishNet.Observing; +using FishNet.Utility.Extension; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Observing +{ + /// + /// When this observer condition is placed on an object, a client must be within the specified distance to view the object. + /// + [CreateAssetMenu(menuName = "FishNet/Observers/Distance Condition", fileName = "New Distance Condition")] + public class DistanceCondition : ObserverCondition + { + #region Serialized. + /// + /// + /// + [Tooltip("Maximum distance a client must be within this object to see it.")] + [SerializeField] + private float _maximumDistance = 100f; + /// + /// Maximum distance a client must be within this object to see it. + /// + public float MaximumDistance { get => _maximumDistance; set => _maximumDistance = value; } + /// + /// Additional percent of distance client must be until this object is hidden. For example, if distance was 100f and percent was 0.5f the client must be 150f units away before this object is hidden again. This can be useful for keeping objects from regularly appearing and disappearing. + /// + [Tooltip("Additional percent of distance client must be until this object is hidden. For example, if distance was 100f and percent was 0.5f the client must be 150f units away before this object is hidden again. This can be useful for keeping objects from regularly appearing and disappearing.")] + [Range(0f, 1f)] + [SerializeField] + private float _hideDistancePercent = 0.1f; + /// + /// + /// + [Tooltip("How often this condition may change for a connection. This prevents objects from appearing and disappearing rapidly. A value of 0f will cause the object the update quickly as possible while any other value will be used as a delay.")] + [Range(0f, 60f)] + [SerializeField] + private float _updateFrequency; + /// + /// How often this condition may change for a connection. This prevents objects from appearing and disappearing rapidly. A value of 0f will cause the object the update quickly as possible while any other value will be used as a delay. + /// + public float UpdateFrequency { get => _updateFrequency; set => _updateFrequency = value; } + #endregion + + #region Private. + /// + /// Tracks when connections may be updated for this object. + /// + private Dictionary _timedUpdates = new Dictionary(); + #endregion + + public void ConditionConstructor(float maximumDistance, float updateFrequency) + { + MaximumDistance = maximumDistance; + _updateFrequency = updateFrequency; + } + + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed) + { + if (_updateFrequency > 0f) + { + float nextAllowedUpdate; + float currentTime = Time.time; + if (!_timedUpdates.TryGetValueIL2CPP(connection, out nextAllowedUpdate)) + { + _timedUpdates[connection] = (currentTime + _updateFrequency); + } + else + { + //Not enough time to process again. + if (currentTime < nextAllowedUpdate) + { + notProcessed = true; + //The return does not really matter since notProcessed is returned. + return false; + } + //Can process again. + else + { + _timedUpdates[connection] = (currentTime + _updateFrequency); + } + } + } + //If here then checks are being processed. + notProcessed = false; + + float sqrMaximumDistance; + /* If already visible then use additional + * distance to determine when to hide. */ + if (currentlyAdded) + { + float maxModified = (MaximumDistance * (1f + _hideDistancePercent)); + sqrMaximumDistance = (maxModified * maxModified); + } + //Not visible, use normal distance. + else + { + sqrMaximumDistance = (MaximumDistance * MaximumDistance); + } + + Vector3 thisPosition = NetworkObject.transform.position; + foreach (NetworkObject nob in connection.Objects) + { + //If within distance. + if (Vector3.SqrMagnitude(nob.transform.position - thisPosition) <= sqrMaximumDistance) + return true; + } + + /* If here no client objects are within distance. */ + return false; + } + + /// + /// True if the condition requires regular updates. + /// + /// + public override bool Timed() + { + return true; + } + + /// + /// Clones referenced ObserverCondition. This must be populated with your conditions settings. + /// + /// + public override ObserverCondition Clone() + { + DistanceCondition copy = ScriptableObject.CreateInstance(); + copy.ConditionConstructor(MaximumDistance, _updateFrequency); + return copy; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs.meta new file mode 100644 index 0000000..0ee3ca9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/DistanceCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c3e28fa2e37d1d41b4f63c8a0cc2553 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor.meta new file mode 100644 index 0000000..adb96b6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f3331c0a5fd72743aa522a6481e635e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs new file mode 100644 index 0000000..a3e0be7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs @@ -0,0 +1,25 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Component.Observing +{ + + namespace FishNet.Component.Prediction.Editing + { + [CustomEditor(typeof(MatchCondition), true)] + [CanEditMultipleObjects] + public class MatchConditionEditor : Editor + { + public override void OnInspectorGUI() + { + + EditorGUILayout.HelpBox("This component is experimental. Documentation may not yet be available.", MessageType.Warning); + base.OnInspectorGUI(); + } + } + } + +} + +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs.meta new file mode 100644 index 0000000..6aa2902 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/Editor/MatchConditionEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6191684f3f9ff1b42a065d121903e68c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs new file mode 100644 index 0000000..c4b8f60 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs @@ -0,0 +1,585 @@ +using FishNet.Connection; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Server; +using FishNet.Object; +using FishNet.Observing; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Component.Observing +{ + /// + /// When this observer condition is placed on an object, a client must be within the same match to view the object. + /// + [CreateAssetMenu(menuName = "FishNet/Observers/Match Condition", fileName = "New Match Condition")] + public class MatchCondition : ObserverCondition + { + #region Private. + /// + /// + /// + private static Dictionary> _matchConnections = new Dictionary>(); + /// + /// Matches and connections in each match. + /// + public static IReadOnlyDictionary> MatchConnections => _matchConnections; + /// + /// + /// + /// //todo this needs to hold hashset so conns can be in multiple matches. + private static Dictionary _connectionMatch = new Dictionary(); + /// + /// Match a connection is in. + /// + public static IReadOnlyDictionary ConnectionMatch => _connectionMatch; + /// + /// + /// + private static Dictionary> _matchObjects = new Dictionary>(); + /// + /// Matches and connections in each match. + /// + public static IReadOnlyDictionary> MatchObjects => _matchObjects; + /// + /// + /// + /// //todo this needs to hold hashset so conns can be in multiple matches. + private static Dictionary _objectMatch = new Dictionary(); + /// + /// Match a connection is in. + /// + public static IReadOnlyDictionary ObjectMatch => _objectMatch; + #endregion + + public void ConditionConstructor() { } + + #region Add to match NetworkConnection. + /// + /// Adds a connection to a match. + /// + /// Match to add conn to. + /// Connection to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, NetworkConnection conn, NetworkManager manager = null, bool replaceMatch = false) + { + if (replaceMatch) + RemoveFromMatchWithoutRebuild(conn, manager); + + HashSet results; + if (!_matchConnections.TryGetValueIL2CPP(match, out results)) + { + results = new HashSet(); + _matchConnections.Add(match, results); + } + + bool r = results.Add(conn); + _connectionMatch[conn] = match; + if (r) + FinalizeChange(match, results, manager); + } + /// + /// Adds connections to a match. + /// + /// Match to add conns to. + /// Connections to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, NetworkConnection[] conns, NetworkManager manager = null, bool replaceMatch = false) + { + AddToMatch(match, conns.ToList(), manager, replaceMatch); + } + /// + /// Adds connections to a match. + /// + /// Match to add conns to. + /// Connections to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, List conns, NetworkManager manager = null, bool replaceMatch = false) + { + if (replaceMatch) + { + foreach (NetworkConnection nc in conns) + RemoveFromMatchWithoutRebuild(nc, manager); + } + + HashSet results; + if (!_matchConnections.TryGetValueIL2CPP(match, out results)) + { + results = new HashSet(); + _matchConnections.Add(match, results); + } + + bool r = false; + for (int i = 0; i < conns.Count; i++) + { + NetworkConnection c = conns[i]; + r |= results.Add(c); + _connectionMatch[c] = match; + } + + if (r) + FinalizeChange(match, results, manager); + } + #endregion + + #region Add to match NetworkObject. + /// + /// Adds an object to a match. + /// + /// Match to add conn to. + /// Connection to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, NetworkObject nob, NetworkManager manager = null, bool replaceMatch = false) + { + if (replaceMatch) + RemoveFromMatchWithoutRebuild(nob, manager); + + HashSet results; + if (!_matchObjects.TryGetValueIL2CPP(match, out results)) + { + results = new HashSet(); + _matchObjects.Add(match, results); + } + + bool r = results.Add(nob); + _objectMatch[nob] = match; + + if (r) + FinalizeChange(match, results, nob, manager); + } + /// + /// Adds objects to a match. + /// + /// Match to add conns to. + /// Connections to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, NetworkObject[] nobs, NetworkManager manager = null, bool replaceMatch = false) + { + AddToMatch(match, nobs.ToList(), manager, replaceMatch); + } + /// + /// Adds objects to a match. + /// + /// Match to add conns to. + /// Connections to add to match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + /// True to replace other matches with the new match. + public static void AddToMatch(int match, List nobs, NetworkManager manager = null, bool replaceMatch = false) + { + if (replaceMatch) + { + foreach (NetworkObject n in nobs) + RemoveFromMatchWithoutRebuild(n, manager); + } + + HashSet results; + if (!_matchObjects.TryGetValueIL2CPP(match, out results)) + { + results = new HashSet(); + _matchObjects.Add(match, results); + } + + bool r = false; + for (int i = 0; i < nobs.Count; i++) + { + NetworkObject n = nobs[i]; + r |= results.Add(n); + _objectMatch[n] = match; + } + + if (r) + FinalizeChange(match, results, nobs, manager); + } + #endregion + + #region Remove from match NetworkConnection. + /// + /// Removes a connection from any match without rebuilding observers. + /// + /// Connection to remove from matches. + /// NetworkManager connection belongs to. This is not currently used. + internal static bool RemoveFromMatchWithoutRebuild(NetworkConnection conn, NetworkManager manager) + { + bool removed = false; + //If found to be in a match. + if (_connectionMatch.TryGetValueIL2CPP(conn, out int match)) + { + //If match is found. + if (_matchConnections.TryGetValue(match, out HashSet conns)) + { + removed |= conns.Remove(conn); + //If no more in hashset remove match. + if (conns.Count == 0) + _matchConnections.Remove(match); + } + } + + //Remove from connectionMatch. + _connectionMatch.Remove(conn); + return removed; + } + /// + /// Removes a connection from all matches. + /// + /// NetworkConnection to remove. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + public static void RemoveFromMatch(NetworkConnection conn, NetworkManager manager) + { + bool removed = RemoveFromMatchWithoutRebuild(conn, manager); + if (removed) + GetServerObjects(manager).RebuildObservers(); + } + /// + /// Removes a connection from a match. + /// + /// Match to remove conn from. + /// Connection to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, NetworkConnection conn, NetworkManager manager) + { + if (_matchConnections.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = results.Remove(conn); + _connectionMatch.Remove(conn); + if (r) + FinalizeChange(match, results, manager); + } + } + /// + /// Removes connections from a match. + /// + /// Match to remove conns from. + /// Connections to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, NetworkConnection[] conns, NetworkManager manager) + { + if (_matchConnections.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = false; + for (int i = 0; i < conns.Length; i++) + { + NetworkConnection c = conns[i]; + r |= results.Remove(c); + _connectionMatch.Remove(c); + } + + if (r) + FinalizeChange(match, results, manager); + } + } + /// + /// Removes connections from a match. + /// + /// Match to remove conns from. + /// Connections to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, List conns, NetworkManager manager) + { + if (_matchConnections.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = false; + for (int i = 0; i < conns.Count; i++) + { + NetworkConnection c = conns[i]; + r |= results.Remove(c); + _connectionMatch.Remove(c); + } + + if (r) + FinalizeChange(match, results, manager); + } + } + #endregion + + #region Remove from match NetworkObject. + /// + /// Removes a network object from any match without rebuilding observers. + /// + /// NetworkObject to remove. + /// Manager which the network object belongs to. This value is not yet used. + internal static bool RemoveFromMatchWithoutRebuild(NetworkObject nob, NetworkManager manager = null) + { + bool removed = false; + //If found to be in a match. + if (_objectMatch.TryGetValueIL2CPP(nob, out int match)) + { + //If match is found. + if (_matchObjects.TryGetValue(match, out HashSet nobs)) + { + removed |= nobs.Remove(nob); + //If no more in hashset remove match. + if (nobs.Count == 0) + _matchObjects.Remove(match); + } + } + + //Remove from connectionMatch. + _objectMatch.Remove(nob); + return removed; + } + /// + /// Removes nob from all matches. + /// + /// NetworkObject to remove. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + public static void RemoveFromMatch(NetworkObject nob, NetworkManager manager = null) + { + bool removed = RemoveFromMatchWithoutRebuild(nob, manager); + if (removed) + GetServerObjects(manager).RebuildObservers(nob); + } + /// + /// Removes a network object from all matches. + /// + /// NetworkObjects to remove. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + public static void RemoveFromMatch(NetworkObject[] nobs, NetworkManager manager = null) + { + RemoveFromMatch(nobs.ToList(), manager); + } + /// + /// Removes network objects from all matches. + /// + /// NetworkObjects to remove. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + public static void RemoveFromMatch(List nobs, NetworkManager manager = null) + { + bool removed = false; + foreach (NetworkObject n in nobs) + removed |= RemoveFromMatchWithoutRebuild(n, manager); + + if (removed) + GetServerObjects(manager).RebuildObservers(nobs); + } + /// + /// Removes a network object from a match. + /// + /// Match to remove conn from. + /// NetworkObject to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, NetworkObject nob, NetworkManager manager = null) + { + if (_matchObjects.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = results.Remove(nob); + _objectMatch.Remove(nob); + if (r) + FinalizeChange(match, results, nob, manager); + } + } + /// + /// Removes network objects from a match. + /// + /// Match to remove conns from. + /// NetworkObjects to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, NetworkObject[] nobs, NetworkManager manager = null) + { + if (_matchObjects.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = false; + for (int i = 0; i < nobs.Length; i++) + { + NetworkObject n = nobs[i]; + r |= results.Remove(n); + _objectMatch.Remove(n); + } + + if (r) + FinalizeChange(match, results, nobs, manager); + } + } + /// + /// Removes network objects from a match. + /// + /// Match to remove conns from. + /// NetworkObjects to remove from match. + /// NetworkManager to rebuild observers on. If null InstanceFinder.NetworkManager will be used. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveFromMatch(int match, List nobs, NetworkManager manager = null) + { + if (_matchObjects.TryGetValueIL2CPP(match, out HashSet results)) + { + bool r = false; + for (int i = 0; i < nobs.Count; i++) + { + NetworkObject n = nobs[i]; + r |= results.Remove(n); + _objectMatch.Remove(n); + } + + if (r) + FinalizeChange(match, results, nobs, manager); + } + } + #endregion + + #region FinalizeChange NetworkConnection. + /// + /// Finalizes changes to observers. + /// + private static void FinalizeChange(int match, HashSet remainingConnsInMatch, NetworkManager manager) + { + if (remainingConnsInMatch.Count == 0) + _matchConnections.Remove(match); + + /* Observers on all objects and all conditions have to be rebuilt. + * This is because the connection changing matches could + * require the connection to be visible for other players in the match, + * as well make other connections in the same match visible. + * But also make all the objects not associated with connections + * of that match visible. In result to tick all of those boxes + * all objects need to be rebuilt for all connections. */ + GetServerObjects(manager).RebuildObservers(); + } + #endregion + + #region FinalizeChange NetworkObject. + /// + /// Finalizes changes to observers. + /// + private static void FinalizeChange(int match, HashSet results, List nobs, NetworkManager manager) + { + ListCache cache = ListCaches.GetNetworkObjectCache(); + cache.AddValues(nobs); + FinalizeChange(match, results, cache, manager); + ListCaches.StoreCache(cache); + } + /// + /// Finalizes changes to observers. + /// + private static void FinalizeChange(int match, HashSet results, NetworkObject[] nobs, NetworkManager manager) + { + ListCache cache = ListCaches.GetNetworkObjectCache(); + cache.AddValues(nobs); + FinalizeChange(match, results, cache, manager); + ListCaches.StoreCache(cache); + } + /// + /// Finalizes changes to observers. + /// + private static void FinalizeChange(int match, HashSet results, NetworkObject nob, NetworkManager manager) + { + ListCache cache = ListCaches.GetNetworkObjectCache(); + cache.AddValue(nob); + FinalizeChange(match, results, cache, manager); + ListCaches.StoreCache(cache); + } + /// + /// Finalizes changes to observers. + /// + private static void FinalizeChange(int match, HashSet results, ListCache nobs, NetworkManager manager) + { + if (results.Count == 0) + _matchConnections.Remove(match); + + GetServerObjects(manager).RebuildObservers(nobs); + } + #endregion + + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + public override bool ConditionMet(NetworkConnection connection, bool alreadyAdded, out bool notProcessed) + { + //If here then checks are being processed. + notProcessed = false; + NetworkConnection owner = base.NetworkObject.Owner; + /* If object is owned then check if owner + * and connection share a match. */ + if (owner.IsValid) + { + //Connection isn't in a match. + if (!_connectionMatch.TryGetValueIL2CPP(connection, out int match)) + { + //Return if this owner is also not in a match. + return !_connectionMatch.TryGetValueIL2CPP(owner, out int _); + } + //Match isn't found. + if (!_matchConnections.TryGetValueIL2CPP(match, out HashSet conns)) + return false; + //If owner is in same match return true. + return conns.Contains(owner); + } + /* If no owner see if the object is in a match and if so + * then compare that. */ + else + { + //Object isn't in a match. + if (!_objectMatch.TryGetValueIL2CPP(base.NetworkObject, out int objectMatch)) + return true; + /* See if connection is in the same match as the object. + * If connection isn't in a match then it fails. */ + if (!_connectionMatch.TryGetValueIL2CPP(connection, out int connectionMatch)) + return false; + return (connectionMatch == objectMatch); + } + } + + + /// + /// Returns which ServerObjects to rebuild observers on. + /// + /// + /// + private static ServerObjects GetServerObjects(NetworkManager manager) + { + return (manager == null) ? InstanceFinder.ServerManager.Objects : manager.ServerManager.Objects; + } + + + /* //todo this needs to be passing in the network manager to clear on, + * otherwise only a single instance of NM is supported. + * Users are already forced to specify which NM to add + * matches for but the functionality separating different NMs in relation + * to such isn't done yet. */ + /// + /// Clears all match information without rebuilding. + /// + internal static void ClearMatchesWithoutRebuilding() + { + _connectionMatch.Clear(); + _matchConnections.Clear(); + _objectMatch.Clear(); + _matchObjects.Clear(); + } + + + /// + /// True if the condition requires regular updates. + /// + /// + public override bool Timed() + { + return false; + } + + /// + /// Clones referenced ObserverCondition. This must be populated with your conditions settings. + /// + /// + public override ObserverCondition Clone() + { + MatchCondition copy = ScriptableObject.CreateInstance(); + copy.ConditionConstructor(); + return copy; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs.meta new file mode 100644 index 0000000..60e6e9e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/MatchCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5afdd6c2de1c76f4faa6840cc29fda8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs new file mode 100644 index 0000000..bd3a7ec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs @@ -0,0 +1,47 @@ +using FishNet.Connection; +using FishNet.Observing; +using UnityEngine; + +namespace FishNet.Component.Observing +{ + /// + /// This condition makes an object only visible to the owner. + /// + [CreateAssetMenu(menuName = "FishNet/Observers/Owner Only Condition", fileName = "New Owner Only Condition")] + public class OwnerOnlyCondition : ObserverCondition + { + + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + public override bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed) + { + notProcessed = false; + /* Returning false immediately indicates no connection will + * meet this condition. */ + return false; + } + + /// + /// True if the condition requires regular updates. + /// + /// + public override bool Timed() + { + return false; + } + + /// + /// Clones referenced ObserverCondition. This must be populated with your conditions settings. + /// + /// + public override ObserverCondition Clone() + { + OwnerOnlyCondition copy = ScriptableObject.CreateInstance(); + return copy; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs.meta new file mode 100644 index 0000000..3a99b3d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/OwnerOnlyCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ca3d8a36a10fd344806a2df999f3eda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs new file mode 100644 index 0000000..f049814 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs @@ -0,0 +1,88 @@ +using FishNet.Connection; +using FishNet.Observing; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Component.Observing +{ + + /// + /// When this observer condition is placed on an object, a client must be within the same scene to view the object. + /// + [CreateAssetMenu(menuName = "FishNet/Observers/Scene Condition", fileName = "New Scene Condition")] + public class SceneCondition : ObserverCondition + { + #region Serialized. + ///// + ///// True to synchronize which scene the object was spawned in to clients. When true this object will be moved to the clients equivelant of the scene it was spawned in on the server. This setting does not continously move this object to the same scene. + ///// + //[Tooltip("True to synchronize which scene the object was spawned in to clients. When true this object will be moved to the clients equivelant of the scene it was spawned in on the server. This setting does not continously move this object to the same scene.")] + //[SerializeField] + //private bool _synchronizeScene; + #endregion + + public void ConditionConstructor() + { + //_synchronizeScene = synchronizeScene; + } + + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + public override bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed) + { + notProcessed = false; + /* If this objects connection is valid then check if + * connection and this objects owner shares any scenes. + * Don't check if the object resides in the same scene + * because thats not reliable as server might be moving + * objects. */ + if (base.NetworkObject.Owner.IsValid) + { + foreach (Scene s in base.NetworkObject.Owner.Scenes) + { + //Scenes match. + if (connection.Scenes.Contains(s)) + return true; + } + + //Fall through, no scenes shared. + return false; + } + /* If there is no owner as a fallback see if + * the connection is in the same scene as this object. */ + else + { + /* When there is no owner only then is the gameobject + * scene checked. That's the only way to know at this point. */ + return connection.Scenes.Contains(base.NetworkObject.gameObject.scene); + } + } + + /// + /// True if the condition requires regular updates. + /// + /// + public override bool Timed() + { + return false; + } + + + /// + /// Clones referenced ObserverCondition. This must be populated with your conditions settings. + /// + /// + public override ObserverCondition Clone() + { + SceneCondition copy = ScriptableObject.CreateInstance(); + //copy.ConditionConstructor(_synchronizeScene); + copy.ConditionConstructor(); + return copy; + } + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs.meta new file mode 100644 index 0000000..edff5be --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/SceneCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fab85d1c51ee2c344b7dd914dc262ec4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs new file mode 100644 index 0000000..0d07537 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs @@ -0,0 +1,49 @@ +using FishNet.Connection; +using FishNet.Observing; +using System; +using UnityEngine; + +namespace FishNet.Component.Observing +{ + /// + /// This condition makes an object only visible to the server. + /// + //[CreateAssetMenu(menuName = "FishNet/Observers/Server Only Condition", fileName = "New Server Only Condition")] + [Obsolete("Use OwnerOnlyCondition instead.")] //Remove on 2023/06/01 + public class ServerOnlyCondition : ObserverCondition + { + + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + public override bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed) + { + notProcessed = false; + /* Returning false immediately indicates no connection will + * meet this condition. */ + return false; + } + + /// + /// True if the condition requires regular updates. + /// + /// + public override bool Timed() + { + return false; + } + + /// + /// Clones referenced ObserverCondition. This must be populated with your conditions settings. + /// + /// + public override ObserverCondition Clone() + { + ServerOnlyCondition copy = ScriptableObject.CreateInstance(); + return copy; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs.meta new file mode 100644 index 0000000..f8085da --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/Conditions/ServerOnlyCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1426e8d4eba17f743839346033d2cec7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs b/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs new file mode 100644 index 0000000..4699aca --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs @@ -0,0 +1,17 @@ + +namespace FishNet.Observing +{ + [System.Flags] + public enum HostVisibilityUpdateTypes : byte + { + /// + /// Include this flag to update manager. + /// + Manager = 1, + /// + /// Include this flag to update spawned. + /// + Spawned = 2, + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs.meta new file mode 100644 index 0000000..671c6cb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/HostVisibilityUpdateTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc90636a96cf14d47812768a9ce3a4d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs b/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs new file mode 100644 index 0000000..1c11341 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs @@ -0,0 +1,355 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing.Logging; +using FishNet.Object; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.Serialization; + +namespace FishNet.Observing +{ + /// + /// Controls which clients can see and get messages for an object. + /// + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Component/NetworkObserver")] + public sealed class NetworkObserver : MonoBehaviour + { + #region Types. + /// + /// How ObserverManager conditions are used. + /// + public enum ConditionOverrideType + { + /// + /// Keep current conditions, add new conditions from manager. + /// + AddMissing = 1, + /// + /// Replace current conditions with manager conditions. + /// + UseManager = 2, + /// + /// Keep current conditions, ignore manager conditions. + /// + IgnoreManager = 3, + } + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("How ObserverManager conditions are used.")] + [SerializeField] + private ConditionOverrideType _overrideType = ConditionOverrideType.IgnoreManager; + /// + /// How ObserverManager conditions are used. + /// + public ConditionOverrideType OverrideType + { + get => _overrideType; + internal set => _overrideType = value; + } + + /// + /// + /// + [Tooltip("True to update visibility for clientHost based on if they are an observer or not.")] + [FormerlySerializedAs("_setHostVisibility")] + [SerializeField] + private bool _updateHostVisibility = true; + /// + /// True to update visibility for clientHost based on if they are an observer or not. + /// + public bool UpdateHostVisibility + { + get => _updateHostVisibility; + private set => _updateHostVisibility = value; + } + /// + /// + /// + [Tooltip("Conditions connections must met to be added as an observer. Multiple conditions may be used.")] + [SerializeField] + internal List _observerConditions = new List(); + /// + /// Conditions connections must met to be added as an observer. Multiple conditions may be used. + /// + public IReadOnlyList ObserverConditions => _observerConditions; + [APIExclude] +#if MIRROR + public List ObserverConditionsInternal +#else + internal List ObserverConditionsInternal +#endif + { + get => _observerConditions; + set => _observerConditions = value; + } + #endregion + + #region Private. + /// + /// Conditions under this component which are timed. + /// + private List _timedConditions = new List(); + /// + /// True if all non-timed conditions passed. + /// + private bool _nonTimedMet; + /// + /// NetworkObject this belongs to. + /// + private NetworkObject _networkObject; + /// + /// Becomes true when registered with ServerObjects as Timed observers. + /// + private bool _registeredAsTimed; + #endregion + + private void OnEnable() + { + if (_networkObject != null && _networkObject.IsServer) + RegisterTimedConditions(); + } + private void OnDisable() + { + if (_networkObject != null && _networkObject.IsDeinitializing) + UnregisterTimedConditions(); + } + private void OnDestroy() + { + if (_networkObject != null) + UnregisterTimedConditions(); + } + + /// + /// Initializes this script for use. + /// + /// + internal void PreInitialize(NetworkObject networkObject) + { + _networkObject = networkObject; + bool ignoringManager = (OverrideType == ConditionOverrideType.IgnoreManager); + + //Check to override SetHostVisibility. + if (!ignoringManager) + UpdateHostVisibility = networkObject.ObserverManager.UpdateHostVisibility; + + bool observerFound = false; + for (int i = 0; i < _observerConditions.Count; i++) + { + if (_observerConditions[i] != null) + { + observerFound = true; + + /* Make an instance of each condition so values are + * not overwritten when the condition exist more than + * once in the scene. Double edged sword of using scriptable + * objects for conditions. */ + _observerConditions[i] = _observerConditions[i].Clone(); + ObserverCondition oc = _observerConditions[i]; + oc.InitializeOnce(_networkObject); + //If timed also register as containing timed conditions. + if (oc.Timed()) + _timedConditions.Add(oc); + } + else + { + _observerConditions.RemoveAt(i); + i--; + } + } + + //No observers specified + if (!observerFound) + { + /* Print warning and remove component if not using + * IgnoreManager. This is because other overrides would + * suggest conditions should be added in someway, but + * none are specified. + * + * Where-as no conditions with ignore manager would + * make sense if the manager had conditions, but you wanted + * this object global visible, thus no conditions. */ + if (!ignoringManager) + { + if (networkObject.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"NetworkObserver exist on {gameObject.name} but there are no observer conditions. This script has been removed."); + Destroy(this); + } + return; + } + + RegisterTimedConditions(); + } + + /// + /// Returns a condition if found within Conditions. + /// + /// + public ObserverCondition GetObserverCondition() where T : ObserverCondition + { + /* Do not bother setting local variables, + * condition collections aren't going to be long + * enough to make doing so worth while. */ + + System.Type conditionType = typeof(T); + for (int i = 0; i < _observerConditions.Count; i++) + { + if (_observerConditions[i].GetType() == conditionType) + return _observerConditions[i]; + } + + //Fall through, not found. + return null; + } + + /// + /// Returns ObserverStateChange by comparing conditions for a connection. + /// + /// True if added to Observers. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool timedOnly) + { + bool currentlyAdded = (_networkObject.Observers.Contains(connection)); + + //True if all conditions are met. + bool allConditionsMet = true; + /* If cnnection is owner then they can see the object. */ + bool notOwner = (connection != _networkObject.Owner); + + /* Only check conditions if not owner. Owner will always + * have visibility. */ + if (notOwner) + { + /* If a timed update and nonTimed + * have not been met then there's + * no reason to check timed. */ + if (timedOnly && !_nonTimedMet) + { + allConditionsMet = false; + } + else + { + //Return as failed if there is a parent nob which doesn't have visibility. + if (_networkObject.ParentNetworkObject != null && !_networkObject.ParentNetworkObject.Observers.Contains(connection)) + { + allConditionsMet = false; + } + else + { + //Becomes true if a non-timed condition fails. + bool nonTimedFailed = false; + + List collection = (timedOnly) ? _timedConditions : _observerConditions; + for (int i = 0; i < collection.Count; i++) + { + ObserverCondition condition = collection[i]; + /* If any observer returns removed then break + * from loop and return removed. If one observer has + * removed then there's no reason to iterate + * the rest. */ + bool conditionMet = condition.ConditionMet(connection, currentlyAdded, out bool notProcessed); + if (notProcessed) + conditionMet = currentlyAdded; + + //Condition not met. + if (!conditionMet) + { + allConditionsMet = false; + if (!condition.Timed()) + nonTimedFailed = true; + break; + } + } + + //If all conditions are being checked. + if (!timedOnly) + _nonTimedMet = !nonTimedFailed; + } + } + } + + //If all conditions met. + if (allConditionsMet) + return ReturnPassedConditions(currentlyAdded); + else + return ReturnFailedCondition(currentlyAdded); + } + + /// + /// Registers timed observer conditions. + /// + private void RegisterTimedConditions() + { + if (_timedConditions.Count == 0) + return; + //Already registered or no timed conditions. + if (_registeredAsTimed) + return; + + _registeredAsTimed = true; + _networkObject.NetworkManager.ServerManager.Objects.AddTimedNetworkObserver(_networkObject); + } + + /// + /// Unregisters timed conditions. + /// + private void UnregisterTimedConditions() + { + if (_timedConditions.Count == 0) + return; + if (!_registeredAsTimed) + return; + + _registeredAsTimed = false; + _networkObject.NetworkManager.ServerManager.Objects.RemoveTimedNetworkObserver(_networkObject); + } + + /// + /// Returns an ObserverStateChange when a condition fails. + /// + /// + /// + private ObserverStateChange ReturnFailedCondition(bool currentlyAdded) + { + if (currentlyAdded) + return ObserverStateChange.Removed; + else + return ObserverStateChange.Unchanged; + } + + /// + /// Returns an ObserverStateChange when all conditions pass. + /// + /// + /// + private ObserverStateChange ReturnPassedConditions(bool currentlyAdded) + { + if (currentlyAdded) + return ObserverStateChange.Unchanged; + else + return ObserverStateChange.Added; + } + + + /// + /// Sets a new value for UpdateHostVisibility. + /// This does not immediately update renderers. + /// You may need to combine with NetworkObject.SetRenderersVisible(bool). + /// + /// New value. + public void SetUpdateHostVisibility(bool value) + { + //Unchanged. + if (value == UpdateHostVisibility) + return; + + UpdateHostVisibility = value; + } + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs.meta new file mode 100644 index 0000000..0809554 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/NetworkObserver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c71fd7f855ec523429999fc4e14a1928 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs new file mode 100644 index 0000000..949f0d2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs @@ -0,0 +1,48 @@ +using FishNet.Connection; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Observing +{ + /// + /// Condition a connection must meet to be added as an observer. + /// This class can be inherited from for custom conditions. + /// + public abstract class ObserverCondition : ScriptableObject + { + #region Public. + /// + /// NetworkObject this condition is for. + /// + [HideInInspector] + public NetworkObject NetworkObject; + #endregion + + /// + /// Initializes this script for use. + /// + /// + public virtual void InitializeOnce(NetworkObject networkObject) + { + NetworkObject = networkObject; + } + /// + /// Returns if the object which this condition resides should be visible to connection. + /// + /// Connection which the condition is being checked for. + /// True if the connection currently has visibility of this object. + /// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value. + public abstract bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed); + /// + /// True if the condition requires regular updates. + /// + /// + public abstract bool Timed(); + /// + /// Creates a clone of this condition to be instantiated. + /// + /// + public abstract ObserverCondition Clone(); + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs.meta new file mode 100644 index 0000000..08b27fe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d496d4febcb07f4abbdc081eaa99234 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs new file mode 100644 index 0000000..d783cc3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs @@ -0,0 +1,12 @@ +namespace FishNet.Observing +{ + /// + /// States which observer(s) can change to. + /// + internal enum ObserverStateChange : byte + { + Unchanged = 0, + Added = 1, + Removed = 2 + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs.meta b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs.meta new file mode 100644 index 0000000..4529100 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Observing/ObserverStateChange.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4a8dca28b7d84548a918c5c32f684ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins.meta b/UnityProject/Assets/FishNet/Runtime/Plugins.meta new file mode 100644 index 0000000..0e82d79 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc3a5558e3b83cc41a1f450b12e9ac14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback.meta new file mode 100644 index 0000000..fc14e86 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a39159d806d05c4a9eb7a7a389d8396 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt new file mode 100644 index 0000000..b548ed0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt @@ -0,0 +1,5 @@ +Attribution to https://assetstore.unity.com/packages/3d/environments/landscapes/low-poly-simple-nature-pack-162153 +"SimpleNaturePack" + +Attribution to Kenny.nl +"Weapon Pack" \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt.meta new file mode 100644 index 0000000..a501e44 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Attributions.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0b87cdb0a34a9254ab77396878d3679e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt new file mode 100644 index 0000000..54c6022 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt @@ -0,0 +1 @@ +This software uses the license for Fish-Networking: https://github.com/FirstGearGames/FishNet/blob/main/LICENSE.md \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt.meta new file mode 100644 index 0000000..a551d13 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/LICENSE.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff1ecc2a24fd9684a862c4b99cfc2fcd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts.meta new file mode 100644 index 0000000..7084ba5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1d5f2c3ff10faa45a45d9cb3b1bfcc1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs new file mode 100644 index 0000000..9ba3166 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs @@ -0,0 +1,23 @@ +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Component.ColliderRollback +{ + + public class ColliderRollback : NetworkBehaviour + { + + + #region Serialized. + /// + /// Objects holding colliders which can rollback. + /// + [Tooltip("Objects holding colliders which can rollback.")] + [SerializeField] + private GameObject[] _colliderParents = new GameObject[0]; + #endregion + + + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs.meta new file mode 100644 index 0000000..6d18cfb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01a271dd97d875347b0cea860df29a9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs new file mode 100644 index 0000000..62ea90c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs @@ -0,0 +1,47 @@ +using FishNet.Managing; +using FishNet.Managing.Timing; +using FishNet.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Component.ColliderRollback +{ + public class RollbackManager : MonoBehaviour + { + + + #region Serialized. + /// + /// + /// + [Tooltip("Maximum time in the past colliders can be rolled back to.")] + [SerializeField] + private float _maximumRollbackTime = 1.25f; + /// + /// Maximum time in the past colliders can be rolled back to. + /// + internal float MaximumRollbackTime => _maximumRollbackTime; + /// + /// + /// + [Tooltip("Interpolation value for the NetworkTransform or object being rolled back.")] + [Range(0, 250)] + [SerializeField] + internal ushort Interpolation = 2; + #endregion + + + + /// + /// Initializes this script for use. + /// + /// + internal void InitializeOnceInternal(NetworkManager manager) + { + + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs.meta new file mode 100644 index 0000000..c7c510b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b185516acd802904383e2a5f1a666750 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak.meta new file mode 100644 index 0000000..dcae338 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0bfce5a10f5315248bf3e7eaed92265d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt new file mode 100644 index 0000000..4f3eea1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt @@ -0,0 +1,2 @@ +1.0.0 + - Initial release. \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta new file mode 100644 index 0000000..959d54e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 65389c57cd9accf47967cc3e6cb7ac1b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core.meta similarity index 77% rename from UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core.meta rename to UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core.meta index 2b3246b..7f0cd25 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core.meta +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e03829cb9e647274db0f6a7b8b1b757b +guid: 3b79a48228ccfcd4cbf0a0514295abeb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs new file mode 100644 index 0000000..e69de29 diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs.meta new file mode 100644 index 0000000..ac679e5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26269fe7187f5da4e957080519ea0f13 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs new file mode 100644 index 0000000..e69de29 diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs.meta new file mode 100644 index 0000000..02600b5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63afa30fa0251df44b9496aded55d795 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs.meta new file mode 100644 index 0000000..32c8808 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f52ce359669f91c4d981dc605a8875b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs new file mode 100644 index 0000000..e69de29 diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs.meta new file mode 100644 index 0000000..16d2d4c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9181ba25449c96446b966d0bd62e5813 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt new file mode 100644 index 0000000..afaf360 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta new file mode 100644 index 0000000..afecaf0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3f0e4449aaa7cf0499df1847fdbd5377 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs new file mode 100644 index 0000000..e69de29 diff --git a/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs.meta b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs.meta new file mode 100644 index 0000000..9b936a3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91f4cf5273666764789e6f8bada05e3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing.meta b/UnityProject/Assets/FishNet/Runtime/Serializing.meta new file mode 100644 index 0000000..a3b0ae4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a3426d8e19d71a4e809a5993e9e6459 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs new file mode 100644 index 0000000..c51081c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs @@ -0,0 +1,21 @@ +namespace FishNet.Serializing +{ + /// + /// How to pack data when using serialization. + /// + public enum AutoPackType + { + /// + /// Data will not be compressed. + /// + Unpacked = 0, + /// + /// Data will be compressed to use the least amount of data possible. + /// + Packed = 1, + /// + /// Data will be compressed but not as much as Packed. + /// + PackedLess = 2 + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs.meta new file mode 100644 index 0000000..37dd541 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/AutoPackType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e94ebaa8f7024845a7e90ebd8246ac6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping.meta new file mode 100644 index 0000000..5ba60eb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29ef966943829104e8b9d8b7fd225599 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs new file mode 100644 index 0000000..583ffca --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs @@ -0,0 +1,12 @@ +using FishNet.Utility.Constant; +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] +namespace FishNet.Serializing.Helping +{ + internal class CodegenMakePublicAttribute : Attribute { } + public class CodegenExcludeAttribute : Attribute { } + internal class CodegenIncludeInternalAttribute : Attribute { } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs.meta new file mode 100644 index 0000000..72d697d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Attributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce079c8f32bf87b46a44681ccc8578fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs new file mode 100644 index 0000000..83b0c90 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs @@ -0,0 +1,34 @@ +using FishNet.Object.Helping; +using FishNet.Transporting; + +namespace FishNet.Serializing.Helping +{ + + internal static class Broadcasts + { + /// + /// Writes a broadcast to writer. + /// + /// + /// + /// + /// + /// + internal static PooledWriter WriteBroadcast(PooledWriter writer, T message, Channel channel) + { + writer.WritePacketId(PacketId.Broadcast); + writer.WriteUInt16(typeof(T).FullName.GetStableHash16()); //muchlater codegen this to pass in hash. use technique similar to rpcs to limit byte/shorts. + //Write data to a new writer. + PooledWriter dataWriter = WriterPool.GetWriter(); + dataWriter.Write(message); + //Write length of data. + writer.WriteLength(dataWriter.Length); + //Write data. + writer.WriteArraySegment(dataWriter.GetArraySegment()); + dataWriter.Dispose(); + + return writer; + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs.meta new file mode 100644 index 0000000..462de30 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Broadcasts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0636e29429649a24795091f80edbd892 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs new file mode 100644 index 0000000..9450ac4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using UnityEngine.SceneManagement; + +namespace FishNet.Serializing.Helping +{ + + public class Comparers + { + /// + /// Returns if A equals B using EqualityCompare. + /// + /// + /// + /// + /// + public static bool EqualityCompare(T a, T b) + { + return (EqualityComparer.Default.Equals(a, b)); + } + + public static bool IsDefault(T t) + { + return t.Equals(default(T)); + } + + } + + + internal class SceneComparer : IEqualityComparer + { + public bool Equals(Scene a, Scene b) + { + if (!a.IsValid() || !b.IsValid()) + return false; + + if (a.handle != 0 || b.handle != 0) + return (a.handle == b.handle); + + return (a.name == b.name); + } + + public int GetHashCode(Scene obj) + { + return obj.GetHashCode(); + } + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs.meta new file mode 100644 index 0000000..c79d11e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e912d0645f10b2c458cc2f01e24ecc27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs new file mode 100644 index 0000000..3fa685a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs @@ -0,0 +1,163 @@ + +using System; +using UnityEngine; + +namespace FishNet.Serializing.Helping +{ + public static class Quaternion32Compression + { + private const float Maximum = +1.0f / 1.414214f; + + private const int BitsPerAxis = 10; + private const int LargestComponentShift = BitsPerAxis * 3; + private const int AShift = BitsPerAxis * 2; + private const int BShift = BitsPerAxis * 1; + private const int IntScale = (1 << (BitsPerAxis - 1)) - 1; + private const int IntMask = (1 << BitsPerAxis) - 1; + + public static uint Compress(Quaternion quaternion) + { + float absX = Mathf.Abs(quaternion.x); + float absY = Mathf.Abs(quaternion.y); + float absZ = Mathf.Abs(quaternion.z); + float absW = Mathf.Abs(quaternion.w); + + ComponentType largestComponent = ComponentType.X; + float largestAbs = absX; + float largest = quaternion.x; + + if (absY > largestAbs) + { + largestAbs = absY; + largestComponent = ComponentType.Y; + largest = quaternion.y; + } + if (absZ > largestAbs) + { + largestAbs = absZ; + largestComponent = ComponentType.Z; + largest = quaternion.z; + } + if (absW > largestAbs) + { + largestComponent = ComponentType.W; + largest = quaternion.w; + } + + float a = 0; + float b = 0; + float c = 0; + switch (largestComponent) + { + case ComponentType.X: + a = quaternion.y; + b = quaternion.z; + c = quaternion.w; + break; + case ComponentType.Y: + a = quaternion.x; + b = quaternion.z; + c = quaternion.w; + break; + case ComponentType.Z: + a = quaternion.x; + b = quaternion.y; + c = quaternion.w; + break; + case ComponentType.W: + a = quaternion.x; + b = quaternion.y; + c = quaternion.z; + break; + } + + if (largest < 0) + { + a = -a; + b = -b; + c = -c; + } + + uint integerA = ScaleToUint(a); + uint integerB = ScaleToUint(b); + uint integerC = ScaleToUint(c); + + return (((uint)largestComponent) << LargestComponentShift) | (integerA << AShift) | (integerB << BShift) | integerC; + } + + private static uint ScaleToUint(float v) + { + float normalized = v / Maximum; + return (uint)Mathf.RoundToInt(normalized * IntScale) & IntMask; + } + + private static float ScaleToFloat(uint v) + { + float unscaled = v * Maximum / IntScale; + + if (unscaled > Maximum) + unscaled -= Maximum * 2; + return unscaled; + } + + public static Quaternion Decompress(uint compressed) + { + var largestComponentType = (ComponentType)(compressed >> LargestComponentShift); + uint integerA = (compressed >> AShift) & IntMask; + uint integerB = (compressed >> BShift) & IntMask; + uint integerC = compressed & IntMask; + + float a = ScaleToFloat(integerA); + float b = ScaleToFloat(integerB); + float c = ScaleToFloat(integerC); + + Quaternion rotation; + switch (largestComponentType) + { + case ComponentType.X: + // (?) y z w + rotation.y = a; + rotation.z = b; + rotation.w = c; + rotation.x = Mathf.Sqrt(1 - rotation.y * rotation.y + - rotation.z * rotation.z + - rotation.w * rotation.w); + break; + case ComponentType.Y: + // x (?) z w + rotation.x = a; + rotation.z = b; + rotation.w = c; + rotation.y = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.z * rotation.z + - rotation.w * rotation.w); + break; + case ComponentType.Z: + // x y (?) w + rotation.x = a; + rotation.y = b; + rotation.w = c; + rotation.z = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.y * rotation.y + - rotation.w * rotation.w); + break; + case ComponentType.W: + // x y z (?) + rotation.x = a; + rotation.y = b; + rotation.z = c; + rotation.w = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.y * rotation.y + - rotation.z * rotation.z); + break; + default: + // Should never happen! + throw new ArgumentOutOfRangeException("Unknown rotation component type: " + + largestComponentType); + } + + return rotation; + } + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs.meta new file mode 100644 index 0000000..0158ec8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion32.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f71e61ed84064a0429577ec462a8fa79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs new file mode 100644 index 0000000..1832ba7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs @@ -0,0 +1,192 @@ + +using System; +using UnityEngine; + +namespace FishNet.Serializing.Helping +{ + /// + /// Credit to https://github.com/viliwonka + /// https://github.com/FirstGearGames/FishNet/pull/23 + /// + public static class Quaternion64Compression + { + // 64 bit quaternion compression + // [4 bits] largest component + // [21 bits] higher res + // [21 bits] higher res + // [20 bits] higher res + // sum is 64 bits + private const float Maximum = +1.0f / 1.414214f; + private const int BitsPerAxis_H = 21; // higher res, 21 bits + private const int BitsPerAxis_L = 20; // lower res, 20 bits + private const int LargestComponentShift = BitsPerAxis_H * 2 + BitsPerAxis_L * 1; + private const int AShift = BitsPerAxis_H + BitsPerAxis_L; + private const int BShift = BitsPerAxis_L; + private const int IntScale_H = (1 << (BitsPerAxis_H - 1)) - 1; + private const int IntMask_H = (1 << BitsPerAxis_H) - 1; + private const int IntScale_L = (1 << (BitsPerAxis_L - 1)) - 1; + private const int IntMask_L = (1 << BitsPerAxis_L) - 1; + + public static ulong Compress(Quaternion quaternion) + { + float absX = Mathf.Abs(quaternion.x); + float absY = Mathf.Abs(quaternion.y); + float absZ = Mathf.Abs(quaternion.z); + float absW = Mathf.Abs(quaternion.w); + + ComponentType largestComponent = ComponentType.X; + float largestAbs = absX; + float largest = quaternion.x; + + if (absY > largestAbs) + { + largestAbs = absY; + largestComponent = ComponentType.Y; + largest = quaternion.y; + } + if (absZ > largestAbs) + { + largestAbs = absZ; + largestComponent = ComponentType.Z; + largest = quaternion.z; + } + if (absW > largestAbs) + { + largestComponent = ComponentType.W; + largest = quaternion.w; + } + + float a = 0; + float b = 0; + float c = 0; + + switch (largestComponent) + { + case ComponentType.X: + a = quaternion.y; + b = quaternion.z; + c = quaternion.w; + break; + case ComponentType.Y: + a = quaternion.x; + b = quaternion.z; + c = quaternion.w; + break; + case ComponentType.Z: + a = quaternion.x; + b = quaternion.y; + c = quaternion.w; + break; + case ComponentType.W: + a = quaternion.x; + b = quaternion.y; + c = quaternion.z; + break; + } + + if (largest < 0) + { + a = -a; + b = -b; + c = -c; + } + + ulong integerA = ScaleToUint_H(a); + ulong integerB = ScaleToUint_H(b); + ulong integerC = ScaleToUint_L(c); + + return (((ulong)largestComponent) << LargestComponentShift) | (integerA << AShift) | (integerB << BShift) | integerC; + } + + private static ulong ScaleToUint_H(float v) + { + float normalized = v / Maximum; + return (ulong)Mathf.RoundToInt(normalized * IntScale_H) & IntMask_H; + } + + private static ulong ScaleToUint_L(float v) + { + float normalized = v / Maximum; + return (ulong)Mathf.RoundToInt(normalized * IntScale_L) & IntMask_L; + } + + private static float ScaleToFloat_H(ulong v) + { + float unscaled = v * Maximum / IntScale_H; + + if (unscaled > Maximum) + unscaled -= Maximum * 2; + return unscaled; + } + + private static float ScaleToFloat_L(ulong v) + { + float unscaled = v * Maximum / IntScale_L; + + if (unscaled > Maximum) + unscaled -= Maximum * 2; + return unscaled; + } + + public static Quaternion Decompress(ulong compressed) + { + var largestComponentType = (ComponentType)(compressed >> LargestComponentShift); + ulong integerA = (compressed >> AShift) & IntMask_H; + ulong integerB = (compressed >> BShift) & IntMask_H; + ulong integerC = compressed & IntMask_L; + + float a = ScaleToFloat_H(integerA); + float b = ScaleToFloat_H(integerB); + float c = ScaleToFloat_L(integerC); + + Quaternion rotation; + switch (largestComponentType) + { + case ComponentType.X: + // (?) y z w + rotation.y = a; + rotation.z = b; + rotation.w = c; + rotation.x = Mathf.Sqrt(1 - rotation.y * rotation.y + - rotation.z * rotation.z + - rotation.w * rotation.w); + break; + case ComponentType.Y: + // x (?) z w + rotation.x = a; + rotation.z = b; + rotation.w = c; + rotation.y = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.z * rotation.z + - rotation.w * rotation.w); + break; + case ComponentType.Z: + // x y (?) w + rotation.x = a; + rotation.y = b; + rotation.w = c; + rotation.z = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.y * rotation.y + - rotation.w * rotation.w); + break; + case ComponentType.W: + // x y z (?) + rotation.x = a; + rotation.y = b; + rotation.z = c; + rotation.w = Mathf.Sqrt(1 - rotation.x * rotation.x + - rotation.y * rotation.y + - rotation.z * rotation.z); + break; + default: + // Should never happen! + throw new ArgumentOutOfRangeException("Unknown rotation component type: " + + largestComponentType); + } + + return rotation; + } + + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs.meta new file mode 100644 index 0000000..68090e2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/Quaternion64.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7afd33d2ca5433f4f831dfaf0169423c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs new file mode 100644 index 0000000..2855a06 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs @@ -0,0 +1,126 @@ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace FishNet.Serializing.Helping +{ + /// + /// Static class used for fast conversion of quaternion structs. Not thread safe! + /// + [StructLayout(LayoutKind.Explicit)] + public struct QuaternionConverter + { + // [FieldOffset(0)] + // public Quaternion Q; + // [FieldOffset(0)] + // public Quaternion64 Q64; + // [FieldOffset(0)] + // public Quaternion128 Q128; + + // public static QuaternionConverter StaticRef = new QuaternionConverter(); + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static Quaternion64 QtoQ64(Quaternion quaternion64) + // { + // StaticRef.Q = quaternion64; + // return StaticRef.Q64; + // } + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static Quaternion Q64toQ(Quaternion64 quaternion) + // { + // StaticRef.Q64 = quaternion; + // return StaticRef.Q; + // } + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static Quaternion128 QtoQ128(Quaternion quaternion128) + // { + // StaticRef.Q = quaternion128; + // return StaticRef.Q128; + // } + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static Quaternion Q128toQ(Quaternion128 quaternion) + // { + // StaticRef.Q128 = quaternion; + // return StaticRef.Q; + // } + //} + + //public struct Quaternion64 + //{ + // public float x; + // public float y; + // public float z; + // public float w; + + // public Quaternion64(float x, float y, float z, float w) + // { + // this.x = x; + // this.y = y; + // this.z = z; + // this.w = w; + // } + + // public Quaternion64(Quaternion q) + // { + // this.x = q.x; + // this.y = q.y; + // this.z = q.z; + // this.w = q.w; + // } + + // /*[MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static implicit operator Quaternion64(Quaternion q) => new Quaternion64(q); + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static implicit operator Quaternion(Quaternion64 q) => new Quaternion(q.x, q.y, q.z, q.w);*/ + //} + + //public struct Quaternion128 + //{ + // public float x; + // public float y; + // public float z; + // public float w; + // public Quaternion128(float x, float y, float z, float w) + // { + // this.x = x; + // this.y = y; + // this.z = z; + // this.w = w; + // } + + // public Quaternion128(Quaternion q) + // { + // x = q.x; + // y = q.y; + // z = q.z; + // w = q.w; + // } + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static implicit operator Quaternion128(Quaternion q) => new Quaternion128(q); + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static implicit operator Quaternion(Quaternion128 q) => new Quaternion(q.x, q.y, q.z, q.w); + //} + + /// + /// Credit to this man for converting gaffer games c code to c# + /// https://gist.github.com/fversnel/0497ad7ab3b81e0dc1dd + /// + } + + public enum ComponentType : uint + { + X = 0, + Y = 1, + Z = 2, + W = 3 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs.meta new file mode 100644 index 0000000..0238ab7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/QuaternionConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7ac59ce12259104fa28fc837fb17ccf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs new file mode 100644 index 0000000..48153c7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; + +namespace FishNet.Serializing.Helping +{ + + + // -- helpers for float conversion without allocations -- + [StructLayout(LayoutKind.Explicit)] + internal struct UIntFloat + { + [FieldOffset(0)] + public float FloatValue; + + [FieldOffset(0)] + public uint UIntValue; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct UIntDouble + { + [FieldOffset(0)] + public double DoubleValue; + + [FieldOffset(0)] + public ulong LongValue; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct UIntDecimal + { + [FieldOffset(0)] + public ulong LongValue1; + + [FieldOffset(8)] + public ulong LongValue2; + + [FieldOffset(0)] + public decimal DecimalValue; + } + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs.meta new file mode 100644 index 0000000..21b772b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 008e79d0f22a2674189acc7eff64408f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs new file mode 100644 index 0000000..0fa3525 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs @@ -0,0 +1,1209 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Constant; +using FishNet.Utility.Extension; +using FishNet.Utility.Performance; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; +using UnityEngine; + + +[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 { internal get; set; } + public static Func ReadAutoPack { internal get; set; } + } + + /// + /// Reads data from a buffer. + /// + public class Reader + { + #region Public. + /// + /// NetworkManager for this reader. Used to lookup objects. + /// + public NetworkManager NetworkManager; + /// + /// Offset within the buffer when the reader was created. + /// + public int Offset { get; private set; } + /// + /// Position for the next read. + /// + public int Position; + /// + /// Total number of bytes available within the buffer. + /// + public int Length { get; private set; } + /// + /// Bytes remaining to be read. This value is Length - Position. + /// + public int Remaining => ((Length + Offset) - Position); + #endregion + + #region Internal. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + /// + /// Last NetworkObject parsed. + /// + public static NetworkObject LastNetworkObject { get; private set; } + /// + /// Last NetworkBehaviour parsed. + /// + public static NetworkBehaviour LastNetworkBehaviour { get; private set; } +#endif + #endregion + + #region Private. + /// + /// Data being read. + /// + private byte[] _buffer; + /// + /// Buffer to copy Guids into. + /// + private byte[] _guidBuffer = new byte[16]; + /// + /// Used to encode strings. + /// + private readonly UTF8Encoding _encoding = new UTF8Encoding(false, true); + #endregion + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Reader(byte[] bytes, NetworkManager networkManager) + { + Initialize(bytes, networkManager); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Reader(ArraySegment segment, NetworkManager networkManager) + { + Initialize(segment, networkManager); + } + + /// + /// Outputs reader to string. + /// + /// + public override string ToString() + { + return $"Position: {Position}, Length: {Length}, Buffer: {BitConverter.ToString(_buffer, Offset, Length)}."; + } + + /// + /// Initializes this reader with data. + /// + /// + /// + internal void Initialize(ArraySegment bytes, NetworkManager networkManager) + { + if (bytes.Array == null) + { + if (_buffer == null) + _buffer = new byte[0]; + } + else + { + _buffer = bytes.Array; + } + + Position = bytes.Offset; + Offset = bytes.Offset; + Length = bytes.Count; + NetworkManager = networkManager; + } + /// + /// Initializes this reader with data. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Initialize(byte[] bytes, NetworkManager networkManager) + { + Initialize(new ArraySegment(bytes), networkManager); + } + + + /// + /// Writes a dictionary. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Dictionary ReadDictionary() + { + bool isNull = ReadBoolean(); + if (isNull) + return null; + + int count = ReadInt32(); + + Dictionary result = new Dictionary(count); + for (int i = 0; i < count; i++) + { + TKey key = Read(); + TValue value = Read(); + result.Add(key, value); + } + + return result; + } + + /// + /// Reads length. This method is used to make debugging easier. + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int ReadLength() + { + return ReadInt32(); + } + + /// + /// Reads a packetId. + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal PacketId ReadPacketId() + { + return (PacketId)ReadUInt16(); + } + + /// + /// Returns a ushort without advancing the reader. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal PacketId PeekPacketId() + { + int currentPosition = Position; + PacketId result = ReadPacketId(); + Position = currentPosition; + return result; + } + + /// + /// Skips a number of bytes in the reader. + /// + /// + [CodegenExclude] + public void Skip(int value) + { + if (value < 1 || Remaining < value) + return; + + Position += value; + } + + /// + /// Returns the buffer as an ArraySegment. + /// + /// + public ArraySegment GetArraySegmentBuffer() + { + return new ArraySegment(_buffer, Offset, Length); + } + /// + /// Returns the buffer as bytes. This does not trim excessive bytes. + /// + /// + public byte[] GetByteBuffer() + { + return _buffer; + } + /// + /// Returns the buffer as bytes and allocates into a new array. + /// + /// + public byte[] GetByteBufferAllocated() + { + byte[] result = new byte[Length]; + Buffer.BlockCopy(_buffer, Offset, result, 0, Length); + return result; + } + /// + /// BlockCopies data from the reader to target and advances reader. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void BlockCopy(ref byte[] target, int targetOffset, int count) + { + Buffer.BlockCopy(_buffer, Position, target, targetOffset, count); + Position += count; + } + + /// + /// Reads a byte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte ReadByte() + { + byte r = _buffer[Position]; + Position += 1; + return r; + } + + /// + /// Read bytes from position into target. + /// + /// + [CodegenExclude] + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadBytes(ref byte[] target, int count) + { + if (target == null) + throw new EndOfStreamException($"Target is null."); + //Target isn't large enough. + if (count > target.Length) + throw new EndOfStreamException($"Count of {count} exceeds target length of {target.Length}."); + + BlockCopy(ref target, 0, count); + } + + /// + /// Creates an ArraySegment by reading a number of bytes from position. + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ArraySegment ReadArraySegment(int count) + { + ArraySegment result = new ArraySegment(_buffer, Position, count); + Position += count; + return result; + } + + /// + /// Reads a sbyte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte ReadSByte() + { + return (sbyte)ReadByte(); + } + + /// + /// Reads a char. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public char ReadChar() => (char)ReadUInt16(); + + /// + /// Reads a boolean. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ReadBoolean() + { + byte result = ReadByte(); + return (result == 1) ? true : false; + } + + /// + /// Reads an int16. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ushort ReadUInt16() + { + ushort result = 0; + result |= _buffer[Position++]; + result |= (ushort)(_buffer[Position++] << 8); + + return result; + } + + /// + /// Reads a uint16. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public short ReadInt16() => (short)ReadUInt16(); + + /// + /// Reads an int32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint ReadUInt32(AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + return (uint)ReadPackedWhole(); + + uint result = 0; + result |= _buffer[Position++]; + result |= (uint)_buffer[Position++] << 8; + result |= (uint)_buffer[Position++] << 16; + result |= (uint)_buffer[Position++] << 24; + + return result; + } + /// + /// Reads a uint32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadInt32(AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + return (int)(long)ZigZagDecode(ReadPackedWhole()); + + return (int)ReadUInt32(packType); + } + + /// + /// Reads a uint64. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public long ReadInt64(AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + return (long)ZigZagDecode(ReadPackedWhole()); + + return (long)ReadUInt64(packType); + } + + /// + /// Reads an int64. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadUInt64(AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + return (ulong)ReadPackedWhole(); + + ulong result = 0; + result |= _buffer[Position++]; + result |= (ulong)_buffer[Position++] << 8; + result |= (ulong)_buffer[Position++] << 16; + result |= (ulong)_buffer[Position++] << 24; + result |= (ulong)_buffer[Position++] << 32; + result |= (ulong)_buffer[Position++] << 40; + result |= (ulong)_buffer[Position++] << 48; + result |= (ulong)_buffer[Position++] << 56; + + return result; + } + + + /// + /// Reads a single. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float ReadSingle(AutoPackType packType = AutoPackType.Unpacked) + { + if (packType == AutoPackType.Unpacked) + { + UIntFloat converter = new UIntFloat(); + converter.UIntValue = ReadUInt32(AutoPackType.Unpacked); + return converter.FloatValue; + } + else + { + long converter = (long)ReadPackedWhole(); + return (float)(converter / 100f); + } + } + + /// + /// Reads a double. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double ReadDouble() + { + UIntDouble converter = new UIntDouble(); + converter.LongValue = ReadUInt64(AutoPackType.Unpacked); + return converter.DoubleValue; + } + + /// + /// Reads a decimal. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public decimal ReadDecimal() + { + UIntDecimal converter = new UIntDecimal(); + converter.LongValue1 = ReadUInt64(AutoPackType.Unpacked); + converter.LongValue2 = ReadUInt64(AutoPackType.Unpacked); + return converter.DecimalValue; + } + + /// + /// Reads a string. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string ReadString() + { + int size = ReadInt32(); + //Null string. + if (size == -1) + return null; + else if (size == 0) + return string.Empty; + + if (!CheckAllocationAttack(size)) + return string.Empty; + ArraySegment data = ReadArraySegment(size); + return _encoding.GetString(data.Array, data.Offset, data.Count); + } + + /// + /// Creates a byte array and reads bytes and size into it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ReadBytesAndSizeAllocated() + { + int size = ReadInt32(); + if (size == -1) + return null; + else + return ReadBytesAllocated(size); + } + + /// + /// Reads bytes and size and copies results into target. Returns -1 if null was written. + /// + /// Bytes read. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadBytesAndSize(ref byte[] target) + { + int size = ReadInt32(); + if (size > 0) + ReadBytes(ref target, size); + + return size; + } + + /// + /// Reads bytes and size and returns as an ArraySegment. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ArraySegment ReadArraySegmentAndSize() + { + int size = ReadInt32(); + /* -1 would be written for null. But since + * ArraySegments cannot be null return default if + * length is 0 or less. */ + if (size <= 0) + return default; + + return ReadArraySegment(size); + } + + /// + /// Reads a Vector2. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2 ReadVector2() + { + return new Vector2(ReadSingle(), ReadSingle()); + } + + /// + /// Reads a Vector3. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ReadVector3() + { + return new Vector3(ReadSingle(), ReadSingle(), ReadSingle()); + } + + /// + /// Reads a Vector4. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ReadVector4() + { + return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); + } + + /// + /// Reads a Vector2Int. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2Int ReadVector2Int(AutoPackType packType = AutoPackType.Packed) + { + return new Vector2Int(ReadInt32(packType), ReadInt32(packType)); + } + + /// + /// Reads a Vector3Int. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3Int ReadVector3Int(AutoPackType packType = AutoPackType.Packed) + { + return new Vector3Int(ReadInt32(packType), ReadInt32(packType), ReadInt32(packType)); + } + + /// + /// Reads a color. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Color ReadColor(AutoPackType packType = AutoPackType.Packed) + { + float r, g, b, a; + if (packType == AutoPackType.Unpacked) + { + r = ReadSingle(); + g = ReadSingle(); + b = ReadSingle(); + a = ReadSingle(); + } + else + { + r = (float)(ReadByte() / 100f); + g = (float)(ReadByte() / 100f); + b = (float)(ReadByte() / 100f); + a = (float)(ReadByte() / 100f); + } + return new Color(r, g, b, a); + } + + /// + /// Reads a Color32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Color32 ReadColor32() + { + return new Color32(ReadByte(), ReadByte(), ReadByte(), ReadByte()); + } + + /// + /// Reads a Quaternion. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Quaternion ReadQuaternion(AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + { + uint result = ReadUInt32(AutoPackType.Unpacked); + return Quaternion32Compression.Decompress(result); + } + else if (packType == AutoPackType.PackedLess) + { + ulong result = ReadUInt64(AutoPackType.Unpacked); + return Quaternion64Compression.Decompress(result); + } + else + { + return new Quaternion( + ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle() + ); + } + } + + /// + /// Reads a Rect. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rect ReadRect() + { + return new Rect(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); + } + + /// + /// Plane. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Plane ReadPlane() + { + return new Plane(ReadVector3(), ReadSingle()); + } + + /// + /// Reads a Ray. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Ray ReadRay() + { + Vector3 position = ReadVector3(); + Vector3 direction = ReadVector3(); + return new Ray(position, direction); + } + + /// + /// Reads a Ray. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Ray2D ReadRay2D() + { + Vector3 position = ReadVector2(); + Vector2 direction = ReadVector2(); + return new Ray2D(position, direction); + } + + /// + /// Reads a Matrix4x4. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Matrix4x4 ReadMatrix4x4() + { + Matrix4x4 result = new Matrix4x4 + { + m00 = ReadSingle(), + m01 = ReadSingle(), + m02 = ReadSingle(), + m03 = ReadSingle(), + m10 = ReadSingle(), + m11 = ReadSingle(), + m12 = ReadSingle(), + m13 = ReadSingle(), + m20 = ReadSingle(), + m21 = ReadSingle(), + m22 = ReadSingle(), + m23 = ReadSingle(), + m30 = ReadSingle(), + m31 = ReadSingle(), + m32 = ReadSingle(), + m33 = ReadSingle() + }; + + return result; + } + + /// + /// Creates a new byte array and reads bytes into it. + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ReadBytesAllocated(int count) + { + byte[] bytes = ByteArrayPool.Retrieve(count); + ReadBytes(ref bytes, count); + return bytes; + } + + /// + /// Reads a Guid. + /// + /// + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public System.Guid ReadGuid() + { + ReadBytes(ref _guidBuffer, 16); + return new System.Guid(_guidBuffer); + } + + + /// + /// Reads a GameObject. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public GameObject ReadGameObject() + { + NetworkObject nob = ReadNetworkObject(); + return (nob == null) ? null : nob.gameObject; + } + + + /// + /// Reads a Transform. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Transform ReadTransform() + { + NetworkObject nob = ReadNetworkObject(); + return (nob == null) ? null : nob.transform; + } + + + /// + /// Reads a NetworkObject. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NetworkObject ReadNetworkObject() + { + return ReadNetworkObject(out _); + } + + + /// + /// Reads a NetworkObject. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NetworkObject ReadNetworkObject(out int objectId) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + LastNetworkBehaviour = null; +#endif + bool isSpawned = ReadBoolean(); + objectId = ReadInt16(); + /* -1 indicates that the object + * is null or no PrefabId is set. + * PrefabIds are set in Awake within + * the NetworkManager so that should + * never happen so long as nob isn't null. */ + if (objectId == -1) + return null; + + bool isServer = NetworkManager.ServerManager.Started; + bool isClient = NetworkManager.ClientManager.Started; + + NetworkObject result; + //Is spawned. + if (isSpawned) + { + result = null; + /* Try to get the object client side first if client + * is running. When acting as a host generally the object + * will be available in the server and client list + * but there can be occasions where the server side + * deinitializes the object, making it unavailable, while + * it is still available in the client side. Since FishNet doesn't + * use a fake host connection like some lesser solutions the client + * has to always be treated as it's own entity. */ + if (isClient) + NetworkManager.ClientManager.Objects.Spawned.TryGetValueIL2CPP(objectId, out result); + //If not found on client and server is running then try server. + if (result == null && isServer) + NetworkManager.ServerManager.Objects.Spawned.TryGetValueIL2CPP(objectId, out result); + } + //Not spawned. + else + { + + //Only look up asServer if not client, otherwise use client. + bool asServer = !isClient; + //Look up prefab. + result = NetworkManager.SpawnablePrefabs.GetObject(asServer, objectId); + } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + LastNetworkObject = result; +#endif + return result; + } + + /// + /// Reads a NetworkBehaviour. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NetworkBehaviour ReadNetworkBehaviour(out int objectId, out byte componentIndex) + { + NetworkObject nob = ReadNetworkObject(out objectId); + componentIndex = ReadByte(); + + NetworkBehaviour result; + if (nob == null) + { + result = null; + } + else + { + if (componentIndex >= nob.NetworkBehaviours.Length) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"ComponentIndex of {componentIndex} is out of bounds on {nob.gameObject.name} [id {nob.ObjectId}]. This may occur if you have modified your gameObject/prefab without saving it, or the scene."); + result = null; + } + else + { + result = nob.NetworkBehaviours[componentIndex]; + } + } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + LastNetworkBehaviour = result; +#endif + return result; + } + + /// + /// Reads a NetworkBehaviour. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NetworkBehaviour ReadNetworkBehaviour() + { + return ReadNetworkBehaviour(out _, out _); + } + + /// + /// Writes a transport channel. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Channel ReadChannel() + { + return (Channel)ReadByte(); + } + + /// + /// Reads the Id for a NetworkConnection. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadNetworkConnectionId() + { + return ReadInt16(); + } + + /// + /// Reads the Id for a NetworkObject. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadNetworkObjectId() + { + //Clear spawned. + ReadBoolean(); + return ReadInt16(); + } + + /// + /// Writes a NetworkConnection. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NetworkConnection ReadNetworkConnection() + { + int value = ReadInt16(); + if (value == -1) + { + return FishNet.Managing.NetworkManager.EmptyConnection; + } + else + { + //Prefer server. + if (NetworkManager.IsServer) + { + NetworkConnection result; + if (NetworkManager.ServerManager.Clients.TryGetValueIL2CPP(value, out result)) + { + return result; + } + //If also client then try client side data. + else if (NetworkManager.IsClient) + { + //If found in client collection then return. + if (NetworkManager.ClientManager.Clients.TryGetValueIL2CPP(value, out result)) + return result; + //Otherwise make a new instance. + else + return new NetworkConnection(NetworkManager, value); + + } + //Only server and not found. + else + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Unable to find connection for read Id {value}. An empty connection will be returned."); + return FishNet.Managing.NetworkManager.EmptyConnection; + } + } + //Try client side, will only be able to fetch against local connection. + else + { + //If value is self then return self. + if (value == NetworkManager.ClientManager.Connection.ClientId) + return NetworkManager.ClientManager.Connection; + //Try client side dictionary. + else if (NetworkManager.ClientManager.Clients.TryGetValueIL2CPP(value, out NetworkConnection result)) + return result; + //Otherwise return a new connection. + else + return new NetworkConnection(NetworkManager, value); //todo make and use NC cache. + } + + } + } + + /// + /// Checks if the size could possibly be an allocation attack. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool CheckAllocationAttack(int size) + { + /* Possible attacks. Impossible size, or size indicates + * more elements in collection or more bytes needed + * than what bytes are available. */ + if (size < -1) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Size of {size} is invalid."); + return false; + } + if (size > Remaining) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Read size of {size} is larger than remaining data of {Remaining}."); + return false; + } + + //Checks pass. + return true; + } + + + #region Packed readers. + /// + /// ZigZag decode an integer. Move the sign bit back to the left. + /// + public ulong ZigZagDecode(ulong value) + { + ulong sign = value << 63; + if (sign > 0) + return ~(value >> 1) | sign; + return value >> 1; + } + /// + /// Reads a packed whole number. + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadPackedWhole() + { + byte data = ReadByte(); + ulong result = (ulong)(data & 0x7F); + if ((data & 0x80) == 0) return result; + + data = ReadByte(); + result |= (ulong)(data & 0x7F) << 7; + if ((data & 0x80) == 0) return result; + + data = ReadByte(); + result |= (ulong)(data & 0x7F) << 14; + if ((data & 0x80) == 0) return result; + + data = ReadByte(); + result |= (ulong)(data & 0x7F) << 21; + if ((data & 0x80) == 0) return result; + + data = ReadByte(); + result |= (ulong)(data & 0x0F) << 28; + int extraBytes = data >> 4; + + switch (extraBytes) + { + case 0: + break; + case 1: + result |= (ulong)ReadByte() << 32; + break; + case 2: + result |= (ulong)ReadByte() << 32; + result |= (ulong)ReadByte() << 40; + break; + case 3: + result |= (ulong)ReadByte() << 32; + result |= (ulong)ReadByte() << 40; + result |= (ulong)ReadByte() << 48; + break; + case 4: + result |= (ulong)ReadByte() << 32; + result |= (ulong)ReadByte() << 40; + result |= (ulong)ReadByte() << 48; + result |= (ulong)ReadByte() << 56; + break; + } + return result; + } + #endregion + + #region Generators. + /// + /// Reads a list. + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public List ReadListAllocated() + { + List result = null; + ReadList(ref result); + return result; + } + /// + /// Reads into collection and returns amount read. + /// + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadList(ref List collection) + { + int count = ReadInt32(); + if (count == -1) + { + return 0; + } + else if (count == 0) + { + if (collection == null) + collection = new List(); + + return 0; + } + else + { + //Initialize buffer if not already done. + if (collection == null) + collection = new List(count); + else if (collection.Count < count) + collection.Capacity = count; + + for (int i = 0; i < count; i++) + collection[i] = Read(); + + return count; + } + } + /// + /// Reads an array. + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T[] ReadArrayAllocated() + { + T[] result = null; + ReadArray(ref result); + return result; + } + /// + /// Reads into collection and returns amount read. + /// + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadArray(ref T[] collection) + { + int count = ReadInt32(); + if (count == -1) + { + return 0; + } + else if (count == 0) + { + if (collection == null) + collection = new T[0]; + + return 0; + } + else + { + //Initialize buffer if not already done. + if (collection == null) + collection = new T[count]; + else if (collection.Length < count) + Array.Resize(ref collection, count); + + for (int i = 0; i < count; i++) + collection[i] = Read(); + + return count; + } + } + + /// + /// Reads any supported type. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Read() + { + if (IsAutoPackType(out AutoPackType packType)) + { + Func del = GenericReader.ReadAutoPack; + if (del == null) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Read method not found for {typeof(T).Name}. Use a supported type or create a custom serializer."); + return default; + } + else + { + return del.Invoke(this, packType); + } + } + else + { + Func del = GenericReader.Read; + if (del == null) + { + if (NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Read method not found for {typeof(T).Name}. Use a supported type or create a custom serializer."); + return default; + } + else + { + return del.Invoke(this); + } + } + + } + + /// + /// Returns if T takes AutoPackType argument. + /// + /// Outputs the default pack type for T. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal bool IsAutoPackType(out AutoPackType packType) => Writer.IsAutoPackType(out packType); + #endregion + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs.meta new file mode 100644 index 0000000..228c99c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Reader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 680939c6cee93b64ba149da2029f4308 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs new file mode 100644 index 0000000..8dd8a5c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs @@ -0,0 +1,66 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using System; +using UnityEngine; + +namespace FishNet.Serializing +{ + /// + /// Extensions to Read methods. Used by Read. + /// Internal use. + /// + [APIExclude] + public static class ReaderExtensions + { + + public static byte ReadByte(this Reader reader) => reader.ReadByte(); + [CodegenExclude] + public static void ReadBytes(this Reader reader, ref byte[] target, int count) => reader.ReadBytes(ref target, count); + public static byte[] ReadBytesAndSizeAllocated(this Reader reader) => reader.ReadBytesAndSizeAllocated(); + [CodegenExclude] + public static int ReadBytesAndSize(this Reader reader, ref byte[] target) => reader.ReadBytesAndSize(ref target); + [CodegenExclude] + public static ArraySegment ReadArraySegment(this Reader reader, int count) => reader.ReadArraySegment(count); + public static ArraySegment ReadArraySegmentAndSize(this Reader reader) => reader.ReadArraySegmentAndSize(); + public static sbyte ReadSByte(this Reader reader) => reader.ReadSByte(); + public static char ReadChar(this Reader reader) => reader.ReadChar(); + public static bool ReadBoolean(this Reader reader) => reader.ReadBoolean(); + public static short ReadInt16(this Reader reader) => reader.ReadInt16(); + public static ushort ReadUInt16(this Reader reader) => reader.ReadUInt16(); + public static int ReadInt32(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadInt32(packType); + public static uint ReadUInt32(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadUInt32(packType); + public static long ReadInt64(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadInt64(packType); + public static ulong ReadUInt64(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadUInt64(packType); + public static float ReadSingle(this Reader reader, AutoPackType packType = AutoPackType.Unpacked) => reader.ReadSingle(packType); + public static double ReadDouble(this Reader reader) => reader.ReadDouble(); + public static decimal ReadDecimal(this Reader reader) => reader.ReadDecimal(); + public static string ReadString(this Reader reader) => reader.ReadString(); + public static Vector2 ReadVector2(this Reader reader) => reader.ReadVector2(); + public static Vector3 ReadVector3(this Reader reader) => reader.ReadVector3(); + public static Vector4 ReadVector4(this Reader reader) => reader.ReadVector4(); + public static Vector2Int ReadVector2Int(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadVector2Int(packType); + public static Vector3Int ReadVector3Int(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadVector3Int(packType); + public static Color ReadColor(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadColor(packType); + public static Color32 ReadColor32(this Reader reader) => reader.ReadColor32(); + public static Quaternion ReadQuaternion(this Reader reader, AutoPackType packType = AutoPackType.Packed) => reader.ReadQuaternion(packType); + public static Rect ReadRect(this Reader reader) => reader.ReadRect(); + public static Plane ReadPlane(this Reader reader) => reader.ReadPlane(); + public static Ray ReadRay(this Reader reader) => reader.ReadRay(); + public static Ray2D ReadRay2D(this Reader reader) => reader.ReadRay2D(); + public static Matrix4x4 ReadMatrix4x4(this Reader reader) => reader.ReadMatrix4x4(); + [CodegenExclude] + public static byte[] ReadBytesAllocated(this Reader reader, int count) => reader.ReadBytesAllocated(count); + public static System.Guid ReadGuid(this Reader reader) => reader.ReadGuid(); + public static GameObject ReadGameObject(this Reader reader) => reader.ReadGameObject(); + public static Transform ReadTransform(this Reader reader) => reader.ReadTransform(); + public static NetworkObject ReadNetworkObject(this Reader reader) => reader.ReadNetworkObject(); + public static NetworkBehaviour ReadNetworkBehaviour(this Reader reader) => reader.ReadNetworkBehaviour(); + public static Channel ReadChannel(this Reader reader) => reader.ReadChannel(); + public static NetworkConnection ReadNetworkConnection(this Reader reader) => reader.ReadNetworkConnection(); + [CodegenExclude] + public static T Read(this Reader reader) => reader.Read(); + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs.meta new file mode 100644 index 0000000..1319c52 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abcc77fe436138b4082ee27da3055bb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs new file mode 100644 index 0000000..da918c0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs @@ -0,0 +1,68 @@ +using FishNet.Managing; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace FishNet.Serializing +{ + /// + /// Reader which is reused to save on garbage collection and performance. + /// + public sealed class PooledReader : Reader, IDisposable + { + internal PooledReader(byte[] bytes, NetworkManager networkManager) : base(bytes, networkManager) { } + internal PooledReader(ArraySegment segment, NetworkManager networkManager) : base(segment, networkManager) { } + public void Dispose() => ReaderPool.Recycle(this); + } + + /// + /// Collection of PooledReader. Stores and gets PooledReader. + /// + public static class ReaderPool + { + #region Private. + /// + /// Pool of readers. + /// + private static readonly Stack _pool = new Stack(); + #endregion + + /// + /// Get the next reader in the pool + /// If pool is empty, creates a new Reader + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PooledReader GetReader(byte[] bytes, NetworkManager networkManager) + { + return GetReader(new ArraySegment(bytes), networkManager); + } + + /// + /// Get the next reader in the pool or creates a new one if none are available. + /// + public static PooledReader GetReader(ArraySegment segment, NetworkManager networkManager) + { + PooledReader result; + if (_pool.Count > 0) + { + result = _pool.Pop(); + result.Initialize(segment, networkManager); + } + else + { + result = new PooledReader(segment, networkManager); + } + + return result; + } + + /// + /// Puts reader back into pool + /// When pool is full, the extra reader is left for the GC + /// + public static void Recycle(PooledReader reader) + { + _pool.Push(reader); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs.meta new file mode 100644 index 0000000..eb0bdae --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/ReaderPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 318b117dd2ebd1b4b9e2021796b45eee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs new file mode 100644 index 0000000..4d1d8d9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs @@ -0,0 +1,10 @@ +namespace FishNet.Serializing +{ + [System.Serializable] + internal class TransformPackingData + { + public AutoPackType Position = AutoPackType.Packed; + public AutoPackType Rotation = AutoPackType.Packed; + public AutoPackType Scale = AutoPackType.Packed; + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs.meta new file mode 100644 index 0000000..2c3013a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/TransformPackingData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80a80dabe02daf6428cce0f16ea49877 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs new file mode 100644 index 0000000..3beefd6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs @@ -0,0 +1,1090 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Object; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using FishNet.Utility.Constant; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using UnityEngine; + +[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; set; } + public static Action WriteAutoPack { get; set; } + } + + /// + /// Writes data to a buffer. + /// + public class Writer + { + #region Public. + /// + /// Current write position. + /// + public int Position; + /// + /// Number of bytes writen to the buffer. + /// + public int Length; + /// + /// NetworkManager associated with this writer. May be null. + /// + public NetworkManager NetworkManager; + #endregion + + #region Private. + /// + /// Buffer to prevent new allocations. This will grow as needed. + /// + private byte[] _buffer = new byte[64]; + /// + /// Encoder for strings. + /// + private readonly UTF8Encoding _encoding = new UTF8Encoding(false, true); + /// + /// StringBuffer to use with encoding. + /// + private byte[] _stringBuffer = new byte[64]; + #endregion + + /// + /// Resets the writer as though it was unused. Does not reset buffers. + /// + public void Reset(NetworkManager manager = null) + { + Length = 0; + Position = 0; + NetworkManager = manager; + } + + /// + /// Writes a dictionary. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteDictionary(Dictionary dict) + { + if (dict == null) + { + WriteBoolean(true); + return; + } + else + { + WriteBoolean(false); + } + + WriteInt32(dict.Count); + foreach (KeyValuePair item in dict) + { + Write(item.Key); + Write(item.Value); + } + } + + /// + /// Ensure a number of bytes to be available in the buffer from current position. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureBufferLength(int count) + { + if (Position + count > _buffer.Length) + { + int nextSize = (_buffer.Length * 2) + count; + Array.Resize(ref _buffer, nextSize); + } + } + + /// + /// Returns the buffer. The returned value will be the full buffer, even if not all of it is used. + /// + /// + public byte[] GetBuffer() + { + return _buffer; + } + + /// + /// Returns the used portion of the buffer as an ArraySegment. + /// + /// + public ArraySegment GetArraySegment() + { + return new ArraySegment(_buffer, 0, Length); + } + + /// + /// Reserves a number of bytes from current position. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reserve(int count) + { + EnsureBufferLength(count); + Position += count; + Length = Math.Max(Length, Position); + } + + /// + /// Writes length. This method is used to make debugging easier. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteLength(int length) + { + WriteInt32(length); + } + + /// + /// Sends a packetId. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WritePacketId(PacketId pid) + { + WriteUInt16((ushort)pid); + } + + /// + /// Inserts value at index within the buffer. + /// This method does not perform error checks. + /// + /// + /// + [CodegenExclude] + public void FastInsertByte(byte value, int index) + { + _buffer[index] = value; + } + + /// + /// Writes a byte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteByte(byte value) + { + EnsureBufferLength(1); + _buffer[Position++] = value; + + Length = Math.Max(Length, Position); + } + + /// + /// Writes bytes. + /// + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytes(byte[] buffer, int offset, int count) + { + EnsureBufferLength(count); + Buffer.BlockCopy(buffer, offset, _buffer, Position, count); + Position += count; + Length = Math.Max(Length, Position); + } + + /// + /// Writes bytes and length of bytes. + /// + /// + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytesAndSize(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + WriteInt32(-1); + } + else + { + WriteInt32(count); + WriteBytes(buffer, offset, count); + } + } + + /// + /// Writes all bytes in value and length of bytes. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytesAndSize(byte[] value) + { + int size = (value == null) ? 0 : value.Length; + // buffer might be null, so we can't use .Length in that case + WriteBytesAndSize(value, 0, size); + } + + + /// + /// Writes a sbyte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteSByte(sbyte value) + { + EnsureBufferLength(1); + _buffer[Position++] = (byte)value; + Length = Math.Max(Length, Position); + } + + /// + /// Writes a char. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteChar(char value) + { + EnsureBufferLength(2); + _buffer[Position++] = (byte)value; + _buffer[Position++] = (byte)(value >> 8); + Length = Math.Max(Length, Position); + } + + /// + /// Writes a boolean. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBoolean(bool value) + { + EnsureBufferLength(1); + _buffer[Position++] = (value) ? (byte)1 : (byte)0; + Length = Math.Max(Length, Position); + } + + /// + /// Writes a uint16. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt16(ushort value) + { + EnsureBufferLength(2); + _buffer[Position++] = (byte)value; + _buffer[Position++] = (byte)(value >> 8); + Length = Math.Max(Length, Position); + } + + /// + /// Writes a int16. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteInt16(short value) + { + EnsureBufferLength(2); + _buffer[Position++] = (byte)value; + _buffer[Position++] = (byte)(value >> 8); + Length = Math.Max(Length, Position); + } + + /// + /// Writes a int32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteInt32(int value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + WritePackedWhole(ZigZagEncode((ulong)value)); + else + WriteUInt32((uint)value, packType); + } + /// + /// Writes a uint32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt32(uint value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Unpacked) + { + EnsureBufferLength(4); + WriterExtensions.WriteUInt32(_buffer, value, ref Position); + Length = Math.Max(Length, Position); + } + else + { + WritePackedWhole(value); + } + } + + /// + /// Writes an int64. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteInt64(long value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + WritePackedWhole(ZigZagEncode((ulong)value)); + else + WriteUInt64((ulong)value, packType); + } + /// + /// Writes a uint64. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt64(ulong value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Unpacked) + { + EnsureBufferLength(8); + _buffer[Position++] = (byte)value; + _buffer[Position++] = (byte)(value >> 8); + _buffer[Position++] = (byte)(value >> 16); + _buffer[Position++] = (byte)(value >> 24); + _buffer[Position++] = (byte)(value >> 32); + _buffer[Position++] = (byte)(value >> 40); + _buffer[Position++] = (byte)(value >> 48); + _buffer[Position++] = (byte)(value >> 56); + + Length = Math.Max(Position, Length); + } + else + { + WritePackedWhole(value); + } + } + + /// + /// Writes a single (float). + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteSingle(float value, AutoPackType packType = AutoPackType.Unpacked) + { + if (packType == AutoPackType.Unpacked) + { + UIntFloat converter = new UIntFloat { FloatValue = value }; + WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); + } + else + { + long converter = (long)(value * 100f); + WritePackedWhole((ulong)converter); + } + } + + /// + /// Writes a double. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteDouble(double value) + { + UIntDouble converter = new UIntDouble { DoubleValue = value }; + WriteUInt64(converter.LongValue, AutoPackType.Unpacked); + } + + /// + /// Writes a decimal. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteDecimal(decimal value) + { + UIntDecimal converter = new UIntDecimal { DecimalValue = value }; + WriteUInt64(converter.LongValue1, AutoPackType.Unpacked); + WriteUInt64(converter.LongValue2, AutoPackType.Unpacked); + } + + /// + /// Writes a string. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteString(string value) + { + if (value == null) + { + WriteInt32(-1); + return; + } + else if (value.Length == 0) + { + WriteInt32(0); + return; + } + + /* Resize string buffer as needed. There's no harm in + * increasing buffer on writer side because sender will + * never intentionally inflict allocations on itself. + * Reader ensures string count cannot exceed received + * packet size. */ + int valueMaxBytes = _encoding.GetMaxByteCount(value.Length); + if (valueMaxBytes >= _stringBuffer.Length) + { + int nextSize = (_stringBuffer.Length * 2) + valueMaxBytes; + Array.Resize(ref _stringBuffer, nextSize); + } + + int size = _encoding.GetBytes(value, 0, value.Length, _stringBuffer, 0); + WriteInt32(size); + WriteBytes(_stringBuffer, 0, size); + } + + /// + /// Writes a byte ArraySegment and it's size. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteArraySegmentAndSize(ArraySegment value) + { + WriteBytesAndSize(value.Array, value.Offset, value.Count); + } + + /// + /// Writes an ArraySegment without size. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteArraySegment(ArraySegment value) + { + WriteBytes(value.Array, value.Offset, value.Count); + } + + /// + /// Writes a Vector2. + /// + /// + [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); + } + + /// + /// Writes a Vector3 + /// + /// + [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); + } + + /// + /// Writes a Vector4. + /// + /// + [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); + } + + /// + /// Writes a Vector2Int. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector2Int(Vector2Int value, AutoPackType packType = AutoPackType.Packed) + { + WriteInt32(value.x, packType); + WriteInt32(value.y, packType); + } + + /// + /// Writes a Vector3Int. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector3Int(Vector3Int value, AutoPackType packType = AutoPackType.Packed) + { + WriteInt32(value.x, packType); + WriteInt32(value.y, packType); + WriteInt32(value.z, packType); + } + + /// + /// Writes a Color. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteColor(Color value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Unpacked) + { + WriteSingle(value.r); + WriteSingle(value.g); + WriteSingle(value.b); + WriteSingle(value.a); + } + else + { + EnsureBufferLength(4); + _buffer[Position++] = (byte)(value.r * 100f); + _buffer[Position++] = (byte)(value.g * 100f); + _buffer[Position++] = (byte)(value.b * 100f); + _buffer[Position++] = (byte)(value.a * 100f); + + Length = Math.Max(Length, Position); + } + } + + /// + /// Writes a Color32. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteColor32(Color32 value) + { + EnsureBufferLength(4); + _buffer[Position++] = value.r; + _buffer[Position++] = value.g; + _buffer[Position++] = value.b; + _buffer[Position++] = value.a; + + Length = Math.Max(Length, Position); + } + + /// + /// Writes a Quaternion. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteQuaternion(Quaternion value, AutoPackType packType = AutoPackType.Packed) + { + if (packType == AutoPackType.Packed) + { + EnsureBufferLength(4); + uint result = Quaternion32Compression.Compress(value); + WriterExtensions.WriteUInt32(_buffer, result, ref Position); + Length = Math.Max(Length, Position); + } + else if (packType == AutoPackType.PackedLess) + { + EnsureBufferLength(8); + ulong result = Quaternion64Compression.Compress(value); + WriterExtensions.WriteUInt64(_buffer, result, ref Position); + Length = Math.Max(Length, Position); + } + else + { + EnsureBufferLength(16); + WriteSingle(value.x); + WriteSingle(value.y); + WriteSingle(value.z); + WriteSingle(value.w); + } + } + + /// + /// Writes a rect. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRect(Rect value) + { + WriteSingle(value.xMin); + WriteSingle(value.yMin); + WriteSingle(value.width); + WriteSingle(value.height); + } + + /// + /// Writes a plane. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WritePlane(Plane value) + { + WriteVector3(value.normal); + WriteSingle(value.distance); + } + + /// + /// Writes a Ray. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRay(Ray value) + { + WriteVector3(value.origin); + WriteVector3(value.direction); + } + + /// + /// Writes a Ray2D. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRay2D(Ray2D value) + { + WriteVector2(value.origin); + WriteVector2(value.direction); + } + + + /// + /// Writes a Matrix4x4. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteMatrix4x4(Matrix4x4 value) + { + WriteSingle(value.m00); + WriteSingle(value.m01); + WriteSingle(value.m02); + WriteSingle(value.m03); + WriteSingle(value.m10); + WriteSingle(value.m11); + WriteSingle(value.m12); + WriteSingle(value.m13); + WriteSingle(value.m20); + WriteSingle(value.m21); + WriteSingle(value.m22); + WriteSingle(value.m23); + WriteSingle(value.m30); + WriteSingle(value.m31); + WriteSingle(value.m32); + WriteSingle(value.m33); + } + + /// + /// Writes a Guid. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteGuidAllocated(System.Guid value) + { + byte[] data = value.ToByteArray(); + WriteBytes(data, 0, data.Length); + } + + /// + /// Writes a GameObject. GameObject must be spawned over the network already or be a prefab with a NetworkObject attached. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteGameObject(GameObject go) + { + if (go == null) + { + WriteNetworkObject(null); + } + else + { + NetworkObject nob = go.GetComponent(); + WriteNetworkObject(nob); + } + } + + /// + /// Writes a Transform. Transform must be spawned over the network already or be a prefab with a NetworkObject attached. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteTransform(Transform t) + { + if (t == null) + { + WriteNetworkObject(null); + } + else + { + NetworkObject nob = t.GetComponent(); + WriteNetworkObject(nob); + } + } + + + /// + /// Writes a NetworkObject. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteNetworkObject(NetworkObject nob) + { + bool isSpawned = (nob != null && nob.IsSpawned); + WriteBoolean(isSpawned); + + if (isSpawned) + { + WriteInt16((short)nob.ObjectId); + } + else + { + if (nob == null) + WriteInt16(-1); + else + WriteInt16(nob.PrefabId); + } + } + + /// + /// Writes a NetworkBehaviour. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteNetworkBehaviour(NetworkBehaviour nb) + { + if (nb == null) + { + WriteNetworkObject(null); + WriteByte(0); + } + else + { + WriteNetworkObject(nb.NetworkObject); + WriteByte(nb.ComponentIndex); + } + } + + /// + /// Writes a transport channel. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteChannel(Channel channel) + { + WriteByte((byte)channel); + } + + /// + /// Writes a NetworkConnection. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteNetworkConnection(NetworkConnection connection) + { + int value = (connection == null) ? -1 : connection.ClientId; + WriteInt16((short)value); + } + + /// + /// Writes a short for a connectionId. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteNetworkConnectionId(short id) + { + WriteInt16(id); + } + + #region Packed writers. + /// + /// ZigZag encode an integer. Move the sign bit to the right. + /// + [CodegenExclude] + public ulong ZigZagEncode(ulong value) + { + if (value >> 63 > 0) + return ~(value << 1) | 1; + return value << 1; + } + /// + /// Writes a packed whole number. + /// + /// + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WritePackedWhole(ulong value) + { + if (value < 0x80UL) + { + EnsureBufferLength(1); + _buffer[Position++] = (byte)(value & 0x7F); + } + else if (value < 0x4000UL) + { + EnsureBufferLength(2); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)((value >> 7) & 0x7F); + } + else if (value < 0x200000UL) + { + EnsureBufferLength(3); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)((value >> 14) & 0x7F); + } + else if (value < 0x10000000UL) + { + EnsureBufferLength(4); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)((value >> 21) & 0x7F); + } + else if (value < 0x100000000UL) + { + EnsureBufferLength(5); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 21) & 0x7F)); + _buffer[Position++] = (byte)((value >> 28) & 0x0F); + } + else if (value < 0x10000000000UL) + { + EnsureBufferLength(6); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 21) & 0x7F)); + _buffer[Position++] = (byte)(0x10 | ((value >> 28) & 0x0F)); + _buffer[Position++] = (byte)((value >> 32) & 0xFF); + } + else if (value < 0x1000000000000UL) + { + EnsureBufferLength(7); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 21) & 0x7F)); + _buffer[Position++] = (byte)(0x20 | ((value >> 28) & 0x0F)); + _buffer[Position++] = (byte)((value >> 32) & 0xFF); + _buffer[Position++] = (byte)((value >> 40) & 0xFF); + } + else if (value < 0x100000000000000UL) + { + EnsureBufferLength(8); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 21) & 0x7F)); + _buffer[Position++] = (byte)(0x30 | ((value >> 28) & 0x0F)); + _buffer[Position++] = (byte)((value >> 32) & 0xFF); + _buffer[Position++] = (byte)((value >> 40) & 0xFF); + _buffer[Position++] = (byte)((value >> 48) & 0xFF); + } + else + { + EnsureBufferLength(9); + _buffer[Position++] = (byte)(0x80 | (value & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 7) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 14) & 0x7F)); + _buffer[Position++] = (byte)(0x80 | ((value >> 21) & 0x7F)); + _buffer[Position++] = (byte)(0x40 | ((value >> 28) & 0x0F)); + _buffer[Position++] = (byte)((value >> 32) & 0xFF); + _buffer[Position++] = (byte)((value >> 40) & 0xFF); + _buffer[Position++] = (byte)((value >> 48) & 0xFF); + _buffer[Position++] = (byte)((value >> 56) & 0xFF); + } + + Length = Math.Max(Length, Position); + } + #endregion + + #region Generators. + /// + /// Writes a list. + /// + /// Collection to write. + /// Offset to begin at. + /// Entries to write. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteList(List value, int offset, int count) + { + if (value == null) + { + WriteInt32(-1); + } + else + { + //Make sure values cannot cause out of bounds. + if ((offset + count > value.Count)) + count = 0; + + WriteInt32(count); + for (int i = 0; i < count; i++) + Write(value[i + offset]); + } + } + /// + /// Writes a list. + /// + /// Collection to write. + /// Offset to begin at. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteList(List value, int offset) + { + if (value == null) + WriteList(null, 0, 0); + else + WriteList(value, offset, value.Count - offset); + } + /// + /// Writes a list. + /// + /// Collection to write. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteList(List value) + { + if (value == null) + WriteList(null, 0, 0); + else + WriteList(value, 0, value.Count); + } + + /// + /// Writes an array. + /// + /// Collection to write. + /// Offset to begin at. + /// Entries to write. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteArray(T[] value, int offset, int count) + { + if (value == null) + { + WriteInt32(-1); + } + else + { + //If theres no values, or offset exceeds count then write 0 for count. + if (value.Length == 0 || (offset >= count)) + { + WriteInt32(0); + } + else + { + WriteInt32(count); + for (int i = offset; i < count; i++) + Write(value[i]); + } + } + } + /// + /// Writes an array. + /// + /// Collection to write. + /// Offset to begin at. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteArray(T[] value, int offset) + { + if (value == null) + WriteArray(null, 0, 0); + else + WriteArray(value, offset, value.Length - offset); + } + /// + /// Writes an array. + /// + /// Collection to write. + [CodegenExclude] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteArray(T[] value) + { + if (value == null) + WriteArray(null, 0, 0); + else + WriteArray(value, 0, value.Length); + } + + + /// + /// Writers any supported type. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(T value) + { + if (IsAutoPackType(out AutoPackType packType)) + { + Action del = GenericWriter.WriteAutoPack; + if (del == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Write method not found for {typeof(T).Name}. Use a supported type or create a custom serializer."); + } + else + { + del.Invoke(this, value, packType); + } + } + else + { + Action del = GenericWriter.Write; + if (del == null) + { + if (NetworkManager.StaticCanLog(LoggingType.Error)) + Debug.LogError($"Write method not found for {typeof(T).Name}. Use a supported type or create a custom serializer."); + } + else + { + del.Invoke(this, value); + } + } + } + + /// + /// Returns if T takes AutoPackType argument. + /// + /// Outputs the default pack type for T. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsAutoPackType(out AutoPackType packType) + { + //performance bench this against using a hash lookup. + System.Type type = typeof(T); + if (WriterExtensions.DefaultPackedTypes.Contains(type)) + { + packType = AutoPackType.Packed; + return true; + } + else if (type == typeof(float)) + { + packType = AutoPackType.Unpacked; + return true; + } + else + { + packType = AutoPackType.Unpacked; + return false; + } + } + #endregion + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs.meta new file mode 100644 index 0000000..bfbcd29 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/Writer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2633f927065d9d43b8a4da09240266c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs new file mode 100644 index 0000000..45f76fb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs @@ -0,0 +1,114 @@ +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Object; +using FishNet.Serializing.Helping; +using FishNet.Transporting; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Serializing +{ + + /// + /// Extensions to Write methods. Used by Write. + /// Internal use. + /// + [APIExclude] + public static class WriterExtensions + { + + /// + /// Types which are are set to auto pack by default. + /// + internal static HashSet DefaultPackedTypes = new HashSet(); + + static WriterExtensions() + { + DefaultPackedTypes.Add(typeof(int)); + DefaultPackedTypes.Add(typeof(uint)); + DefaultPackedTypes.Add(typeof(long)); + DefaultPackedTypes.Add(typeof(ulong)); + DefaultPackedTypes.Add(typeof(Color)); + DefaultPackedTypes.Add(typeof(Vector2Int)); + DefaultPackedTypes.Add(typeof(Vector3Int)); + DefaultPackedTypes.Add(typeof(Quaternion)); + } + + /// + /// Writes value to dst without error checking. + /// + [CodegenExclude] + internal static void WriteUInt32(byte[] dst, uint value, ref int position) + { + dst[position++] = (byte)value; + dst[position++] = (byte)(value >> 8); + dst[position++] = (byte)(value >> 16); + dst[position++] = (byte)(value >> 24); + } + /// + /// Writes value to dst without error checking. + /// + [CodegenExclude] + internal static void WriteUInt64(byte[] dst, ulong value, ref int position) + { + dst[position++] = (byte)value; + dst[position++] = (byte)(value >> 8); + dst[position++] = (byte)(value >> 16); + dst[position++] = (byte)(value >> 24); + dst[position++] = (byte)(value >> 32); + dst[position++] = (byte)(value >> 40); + dst[position++] = (byte)(value >> 48); + dst[position++] = (byte)(value >> 56); + } + + + public static void WriteDictionary(this Writer writer, Dictionary dict) => writer.WriteDictionary(dict); + public static void WriteByte(this Writer writer, byte value) => writer.WriteByte(value); + [CodegenExclude] + public static void WriteBytes(this Writer writer, byte[] buffer, int offset, int count) => writer.WriteBytes(buffer, offset, count); + [CodegenExclude] + public static void WriteBytesAndSize(this Writer writer, byte[] buffer, int offset, int count) => writer.WriteBytesAndSize(buffer, offset, count); + public static void WriteBytesAndSize(this Writer writer, byte[] value) => writer.WriteBytesAndSize(value); + + public static void WriteSByte(this Writer writer, sbyte value) => writer.WriteSByte(value); + public static void WriteChar(this Writer writer, char value) => writer.WriteChar(value); + public static void WriteBoolean(this Writer writer, bool value) => writer.WriteBoolean(value); + public static void WriteUInt16(this Writer writer, ushort value) => writer.WriteUInt16(value); + public static void WriteInt16(this Writer writer, short value) => writer.WriteInt16(value); + public static void WriteInt32(this Writer writer, int value, AutoPackType packType = AutoPackType.Packed) => writer.WriteInt32(value, packType); + public static void WriteUInt32(this Writer writer, uint value, AutoPackType packType = AutoPackType.Packed) => writer.WriteUInt32(value, packType); + public static void WriteInt64(this Writer writer, long value, AutoPackType packType = AutoPackType.Packed) => writer.WriteInt64(value, packType); + public static void WriteUInt64(this Writer writer, ulong value, AutoPackType packType = AutoPackType.Packed) => writer.WriteUInt64(value, packType); + public static void WriteSingle(this Writer writer, float value, AutoPackType packType = AutoPackType.Unpacked) => writer.WriteSingle(value, packType); + public static void WriteDouble(this Writer writer, double value) => writer.WriteDouble(value); + public static void WriteDecimal(this Writer writer, decimal value) => writer.WriteDecimal(value); + public static void WriteString(this Writer writer, string value) => writer.WriteString(value); + public static void WriteArraySegmentAndSize(this Writer writer, ArraySegment value) => writer.WriteArraySegmentAndSize(value); + [CodegenExclude] + public static void WriteArraySegment(this Writer writer, ArraySegment value) => writer.WriteArraySegment(value); + public static void WriteVector2(this Writer writer, Vector2 value) => writer.WriteVector2(value); + public static void WriteVector3(this Writer writer, Vector3 value) => writer.WriteVector3(value); + public static void WriteVector4(this Writer writer, Vector4 value) => writer.WriteVector4(value); + public static void WriteVector2Int(this Writer writer, Vector2Int value, AutoPackType packType = AutoPackType.Packed) => writer.WriteVector2Int(value, packType); + public static void WriteVector3Int(this Writer writer, Vector3Int value, AutoPackType packType = AutoPackType.Packed) => writer.WriteVector3Int(value, packType); + public static void WriteColor(this Writer writer, Color value, AutoPackType packType) => writer.WriteColor(value, packType); + public static void WriteColor32(this Writer writer, Color32 value) => writer.WriteColor32(value); + public static void WriteQuaternion(this Writer writer, Quaternion value, AutoPackType packType = AutoPackType.Packed) => writer.WriteQuaternion(value, packType); + public static void WriteRect(this Writer writer, Rect value) => writer.WriteRect(value); + public static void WritePlane(this Writer writer, Plane value) => writer.WritePlane(value); + public static void WriteRay(this Writer writer, Ray value) => writer.WriteRay(value); + public static void WriteRay2D(this Writer writer, Ray2D value) => writer.WriteRay2D(value); + public static void WriteMatrix4x4(this Writer writer, Matrix4x4 value) => writer.WriteMatrix4x4(value); + public static void WriteGuidAllocated(this Writer writer, System.Guid value) => writer.WriteGuidAllocated(value); + public static void WriteGameObject(this Writer writer, GameObject value) => writer.WriteGameObject(value); + public static void WriteTransform(this Writer writer, Transform value) => writer.WriteTransform(value); + public static void WriteNetworkObject(this Writer writer, NetworkObject value) => writer.WriteNetworkObject(value); + public static void WriteNetworkBehaviour(this Writer writer, NetworkBehaviour value) => writer.WriteNetworkBehaviour(value); + public static void WriteChannel(this Writer writer, Channel value) => writer.WriteChannel(value); + public static void WriteNetworkConnection(this Writer writer, NetworkConnection value) => writer.WriteNetworkConnection(value); + [CodegenExclude] + public static void Write(this Writer writer, T value) => writer.Write(value); + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs.meta new file mode 100644 index 0000000..a2229b9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 493e880d63e9372449c0f0e63890aaef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs new file mode 100644 index 0000000..2f2ca67 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs @@ -0,0 +1,56 @@ +using FishNet.Managing; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace FishNet.Serializing +{ + /// + /// Writer which is reused to save on garbage collection and performance. + /// + public sealed class PooledWriter : Writer, IDisposable + { + public void Dispose() => WriterPool.Recycle(this); + } + + /// + /// Collection of PooledWriter. Stores and gets PooledWriter. + /// + public static class WriterPool + { + #region Private. + /// + /// Pool of writers. + /// + private static readonly Stack _pool = new Stack(); + #endregion + + /// + /// Get the next writer in the pool. + /// If pool is empty, creates a new Reader + /// + public static PooledWriter GetWriter(NetworkManager networkManager) + { + PooledWriter result = (_pool.Count > 0) ? _pool.Pop() : new PooledWriter(); + result.Reset(networkManager); + return result; + } + /// + /// Get the next writer in the pool. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PooledWriter GetWriter() + { + return GetWriter(null); + } + + /// + /// Puts writer back into pool + /// When pool is full, the extra writer is left for the GC + /// + public static void Recycle(PooledWriter writer) + { + _pool.Push(writer); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs.meta b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs.meta new file mode 100644 index 0000000..2507ad0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Serializing/WriterPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 99b13ccd24eb7264abf67780ef86e44a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting.meta b/UnityProject/Assets/FishNet/Runtime/Transporting.meta new file mode 100644 index 0000000..b4e33ce --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 693688363b7a8f746a35a5a6168d82b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs new file mode 100644 index 0000000..195adef --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs @@ -0,0 +1,19 @@ +namespace FishNet.Transporting +{ + /// + /// Channel which data is sent or received. + /// + public enum Channel : byte + { + /// + /// Data will be sent ordered reliable. + /// + Reliable = 0, + /// + /// Data will be sent unreliable. + /// + Unreliable = 1 + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs.meta new file mode 100644 index 0000000..1227bfa --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Channels.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7cd503d67a974984385164c53bd3e518 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs new file mode 100644 index 0000000..ba0a35b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs @@ -0,0 +1,43 @@ +namespace FishNet.Transporting +{ + + /// + /// States the local connection can be in. + /// + public enum LocalConnectionState : byte + { + /// + /// Connection is fully stopped. + /// + Stopped = 0, + /// + /// Connection is starting but not yet established. + /// + Starting = 1, + /// + /// Connection is established. + /// + Started = 2, + /// + /// Connection is stopping. + /// + Stopping = 3 + } + + /// + /// States a remote client can be in. + /// + public enum RemoteConnectionState : byte + { + /// + /// Connection is fully stopped. + /// + Stopped = 0, + /// + /// Connection is established. + /// + Started = 2, + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs.meta new file mode 100644 index 0000000..cb22c93 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/ConnectionStates.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45640e2b3919981499b359ecc2154d3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs new file mode 100644 index 0000000..93ef9ae --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs @@ -0,0 +1,152 @@ +using System; + +namespace FishNet.Transporting +{ + /// + /// Container about data received on the server. + /// + public struct ServerReceivedDataArgs + { + /// + /// Data received. + /// + public ArraySegment Data; + /// + /// Channel data was received on. + /// + public Channel Channel; + /// + /// ConnectionId from which client sent data, if data was received on the server. + /// + public int ConnectionId; + /// + /// Index of the transport that is for. + /// This is primarily used when supporting multiple transports. + /// + public int TransportIndex; + /// + /// Delegate to invoke after data is processed. + /// + /// + public Action FinalizeMethod; + + public ServerReceivedDataArgs(ArraySegment data, Channel channel, int connectionId, int transportIndex) + { + Data = data; + Channel = channel; + ConnectionId = connectionId; + TransportIndex = transportIndex; + FinalizeMethod = null; + } + public ServerReceivedDataArgs(ArraySegment data, Channel channel, int connectionId, int transportIndex, Action finalizeMethod) + { + Data = data; + Channel = channel; + ConnectionId = connectionId; + TransportIndex = transportIndex; + FinalizeMethod = finalizeMethod; + } + } + + + /// + /// Container about data received on the local client. + /// + public struct ClientReceivedDataArgs + { + /// + /// Data received. + /// + public ArraySegment Data; + /// + /// Channel data was received on. + /// + public Channel Channel; + /// + /// Index of the transport that is for. + /// This is primarily used when supporting multiple transports. + /// + public int TransportIndex; + + public ClientReceivedDataArgs(ArraySegment data, Channel channel, int transportIndex) + { + Data = data; + Channel = channel; + TransportIndex = transportIndex; + } + } + + + + /// + /// Container about a connection state change for a client. + /// + public struct RemoteConnectionStateArgs + { + /// + /// Index of the transport that is for. + /// This is primarily used when supporting multiple transports. + /// + public int TransportIndex; + /// + /// New connection state. + /// + public RemoteConnectionState ConnectionState; + /// + /// ConnectionId for which client the state changed. Will be -1 if ConnectionState was for the local server. + /// + public int ConnectionId; + + public RemoteConnectionStateArgs(RemoteConnectionState connectionState, int connectionId, int transportIndex) + { + ConnectionState = connectionState; + ConnectionId = connectionId; + TransportIndex = transportIndex; + } + } + + /// + /// Container about a connection state change for the server. + /// + public struct ServerConnectionStateArgs + { + /// + /// Index of the transport that is for. + /// This is primarily used when supporting multiple transports. + /// + public int TransportIndex; + /// + /// New connection state. + /// + public LocalConnectionState ConnectionState; + + public ServerConnectionStateArgs(LocalConnectionState connectionState, int transportIndex) + { + ConnectionState = connectionState; + TransportIndex = transportIndex; + } + } + + /// + /// Container about a connection state change for the local client. + /// + public struct ClientConnectionStateArgs + { + /// + /// New connection state. + /// + public LocalConnectionState ConnectionState; + /// + /// Index of the transport that is for. + /// This is primarily used when supporting multiple transports. + /// + public int TransportIndex; + + public ClientConnectionStateArgs(LocalConnectionState connectionState, int transportIndex) + { + ConnectionState = connectionState; + TransportIndex = transportIndex; + } + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs.meta new file mode 100644 index 0000000..3113c88 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/EventStructures.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 718b9d27800e70848b50b2c7b0117e5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs new file mode 100644 index 0000000..0cc079e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs @@ -0,0 +1,19 @@ +namespace FishNet.Transporting +{ + /// + /// Channel which data is sent or received. + /// + public enum IPAddressType : byte + { + /// + /// Address is IPv4. + /// + IPv4 = 0, + /// + /// Address is IPv6. + /// + IPv6 = 1 + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs.meta new file mode 100644 index 0000000..4522f21 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/IPAddressType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11a2c7610ce4ce34a915683bd4607714 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs new file mode 100644 index 0000000..e5953b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs @@ -0,0 +1,33 @@ +using FishNet.Managing.Timing; +using UnityEngine; + +namespace FishNet.Transporting +{ + [DisallowMultipleComponent] + [DefaultExecutionOrder(short.MinValue)] + internal class NetworkReaderLoop : MonoBehaviour + { + #region Private. + /// + /// TimeManager this loop is for. + /// + private TimeManager _timeManager; + #endregion + + private void Awake() + { + _timeManager = GetComponent(); + } + + private void FixedUpdate() + { + _timeManager.TickFixedUpdate(); + } + private void Update() + { + _timeManager.TickUpdate(); + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs.meta new file mode 100644 index 0000000..f4ed745 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkReaderLoop.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d359d6ef33641f41a2ae67d1abdfdd3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs new file mode 100644 index 0000000..634ee44 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs @@ -0,0 +1,38 @@ +using FishNet.Managing.Timing; +using UnityEngine; + +namespace FishNet.Transporting +{ + [DisallowMultipleComponent] + [DefaultExecutionOrder(short.MaxValue)] + internal class NetworkWriterLoop : MonoBehaviour + { + #region Private. + /// + /// TimeManager this loop is for. + /// + private TimeManager _timeManager; + #endregion + + private void Awake() + { + _timeManager = GetComponent(); + } + + private void LateUpdate() + { + Iterate(); + } + + /// + /// Performs read on transport. + /// + private void Iterate() + { + _timeManager.TickLateUpdate(); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs.meta new file mode 100644 index 0000000..3038d73 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/NetworkWriterLoop.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2fed05d526ab23949bac6cd2bf041c35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs new file mode 100644 index 0000000..c153303 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs @@ -0,0 +1,32 @@ +using FishNet.Documenting; + +namespace FishNet.Transporting +{ + + /// + /// PacketIds to indicate the type of packet which is being sent or arriving. + /// + [APIExclude] + public enum PacketId : ushort + { + Unset = 0, + Authenticated = 1, + Split = 2, + ObjectSpawn = 3, + ObjectDespawn = 4, + Event = 5, + SyncVar = 6, + ServerRpc = 7, + ObserversRpc = 8, + TargetRpc = 10, + OwnershipChange = 11, + Broadcast = 12, + SyncObject = 13, + PingPong = 14, + Replicate = 15, + Reconcile = 16, + Disconnect = 17, + TimingUpdate = 18 + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs.meta new file mode 100644 index 0000000..6fa4a88 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/PacketId.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f3b7256982245b46a2925e2b94ce149 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs new file mode 100644 index 0000000..5642d86 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs @@ -0,0 +1,248 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using System; +using UnityEngine; + +namespace FishNet.Transporting +{ + + /// + /// Processes connection states, and data sent to and from a socket. + /// + public abstract class Transport : MonoBehaviour + { + #region Private. + /// + /// NetworkManager for this transport. + /// + public NetworkManager NetworkManager { get; private set; } + /// + /// Index this transport belongs to when using multiple transports at once. + /// + public int Index { get; private set; } + #endregion + + #region Initialization and unity. + /// + /// Initializes the transport. Use this instead of Awake. + /// Index this transport belongs to when using multiple transports at once. + /// + public virtual void Initialize(NetworkManager networkManager, int transportIndex) + { + NetworkManager = networkManager; + Index = transportIndex; + } + #endregion + + #region ConnectionStates. + /// + /// Gets the address of a remote connection Id. + /// + /// Connectionid to get the address for. + /// + public abstract string GetConnectionAddress(int connectionId); + /// + /// Called when a connection state changes for the local client. + /// + public abstract event Action OnClientConnectionState; + /// + /// Called when a connection state changes for the local server. + /// + public abstract event Action OnServerConnectionState; + /// + /// Called when a connection state changes for a remote client. + /// + public abstract event Action OnRemoteConnectionState; + /// + /// Handles a ConnectionStateArgs for the local client. + /// + /// Data being handled. + public abstract void HandleClientConnectionState(ClientConnectionStateArgs connectionStateArgs); + /// + /// Handles a ConnectionStateArgs for the local server. + /// + /// Data being handled. + public abstract void HandleServerConnectionState(ServerConnectionStateArgs connectionStateArgs); + /// + /// Handles a ConnectionStateArgs for a remote client. + /// + /// Data being handled. + public abstract void HandleRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs); + /// + /// Gets the current local ConnectionState. + /// + /// True if getting ConnectionState for the server. + public abstract LocalConnectionState GetConnectionState(bool server); + /// + /// Gets the current ConnectionState of a client connected to the server. Can only be called on the server. + /// + /// ConnectionId to get ConnectionState for. + public abstract RemoteConnectionState GetConnectionState(int connectionId); + #endregion + + #region Sending. + /// + /// Sends to the server. + /// + /// Channel to use. + /// Data to send. + public abstract void SendToServer(byte channelId, ArraySegment segment); + /// + /// Sends to a client. + /// + /// Channel to use. + /// Data to send. + /// ConnectionId to send to. When sending to clients can be used to specify which connection to send to. + public abstract void SendToClient(byte channelId, ArraySegment segment, int connectionId); + #endregion + + #region Receiving + /// + /// Called when the client receives data. + /// + public abstract event Action OnClientReceivedData; + /// + /// Handles a ClientReceivedDataArgs. + /// + /// Data being handled. + public abstract void HandleClientReceivedDataArgs(ClientReceivedDataArgs receivedDataArgs); + /// + /// Called when the server receives data. + /// + public abstract event Action OnServerReceivedData; + /// + /// Handles a ServerReceivedDataArgs. + /// + /// Data being handled. + public abstract void HandleServerReceivedDataArgs(ServerReceivedDataArgs receivedDataArgs); + #endregion + + #region Iterating. + /// + /// Processes data received by the socket. + /// + /// True to process data received on the server. + public abstract void IterateIncoming(bool server); + /// + /// Processes data to be sent by the socket. + /// + /// True to process data received on the server. + public abstract void IterateOutgoing(bool server); + #endregion + + #region Configuration. + /// + /// Returns if the transport is only run locally, offline. + /// While true several security checks are disabled. + /// + public virtual bool IsLocalTransport(int connectionid) => false; + /// + /// Gets how long in seconds until either the server or client socket must go without data before being timed out. + /// + /// True to get the timeout for the server socket, false for the client socket. + /// + public virtual float GetTimeout(bool asServer) => -1f; + /// + /// Sets how long in seconds until either the server or client socket must go without data before being timed out. + /// + /// True to set the timeout for the server socket, false for the client socket. + public virtual void SetTimeout(float value, bool asServer) { } + /// + /// 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. + /// + /// Maximum clients transport allows. + public virtual int GetMaximumClients() + { + bool canLog = (NetworkManager == null) ? NetworkManager.StaticCanLog(LoggingType.Warning) : NetworkManager.CanLog(LoggingType.Warning); + if (canLog) + Debug.LogWarning($"The current transport does not support this feature."); + return -1; + } + /// + /// Sets the 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. + /// + /// Maximum clients to allow. + public virtual void SetMaximumClients(int value) + { + bool canLog = (NetworkManager == null) ? NetworkManager.StaticCanLog(LoggingType.Warning) : NetworkManager.CanLog(LoggingType.Warning); + if (canLog) + Debug.LogWarning($"The current transport does not support this feature."); + } + /// + /// Sets which address the client will connect to. + /// + /// Address client will connect to. + public virtual void SetClientAddress(string address) { } + /// + /// Returns which address the client will connect to. + /// + public virtual string GetClientAddress() => string.Empty; + /// + /// Sets which address the server will bind to. + /// + /// Address server will bind to. + [Obsolete("Use SetServerBindAddress(string, IPAddressType)")] //Remove on 01/01/2023 + public virtual void SetServerBindAddress(string address) { } + /// + /// Gets which address the server will bind to. + /// + [Obsolete("Use GetServerBindAddress(IPAddressType)")] //Remove on 01/01/2023 + public virtual string GetServerBindAddress() => string.Empty; + /// + /// Sets which address the server will bind to. + /// + /// Address server will bind to. + /// Address type to set. + public virtual void SetServerBindAddress(string address, IPAddressType addressType) { } + /// + /// Gets which address the server will bind to. + /// + /// Address type to return. + public virtual string GetServerBindAddress(IPAddressType addressType) => string.Empty; + /// + /// Sets which port to use. + /// + /// Port to use. + public virtual void SetPort(ushort port) { } + /// + /// Gets which port to use. + /// + public virtual ushort GetPort() => 0; + #endregion + + #region Start and stop. + /// + /// Starts the local server or client using configured settings. + /// + /// True to start server. + public abstract bool StartConnection(bool server); + /// + /// Stops the local server or client. + /// + /// True to stop server. + public abstract bool StopConnection(bool server); + /// + /// Stops a remote client from the server, disconnecting the client. + /// + /// ConnectionId of the client to disconnect. + /// True to abrutly stop the client socket. The technique used to accomplish immediate disconnects may vary depending on the transport. + /// When not using immediate disconnects it's recommended to perform disconnects using the ServerManager rather than accessing the transport directly. + /// + public abstract bool StopConnection(int connectionId, bool immediately); + /// + /// Stops both client and server. + /// + public abstract void Shutdown(); + #endregion + + #region Channels. + /// + /// Gets the MTU for a channel. + /// + /// Channel to get MTU for. + /// MTU of channel. + public abstract int GetMTU(byte channel); + #endregion + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs.meta new file mode 100644 index 0000000..4f1ee6f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 78aba14618b37ea4bb067fa95ede84e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports.meta new file mode 100644 index 0000000..a0f770e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bb8b443596223e84aaca2634238adda3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass.meta new file mode 100644 index 0000000..421c7c8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f35b43a13fceaa40ac25cef58d8e53b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt new file mode 100644 index 0000000..4f3eea1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt @@ -0,0 +1,2 @@ +1.0.0 + - Initial release. \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt.meta new file mode 100644 index 0000000..8a99e4e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/CHANGELOG.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9b339dd67a0ce7f458236a3ad1d97322 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs new file mode 100644 index 0000000..cae1528 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs @@ -0,0 +1,963 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Serializing; +using FishNet.Utility.Extension; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Transporting.Multipass +{ + [AddComponentMenu("FishNet/Transport/Multipass")] + public class Multipass : Transport + { + #region Types. + public struct TransportIdData + { + public int MultipassId; + public int TransportIndex; + + public TransportIdData(int multipassId, int transportIndex) + { + MultipassId = multipassId; + TransportIndex = transportIndex; + } + } + #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) + { + bool canLogError = base.NetworkManager.CanLog(LoggingType.Error); + //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 (canLogError) + { + if (_clientTransport == null) + Debug.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 + Debug.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 IReadOnlyCollection Transports => _transports; + #endregion + + #region Private. + /// + /// Key is the transport connectionid, Value is the TransportIdData. + /// + private Dictionary _multipassToTransport = new Dictionary(); + /// + /// Key is the Multipass connectionId, Value is the transport connectionId. + /// + private List> _transportToMultipass = new List>(); + /// + /// Ids available to new connections. + /// + private Queue _availableIds = new Queue(); + #endregion + + #region Const. + /// + /// Id to use for client when acting as host. + /// + internal const int CLIENT_HOST_ID = short.MaxValue; + #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) + { + if (base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Transports contains a null entry on index {i}."); + _transports.RemoveAt(i); + i--; + } + } + + //No transports to use. + if (Transports.Count == 0) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"No transports are set within Multipass."); + return; + } + + //Create transportsToMultipass. + for (int i = 0; i < Transports.Count; i++) + { + Dictionary dict = new Dictionary(); + _transportToMultipass.Add(dict); + } + + //Initialize each transport. + for (int i = 0; i < Transports.Count; i++) + { + _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(); + } + + + #region ClientIds. + /// + /// 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; + } + } + + _multipassToTransport.Clear(); + foreach (Dictionary item in _transportToMultipass) + item.Clear(); + CreateAvailableIds(); + } + + /// + /// Gets the Multipass connectionId using a transport connectionid. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool GetMultipassId(int transportIndex, int transportId, out int multipassId) + { + Dictionary dict = _transportToMultipass[transportIndex]; + if (!dict.TryGetValueIL2CPP(transportId, out multipassId)) + { + multipassId = -1; + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Multipass connectionId could not be found for transportIndex {transportIndex}, connectionId of {transportId}."); + + return false; + } + + return true; + } + + /// + /// Gets the TransportIdData using a Multipass connectionId. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool GetTransportIdData(int multipassId, out TransportIdData data) + { + if (!_multipassToTransport.TryGetValueIL2CPP(multipassId, out data)) + { + //Fall through. + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"TransportIdData could not be found for Multiass connectionId of {multipassId}."); + return false; + } + + return true; + } + #endregion + + #region ConnectionStates. + /// + /// Gets the IP address of a remote connectionId. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string GetConnectionAddress(int connectionId) + { + TransportIdData data; + if (!GetTransportIdData(connectionId, out data)) + return string.Empty; + + return _transports[data.TransportIndex].GetConnectionAddress(connectionId); + } + /// + /// 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) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.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 index) + { + if (!IndexInRange(index, true)) + return LocalConnectionState.Stopped; + + return _transports[index].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 connectionId) + { + + TransportIdData data; + if (!GetTransportIdData(connectionId, out data)) + return RemoteConnectionState.Stopped; + + return _transports[data.TransportIndex].GetConnectionState(connectionId); + } + /// + /// 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 transportId = connectionStateArgs.ConnectionId; + int multipassId; + Dictionary transportToMultipassDict = _transportToMultipass[transportIndex]; + + //Started. + if (connectionStateArgs.ConnectionState == RemoteConnectionState.Started) + { + multipassId = _availableIds.Dequeue(); + transportToMultipassDict[transportId] = multipassId; + _multipassToTransport[multipassId] = new TransportIdData(transportId, transportIndex); + } + //Stopped. + else + { + if (!GetMultipassId(transportIndex, transportId, out multipassId)) + return; + + _availableIds.Enqueue(multipassId); + transportToMultipassDict.Remove(transportId); + _multipassToTransport.Remove(multipassId); + } + + connectionStateArgs.ConnectionId = 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) + { + int multipassId; + if (!GetMultipassId(receivedDataArgs.TransportIndex, receivedDataArgs.ConnectionId, out multipassId)) + return; + + receivedDataArgs.ConnectionId = 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 connectionId) + { + TransportIdData data; + if (GetTransportIdData(connectionId, out data)) + _transports[data.TransportIndex].SendToClient(channelId, segment, data.MultipassId); + } + #endregion + + #region Configuration. + /// + /// Returns if GlobalServerActions is true and if not logs an error. + /// + /// + private bool UseGlobalServerActionsWithError(string methodText) + { + if (!GlobalServerActions) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.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) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"ClientTransport is not set. Use SetClientTransport before calling {methodText}."); + return false; + } + else + { + return true; + } + } + /// + /// Populates the availableIds collection. + /// + private void CreateAvailableIds() + { + _availableIds.Clear(); + for (int i = 0; i < short.MaxValue; i++) + _availableIds.Enqueue(i); + } + + /// + /// 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 Transport GetTransport() + { + foreach (Transport t in Transports) + { + if (t.GetType() == typeof(T)) + return t; + } + + return null; + } + /// + /// Returns if the transport for connectId is a local transport. + /// While true several security checks are disabled. + /// + public override bool IsLocalTransport(int connectionid) + { + //If able to get transport data return value from transport. + if (GetTransportIdData(connectionid, out TransportIdData data)) + return _transports[data.TransportIndex].IsLocalTransport(connectionid); + //Otherwise return false forcing checks. + else + return false; + } + + /// + /// 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 override int GetMaximumClients() + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.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 to the transport on the first index. + /// + /// + public override void SetMaximumClients(int value) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"This method is not supported. Use SetMaximumClients(value, transportIndex) instead."); + } + /// + /// 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); + } + public override void SetServerBindAddress(string address, IPAddressType addressType) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"This method is not supported. Use SetServerBindAddress(address, transportIndex) instead."); + } + /// 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 on the first transport. + /// + public override void SetPort(ushort port) + { + if (base.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"This method is not supported. Use SetPort(port, transportIndex) instead."); + } + /// + /// 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 connectionIds as ServerManager knows them. + int[] multipassIds = _transportToMultipass[transportIndex].Keys.ToArray(); + //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 connectionId, bool immediately) + { + TransportIdData data; + if (!GetTransportIdData(connectionId, out data)) + return false; + + return _transports[data.TransportIndex].StopConnection(connectionId, 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.CanLog(LoggingType.Error)) + Debug.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 + + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs.meta new file mode 100644 index 0000000..f58b9fb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 314b449d3505bd24487ba69b61c2fda5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt new file mode 100644 index 0000000..afaf360 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt.meta new file mode 100644 index 0000000..7333afa --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Multipass/VERSION.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e4f9d944e2ca8484587859cf4ec80b6c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat.meta new file mode 100644 index 0000000..eeec7bc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43760836a07366846a82fe7f158bd84e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core.meta new file mode 100644 index 0000000..1ad2510 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4dad76b44081bb54b97e6da2e0e6f26d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs new file mode 100644 index 0000000..a8406ec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs @@ -0,0 +1,308 @@ +using FishNet.Managing.Logging; +using LiteNetLib; +using LiteNetLib.Layers; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using UnityEngine; + +namespace FishNet.Transporting.Tugboat.Client +{ + public class ClientSocket : CommonSocket + { + ~ClientSocket() + { + StopConnection(); + } + + #region Private. + #region Configuration. + /// + /// Address to bind server to. + /// + private string _address = string.Empty; + /// + /// Port used by server. + /// + private ushort _port; + /// + /// MTU sizes for each channel. + /// + private int _mtu; + #endregion + #region Queues. + /// + /// Changes to the sockets local connection state. + /// + private Queue _localConnectionStates = new Queue(); + /// + /// Inbound messages which need to be handled. + /// + private Queue _incoming = new Queue(); + /// + /// Outbound messages which need to be handled. + /// + private Queue _outgoing = new Queue(); + #endregion + /// + /// Client socket manager. + /// + private NetManager _client; + /// + /// How long in seconds until client times from server. + /// + private int _timeout; + /// + /// PacketLayer to use with LiteNetLib. + /// + private PacketLayerBase _packetLayer; + /// + /// Locks the NetManager to stop it. + /// + private readonly object _stopLock = new object(); + #endregion + + /// + /// Initializes this for use. + /// + /// + internal void Initialize(Transport t, int unreliableMTU, PacketLayerBase packetLayer) + { + base.Transport = t; + _mtu = unreliableMTU; + _packetLayer = packetLayer; + } + + /// + /// Updates the Timeout value as seconds. + /// + internal void UpdateTimeout(int timeout) + { + _timeout = timeout; + base.UpdateTimeout(_client, timeout); + } + + /// + /// Threaded operation to process client actions. + /// + private void ThreadedSocket() + { + EventBasedNetListener listener = new EventBasedNetListener(); + listener.NetworkReceiveEvent += Listener_NetworkReceiveEvent; + listener.PeerConnectedEvent += Listener_PeerConnectedEvent; + listener.PeerDisconnectedEvent += Listener_PeerDisconnectedEvent; + + _client = new NetManager(listener, _packetLayer); + _client.MtuOverride = (_mtu + NetConstants.FragmentedHeaderTotalSize); + + UpdateTimeout(_timeout); + + _localConnectionStates.Enqueue(LocalConnectionState.Starting); + _client.Start(); + _client.Connect(_address, _port, string.Empty); + } + + + /// + /// Stops the socket on a new thread. + /// + private void StopSocketOnThread() + { + if (_client == null) + return; + + Task t = Task.Run(() => + { + lock (_stopLock) + { + _client?.Stop(); + _client = null; + } + + //If not stopped yet also enqueue stop. + if (base.GetConnectionState() != LocalConnectionState.Stopped) + _localConnectionStates.Enqueue(LocalConnectionState.Stopped); + }); + } + + /// + /// Starts the client connection. + /// + /// + /// + /// + /// + internal bool StartConnection(string address, ushort port) + { + if (base.GetConnectionState() != LocalConnectionState.Stopped) + return false; + + base.SetConnectionState(LocalConnectionState.Starting, false); + + //Assign properties. + _port = port; + _address = address; + + ResetQueues(); + Task t = Task.Run(() => ThreadedSocket()); + + return true; + } + + + /// + /// Stops the local socket. + /// + internal bool StopConnection(DisconnectInfo? info = null) + { + if (base.GetConnectionState() == LocalConnectionState.Stopped || base.GetConnectionState() == LocalConnectionState.Stopping) + return false; + + if (info != null && base.Transport.NetworkManager.CanLog(LoggingType.Common)) + Debug.Log($"Local client disconnect reason: {info.Value.Reason}."); + + base.SetConnectionState(LocalConnectionState.Stopping, false); + StopSocketOnThread(); + return true; + } + + /// + /// Resets queues. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ResetQueues() + { + _localConnectionStates.Clear(); + base.ClearPacketQueue(ref _incoming); + base.ClearPacketQueue(ref _outgoing); + } + + + /// + /// Called when disconnected from the server. + /// + private void Listener_PeerDisconnectedEvent(NetPeer peer, DisconnectInfo disconnectInfo) + { + StopConnection(disconnectInfo); + } + + /// + /// Called when connected to the server. + /// + private void Listener_PeerConnectedEvent(NetPeer peer) + { + _localConnectionStates.Enqueue(LocalConnectionState.Started); + } + + /// + /// Called when data is received from a peer. + /// + private void Listener_NetworkReceiveEvent(NetPeer fromPeer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) + { + base.Listener_NetworkReceiveEvent(_incoming, fromPeer, reader, deliveryMethod, _mtu); + } + + /// + /// Dequeues and processes outgoing. + /// + private void DequeueOutgoing() + { + NetPeer peer = null; + if (_client != null) + peer = _client.FirstPeer; + //Server connection hasn't been made. + if (peer == null) + { + /* Only dequeue outgoing because other queues might have + * relevant information, such as the local connection queue. */ + base.ClearPacketQueue(ref _outgoing); + } + else + { + int count = _outgoing.Count; + for (int i = 0; i < count; i++) + { + Packet outgoing = _outgoing.Dequeue(); + + ArraySegment segment = outgoing.GetArraySegment(); + DeliveryMethod dm = (outgoing.Channel == (byte)Channel.Reliable) ? + DeliveryMethod.ReliableOrdered : DeliveryMethod.Unreliable; + + //If over the MTU. + if (outgoing.Channel == (byte)Channel.Unreliable && segment.Count > _mtu) + { + if (base.Transport.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Client is sending of {segment.Count} length on the unreliable channel, while the MTU is only {_mtu}. The channel has been changed to reliable for this send."); + dm = DeliveryMethod.ReliableOrdered; + } + + peer.Send(segment.Array, segment.Offset, segment.Count, dm); + + outgoing.Dispose(); + } + } + } + + /// + /// Allows for Outgoing queue to be iterated. + /// + internal void IterateOutgoing() + { + DequeueOutgoing(); + } + + /// + /// Iterates the Incoming queue. + /// + internal void IterateIncoming() + { + _client?.PollEvents(); + + /* Run local connection states first so we can begin + * to read for data at the start of the frame, as that's + * where incoming is read. */ + while (_localConnectionStates.Count > 0) + base.SetConnectionState(_localConnectionStates.Dequeue(), false); + + //Not yet started, cannot continue. + LocalConnectionState localState = base.GetConnectionState(); + if (localState != LocalConnectionState.Started) + { + ResetQueues(); + //If stopped try to kill task. + if (localState == LocalConnectionState.Stopped) + { + StopSocketOnThread(); + return; + } + } + + /* Incoming. */ + while (_incoming.Count > 0) + { + Packet incoming = _incoming.Dequeue(); + ClientReceivedDataArgs dataArgs = new ClientReceivedDataArgs( + incoming.GetArraySegment(), + (Channel)incoming.Channel, base.Transport.Index); + base.Transport.HandleClientReceivedDataArgs(dataArgs); + //Dispose of packet. + incoming.Dispose(); + } + } + + /// + /// Sends a packet to the server. + /// + internal void SendToServer(byte channelId, ArraySegment segment) + { + //Not started, cannot send. + if (base.GetConnectionState() != LocalConnectionState.Started) + return; + + base.Send(ref _outgoing, channelId, segment, -1, _mtu); + } + + + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs.meta new file mode 100644 index 0000000..989bf71 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7944de5e4da77594db036e276174ee60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs new file mode 100644 index 0000000..cdc77b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs @@ -0,0 +1,125 @@ +using FishNet.Utility.Performance; +using LiteNetLib; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace FishNet.Transporting.Tugboat +{ + + public abstract class CommonSocket + { + + #region Public. + /// + /// Current ConnectionState. + /// + private LocalConnectionState _connectionState = LocalConnectionState.Stopped; + /// + /// Returns the current ConnectionState. + /// + /// + internal LocalConnectionState GetConnectionState() + { + return _connectionState; + } + /// + /// Sets a new connection state. + /// + /// + protected void SetConnectionState(LocalConnectionState connectionState, bool asServer) + { + //If state hasn't changed. + if (connectionState == _connectionState) + return; + + _connectionState = connectionState; + if (asServer) + Transport.HandleServerConnectionState(new ServerConnectionStateArgs(connectionState, Transport.Index)); + else + Transport.HandleClientConnectionState(new ClientConnectionStateArgs(connectionState, Transport.Index)); + } + #endregion + + #region Protected. + /// + /// Transport controlling this socket. + /// + protected Transport Transport = null; + #endregion + + + /// + /// Sends data to connectionId. + /// + internal void Send(ref Queue queue, byte channelId, ArraySegment segment, int connectionId, int mtu) + { + if (GetConnectionState() != LocalConnectionState.Started) + return; + + //ConnectionId isn't used from client to server. + Packet outgoing = new Packet(connectionId, segment, channelId, mtu); + queue.Enqueue(outgoing); + } + + /// + /// Updates the timeout for NetManager. + /// + protected void UpdateTimeout(NetManager netManager, int timeout) + { + if (netManager == null) + return; + + timeout = (timeout == 0) ? int.MaxValue : Math.Min(int.MaxValue, (timeout * 1000)); + netManager.DisconnectTimeout = timeout; + } + /// + /// Clears a queue using Packet type. + /// + /// + internal void ClearPacketQueue(ref ConcurrentQueue queue) + { + while (queue.TryDequeue(out Packet p)) + p.Dispose(); + } + + /// + /// Clears a queue using Packet type. + /// + /// + internal void ClearPacketQueue(ref Queue queue) + { + int count = queue.Count; + for (int i = 0; i < count; i++) + { + Packet p = queue.Dequeue(); + p.Dispose(); + } + } + + /// + /// Called when data is received. + /// + internal virtual void Listener_NetworkReceiveEvent(Queue queue, NetPeer fromPeer, NetPacketReader reader, DeliveryMethod deliveryMethod, int mtu) + { + //Set buffer. + int dataLen = reader.AvailableBytes; + //Prefer to max out returned array to mtu to reduce chance of resizing. + int arraySize = Math.Max(dataLen, mtu); + byte[] data = ByteArrayPool.Retrieve(arraySize); + reader.GetBytes(data, dataLen); + //Id. + int id = fromPeer.Id; + //Channel. + byte channel = (deliveryMethod == DeliveryMethod.Unreliable) ? + (byte)Channel.Unreliable : (byte)Channel.Reliable; + //Add to packets. + Packet packet = new Packet(id, data, dataLen, channel); + queue.Enqueue(packet); + //Recycle reader. + reader.Recycle(); + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs.meta new file mode 100644 index 0000000..640e1fa --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/CommonSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 329169cdf51866c43a8c42e8aeb291fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs new file mode 100644 index 0000000..11bff56 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs @@ -0,0 +1,500 @@ +using FishNet.Managing.Logging; +using LiteNetLib; +using LiteNetLib.Layers; +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using UnityEngine; + +namespace FishNet.Transporting.Tugboat.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) + { + NetPeer peer = GetNetPeer(connectionId, false); + if (peer == null || peer.ConnectionState != ConnectionState.Connected) + return RemoteConnectionState.Stopped; + else + return RemoteConnectionState.Started; + } + #endregion + + #region Private. + #region Configuration. + /// + /// Port used by server. + /// + private ushort _port; + /// + /// Maximum number of allowed clients. + /// + private int _maximumClients; + /// + /// MTU size per packet. + /// + private int _mtu; + #endregion + #region Queues. + /// + /// Changes to the sockets local connection state. + /// + private Queue _localConnectionStates = new Queue(); + /// + /// Inbound messages which need to be handled. + /// + private Queue _incoming = new Queue(); + /// + /// Outbound messages which need to be handled. + /// + private Queue _outgoing = new Queue(); + /// + /// ConnectionEvents which need to be handled. + /// + private Queue _remoteConnectionEvents = new Queue(); + #endregion + /// + /// Key required to connect. + /// + private string _key = string.Empty; + /// + /// How long in seconds until client times from server. + /// + private int _timeout; + /// + /// Server socket manager. + /// + private NetManager _server; + /// + /// IPv4 address to bind server to. + /// + private string _ipv4BindAddress; + /// + /// IPv6 address to bind server to. + /// + private string _ipv6BindAddress; + /// + /// PacketLayer to use with LiteNetLib. + /// + private PacketLayerBase _packetLayer; + /// + /// Locks the NetManager to stop it. + /// + private readonly object _stopLock = new object(); + #endregion + + ~ServerSocket() + { + StopConnection(); + } + + /// + /// Initializes this for use. + /// + /// + internal void Initialize(Transport t, int unreliableMTU, PacketLayerBase packetLayer) + { + base.Transport = t; + _mtu = unreliableMTU; + _packetLayer = packetLayer; + } + + /// + /// Updates the Timeout value as seconds. + /// + internal void UpdateTimeout(int timeout) + { + _timeout = timeout; + base.UpdateTimeout(_server, timeout); + } + + + /// + /// Threaded operation to process server actions. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ThreadedSocket() + { + EventBasedNetListener listener = new EventBasedNetListener(); + listener.ConnectionRequestEvent += Listener_ConnectionRequestEvent; + listener.PeerConnectedEvent += Listener_PeerConnectedEvent; + listener.NetworkReceiveEvent += Listener_NetworkReceiveEvent; + listener.PeerDisconnectedEvent += Listener_PeerDisconnectedEvent; + + _server = new NetManager(listener, _packetLayer); + _server.MtuOverride = (_mtu + NetConstants.FragmentedHeaderTotalSize); + + UpdateTimeout(_timeout); + + //Set bind addresses. + IPAddress ipv4; + IPAddress ipv6; + //Set ipv4 + if (!string.IsNullOrEmpty(_ipv4BindAddress)) + { + if (!IPAddress.TryParse(_ipv4BindAddress, out ipv4)) + ipv4 = null; + } + else + { + IPAddress.TryParse("0.0.0.0", out ipv4); + } + //Set ipv6. + if (!string.IsNullOrEmpty(_ipv6BindAddress)) + { + if (!IPAddress.TryParse(_ipv6BindAddress, out ipv6)) + ipv6 = null; + } + else + { + IPAddress.TryParse("0:0:0:0:0:0:0:0", out ipv6); + } + + string ipv4FailText = (ipv4 == null) ? $"IPv4 address {_ipv4BindAddress} failed to parse. " : string.Empty; + string ipv6FailText = (ipv6 == null) ? $"IPv6 address {_ipv6BindAddress} failed to parse. " : string.Empty; + if (ipv4FailText != string.Empty || ipv6FailText != string.Empty) + { + if (base.Transport.NetworkManager.CanLog(LoggingType.Error)) + Debug.Log($"{ipv4FailText}{ipv6FailText}Clear the bind address field to use any bind address."); + + StopConnection(); + return; + } + + bool startResult = _server.Start(ipv4, ipv6, _port); + //If started succcessfully. + if (startResult) + { + _localConnectionStates.Enqueue(LocalConnectionState.Started); + } + //Failed to start. + else + { + if (base.Transport.NetworkManager.CanLog(LoggingType.Error)) + Debug.LogError($"Server failed to start. This usually occurs when the specified port is unavailable, be it closed or already in use."); + + StopConnection(); + } + } + + /// + /// Stops the socket on a new thread. + /// + private void StopSocketOnThread() + { + if (_server == null) + return; + + Task t = Task.Run(() => + { + lock (_stopLock) + { + _server?.Stop(); + _server = null; + } + + //If not stopped yet also enqueue stop. + if (base.GetConnectionState() != LocalConnectionState.Stopped) + _localConnectionStates.Enqueue(LocalConnectionState.Stopped); + }); + } + + /// + /// Gets the address of a remote connection Id. + /// + /// + /// Returns string.empty if Id is not found. + internal string GetConnectionAddress(int connectionId) + { + NetPeer peer = GetNetPeer(connectionId, false); + return peer.EndPoint.Address.ToString(); + } + + /// + /// Returns a NetPeer for connectionId. + /// + /// + /// + private NetPeer GetNetPeer(int connectionId, bool connectedOnly) + { + NetPeer peer = null; + if (_server != null) + { + if (connectionId >= 0 || connectionId < _server.ConnectedPeersCount) + peer = _server.GetPeerById(connectionId); + if (connectedOnly && peer != null && peer.ConnectionState != ConnectionState.Connected) + peer = null; + } + + return peer; + } + + /// + /// Starts the server. + /// + internal bool StartConnection(ushort port, int maximumClients, string ipv4BindAddress, string ipv6BindAddress) + { + if (base.GetConnectionState() != LocalConnectionState.Stopped) + return false; + + base.SetConnectionState(LocalConnectionState.Starting, true); + + //Assign properties. + _port = port; + _maximumClients = maximumClients; + _ipv4BindAddress = ipv4BindAddress; + _ipv6BindAddress = ipv6BindAddress; + ResetQueues(); + + Task t = Task.Run(() => ThreadedSocket()); + + return true; + } + + /// + /// Stops the local socket. + /// + internal bool StopConnection() + { + if (_server == null || base.GetConnectionState() == LocalConnectionState.Stopped || base.GetConnectionState() == LocalConnectionState.Stopping) + return false; + + _localConnectionStates.Enqueue(LocalConnectionState.Stopping); + StopSocketOnThread(); + return true; + } + + /// + /// Stops a remote client disconnecting the client from the server. + /// + /// ConnectionId of the client to disconnect. + internal bool StopConnection(int connectionId) + { + //Server isn't running. + if (_server == null || base.GetConnectionState() != LocalConnectionState.Started) + return false; + + NetPeer peer = GetNetPeer(connectionId, false); + if (peer == null) + return false; + + try + { + peer.Disconnect(); + base.Transport.HandleRemoteConnectionState(new RemoteConnectionStateArgs(RemoteConnectionState.Stopped, connectionId, base.Transport.Index)); + } + catch + { + return false; + } + + return true; + } + + /// + /// Resets queues. + /// + private void ResetQueues() + { + _localConnectionStates.Clear(); + base.ClearPacketQueue(ref _incoming); + base.ClearPacketQueue(ref _outgoing); + _remoteConnectionEvents.Clear(); + } + + + /// + /// Called when a peer disconnects or times out. + /// + private void Listener_PeerDisconnectedEvent(NetPeer peer, DisconnectInfo disconnectInfo) + { + _remoteConnectionEvents.Enqueue(new RemoteConnectionEvent(false, peer.Id)); + } + + /// + /// Called when a peer completes connection. + /// + private void Listener_PeerConnectedEvent(NetPeer peer) + { + _remoteConnectionEvents.Enqueue(new RemoteConnectionEvent(true, peer.Id)); + } + + /// + /// Called when data is received from a peer. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Listener_NetworkReceiveEvent(NetPeer fromPeer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) + { + //If over the MTU. + if (reader.AvailableBytes > _mtu) + { + _remoteConnectionEvents.Enqueue(new RemoteConnectionEvent(false, fromPeer.Id)); + fromPeer.Disconnect(); + } + else + { + base.Listener_NetworkReceiveEvent(_incoming, fromPeer, reader, deliveryMethod, _mtu); + } + } + + + /// + /// Called when a remote connection request is made. + /// + private void Listener_ConnectionRequestEvent(ConnectionRequest request) + { + if (_server == null) + return; + + //At maximum peers. + if (_server.ConnectedPeersCount >= _maximumClients) + { + request.Reject(); + return; + } + + request.AcceptIfKey(_key); + } + + /// + /// Dequeues and processes outgoing. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void DequeueOutgoing() + { + if (base.GetConnectionState() != LocalConnectionState.Started || _server == null) + { + //Not started, clear outgoing. + base.ClearPacketQueue(ref _outgoing); + } + else + { + int count = _outgoing.Count; + for (int i = 0; i < count; i++) + { + Packet outgoing = _outgoing.Dequeue(); + int connectionId = outgoing.ConnectionId; + + ArraySegment segment = outgoing.GetArraySegment(); + DeliveryMethod dm = (outgoing.Channel == (byte)Channel.Reliable) ? + DeliveryMethod.ReliableOrdered : DeliveryMethod.Unreliable; + + //If over the MTU. + if (outgoing.Channel == (byte)Channel.Unreliable && segment.Count > _mtu) + { + if (base.Transport.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Server is sending of {segment.Count} length on the unreliable channel, while the MTU is only {_mtu}. The channel has been changed to reliable for this send."); + dm = DeliveryMethod.ReliableOrdered; + } + + //Send to all clients. + if (connectionId == -1) + { + _server.SendToAll(segment.Array, segment.Offset, segment.Count, dm); + } + //Send to one client. + else + { + NetPeer peer = GetNetPeer(connectionId, true); + //If peer is found. + if (peer != null) + peer.Send(segment.Array, segment.Offset, segment.Count, dm); + } + + outgoing.Dispose(); + } + } + } + + /// + /// Allows for Outgoing queue to be iterated. + /// + internal void IterateOutgoing() + { + DequeueOutgoing(); + } + + /// + /// Iterates the Incoming queue. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void IterateIncoming() + { + _server?.PollEvents(); + + /* Run local connection states first so we can begin + * to read for data at the start of the frame, as that's + * where incoming is read. */ + while (_localConnectionStates.Count > 0) + base.SetConnectionState(_localConnectionStates.Dequeue(), true); + + //Not yet started. + LocalConnectionState localState = base.GetConnectionState(); + if (localState != LocalConnectionState.Started) + { + ResetQueues(); + //If stopped try to kill task. + if (localState == LocalConnectionState.Stopped) + { + StopSocketOnThread(); + return; + } + } + + //Handle connection and disconnection events. + while (_remoteConnectionEvents.Count > 0) + { + RemoteConnectionEvent connectionEvent = _remoteConnectionEvents.Dequeue(); + RemoteConnectionState state = (connectionEvent.Connected) ? RemoteConnectionState.Started : RemoteConnectionState.Stopped; + base.Transport.HandleRemoteConnectionState(new RemoteConnectionStateArgs(state, connectionEvent.ConnectionId, base.Transport.Index)); + } + + //Handle packets. + while (_incoming.Count > 0) + { + Packet incoming = _incoming.Dequeue(); + //Make sure peer is still connected. + NetPeer peer = GetNetPeer(incoming.ConnectionId, true); + if (peer != null) + { + ServerReceivedDataArgs dataArgs = new ServerReceivedDataArgs( + incoming.GetArraySegment(), + (Channel)incoming.Channel, + incoming.ConnectionId, + base.Transport.Index); + + base.Transport.HandleServerReceivedDataArgs(dataArgs); + } + + incoming.Dispose(); + } + + } + + /// + /// Sends a packet to a single, or all clients. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SendToClient(byte channelId, ArraySegment segment, int connectionId) + { + Send(ref _outgoing, channelId, segment, connectionId, _mtu); + } + + /// + /// 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. + /// + /// + internal int GetMaximumClients() + { + return _maximumClients; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs.meta new file mode 100644 index 0000000..9cb8afc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5c6703e8024041e45ae92566123865ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs new file mode 100644 index 0000000..af55ed3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs @@ -0,0 +1,63 @@ +using FishNet.Utility.Performance; +using System; + +namespace FishNet.Transporting.Tugboat +{ + + + internal struct Packet + { + public readonly int ConnectionId; + public readonly byte[] Data; + public readonly int Length; + public readonly byte Channel; + + public Packet(int connectionId, byte[] data, int length, byte channel) + { + ConnectionId = connectionId; + Data = data; + Length = length; + Channel = channel; + } + + public Packet(int sender, ArraySegment segment, byte channel, int mtu) + { + //Prefer to max out returned array to mtu to reduce chance of resizing. + int arraySize = Math.Max(segment.Count, mtu); + Data = ByteArrayPool.Retrieve(arraySize); + Buffer.BlockCopy(segment.Array, segment.Offset, Data, 0, segment.Count); + ConnectionId = sender; + Length = segment.Count; + Channel = channel; + } + + public ArraySegment GetArraySegment() + { + return new ArraySegment(Data, 0, Length); + } + + public void Dispose() + { + ByteArrayPool.Store(Data); + } + + } + + +} + +namespace FishNet.Transporting.Tugboat.Server +{ + + internal struct RemoteConnectionEvent + { + public readonly bool Connected; + public readonly int ConnectionId; + public RemoteConnectionEvent(bool connected, int connectionId) + { + Connected = connected; + ConnectionId = connectionId; + } + } +} + diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs.meta new file mode 100644 index 0000000..307a74f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/Supporting.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80c810a1a6a8f3345bb48abfb75c804a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib.meta new file mode 100644 index 0000000..6708b0d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9af335f3230cff649a5cc0c50e34a206 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs new file mode 100644 index 0000000..261839d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs @@ -0,0 +1,46 @@ +using System.Collections.Concurrent; +using System.Threading; + +namespace LiteNetLib +{ + internal abstract class BaseChannel + { + protected readonly NetPeer Peer; + protected readonly ConcurrentQueue OutgoingQueue; + private int _isAddedToPeerChannelSendQueue; + + public int PacketsInQueue => OutgoingQueue.Count; + + protected BaseChannel(NetPeer peer) + { + Peer = peer; + OutgoingQueue = new ConcurrentQueue(); + } + + public void AddToQueue(NetPacket packet) + { + OutgoingQueue.Enqueue(packet); + AddToPeerChannelSendQueue(); + } + + protected void AddToPeerChannelSendQueue() + { + if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0) + { + Peer.AddToReliableChannelSendQueue(this); + } + } + + public bool SendAndCheckQueue() + { + bool hasPacketsToSend = SendNextPackets(); + if (!hasPacketsToSend) + Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0); + + return hasPacketsToSend; + } + + protected abstract bool SendNextPackets(); + public abstract bool ProcessPacket(NetPacket packet); + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs.meta new file mode 100644 index 0000000..0d6a9bf --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70b7c357a9f57f5479c5d94550d26280 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs new file mode 100644 index 0000000..4a2cdd9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs @@ -0,0 +1,134 @@ +using System.Net; +using System.Threading; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + internal enum ConnectionRequestResult + { + None, + Accept, + Reject, + RejectForce + } + + public class ConnectionRequest + { + private readonly NetManager _listener; + private int _used; + + public NetDataReader Data => InternalPacket.Data; + + internal ConnectionRequestResult Result { get; private set; } + internal NetConnectRequestPacket InternalPacket; + + public readonly IPEndPoint RemoteEndPoint; + + internal void UpdateRequest(NetConnectRequestPacket connectRequest) + { + //old request + if (connectRequest.ConnectionTime < InternalPacket.ConnectionTime) + return; + + if (connectRequest.ConnectionTime == InternalPacket.ConnectionTime && + connectRequest.ConnectionNumber == InternalPacket.ConnectionNumber) + return; + + InternalPacket = connectRequest; + } + + private bool TryActivate() + { + return Interlocked.CompareExchange(ref _used, 1, 0) == 0; + } + + internal ConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, NetManager listener) + { + InternalPacket = requestPacket; + RemoteEndPoint = remoteEndPoint; + _listener = listener; + } + + public NetPeer AcceptIfKey(string key) + { + if (!TryActivate()) + return null; + try + { + if (Data.GetString() == key) + Result = ConnectionRequestResult.Accept; + } + catch + { + NetDebug.WriteError("[AC] Invalid incoming data"); + } + if (Result == ConnectionRequestResult.Accept) + return _listener.OnConnectionSolved(this, null, 0, 0); + + Result = ConnectionRequestResult.Reject; + _listener.OnConnectionSolved(this, null, 0, 0); + return null; + } + + /// + /// Accept connection and get new NetPeer as result + /// + /// Connected NetPeer + public NetPeer Accept() + { + if (!TryActivate()) + return null; + Result = ConnectionRequestResult.Accept; + return _listener.OnConnectionSolved(this, null, 0, 0); + } + + public void Reject(byte[] rejectData, int start, int length, bool force) + { + if (!TryActivate()) + return; + Result = force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject; + _listener.OnConnectionSolved(this, rejectData, start, length); + } + + public void Reject(byte[] rejectData, int start, int length) + { + Reject(rejectData, start, length, false); + } + + + public void RejectForce(byte[] rejectData, int start, int length) + { + Reject(rejectData, start, length, true); + } + + public void RejectForce() + { + Reject(null, 0, 0, true); + } + + public void RejectForce(byte[] rejectData) + { + Reject(rejectData, 0, rejectData.Length, true); + } + + public void RejectForce(NetDataWriter rejectData) + { + Reject(rejectData.Data, 0, rejectData.Length, true); + } + + public void Reject() + { + Reject(null, 0, 0, false); + } + + public void Reject(byte[] rejectData) + { + Reject(rejectData, 0, rejectData.Length, false); + } + + public void Reject(NetDataWriter rejectData) + { + Reject(rejectData.Data, 0, rejectData.Length, false); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs.meta new file mode 100644 index 0000000..f1c5f19 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ConnectionRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e609855f95e9034889c882b51aaec68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs new file mode 100644 index 0000000..13d8852 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs @@ -0,0 +1,272 @@ +using System.Net; +using System.Net.Sockets; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + /// + /// Type of message that you receive in OnNetworkReceiveUnconnected event + /// + public enum UnconnectedMessageType + { + BasicMessage, + Broadcast + } + + /// + /// Disconnect reason that you receive in OnPeerDisconnected event + /// + public enum DisconnectReason + { + ConnectionFailed, + Timeout, + HostUnreachable, + NetworkUnreachable, + RemoteConnectionClose, + DisconnectPeerCalled, + ConnectionRejected, + InvalidProtocol, + UnknownHost, + Reconnect, + PeerToPeerConnection, + PeerNotFound + } + + /// + /// Additional information about disconnection + /// + public struct DisconnectInfo + { + /// + /// Additional info why peer disconnected + /// + public DisconnectReason Reason; + + /// + /// Error code (if reason is SocketSendError or SocketReceiveError) + /// + public SocketError SocketErrorCode; + + /// + /// Additional data that can be accessed (only if reason is RemoteConnectionClose) + /// + public NetPacketReader AdditionalData; + } + + public interface INetEventListener + { + /// + /// New remote peer connected to host, or client connected to remote host + /// + /// Connected peer object + void OnPeerConnected(NetPeer peer); + + /// + /// Peer disconnected + /// + /// disconnected peer + /// additional info about reason, errorCode or data received with disconnect message + void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); + + /// + /// Network error (on send or receive) + /// + /// From endPoint (can be null) + /// Socket error + void OnNetworkError(IPEndPoint endPoint, SocketError socketError); + + /// + /// Received some data + /// + /// From peer + /// DataReader containing all received data + /// Number of channel at which packet arrived + /// Type of received packet + void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod); + + /// + /// Received unconnected message + /// + /// From address (IP and Port) + /// Message data + /// Message type (simple, discovery request or response) + void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); + + /// + /// Latency information updated + /// + /// Peer with updated latency + /// latency value in milliseconds + void OnNetworkLatencyUpdate(NetPeer peer, int latency); + + /// + /// On peer connection requested + /// + /// Request information (EndPoint, internal id, additional data) + void OnConnectionRequest(ConnectionRequest request); + } + + public interface IDeliveryEventListener + { + /// + /// On reliable message delivered + /// + /// + /// + void OnMessageDelivered(NetPeer peer, object userData); + } + + public interface INtpEventListener + { + /// + /// Ntp response + /// + /// + void OnNtpResponse(NtpPacket packet); + } + + public interface IPeerAddressChangedListener + { + /// + /// Called when peer address changed (when AllowPeerAddressChange is enabled) + /// + /// Peer that changed address (with new address) + /// previous IP + void OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress); + } + + public class EventBasedNetListener : INetEventListener, IDeliveryEventListener, INtpEventListener, IPeerAddressChangedListener + { + public delegate void OnPeerConnected(NetPeer peer); + public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); + public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError); + public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod); + public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); + public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency); + public delegate void OnConnectionRequest(ConnectionRequest request); + public delegate void OnDeliveryEvent(NetPeer peer, object userData); + public delegate void OnNtpResponseEvent(NtpPacket packet); + public delegate void OnPeerAddressChangedEvent(NetPeer peer, IPEndPoint previousAddress); + + public event OnPeerConnected PeerConnectedEvent; + public event OnPeerDisconnected PeerDisconnectedEvent; + public event OnNetworkError NetworkErrorEvent; + public event OnNetworkReceive NetworkReceiveEvent; + public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent; + public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent; + public event OnConnectionRequest ConnectionRequestEvent; + public event OnDeliveryEvent DeliveryEvent; + public event OnNtpResponseEvent NtpResponseEvent; + public event OnPeerAddressChangedEvent PeerAddressChangedEvent; + + public void ClearPeerConnectedEvent() + { + PeerConnectedEvent = null; + } + + public void ClearPeerDisconnectedEvent() + { + PeerDisconnectedEvent = null; + } + + public void ClearNetworkErrorEvent() + { + NetworkErrorEvent = null; + } + + public void ClearNetworkReceiveEvent() + { + NetworkReceiveEvent = null; + } + + public void ClearNetworkReceiveUnconnectedEvent() + { + NetworkReceiveUnconnectedEvent = null; + } + + public void ClearNetworkLatencyUpdateEvent() + { + NetworkLatencyUpdateEvent = null; + } + + public void ClearConnectionRequestEvent() + { + ConnectionRequestEvent = null; + } + + public void ClearDeliveryEvent() + { + DeliveryEvent = null; + } + + public void ClearNtpResponseEvent() + { + NtpResponseEvent = null; + } + + public void ClearPeerAddressChangedEvent() + { + PeerAddressChangedEvent = null; + } + + void INetEventListener.OnPeerConnected(NetPeer peer) + { + if (PeerConnectedEvent != null) + PeerConnectedEvent(peer); + } + + void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) + { + if (PeerDisconnectedEvent != null) + PeerDisconnectedEvent(peer, disconnectInfo); + } + + void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode) + { + if (NetworkErrorEvent != null) + NetworkErrorEvent(endPoint, socketErrorCode); + } + + void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod) + { + if (NetworkReceiveEvent != null) + NetworkReceiveEvent(peer, reader, channelNumber, deliveryMethod); + } + + void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType) + { + if (NetworkReceiveUnconnectedEvent != null) + NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType); + } + + void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency) + { + if (NetworkLatencyUpdateEvent != null) + NetworkLatencyUpdateEvent(peer, latency); + } + + void INetEventListener.OnConnectionRequest(ConnectionRequest request) + { + if (ConnectionRequestEvent != null) + ConnectionRequestEvent(request); + } + + void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData) + { + if (DeliveryEvent != null) + DeliveryEvent(peer, userData); + } + + void INtpEventListener.OnNtpResponse(NtpPacket packet) + { + if (NtpResponseEvent != null) + NtpResponseEvent(packet); + } + + void IPeerAddressChangedListener.OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress) + { + if (PeerAddressChangedEvent != null) + PeerAddressChangedEvent(peer, previousAddress); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs.meta new file mode 100644 index 0000000..d4fc4bb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/INetEventListener.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79436ed5864cf48418ac341ea3c70a6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs new file mode 100644 index 0000000..2eb09fe --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs @@ -0,0 +1,133 @@ +using System; +using System.Net; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + internal sealed class NetConnectRequestPacket + { + public const int HeaderSize = 18; + public readonly long ConnectionTime; + public byte ConnectionNumber; + public readonly byte[] TargetAddress; + public readonly NetDataReader Data; + public readonly int PeerId; + + private NetConnectRequestPacket(long connectionTime, byte connectionNumber, int localId, byte[] targetAddress, NetDataReader data) + { + ConnectionTime = connectionTime; + ConnectionNumber = connectionNumber; + TargetAddress = targetAddress; + Data = data; + PeerId = localId; + } + + public static int GetProtocolId(NetPacket packet) + { + return BitConverter.ToInt32(packet.RawData, 1); + } + + public static NetConnectRequestPacket FromData(NetPacket packet) + { + if (packet.ConnectionNumber >= NetConstants.MaxConnectionNumber) + return null; + + //Getting connection time for peer + long connectionTime = BitConverter.ToInt64(packet.RawData, 5); + + //Get peer id + int peerId = BitConverter.ToInt32(packet.RawData, 13); + + //Get target address + int addrSize = packet.RawData[HeaderSize-1]; + if (addrSize != 16 && addrSize != 28) + return null; + byte[] addressBytes = new byte[addrSize]; + Buffer.BlockCopy(packet.RawData, HeaderSize, addressBytes, 0, addrSize); + + // Read data and create request + var reader = new NetDataReader(null, 0, 0); + if (packet.Size > HeaderSize+addrSize) + reader.SetSource(packet.RawData, HeaderSize + addrSize, packet.Size); + + return new NetConnectRequestPacket(connectionTime, packet.ConnectionNumber, peerId, addressBytes, reader); + } + + public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectTime, int localId) + { + //Make initial packet + var packet = new NetPacket(PacketProperty.ConnectRequest, connectData.Length+addressBytes.Size); + + //Add data + FastBitConverter.GetBytes(packet.RawData, 1, NetConstants.ProtocolId); + FastBitConverter.GetBytes(packet.RawData, 5, connectTime); + FastBitConverter.GetBytes(packet.RawData, 13, localId); + packet.RawData[HeaderSize-1] = (byte)addressBytes.Size; + for (int i = 0; i < addressBytes.Size; i++) + packet.RawData[HeaderSize + i] = addressBytes[i]; + Buffer.BlockCopy(connectData.Data, 0, packet.RawData, HeaderSize + addressBytes.Size, connectData.Length); + return packet; + } + } + + internal sealed class NetConnectAcceptPacket + { + public const int Size = 15; + public readonly long ConnectionTime; + public readonly byte ConnectionNumber; + public readonly int PeerId; + public readonly bool PeerNetworkChanged; + + private NetConnectAcceptPacket(long connectionTime, byte connectionNumber, int peerId, bool peerNetworkChanged) + { + ConnectionTime = connectionTime; + ConnectionNumber = connectionNumber; + PeerId = peerId; + PeerNetworkChanged = peerNetworkChanged; + } + + public static NetConnectAcceptPacket FromData(NetPacket packet) + { + if (packet.Size != Size) + return null; + + long connectionId = BitConverter.ToInt64(packet.RawData, 1); + + //check connect num + byte connectionNumber = packet.RawData[9]; + if (connectionNumber >= NetConstants.MaxConnectionNumber) + return null; + + //check reused flag + byte isReused = packet.RawData[10]; + if (isReused > 1) + return null; + + //get remote peer id + int peerId = BitConverter.ToInt32(packet.RawData, 11); + if (peerId < 0) + return null; + + return new NetConnectAcceptPacket(connectionId, connectionNumber, peerId, isReused == 1); + } + + public static NetPacket Make(long connectTime, byte connectNum, int localPeerId) + { + var packet = new NetPacket(PacketProperty.ConnectAccept, 0); + FastBitConverter.GetBytes(packet.RawData, 1, connectTime); + packet.RawData[9] = connectNum; + FastBitConverter.GetBytes(packet.RawData, 11, localPeerId); + return packet; + } + + public static NetPacket MakeNetworkChanged(NetPeer peer) + { + var packet = new NetPacket(PacketProperty.PeerNotFound, Size-1); + FastBitConverter.GetBytes(packet.RawData, 1, peer.ConnectTime); + packet.RawData[9] = peer.ConnectionNum; + packet.RawData[10] = 1; + FastBitConverter.GetBytes(packet.RawData, 11, peer.RemoteId); + return packet; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs.meta new file mode 100644 index 0000000..5415d5d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/InternalPackets.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8582459906515843a2f2adb010c3fd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers.meta new file mode 100644 index 0000000..f2e0b72 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcd79f96aed490043aa493beed54d929 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs new file mode 100644 index 0000000..3ee97d6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs @@ -0,0 +1,41 @@ +using LiteNetLib.Utils; +using System; +using System.Net; + +namespace LiteNetLib.Layers +{ + public sealed class Crc32cLayer : PacketLayerBase + { + public Crc32cLayer() : base(CRC32C.ChecksumSize) + { + + } + + public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + { + if (length < NetConstants.HeaderSize + CRC32C.ChecksumSize) + { + NetDebug.WriteError("[NM] DataReceived size: bad!"); + //Set length to 0 to have netManager drop the packet. + length = 0; + return; + } + + int checksumPoint = length - CRC32C.ChecksumSize; + if (CRC32C.Compute(data, offset, checksumPoint) != BitConverter.ToUInt32(data, checksumPoint)) + { + NetDebug.Write("[NM] DataReceived checksum: bad!"); + //Set length to 0 to have netManager drop the packet. + length = 0; + return; + } + length -= CRC32C.ChecksumSize; + } + + public override void ProcessOutBoundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + { + FastBitConverter.GetBytes(data, length, CRC32C.Compute(data, offset, length)); + length += CRC32C.ChecksumSize; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs.meta new file mode 100644 index 0000000..45504b8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d52aafc1486ec842a8d133ef41dfd39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs new file mode 100644 index 0000000..b3d9b3a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs @@ -0,0 +1,17 @@ +using System.Net; + +namespace LiteNetLib.Layers +{ + public abstract class PacketLayerBase + { + public readonly int ExtraPacketSizeForLayer; + + protected PacketLayerBase(int extraPacketSizeForLayer) + { + ExtraPacketSizeForLayer = extraPacketSizeForLayer; + } + + public abstract void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length); + public abstract void ProcessOutBoundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length); + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs.meta new file mode 100644 index 0000000..43aaedb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bddd0b5590cce7e42918c72429b84bde +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs new file mode 100644 index 0000000..9b67196 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs @@ -0,0 +1,60 @@ +using System; +using System.Net; +using System.Text; + +namespace LiteNetLib.Layers +{ + public class XorEncryptLayer : PacketLayerBase + { + private byte[] _byteKey; + + public XorEncryptLayer() : base(0) + { + + } + + public XorEncryptLayer(byte[] key) : this() + { + SetKey(key); + } + + public XorEncryptLayer(string key) : this() + { + SetKey(key); + } + + public void SetKey(string key) + { + _byteKey = Encoding.UTF8.GetBytes(key); + } + + public void SetKey(byte[] key) + { + if (_byteKey == null || _byteKey.Length != key.Length) + _byteKey = new byte[key.Length]; + Buffer.BlockCopy(key, 0, _byteKey, 0, key.Length); + } + + public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + { + if (_byteKey == null) + return; + var cur = offset; + for (var i = 0; i < length; i++, cur++) + { + data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]); + } + } + + public override void ProcessOutBoundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + { + if (_byteKey == null) + return; + var cur = offset; + for (var i = 0; i < length; i++, cur++) + { + data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs.meta new file mode 100644 index 0000000..14a4601 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb37499ecdd1ce145b0bcaf4b4f0279e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta new file mode 100644 index 0000000..f9c48e9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ad85b0f43f25f1499c27a4dca23ddd8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs new file mode 100644 index 0000000..bab2fca --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs @@ -0,0 +1,259 @@ +using System.Collections.Concurrent; +using System.Net; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + public enum NatAddressType + { + Internal, + External + } + + public interface INatPunchListener + { + void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); + void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); + } + + public class EventBasedNatPunchListener : INatPunchListener + { + public delegate void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token); + public delegate void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token); + + public event OnNatIntroductionRequest NatIntroductionRequest; + public event OnNatIntroductionSuccess NatIntroductionSuccess; + + void INatPunchListener.OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token) + { + if(NatIntroductionRequest != null) + NatIntroductionRequest(localEndPoint, remoteEndPoint, token); + } + + void INatPunchListener.OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token) + { + if (NatIntroductionSuccess != null) + NatIntroductionSuccess(targetEndPoint, type, token); + } + } + + /// + /// Module for UDP NAT Hole punching operations. Can be accessed from NetManager + /// + public sealed class NatPunchModule + { + struct RequestEventData + { + public IPEndPoint LocalEndPoint; + public IPEndPoint RemoteEndPoint; + public string Token; + } + + struct SuccessEventData + { + public IPEndPoint TargetEndPoint; + public NatAddressType Type; + public string Token; + } + + class NatIntroduceRequestPacket + { + public IPEndPoint Internal { get; set; } + public string Token { get; set; } + } + + class NatIntroduceResponsePacket + { + public IPEndPoint Internal { get; set; } + public IPEndPoint External { get; set; } + public string Token { get; set; } + } + + class NatPunchPacket + { + public string Token { get; set; } + public bool IsExternal { get; set; } + } + + private readonly NetManager _socket; + private readonly ConcurrentQueue _requestEvents = new ConcurrentQueue(); + private readonly ConcurrentQueue _successEvents = new ConcurrentQueue(); + private readonly NetDataReader _cacheReader = new NetDataReader(); + private readonly NetDataWriter _cacheWriter = new NetDataWriter(); + private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(MaxTokenLength); + private INatPunchListener _natPunchListener; + public const int MaxTokenLength = 256; + + /// + /// Events automatically will be called without PollEvents method from another thread + /// + public bool UnsyncedEvents = false; + + internal NatPunchModule(NetManager socket) + { + _socket = socket; + _netPacketProcessor.SubscribeReusable(OnNatIntroductionResponse); + _netPacketProcessor.SubscribeReusable(OnNatIntroductionRequest); + _netPacketProcessor.SubscribeReusable(OnNatPunch); + } + + internal void ProcessMessage(IPEndPoint senderEndPoint, NetPacket packet) + { + lock (_cacheReader) + { + _cacheReader.SetSource(packet.RawData, NetConstants.HeaderSize, packet.Size); + _netPacketProcessor.ReadAllPackets(_cacheReader, senderEndPoint); + } + } + + public void Init(INatPunchListener listener) + { + _natPunchListener = listener; + } + + private void Send(T packet, IPEndPoint target) where T : class, new() + { + _cacheWriter.Reset(); + _cacheWriter.Put((byte)PacketProperty.NatMessage); + _netPacketProcessor.Write(_cacheWriter, packet); + _socket.SendRaw(_cacheWriter.Data, 0, _cacheWriter.Length, target); + } + + public void NatIntroduce( + IPEndPoint hostInternal, + IPEndPoint hostExternal, + IPEndPoint clientInternal, + IPEndPoint clientExternal, + string additionalInfo) + { + var req = new NatIntroduceResponsePacket + { + Token = additionalInfo + }; + + //First packet (server) send to client + req.Internal = hostInternal; + req.External = hostExternal; + Send(req, clientExternal); + + //Second packet (client) send to server + req.Internal = clientInternal; + req.External = clientExternal; + Send(req, hostExternal); + } + + public void PollEvents() + { + if (UnsyncedEvents) + return; + + if (_natPunchListener == null || (_successEvents.IsEmpty && _requestEvents.IsEmpty)) + return; + + while (_successEvents.TryDequeue(out var evt)) + { + _natPunchListener.OnNatIntroductionSuccess( + evt.TargetEndPoint, + evt.Type, + evt.Token); + } + + while (_requestEvents.TryDequeue(out var evt)) + { + _natPunchListener.OnNatIntroductionRequest(evt.LocalEndPoint, evt.RemoteEndPoint, evt.Token); + } + } + + public void SendNatIntroduceRequest(string host, int port, string additionalInfo) + { + SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo); + } + + public void SendNatIntroduceRequest(IPEndPoint masterServerEndPoint, string additionalInfo) + { + //prepare outgoing data + string networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv4); + if (string.IsNullOrEmpty(networkIp)) + { + networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv6); + } + + Send( + new NatIntroduceRequestPacket + { + Internal = NetUtils.MakeEndPoint(networkIp, _socket.LocalPort), + Token = additionalInfo + }, + masterServerEndPoint); + } + + //We got request and must introduce + private void OnNatIntroductionRequest(NatIntroduceRequestPacket req, IPEndPoint senderEndPoint) + { + if (UnsyncedEvents) + { + _natPunchListener.OnNatIntroductionRequest( + req.Internal, + senderEndPoint, + req.Token); + } + else + { + _requestEvents.Enqueue(new RequestEventData + { + LocalEndPoint = req.Internal, + RemoteEndPoint = senderEndPoint, + Token = req.Token + }); + } + } + + //We got introduce and must punch + private void OnNatIntroductionResponse(NatIntroduceResponsePacket req) + { + NetDebug.Write(NetLogLevel.Trace, "[NAT] introduction received"); + + // 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); + + // hack for some routers + _socket.Ttl = 2; + _socket.SendRaw(new[] { (byte)PacketProperty.Empty }, 0, 1, req.External); + + // send external punch + _socket.Ttl = NetConstants.SocketTTL; + punchPacket.IsExternal = true; + Send(punchPacket, 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); + + //Release punch success to client; enabling him to Connect() to Sender if token is ok + if(UnsyncedEvents) + { + _natPunchListener.OnNatIntroductionSuccess( + senderEndPoint, + req.IsExternal ? NatAddressType.External : NatAddressType.Internal, + req.Token + ); + } + else + { + _successEvents.Enqueue(new SuccessEventData + { + TargetEndPoint = senderEndPoint, + Type = req.IsExternal ? NatAddressType.External : NatAddressType.Internal, + Token = req.Token + }); + } + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs.meta new file mode 100644 index 0000000..887acb2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e608aa88ab820244a90b83eca0f716c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs new file mode 100644 index 0000000..fc846c8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +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 + { + private const string LibName = "ws2_32.dll"; + + [DllImport(LibName, SetLastError = true)] + public static extern int recvfrom( + IntPtr socketHandle, + [In, Out] byte[] pinnedBuffer, + [In] int len, + [In] SocketFlags socketFlags, + [Out] byte[] socketAddress, + [In, Out] ref int socketAddressSize); + + [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 + { + private const string LibName = "libc"; + + [DllImport(LibName, SetLastError = true)] + public static extern int recvfrom( + IntPtr socketHandle, + [In, Out] byte[] pinnedBuffer, + [In] int len, + [In] SocketFlags socketFlags, + [Out] byte[] socketAddress, + [In, Out] ref int socketAddressSize); + + [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); + } + + public static readonly bool IsSupported = false; + public static readonly bool UnixMode = false; + + public const int IPv4AddrSize = 16; + public const int IPv6AddrSize = 28; + public const int AF_INET = 2; + public const int AF_INET6 = 10; + + private static readonly Dictionary NativeErrorToSocketError = new Dictionary + { + { 13, SocketError.AccessDenied }, //EACCES + { 98, SocketError.AddressAlreadyInUse }, //EADDRINUSE + { 99, SocketError.AddressNotAvailable }, //EADDRNOTAVAIL + { 97, SocketError.AddressFamilyNotSupported }, //EAFNOSUPPORT + { 11, SocketError.WouldBlock }, //EAGAIN + { 114, SocketError.AlreadyInProgress }, //EALREADY + { 9, SocketError.OperationAborted }, //EBADF + { 125, SocketError.OperationAborted }, //ECANCELED + { 103, SocketError.ConnectionAborted }, //ECONNABORTED + { 111, SocketError.ConnectionRefused }, //ECONNREFUSED + { 104, SocketError.ConnectionReset }, //ECONNRESET + { 89, SocketError.DestinationAddressRequired }, //EDESTADDRREQ + { 14, SocketError.Fault }, //EFAULT + { 112, SocketError.HostDown }, //EHOSTDOWN + { 6, SocketError.HostNotFound }, //ENXIO + { 113, SocketError.HostUnreachable }, //EHOSTUNREACH + { 115, SocketError.InProgress }, //EINPROGRESS + { 4, SocketError.Interrupted }, //EINTR + { 22, SocketError.InvalidArgument }, //EINVAL + { 106, SocketError.IsConnected }, //EISCONN + { 24, SocketError.TooManyOpenSockets }, //EMFILE + { 90, SocketError.MessageSize }, //EMSGSIZE + { 100, SocketError.NetworkDown }, //ENETDOWN + { 102, SocketError.NetworkReset }, //ENETRESET + { 101, SocketError.NetworkUnreachable }, //ENETUNREACH + { 23, SocketError.TooManyOpenSockets }, //ENFILE + { 105, SocketError.NoBufferSpaceAvailable }, //ENOBUFS + { 61, SocketError.NoData }, //ENODATA + { 2, SocketError.AddressNotAvailable }, //ENOENT + { 92, SocketError.ProtocolOption }, //ENOPROTOOPT + { 107, SocketError.NotConnected }, //ENOTCONN + { 88, SocketError.NotSocket }, //ENOTSOCK + { 3440, SocketError.OperationNotSupported }, //ENOTSUP + { 1, SocketError.AccessDenied }, //EPERM + { 32, SocketError.Shutdown }, //EPIPE + { 96, SocketError.ProtocolFamilyNotSupported }, //EPFNOSUPPORT + { 93, SocketError.ProtocolNotSupported }, //EPROTONOSUPPORT + { 91, SocketError.ProtocolType }, //EPROTOTYPE + { 94, SocketError.SocketNotSupported }, //ESOCKTNOSUPPORT + { 108, SocketError.Disconnecting }, //ESHUTDOWN + { 110, SocketError.TimedOut }, //ETIMEDOUT + { 0, SocketError.Success } + }; + + static NativeSocket() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + IsSupported = true; + UnixMode = true; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IsSupported = true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int RecvFrom( + IntPtr socketHandle, + byte[] pinnedBuffer, + int len, + byte[] socketAddress, + ref int socketAddressSize) + { + return UnixMode + ? UnixSock.recvfrom(socketHandle, pinnedBuffer, len, 0, socketAddress, ref socketAddressSize) + : WinSock.recvfrom(socketHandle, pinnedBuffer, len, 0, socketAddress, ref socketAddressSize); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public +#if LITENETLIB_UNSAFE + unsafe +#endif + static int SendTo( + IntPtr socketHandle, +#if LITENETLIB_UNSAFE + byte* pinnedBuffer, +#else + byte[] pinnedBuffer, +#endif + int len, + byte[] socketAddress, + int socketAddressSize) + { + return UnixMode + ? UnixSock.sendto(socketHandle, pinnedBuffer, len, 0, socketAddress, socketAddressSize) + : WinSock.sendto(socketHandle, pinnedBuffer, len, 0, socketAddress, socketAddressSize); + } + + public static SocketError GetSocketError() + { + int error = Marshal.GetLastWin32Error(); + if (UnixMode) + return NativeErrorToSocketError.TryGetValue(error, out var err) + ? err + : SocketError.SocketError; + return (SocketError)error; + } + + public static SocketException GetSocketException() + { + int error = Marshal.GetLastWin32Error(); + if (UnixMode) + return NativeErrorToSocketError.TryGetValue(error, out var err) + ? new SocketException((int)err) + : new SocketException((int)SocketError.SocketError); + return new SocketException(error); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short GetNativeAddressFamily(IPEndPoint remoteEndPoint) + { + return UnixMode + ? (short)(remoteEndPoint.AddressFamily == AddressFamily.InterNetwork ? AF_INET : AF_INET6) + : (short)remoteEndPoint.AddressFamily; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs.meta new file mode 100644 index 0000000..f18fd7c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12cfcf4490f2b8f4db979ee833ecf5af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs new file mode 100644 index 0000000..ca7dfbc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs @@ -0,0 +1,75 @@ +namespace LiteNetLib +{ + /// + /// Sending method type + /// + public enum DeliveryMethod : byte + { + /// + /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. + /// + Unreliable = 4, + + /// + /// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. + /// + ReliableUnordered = 0, + + /// + /// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. + /// + Sequenced = 1, + + /// + /// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. + /// + ReliableOrdered = 2, + + /// + /// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. + /// Cannot be fragmented + /// + ReliableSequenced = 3 + } + + /// + /// Network constants. Can be tuned from sources for your purposes. + /// + public static class NetConstants + { + //can be tuned + public const int DefaultWindowSize = 64; + public const int SocketBufferSize = 1024 * 1024; //1mb + public const int SocketTTL = 255; + + public const int HeaderSize = 1; + public const int ChanneledHeaderSize = 4; + public const int FragmentHeaderSize = 6; + public const int FragmentedHeaderTotalSize = ChanneledHeaderSize + FragmentHeaderSize; + public const ushort MaxSequence = 32768; + public const ushort HalfMaxSequence = MaxSequence / 2; + + //protocol + internal const int ProtocolId = 13; + internal const int MaxUdpHeaderSize = 68; + internal const int ChannelTypeCount = 4; + + internal static readonly int[] PossibleMtu = + { + 576 - MaxUdpHeaderSize, //minimal (RFC 1191) + 1024, //most games standard + 1232 - MaxUdpHeaderSize, + 1460 - MaxUdpHeaderSize, //google cloud + 1472 - MaxUdpHeaderSize, //VPN + 1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042) + 1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191) + }; + + //Max possible single packet size + public static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; + public static readonly int MaxUnreliableDataSize = MaxPacketSize - HeaderSize; + + //peer specific + public const byte MaxConnectionNumber = 4; + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs.meta new file mode 100644 index 0000000..653da3e --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetConstants.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b42ee5a523e67ff4c9149f91f7fe4245 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs new file mode 100644 index 0000000..a326c0d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs @@ -0,0 +1,92 @@ +using System; +using System.Diagnostics; + +namespace LiteNetLib +{ + public class InvalidPacketException : ArgumentException + { + public InvalidPacketException(string message) : base(message) + { + } + } + + public class TooBigPacketException : InvalidPacketException + { + public TooBigPacketException(string message) : base(message) + { + } + } + + public enum NetLogLevel + { + Warning, + Error, + Trace, + Info + } + + /// + /// Interface to implement for your own logger + /// + public interface INetLogger + { + void WriteNet(NetLogLevel level, string str, params object[] args); + } + + /// + /// Static class for defining your own LiteNetLib logger instead of Console.WriteLine + /// or Debug.Log if compiled with UNITY flag + /// + public static class NetDebug + { + public static INetLogger Logger = null; + private static readonly object DebugLogLock = new object(); + private static void WriteLogic(NetLogLevel logLevel, string str, params object[] args) + { + lock (DebugLogLock) + { + if (Logger == null) + { +#if UNITY_5_3_OR_NEWER + UnityEngine.Debug.Log(string.Format(str, args)); +#else + Console.WriteLine(str, args); +#endif + } + else + { + Logger.WriteNet(logLevel, str, args); + } + } + } + + [Conditional("DEBUG_MESSAGES")] + internal static void Write(string str, params object[] args) + { + WriteLogic(NetLogLevel.Trace, str, args); + } + + [Conditional("DEBUG_MESSAGES")] + internal static void Write(NetLogLevel level, string str, params object[] args) + { + WriteLogic(level, str, args); + } + + [Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")] + internal static void WriteForce(string str, params object[] args) + { + WriteLogic(NetLogLevel.Trace, str, args); + } + + [Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")] + internal static void WriteForce(NetLogLevel level, string str, params object[] args) + { + WriteLogic(level, str, args); + } + + internal static void WriteError(string str, params object[] args) + { + WriteLogic(NetLogLevel.Error, str, args); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs.meta new file mode 100644 index 0000000..73bd709 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f50ae51c124bf1439e339eee1fcd6f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs new file mode 100644 index 0000000..b2ae5e5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading; + +namespace LiteNetLib +{ + public partial class NetManager + { + private NetPacket _poolHead; + private int _poolCount; + private readonly object _poolLock = new object(); + + /// + /// Maximum packet pool size (increase if you have tons of packets sending) + /// + public int PacketPoolSize = 1000; + + public int PoolCount => _poolCount; + + private NetPacket PoolGetWithData(PacketProperty property, byte[] data, int start, int length) + { + int headerSize = NetPacket.GetHeaderSize(property); + NetPacket packet = PoolGetPacket(length + headerSize); + packet.Property = property; + Buffer.BlockCopy(data, start, packet.RawData, headerSize, length); + return packet; + } + + //Get packet with size + private NetPacket PoolGetWithProperty(PacketProperty property, int size) + { + NetPacket packet = PoolGetPacket(size + NetPacket.GetHeaderSize(property)); + packet.Property = property; + return packet; + } + + private NetPacket PoolGetWithProperty(PacketProperty property) + { + NetPacket packet = PoolGetPacket(NetPacket.GetHeaderSize(property)); + packet.Property = property; + return packet; + } + + internal NetPacket PoolGetPacket(int size) + { + NetPacket packet; + lock (_poolLock) + { + packet = _poolHead; + if (packet == null) + return new NetPacket(size); + + _poolHead = _poolHead.Next; + _poolCount--; + } + + packet.Size = size; + if (packet.RawData.Length < size) + packet.RawData = new byte[size]; + return packet; + } + + internal void PoolRecycle(NetPacket packet) + { + if (packet.RawData.Length > NetConstants.MaxPacketSize || _poolCount >= PacketPoolSize) + { + //Don't pool big packets. Save memory + return; + } + + //Clean fragmented flag + packet.RawData[0] = 0; + lock (_poolLock) + { + packet.Next = _poolHead; + _poolHead = packet; + _poolCount++; + } + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs.meta new file mode 100644 index 0000000..1927ff0 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d384bada29340e542945f001cad348ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs new file mode 100644 index 0000000..706e8f8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs @@ -0,0 +1,751 @@ +#if UNITY_IOS && !UNITY_EDITOR +using UnityEngine; +#endif +using System.Runtime.InteropServices; + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ +#if UNITY_IOS && !UNITY_EDITOR + public class UnitySocketFix : MonoBehaviour + { + internal IPAddress BindAddrIPv4; + internal IPAddress BindAddrIPv6; + internal int Port; + internal bool Paused; + internal NetManager Socket; + internal bool ManualMode; + + private void Update() + { + if (Socket == null) + Destroy(gameObject); + } + + private void OnApplicationPause(bool pause) + { + if (Socket == null) + return; + if (pause) + { + Paused = true; + Socket.CloseSocket(true); + } + else if (Paused) + { + if (!Socket.Start(BindAddrIPv4, BindAddrIPv6, Port, ManualMode)) + { + NetDebug.WriteError("[S] Cannot restore connection \"{0}\",\"{1}\" port {2}", BindAddrIPv4, BindAddrIPv6, Port); + Socket.CloseSocket(false); + } + } + } + } +#endif + + public partial class NetManager + { + private const int ReceivePollingTime = 500000; //0.5 second + + private Socket _udpSocketv4; + private Socket _udpSocketv6; + private Thread _threadv4; + private Thread _threadv6; + private IPEndPoint _bufferEndPointv4; + private IPEndPoint _bufferEndPointv6; + +#if !LITENETLIB_UNSAFE + [ThreadStatic] private static byte[] _sendToBuffer; +#endif + [ThreadStatic] private static byte[] _endPointBuffer; + + private readonly Dictionary _nativeAddrMap = new Dictionary(); + + 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; +#if UNITY_IOS && !UNITY_EDITOR + private UnitySocketFix _unitySocketFix; +#endif + + /// + /// Maximum packets count that will be processed in Manual PollEvents + /// + public int MaxPacketsReceivePerUpdate = 0; + + public short Ttl + { + get + { +#if UNITY_SWITCH + return 0; +#else + return _udpSocketv4.Ttl; +#endif + } + internal set + { +#if !UNITY_SWITCH + _udpSocketv4.Ttl = value; +#endif + } + } + + static NetManager() + { +#if DISABLE_IPV6 + IPv6Support = false; +#elif !UNITY_2019_1_OR_NEWER && !UNITY_2018_4_OR_NEWER && (!UNITY_EDITOR && ENABLE_IL2CPP) + string version = UnityEngine.Application.unityVersion; + IPv6Support = Socket.OSSupportsIPv6 && int.Parse(version.Remove(version.IndexOf('f')).Split('.')[2]) >= 6; +#else + IPv6Support = Socket.OSSupportsIPv6; +#endif + } + + private bool IsActive() + { +#if UNITY_IOS && !UNITY_EDITOR + var unitySocketFix = _unitySocketFix; //save for multithread + if (unitySocketFix != null && unitySocketFix.Paused) + return false; +#endif + 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); + } + } + + private bool ProcessError(SocketException ex) + { + switch (ex.SocketErrorCode) + { +#if UNITY_IOS && !UNITY_EDITOR + case SocketError.NotConnected: +#endif + case SocketError.Interrupted: + case SocketError.NotSocket: + case SocketError.OperationAborted: + return true; + case SocketError.ConnectionReset: + case SocketError.MessageSize: + case SocketError.TimedOut: + case SocketError.NetworkReset: + //NetDebug.Write($"[R]Ignored error: {(int)ex.SocketErrorCode} - {ex}"); + break; + default: + NetDebug.WriteError($"[R]Error code: {(int)ex.SocketErrorCode} - {ex}"); + CreateEvent(NetEvent.EType.Error, errorCode: ex.SocketErrorCode); + break; + } + return false; + } + + private void ManualReceive(Socket socket, EndPoint bufferEndPoint) + { + //Reading data + try + { + 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); + packetsReceived++; + if (packetsReceived == MaxPacketsReceivePerUpdate) + break; + } + } + catch (SocketException ex) + { + ProcessError(ex); + } + catch (ObjectDisposedException) + { + + } + catch (Exception e) + { + //protects socket receive thread + NetDebug.WriteError("[NM] SocketReceiveThread error: " + e ); + } + } + + private void NativeReceiveLogic(object state) + { + Socket socket = (Socket)state; + IntPtr socketHandle = socket.Handle; + byte[] addrBuffer = new byte[socket.AddressFamily == AddressFamily.InterNetwork + ? NativeSocket.IPv4AddrSize + : NativeSocket.IPv6AddrSize]; + + int addrSize = addrBuffer.Length; + NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize); + + while (IsActive()) + { + //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)) + continue; + NetPacket 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); + } + 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 ); + } + } + } + + /// + /// Start logic thread and listening on selected port + /// + /// bind to specific ipv4 address + /// bind to specific ipv6 address + /// port to listen + /// mode of library + public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode) + { + if (IsRunning && !IsActive()) + return 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))) + return false; + + LocalPort = ((IPEndPoint) _udpSocketv4.LocalEndPoint).Port; + +#if UNITY_IOS && !UNITY_EDITOR + if (_unitySocketFix == null) + { + var unityFixObj = new GameObject("LiteNetLib_UnitySocketFix"); + GameObject.DontDestroyOnLoad(unityFixObj); + _unitySocketFix = unityFixObj.AddComponent(); + _unitySocketFix.Socket = this; + _unitySocketFix.BindAddrIPv4 = addressIPv4; + _unitySocketFix.BindAddrIPv6 = addressIPv6; + _unitySocketFix.Port = LocalPort; + _unitySocketFix.ManualMode = _manualMode; + } + else + { + _unitySocketFix.Paused = false; + } +#endif + if (dualMode) + _udpSocketv6 = _udpSocketv4; + + 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 + { + _bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0); + } + + //Check IPv6 support + if (IPv6Support && IPv6Mode == IPv6Mode.SeparateSocket) + { + _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); + } + } + } + + return true; + } + + private bool BindSocket(Socket socket, IPEndPoint ep) + { + //Setup socket + socket.ReceiveTimeout = 500; + socket.SendTimeout = 500; + socket.ReceiveBufferSize = NetConstants.SocketBufferSize; + socket.SendBufferSize = NetConstants.SocketBufferSize; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + try + { + socket.IOControl(SioUdpConnreset, new byte[] {0}, null); + } + catch + { + //ignored + } + } + + try + { + socket.ExclusiveAddressUse = !ReuseAddress; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ReuseAddress); + } + catch + { + //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) + { + Ttl = NetConstants.SocketTTL; + + try { socket.EnableBroadcast = true; } + catch (SocketException e) + { + 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)) + { + try { socket.DontFragment = true; } + catch (SocketException e) + { + NetDebug.WriteError($"[B]DontFragment error: {e.SocketErrorCode}"); + } + } + } + //Bind + try + { + socket.Bind(ep); + NetDebug.Write(NetLogLevel.Trace, $"[B]Successfully binded to port: {((IPEndPoint)socket.LocalEndPoint).Port}, AF: {socket.AddressFamily}"); + + //join multicast + if (ep.AddressFamily == AddressFamily.InterNetworkV6) + { + try + { +#if !UNITY_2018_3_OR_NEWER + socket.SetSocketOption( + SocketOptionLevel.IPv6, + SocketOptionName.AddMembership, + new IPv6MulticastOption(MulticastAddressV6)); +#endif + } + catch (Exception) + { + // Unity3d throws exception - ignored + } + } + } + catch (SocketException bindException) + { + switch (bindException.SocketErrorCode) + { + //IPv6 bind fix + case SocketError.AddressAlreadyInUse: + if (socket.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Mode != IPv6Mode.DualMode) + { + try + { + //Set IPv6Only + socket.DualMode = false; + socket.Bind(ep); + } + catch (SocketException ex) + { + //because its fixed in 2018_3 + NetDebug.WriteError($"[B]Bind exception: {ex}, errorCode: {ex.SocketErrorCode}"); + return false; + } + return true; + } + break; + //hack for iOS (Unity3D) + case SocketError.AddressFamilyNotSupported: + return true; + } + NetDebug.WriteError($"[B]Bind exception: {bindException}, errorCode: {bindException.SocketErrorCode}"); + return false; + } + return true; + } + + internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint) + { + int result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); + PoolRecycle(packet); + return result; + } + + internal int SendRaw(NetPacket packet, IPEndPoint remoteEndPoint) + { + return SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); + } + + internal int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint) + { + if (!IsRunning) + return 0; + + NetPacket expandedPacket = null; + if (_extraPacketLayer != null) + { + expandedPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer); + Buffer.BlockCopy(message, start, expandedPacket.RawData, 0, length); + start = 0; + _extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref expandedPacket.RawData, ref start, ref length); + message = expandedPacket.RawData; + } + + var socket = _udpSocketv4; + if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support) + { + socket = _udpSocketv6; + if (socket == null) + return 0; + } + + int result; + try + { + if (UseNativeSockets) + { + 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); + } + } +#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 + { + result = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint); + } + //NetDebug.WriteForce("[S]Send packet to {0}, result: {1}", remoteEndPoint, result); + } + catch (SocketException ex) + { + switch (ex.SocketErrorCode) + { + case SocketError.NoBufferSpaceAvailable: + case SocketError.Interrupted: + return 0; + case SocketError.MessageSize: + NetDebug.Write(NetLogLevel.Trace, "[SRD] 10040, datalen: {0}", length); + return 0; + + case SocketError.HostUnreachable: + case SocketError.NetworkUnreachable: + if (DisconnectOnUnreachable && TryGetPeer(remoteEndPoint, out var fromPeer)) + { + DisconnectPeerForce( + fromPeer, + ex.SocketErrorCode == SocketError.HostUnreachable + ? DisconnectReason.HostUnreachable + : DisconnectReason.NetworkUnreachable, + ex.SocketErrorCode, + null); + } + + CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: ex.SocketErrorCode); + return -1; + + default: + NetDebug.WriteError($"[S] {ex}"); + return -1; + } + } + catch (Exception ex) + { + NetDebug.WriteError($"[S] {ex}"); + return 0; + } + finally + { + if (expandedPacket != null) + { + PoolRecycle(expandedPacket); + } + } + + if (result <= 0) + return 0; + + if (EnableStatistics) + { + Statistics.IncrementPacketsSent(); + Statistics.AddBytesSent(length); + } + + return result; + } + + public bool SendBroadcast(NetDataWriter writer, int port) + { + return SendBroadcast(writer.Data, 0, writer.Length, port); + } + + public bool SendBroadcast(byte[] data, int port) + { + return SendBroadcast(data, 0, data.Length, port); + } + + public bool SendBroadcast(byte[] data, int start, int length, int port) + { + if (!IsActive()) + return false; + + NetPacket packet; + if (_extraPacketLayer != null) + { + var headerSize = NetPacket.GetHeaderSize(PacketProperty.Broadcast); + packet = PoolGetPacket(headerSize + length + _extraPacketLayer.ExtraPacketSizeForLayer); + packet.Property = PacketProperty.Broadcast; + Buffer.BlockCopy(data, start, packet.RawData, headerSize, length); + var checksumComputeStart = 0; + int preCrcLength = length + headerSize; + IPEndPoint emptyEp = null; + _extraPacketLayer.ProcessOutBoundPacket(ref emptyEp, ref packet.RawData, ref checksumComputeStart, ref preCrcLength); + } + else + { + packet = PoolGetWithData(PacketProperty.Broadcast, data, start, length); + } + + bool broadcastSuccess = false; + bool multicastSuccess = false; + try + { + broadcastSuccess = _udpSocketv4.SendTo( + packet.RawData, + 0, + packet.Size, + SocketFlags.None, + new IPEndPoint(IPAddress.Broadcast, port)) > 0; + + if (_udpSocketv6 != null) + { + multicastSuccess = _udpSocketv6.SendTo( + packet.RawData, + 0, + packet.Size, + SocketFlags.None, + new IPEndPoint(MulticastAddressV6, port)) > 0; + } + } + catch (Exception ex) + { + NetDebug.WriteError($"[S][MCAST] {ex}"); + return broadcastSuccess; + } + finally + { + PoolRecycle(packet); + } + + return broadcastSuccess || multicastSuccess; + } + + internal void CloseSocket(bool suspend) + { + if (!suspend) + { + IsRunning = false; +#if UNITY_IOS && !UNITY_EDITOR + _unitySocketFix.Socket = null; + _unitySocketFix = null; +#endif + } + //cleanup dual mode + if (_udpSocketv4 == _udpSocketv6) + _udpSocketv6 = null; + + _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; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs.meta new file mode 100644 index 0000000..a418311 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cc0423407df3e74a8e5a15dbbad2598 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs new file mode 100644 index 0000000..48293f9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs @@ -0,0 +1,1786 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using LiteNetLib.Layers; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + public enum IPv6Mode + { + Disabled, + SeparateSocket, + DualMode + } + + public sealed class NetPacketReader : NetDataReader + { + private NetPacket _packet; + private readonly NetManager _manager; + private readonly NetEvent _evt; + + internal NetPacketReader(NetManager manager, NetEvent evt) + { + _manager = manager; + _evt = evt; + } + + internal void SetSource(NetPacket packet, int headerSize) + { + if (packet == null) + return; + _packet = packet; + SetSource(packet.RawData, headerSize, packet.Size); + } + + internal void RecycleInternal() + { + Clear(); + if (_packet != null) + _manager.PoolRecycle(_packet); + _packet = null; + _manager.RecycleEvent(_evt); + } + + public void Recycle() + { + if (_manager.AutoRecycle) + return; + RecycleInternal(); + } + } + + internal sealed class NetEvent + { + public NetEvent Next; + + public enum EType + { + Connect, + Disconnect, + Receive, + ReceiveUnconnected, + Error, + ConnectionLatencyUpdated, + Broadcast, + ConnectionRequest, + MessageDelivered, + PeerAddressChanged + } + public EType Type; + + public NetPeer Peer; + public IPEndPoint RemoteEndPoint; + public object UserData; + public int Latency; + public SocketError ErrorCode; + public DisconnectReason DisconnectReason; + public ConnectionRequest ConnectionRequest; + public DeliveryMethod DeliveryMethod; + public byte ChannelNumber; + public readonly NetPacketReader DataReader; + + public NetEvent(NetManager manager) + { + DataReader = new NetPacketReader(manager, this); + } + } + + /// + /// Main class for all network operations. Can be used as client and/or server. + /// + 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; + private NetPeer _p; + + public NetPeerEnumerator(NetPeer p) + { + _initialPeer = p; + _p = null; + } + + public void Dispose() + { + + } + + public bool MoveNext() + { + _p = _p == null ? _initialPeer : _p.NextPeer; + return _p != null; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public NetPeer Current => _p; + object IEnumerator.Current => _p; + } + +#if DEBUG + private struct IncomingData + { + public NetPacket Data; + public IPEndPoint EndPoint; + public DateTime TimeWhenGet; + } + private readonly List _pingSimulationList = new List(); + private readonly Random _randomGenerator = new Random(); + private const int MinLatencyThreshold = 5; +#endif + + private Thread _logicThread; + private bool _manualMode; + private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(true); + + private Queue _netEventsProduceQueue = new Queue(); + private Queue _netEventsConsumeQueue = new Queue(); + + private NetEvent _netEventPoolHead; + private readonly INetEventListener _netEventListener; + private readonly IDeliveryEventListener _deliveryEventListener; + 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 List _connectedPeerListCache = new List(); + private NetPeer[] _peersArray = new NetPeer[32]; + private readonly PacketLayerBase _extraPacketLayer; + private int _lastPeerId; + private ConcurrentQueue _peerIds = new ConcurrentQueue(); + private byte _channelsCount = 1; + private readonly object _eventLock = new object(); + + //config section + /// + /// Enable messages receiving without connection. (with SendUnconnectedMessage method) + /// + public bool UnconnectedMessagesEnabled = false; + + /// + /// Enable nat punch messages + /// + public bool NatPunchEnabled = false; + + /// + /// Library logic update and send period in milliseconds + /// Lowest values in Windows doesn't change much because of Thread.Sleep precision + /// To more frequent sends (or sends tied to your game logic) use + /// + public int UpdateTime = 15; + + /// + /// Interval for latency detection and checking connection (in milliseconds) + /// + public int PingInterval = 1000; + + /// + /// If NetManager doesn't receive any packet from remote peer during this time (in milliseconds) then connection will be closed + /// (including library internal keepalive packets) + /// + public int DisconnectTimeout = 5000; + + /// + /// Simulate packet loss by dropping random amount of packets. (Works only in DEBUG mode) + /// + public bool SimulatePacketLoss = false; + + /// + /// Simulate latency by holding packets for random time. (Works only in DEBUG mode) + /// + public bool SimulateLatency = false; + + /// + /// Chance of packet loss when simulation enabled. value in percents (1 - 100). + /// + public int SimulationPacketLossChance = 10; + + /// + /// Minimum simulated latency (in milliseconds) + /// + public int SimulationMinLatency = 30; + + /// + /// Maximum simulated latency (in milliseconds) + /// + public int SimulationMaxLatency = 100; + + /// + /// Events automatically will be called without PollEvents method from another thread + /// + public bool UnsyncedEvents = false; + + /// + /// If true - receive event will be called from "receive" thread immediately otherwise on PollEvents call + /// + public bool UnsyncedReceiveEvent = false; + + /// + /// If true - delivery event will be called from "receive" thread immediately otherwise on PollEvents call + /// + public bool UnsyncedDeliveryEvent = false; + + /// + /// Allows receive broadcast packets + /// + public bool BroadcastReceiveEnabled = false; + + /// + /// Delay between initial connection attempts (in milliseconds) + /// + public int ReconnectDelay = 500; + + /// + /// Maximum connection attempts before client stops and call disconnect event. + /// + public int MaxConnectAttempts = 10; + + /// + /// Enables socket option "ReuseAddress" for specific purposes + /// + public bool ReuseAddress = false; + + /// + /// Statistics of all connections + /// + public readonly NetStatistics Statistics = new NetStatistics(); + + /// + /// Toggles the collection of network statistics for the instance and all known peers + /// + public bool EnableStatistics = false; + + /// + /// NatPunchModule for NAT hole punching operations + /// + public readonly NatPunchModule NatPunchModule; + + /// + /// Returns true if socket listening and update thread is running + /// + public bool IsRunning { get; private set; } + + /// + /// Local EndPoint (host and port) + /// + public int LocalPort { get; private set; } + + /// + /// Automatically recycle NetPacketReader after OnReceive event + /// + public bool AutoRecycle; + + /// + /// IPv6 support + /// + public IPv6Mode IPv6Mode = IPv6Mode.SeparateSocket; + + /// + /// Override MTU for all new peers registered in this NetManager, will ignores MTU Discovery! + /// + public int MtuOverride = 0; + + /// + /// Sets initial MTU to lowest possible value according to RFC1191 (576 bytes) + /// + public bool UseSafeMtu = false; + + /// + /// First peer. Useful for Client mode + /// + public NetPeer FirstPeer => _headPeer; + + /// + /// Experimental feature mostly for servers. Only for Windows/Linux + /// use direct socket calls for send/receive to drastically increase speed and reduce GC pressure + /// + public bool UseNativeSockets = false; + + /// + /// Disconnect peers if HostUnreachable or NetworkUnreachable spawned (old behaviour 0.9.x was true) + /// + public bool DisconnectOnUnreachable = false; + + /// + /// Allows peer change it's ip (lte to wifi, wifi to lte, etc). Use only on server + /// + public bool AllowPeerAddressChange = false; + + /// + /// QoS channel count per message type (value must be between 1 and 64 channels) + /// + public byte ChannelsCount + { + get => _channelsCount; + set + { + if (value < 1 || value > 64) + throw new ArgumentException("Channels count must be between 1 and 64"); + _channelsCount = value; + } + } + + /// + /// Returns connected peers list (with internal cached list) + /// + public List ConnectedPeerList + { + get + { + GetPeersNonAlloc(_connectedPeerListCache, ConnectionState.Connected); + return _connectedPeerListCache; + } + } + + /// + /// 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 ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0; + + private bool TryGetPeer(IPEndPoint endPoint, out NetPeer peer) + { + _peersLock.EnterReadLock(); + bool result = _peersDict.TryGetValue(endPoint, out peer); + _peersLock.ExitReadLock(); + return result; + } + + 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(); + RemovePeerInternal(peer); + _peersLock.ExitWriteLock(); + } + + private void RemovePeerInternal(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. + public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null) + { + _netEventListener = listener; + _deliveryEventListener = listener as IDeliveryEventListener; + _ntpEventListener = listener as INtpEventListener; + _peerAddressChangedListener = listener as IPeerAddressChangedListener; + NatPunchModule = new NatPunchModule(this); + _extraPacketLayer = extraPacketLayer; + } + + internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency) + { + CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, latency: latency); + } + + internal void MessageDelivered(NetPeer fromPeer, object userData) + { + if(_deliveryEventListener != null) + CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, userData: userData); + } + + internal void DisconnectPeerForce(NetPeer peer, + DisconnectReason reason, + SocketError socketErrorCode, + NetPacket eventData) + { + DisconnectPeer(peer, reason, socketErrorCode, true, null, 0, 0, eventData); + } + + private void DisconnectPeer( + NetPeer peer, + DisconnectReason reason, + SocketError socketErrorCode, + bool force, + byte[] data, + int start, + int count, + NetPacket eventData) + { + var shutdownResult = peer.Shutdown(data, start, count, force); + if (shutdownResult == ShutdownResult.None) + return; + if(shutdownResult == ShutdownResult.WasConnected) + Interlocked.Decrement(ref _connectedPeersCount); + CreateEvent( + NetEvent.EType.Disconnect, + peer, + errorCode: socketErrorCode, + disconnectReason: reason, + readerSource: eventData); + } + + private void CreateEvent( + NetEvent.EType type, + NetPeer peer = null, + IPEndPoint remoteEndPoint = null, + SocketError errorCode = 0, + int latency = 0, + DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, + ConnectionRequest connectionRequest = null, + DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, + byte channelNumber = 0, + NetPacket readerSource = null, + object userData = null) + { + NetEvent evt; + bool unsyncEvent = UnsyncedEvents; + + if (type == NetEvent.EType.Connect) + Interlocked.Increment(ref _connectedPeersCount); + else if (type == NetEvent.EType.MessageDelivered) + unsyncEvent = UnsyncedDeliveryEvent; + + lock(_eventLock) + { + evt = _netEventPoolHead; + if (evt == null) + evt = new NetEvent(this); + else + _netEventPoolHead = evt.Next; + } + + evt.Type = type; + evt.DataReader.SetSource(readerSource, readerSource?.GetHeaderSize() ?? 0); + evt.Peer = peer; + evt.RemoteEndPoint = remoteEndPoint; + evt.Latency = latency; + evt.ErrorCode = errorCode; + evt.DisconnectReason = disconnectReason; + evt.ConnectionRequest = connectionRequest; + evt.DeliveryMethod = deliveryMethod; + evt.ChannelNumber = channelNumber; + evt.UserData = userData; + + if (unsyncEvent || _manualMode) + { + ProcessEvent(evt); + } + else + { + lock(_netEventsProduceQueue) + _netEventsProduceQueue.Enqueue(evt); + } + } + + private void ProcessEvent(NetEvent evt) + { + NetDebug.Write("[NM] Processing event: " + evt.Type); + bool emptyData = evt.DataReader.IsNull; + switch (evt.Type) + { + case NetEvent.EType.Connect: + _netEventListener.OnPeerConnected(evt.Peer); + break; + case NetEvent.EType.Disconnect: + var info = new DisconnectInfo + { + Reason = evt.DisconnectReason, + AdditionalData = evt.DataReader, + SocketErrorCode = evt.ErrorCode + }; + _netEventListener.OnPeerDisconnected(evt.Peer, info); + break; + case NetEvent.EType.Receive: + _netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.ChannelNumber, evt.DeliveryMethod); + break; + case NetEvent.EType.ReceiveUnconnected: + _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.BasicMessage); + break; + case NetEvent.EType.Broadcast: + _netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Broadcast); + break; + case NetEvent.EType.Error: + _netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode); + break; + case NetEvent.EType.ConnectionLatencyUpdated: + _netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency); + break; + case NetEvent.EType.ConnectionRequest: + _netEventListener.OnConnectionRequest(evt.ConnectionRequest); + break; + case NetEvent.EType.MessageDelivered: + _deliveryEventListener.OnMessageDelivered(evt.Peer, evt.UserData); + break; + case NetEvent.EType.PeerAddressChanged: + _peersLock.EnterUpgradeableReadLock(); + IPEndPoint previousAddress = null; + if (_peersDict.ContainsKey(evt.Peer.EndPoint)) + { + _peersLock.EnterWriteLock(); + _peersDict.Remove(evt.Peer.EndPoint); + previousAddress = evt.Peer.EndPoint; + evt.Peer.FinishEndPointChange(evt.RemoteEndPoint); + _peersDict.Add(evt.Peer.EndPoint, evt.Peer); + _peersLock.ExitWriteLock(); + } + _peersLock.ExitUpgradeableReadLock(); + if(previousAddress != null) + _peerAddressChangedListener.OnPeerAddressChanged(evt.Peer, previousAddress); + break; + } + //Recycle if not message + if (emptyData) + RecycleEvent(evt); + else if (AutoRecycle) + evt.DataReader.RecycleInternal(); + } + + internal void RecycleEvent(NetEvent evt) + { + evt.Peer = null; + evt.ErrorCode = 0; + evt.RemoteEndPoint = null; + evt.ConnectionRequest = null; + lock(_eventLock) + { + evt.Next = _netEventPoolHead; + _netEventPoolHead = evt; + } + } + + //Update function + private void UpdateLogic() + { + var peersToRemove = new List(); + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (IsRunning) + { + try + { + ProcessDelayedPackets(); + int elapsed = (int)stopwatch.ElapsedMilliseconds; + elapsed = elapsed <= 0 ? 1 : elapsed; + stopwatch.Restart(); + + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if (netPeer.ConnectionState == ConnectionState.Disconnected && + netPeer.TimeSinceLastPacket > DisconnectTimeout) + { + peersToRemove.Add(netPeer); + } + else + { + netPeer.Update(elapsed); + } + } + + if (peersToRemove.Count > 0) + { + _peersLock.EnterWriteLock(); + for (int i = 0; i < peersToRemove.Count; i++) + RemovePeerInternal(peersToRemove[i]); + _peersLock.ExitWriteLock(); + peersToRemove.Clear(); + } + + ProcessNtpRequests(elapsed); + + int sleepTime = UpdateTime - (int)stopwatch.ElapsedMilliseconds; + if (sleepTime > 0) + _updateTriggerEvent.WaitOne(sleepTime); + } + catch (ThreadAbortException) + { + return; + } + catch (Exception e) + { + NetDebug.WriteError("[NM] LogicThread error: " + e); + } + } + stopwatch.Stop(); + } + + [Conditional("DEBUG")] + private void ProcessDelayedPackets() + { +#if DEBUG + if (!SimulateLatency) + return; + + var time = DateTime.UtcNow; + lock (_pingSimulationList) + { + for (int i = 0; i < _pingSimulationList.Count; i++) + { + var incomingData = _pingSimulationList[i]; + if (incomingData.TimeWhenGet <= time) + { + DebugMessageReceived(incomingData.Data, incomingData.EndPoint); + _pingSimulationList.RemoveAt(i); + i--; + } + } + } +#endif + } + + private void ProcessNtpRequests(int elapsedMilliseconds) + { + List requestsToRemove = null; + foreach (var ntpRequest in _ntpRequests) + { + ntpRequest.Value.Send(_udpSocketv4, elapsedMilliseconds); + if(ntpRequest.Value.NeedToKill) + { + if (requestsToRemove == null) + requestsToRemove = new List(); + requestsToRemove.Add(ntpRequest.Key); + } + } + + if (requestsToRemove != null) + { + foreach (var ipEndPoint in requestsToRemove) + { + _ntpRequests.Remove(ipEndPoint); + } + } + } + + /// + /// Update and send logic. Use this only when NetManager started in manual mode + /// + /// elapsed milliseconds since last update call + public void ManualUpdate(int elapsedMilliseconds) + { + if (!_manualMode) + return; + + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > DisconnectTimeout) + { + RemovePeerInternal(netPeer); + } + else + { + netPeer.Update(elapsedMilliseconds); + } + } + ProcessNtpRequests(elapsedMilliseconds); + } + + internal NetPeer OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length) + { + NetPeer netPeer = null; + + if (request.Result == ConnectionRequestResult.RejectForce) + { + NetDebug.Write(NetLogLevel.Trace, "[NM] Peer connect reject force."); + if (rejectData != null && length > 0) + { + var shutdownPacket = PoolGetWithProperty(PacketProperty.Disconnect, length); + shutdownPacket.ConnectionNumber = request.InternalPacket.ConnectionNumber; + FastBitConverter.GetBytes(shutdownPacket.RawData, 1, request.InternalPacket.ConnectionTime); + if (shutdownPacket.Size >= NetConstants.PossibleMtu[0]) + NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU!"); + else + Buffer.BlockCopy(rejectData, start, shutdownPacket.RawData, 9, length); + SendRawAndRecycle(shutdownPacket, request.RemoteEndPoint); + } + } + else + { + _peersLock.EnterUpgradeableReadLock(); + if (_peersDict.TryGetValue(request.RemoteEndPoint, out netPeer)) + { + //already have peer + _peersLock.ExitUpgradeableReadLock(); + } + 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++; + } + + private void ProcessConnectRequest( + IPEndPoint remoteEndPoint, + NetPeer netPeer, + NetConnectRequestPacket connRequest) + { + //if we have peer + 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); + + switch (processResult) + { + case ConnectRequestResult.Reconnection: + DisconnectPeerForce(netPeer, DisconnectReason.Reconnect, 0, null); + RemovePeer(netPeer); + //go to new connection + break; + case ConnectRequestResult.NewConnection: + RemovePeer(netPeer); + //go to new connection + break; + case ConnectRequestResult.P2PLose: + DisconnectPeerForce(netPeer, DisconnectReason.PeerToPeerConnection, 0, null); + RemovePeer(netPeer); + //go to new connection + break; + default: + //no operations needed + return; + } + //ConnectRequestResult.NewConnection + //Set next connection number + 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); + } + + ConnectionRequest req; + lock (_requestsDict) + { + if (_requestsDict.TryGetValue(remoteEndPoint, out req)) + { + req.UpdateRequest(connRequest); + return; + } + req = new ConnectionRequest(remoteEndPoint, connRequest, this); + _requestsDict.Add(remoteEndPoint, req); + } + NetDebug.Write("[NM] Creating request event: " + connRequest.ConnectionTime); + CreateEvent(NetEvent.EType.ConnectionRequest, connectionRequest: req); + } + + private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) + { +#if DEBUG + if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100 < SimulationPacketLossChance) + { + //drop packet + return; + } + if (SimulateLatency) + { + int latency = _randomGenerator.Next(SimulationMinLatency, SimulationMaxLatency); + if (latency > MinLatencyThreshold) + { + lock (_pingSimulationList) + { + _pingSimulationList.Add(new IncomingData + { + Data = packet, + EndPoint = remoteEndPoint, + TimeWhenGet = DateTime.UtcNow.AddMilliseconds(latency) + }); + } + //hold packet + return; + } + } + + //ProcessEvents + DebugMessageReceived(packet, remoteEndPoint); + } + + private void DebugMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) + { +#endif + if (EnableStatistics) + { + Statistics.IncrementPacketsReceived(); + Statistics.AddBytesReceived(packet.Size); + } + + if (_ntpRequests.Count > 0) + { + if (_ntpRequests.TryGetValue(remoteEndPoint, out var request)) + { + 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); + } + return; + } + } + + if (_extraPacketLayer != null) + { + int start = 0; + _extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref start, ref packet.Size); + if (packet.Size == 0) + return; + } + + if (!packet.Verify()) + { + NetDebug.WriteError("[NM] DataReceived: bad!"); + PoolRecycle(packet); + return; + } + + switch (packet.Property) + { + //special case connect request + case PacketProperty.ConnectRequest: + if (NetConnectRequestPacket.GetProtocolId(packet) != NetConstants.ProtocolId) + { + SendRawAndRecycle(PoolGetWithProperty(PacketProperty.InvalidProtocol), remoteEndPoint); + return; + } + break; + //unconnected messages + case PacketProperty.Broadcast: + if (!BroadcastReceiveEnabled) + return; + CreateEvent(NetEvent.EType.Broadcast, remoteEndPoint: remoteEndPoint, readerSource: packet); + return; + case PacketProperty.UnconnectedMessage: + if (!UnconnectedMessagesEnabled) + return; + CreateEvent(NetEvent.EType.ReceiveUnconnected, remoteEndPoint: remoteEndPoint, readerSource: packet); + return; + case PacketProperty.NatMessage: + if (NatPunchEnabled) + NatPunchModule.ProcessMessage(remoteEndPoint, packet); + return; + } + + //Check normal packets + _peersLock.EnterReadLock(); + bool peerFound = _peersDict.TryGetValue(remoteEndPoint, out var netPeer); + _peersLock.ExitReadLock(); + + switch (packet.Property) + { + case PacketProperty.ConnectRequest: + var connRequest = NetConnectRequestPacket.FromData(packet); + if (connRequest != null) + ProcessConnectRequest(remoteEndPoint, netPeer, connRequest); + break; + case PacketProperty.PeerNotFound: + if (peerFound) //local + { + if (netPeer.ConnectionState != ConnectionState.Connected) + return; + if (packet.Size == 1) + { + //first reply + //send NetworkChanged packet + netPeer.ResetMtu(); + SendRaw(NetConnectAcceptPacket.MakeNetworkChanged(netPeer), remoteEndPoint); + NetDebug.Write($"PeerNotFound sending connection info: {remoteEndPoint}"); + } + else if (packet.Size == 2 && packet.RawData[1] == 1) + { + //second reply + DisconnectPeerForce(netPeer, DisconnectReason.PeerNotFound, 0, null); + } + } + else if (packet.Size > 1) //remote + { + //check if this is old peer + bool isOldPeer = false; + + if (AllowPeerAddressChange) + { + NetDebug.Write($"[NM] Looks like address change: {packet.Size}"); + var remoteData = NetConnectAcceptPacket.FromData(packet); + if (remoteData != null && + remoteData.PeerNetworkChanged && + remoteData.PeerId < _peersArray.Length) + { + _peersLock.EnterUpgradeableReadLock(); + var peer = _peersArray[remoteData.PeerId]; + if (peer != null && + peer.ConnectTime == remoteData.ConnectionTime && + peer.ConnectionNum == remoteData.ConnectionNumber) + { + if (peer.ConnectionState == ConnectionState.Connected) + { + peer.InitiateEndPointChange(); + if (_peerAddressChangedListener != null) + { + CreateEvent(NetEvent.EType.PeerAddressChanged, peer, remoteEndPoint); + } + NetDebug.Write("[NM] PeerNotFound change address of remote peer"); + } + isOldPeer = true; + } + _peersLock.ExitUpgradeableReadLock(); + } + } + + PoolRecycle(packet); + + //else peer really not found + if (!isOldPeer) + { + var secondResponse = PoolGetWithProperty(PacketProperty.PeerNotFound, 1); + secondResponse.RawData[1] = 1; + SendRawAndRecycle(secondResponse, remoteEndPoint); + } + } + break; + case PacketProperty.InvalidProtocol: + if (peerFound && netPeer.ConnectionState == ConnectionState.Outgoing) + DisconnectPeerForce(netPeer, DisconnectReason.InvalidProtocol, 0, null); + break; + case PacketProperty.Disconnect: + if (peerFound) + { + var disconnectResult = netPeer.ProcessDisconnect(packet); + if (disconnectResult == DisconnectResult.None) + { + PoolRecycle(packet); + return; + } + DisconnectPeerForce( + netPeer, + disconnectResult == DisconnectResult.Disconnect + ? DisconnectReason.RemoteConnectionClose + : DisconnectReason.ConnectionRejected, + 0, packet); + } + else + { + PoolRecycle(packet); + } + //Send shutdown + SendRawAndRecycle(PoolGetWithProperty(PacketProperty.ShutdownOk), remoteEndPoint); + break; + case PacketProperty.ConnectAccept: + if (!peerFound) + return; + var connAccept = NetConnectAcceptPacket.FromData(packet); + if (connAccept != null && netPeer.ProcessConnectAccept(connAccept)) + CreateEvent(NetEvent.EType.Connect, netPeer); + break; + default: + if(peerFound) + netPeer.ProcessPacket(packet); + else + SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint); + break; + } + } + + 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) + { + ProcessEvent(evt); + } + else + { + lock(_netEventsProduceQueue) + _netEventsProduceQueue.Enqueue(evt); + } + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// DataWriter with data + /// Send options (reliable, unreliable, etc.) + public void SendToAll(NetDataWriter writer, DeliveryMethod options) + { + SendToAll(writer.Data, 0, writer.Length, options); + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + public void SendToAll(byte[] data, DeliveryMethod options) + { + SendToAll(data, 0, data.Length, options); + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Start of data + /// Length of data + /// Send options (reliable, unreliable, etc.) + public void SendToAll(byte[] data, int start, int length, DeliveryMethod options) + { + SendToAll(data, start, length, 0, options); + } + + /// + /// Send data to all connected peers + /// + /// DataWriter with data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options) + { + SendToAll(writer.Data, 0, writer.Length, channelNumber, options); + } + + /// + /// Send data to all connected peers + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options) + { + SendToAll(data, 0, data.Length, channelNumber, options); + } + + /// + /// Send data to all connected peers + /// + /// Data + /// Start of data + /// Length of data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options) + { + try + { + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + netPeer.Send(data, start, length, channelNumber, options); + } + finally + { + _peersLock.ExitReadLock(); + } + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// DataWriter with data + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(NetDataWriter writer, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(writer.Data, 0, writer.Length, 0, options, excludePeer); + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(byte[] data, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(data, 0, data.Length, 0, options, excludePeer); + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Start of data + /// Length of data + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(byte[] data, int start, int length, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(data, start, length, 0, options, excludePeer); + } + + /// + /// Send data to all connected peers + /// + /// DataWriter with data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(writer.Data, 0, writer.Length, channelNumber, 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(byte[] data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(data, 0, data.Length, channelNumber, options, excludePeer); + } + + + /// + /// Send data to all connected peers + /// + /// Data + /// Start of data + /// Length of data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) + { + try + { + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if (netPeer != excludePeer) + netPeer.Send(data, start, length, channelNumber, options); + } + } + finally + { + _peersLock.ExitReadLock(); + } + } + + /// + /// Start logic thread and listening on available port + /// + public bool Start() + { + return Start(0); + } + + /// + /// Start logic thread and listening on selected port + /// + /// bind to specific ipv4 address + /// bind to specific ipv6 address + /// port to listen + public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port) + { + return Start(addressIPv4, addressIPv6, port, false); + } + + /// + /// Start logic thread and listening on selected port + /// + /// bind to specific ipv4 address + /// bind to specific ipv6 address + /// port to listen + public bool Start(string addressIPv4, string addressIPv6, int port) + { + IPAddress ipv4 = NetUtils.ResolveAddress(addressIPv4); + IPAddress ipv6 = NetUtils.ResolveAddress(addressIPv6); + return Start(ipv4, ipv6, port); + } + + /// + /// Start logic thread and listening on selected port + /// + /// port to listen + public bool Start(int port) + { + return Start(IPAddress.Any, IPAddress.IPv6Any, port); + } + + /// + /// Start in manual mode and listening on selected port + /// In this mode you should use ManualReceive (without PollEvents) for receive packets + /// and ManualUpdate(...) for update and send packets + /// This mode useful mostly for single-threaded servers + /// + /// bind to specific ipv4 address + /// bind to specific ipv6 address + /// port to listen + public bool StartInManualMode(IPAddress addressIPv4, IPAddress addressIPv6, int port) + { + return Start(addressIPv4, addressIPv6, port, true); + } + + /// + /// Start in manual mode and listening on selected port + /// In this mode you should use ManualReceive (without PollEvents) for receive packets + /// and ManualUpdate(...) for update and send packets + /// This mode useful mostly for single-threaded servers + /// + /// bind to specific ipv4 address + /// bind to specific ipv6 address + /// port to listen + public bool StartInManualMode(string addressIPv4, string addressIPv6, int port) + { + IPAddress ipv4 = NetUtils.ResolveAddress(addressIPv4); + IPAddress ipv6 = NetUtils.ResolveAddress(addressIPv6); + return StartInManualMode(ipv4, ipv6, port); + } + + /// + /// Start in manual mode and listening on selected port + /// In this mode you should use ManualReceive (without PollEvents) for receive packets + /// and ManualUpdate(...) for update and send packets + /// This mode useful mostly for single-threaded servers + /// + /// port to listen + public bool StartInManualMode(int port) + { + return StartInManualMode(IPAddress.Any, IPAddress.IPv6Any, port); + } + + /// + /// Send message without connection + /// + /// Raw data + /// Packet destination + /// Operation result + public bool SendUnconnectedMessage(byte[] message, IPEndPoint remoteEndPoint) + { + return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint); + } + + /// + /// Send message without connection. WARNING This method allocates a new IPEndPoint object and + /// synchronously makes a DNS request. If you're calling this method every frame it will be + /// much faster to just cache the IPEndPoint. + /// + /// Data serializer + /// Packet destination IP or hostname + /// Packet destination port + /// Operation result + public bool SendUnconnectedMessage(NetDataWriter writer, string address, int port) + { + IPEndPoint remoteEndPoint = NetUtils.MakeEndPoint(address, port); + + return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); + } + + /// + /// Send message without connection + /// + /// Data serializer + /// Packet destination + /// Operation result + public bool SendUnconnectedMessage(NetDataWriter writer, IPEndPoint remoteEndPoint) + { + return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint); + } + + /// + /// Send message without connection + /// + /// Raw data + /// data start + /// data length + /// Packet destination + /// Operation result + public bool SendUnconnectedMessage(byte[] message, int start, int length, IPEndPoint remoteEndPoint) + { + //No need for CRC here, SendRaw does that + NetPacket packet = PoolGetWithData(PacketProperty.UnconnectedMessage, message, start, length); + return SendRawAndRecycle(packet, remoteEndPoint) > 0; + } + + /// + /// Triggers update and send logic immediately (works asynchronously) + /// + public void TriggerUpdate() + { + _updateTriggerEvent.Set(); + } + + /// + /// Receive all pending events. Call this in game update code + /// In Manual mode it will call also socket Receive (which can be slow) + /// + public void PollEvents() + { + if (_manualMode) + { + if (_udpSocketv4 != null) + ManualReceive(_udpSocketv4, _bufferEndPointv4); + if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4) + ManualReceive(_udpSocketv6, _bufferEndPointv6); + ProcessDelayedPackets(); + return; + } + if (UnsyncedEvents) + return; + lock (_netEventsProduceQueue) + { + (_netEventsConsumeQueue, _netEventsProduceQueue) = (_netEventsProduceQueue, _netEventsConsumeQueue); + } + + while(_netEventsConsumeQueue.Count > 0) + ProcessEvent(_netEventsConsumeQueue.Dequeue()); + } + + /// + /// Connect to remote host + /// + /// Server IP or hostname + /// Server Port + /// Connection key + /// New NetPeer if new connection, Old NetPeer if already connected, null peer if there is ConnectionRequest awaiting + /// Manager is not running. Call + public NetPeer Connect(string address, int port, string key) + { + return Connect(address, port, NetDataWriter.FromString(key)); + } + + /// + /// Connect to remote host + /// + /// Server IP or hostname + /// Server Port + /// Additional data for remote peer + /// New NetPeer if new connection, Old NetPeer if already connected, null peer if there is ConnectionRequest awaiting + /// Manager is not running. Call + public NetPeer Connect(string address, int port, NetDataWriter connectionData) + { + IPEndPoint ep; + try + { + ep = NetUtils.MakeEndPoint(address, port); + } + catch + { + CreateEvent(NetEvent.EType.Disconnect, disconnectReason: DisconnectReason.UnknownHost); + return null; + } + return Connect(ep, connectionData); + } + + /// + /// Connect to remote host + /// + /// Server end point (ip and port) + /// Connection key + /// New NetPeer if new connection, Old NetPeer if already connected, null peer if there is ConnectionRequest awaiting + /// Manager is not running. Call + public NetPeer Connect(IPEndPoint target, string key) + { + return Connect(target, NetDataWriter.FromString(key)); + } + + /// + /// Connect to remote host + /// + /// Server end point (ip and port) + /// Additional data for remote peer + /// New NetPeer if new connection, Old NetPeer if already connected, null peer if there is ConnectionRequest awaiting + /// Manager is not running. Call + public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData) + { + if (!IsRunning) + throw new InvalidOperationException("Client is not running"); + + lock(_requestsDict) + { + if (_requestsDict.ContainsKey(target)) + return null; + } + + byte connectionNumber = 0; + _peersLock.EnterUpgradeableReadLock(); + if (_peersDict.TryGetValue(target, out var peer)) + { + switch (peer.ConnectionState) + { + //just return already connected peer + case ConnectionState.Connected: + case ConnectionState.Outgoing: + _peersLock.ExitUpgradeableReadLock(); + return 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); + _peersLock.ExitUpgradeableReadLock(); + + return peer; + } + + /// + /// Force closes connection and stop all threads. + /// + public void Stop() + { + Stop(true); + } + + /// + /// Force closes connection and stop all threads. + /// + /// Send disconnect messages + public void Stop(bool sendDisconnectMessages) + { + if (!IsRunning) + return; + NetDebug.Write("[NM] Stop"); + + //Send last disconnect + for(var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + netPeer.Shutdown(null, 0, 0, !sendDisconnectMessages); + + //Stop + CloseSocket(false); + _updateTriggerEvent.Set(); + if (!_manualMode) + { + _logicThread.Join(); + _logicThread = null; + } + + //clear peers + _peersLock.EnterWriteLock(); + _headPeer = null; + _peersDict.Clear(); + _peersArray = new NetPeer[32]; + _peersLock.ExitWriteLock(); + _peerIds = new ConcurrentQueue(); + _lastPeerId = 0; +#if DEBUG + lock (_pingSimulationList) + _pingSimulationList.Clear(); +#endif + _connectedPeersCount = 0; + _netEventsProduceQueue.Clear(); + _netEventsConsumeQueue.Clear(); + } + + /// + /// Return peers count with connection state + /// + /// peer connection state (you can use as bit flags) + /// peers count + public int GetPeersCount(ConnectionState peerState) + { + int count = 0; + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if ((netPeer.ConnectionState & peerState) != 0) + count++; + } + _peersLock.ExitReadLock(); + return count; + } + + /// + /// Get copy of peers (without allocations) + /// + /// List that will contain result + /// State of peers + public void GetPeersNonAlloc(List peers, ConnectionState peerState) + { + peers.Clear(); + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if ((netPeer.ConnectionState & peerState) != 0) + peers.Add(netPeer); + } + _peersLock.ExitReadLock(); + } + + /// + /// Disconnect all peers without any additional data + /// + public void DisconnectAll() + { + DisconnectAll(null, 0, 0); + } + + /// + /// Disconnect all peers with shutdown message + /// + /// Data to send (must be less or equal MTU) + /// Data start + /// Data count + public void DisconnectAll(byte[] data, int start, int count) + { + //Send disconnect packets + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + DisconnectPeer( + netPeer, + DisconnectReason.DisconnectPeerCalled, + 0, + false, + data, + start, + count, + null); + } + _peersLock.ExitReadLock(); + } + + /// + /// Immediately disconnect peer from server without additional data + /// + /// peer to disconnect + public void DisconnectPeerForce(NetPeer peer) + { + DisconnectPeerForce(peer, DisconnectReason.DisconnectPeerCalled, 0, null); + } + + /// + /// Disconnect peer from server + /// + /// peer to disconnect + public void DisconnectPeer(NetPeer peer) + { + DisconnectPeer(peer, null, 0, 0); + } + + /// + /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8) + /// + /// peer to disconnect + /// additional data + public void DisconnectPeer(NetPeer peer, byte[] data) + { + DisconnectPeer(peer, data, 0, data.Length); + } + + /// + /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8) + /// + /// peer to disconnect + /// additional data + public void DisconnectPeer(NetPeer peer, NetDataWriter writer) + { + DisconnectPeer(peer, writer.Data, 0, writer.Length); + } + + /// + /// Disconnect peer from server and send additional data (Size must be less or equal MTU - 8) + /// + /// peer to disconnect + /// additional data + /// data start + /// data length + public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count) + { + DisconnectPeer( + peer, + DisconnectReason.DisconnectPeerCalled, + 0, + false, + data, + start, + count, + null); + } + + /// + /// Create the requests for NTP server + /// + /// NTP Server address. + public void CreateNtpRequest(IPEndPoint endPoint) + { + _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + } + + /// + /// Create the requests for NTP server + /// + /// NTP Server address. + /// port + public void CreateNtpRequest(string ntpServerAddress, int port) + { + IPEndPoint endPoint = NetUtils.MakeEndPoint(ntpServerAddress, port); + _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + } + + /// + /// Create the requests for NTP server (default port) + /// + /// NTP Server address. + public void CreateNtpRequest(string ntpServerAddress) + { + IPEndPoint endPoint = NetUtils.MakeEndPoint(ntpServerAddress, NtpRequest.DefaultPort); + _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + } + + public NetPeerEnumerator GetEnumerator() + { + return new NetPeerEnumerator(_headPeer); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new NetPeerEnumerator(_headPeer); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new NetPeerEnumerator(_headPeer); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs.meta new file mode 100644 index 0000000..673e75f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37d95580df7122c44b9333cd3ab77732 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs new file mode 100644 index 0000000..7e29fe9 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs @@ -0,0 +1,161 @@ +using System; +using System.Net; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + internal enum PacketProperty : byte + { + Unreliable, + Channeled, + Ack, + Ping, + Pong, + ConnectRequest, + ConnectAccept, + Disconnect, + UnconnectedMessage, + MtuCheck, + MtuOk, + Broadcast, + Merged, + ShutdownOk, + PeerNotFound, + InvalidProtocol, + NatMessage, + Empty + } + + internal sealed class NetPacket + { + private static readonly int PropertiesCount = Enum.GetValues(typeof(PacketProperty)).Length; + private static readonly int[] HeaderSizes; + + static NetPacket() + { + HeaderSizes = NetUtils.AllocatePinnedUninitializedArray(PropertiesCount); + for (int i = 0; i < HeaderSizes.Length; i++) + { + switch ((PacketProperty)i) + { + case PacketProperty.Channeled: + case PacketProperty.Ack: + HeaderSizes[i] = NetConstants.ChanneledHeaderSize; + break; + case PacketProperty.Ping: + HeaderSizes[i] = NetConstants.HeaderSize + 2; + break; + case PacketProperty.ConnectRequest: + HeaderSizes[i] = NetConnectRequestPacket.HeaderSize; + break; + case PacketProperty.ConnectAccept: + HeaderSizes[i] = NetConnectAcceptPacket.Size; + break; + case PacketProperty.Disconnect: + HeaderSizes[i] = NetConstants.HeaderSize + 8; + break; + case PacketProperty.Pong: + HeaderSizes[i] = NetConstants.HeaderSize + 10; + break; + default: + HeaderSizes[i] = NetConstants.HeaderSize; + break; + } + } + } + + //Header + public PacketProperty Property + { + get => (PacketProperty)(RawData[0] & 0x1F); + set => RawData[0] = (byte)((RawData[0] & 0xE0) | (byte)value); + } + + public byte ConnectionNumber + { + get => (byte)((RawData[0] & 0x60) >> 5); + set => RawData[0] = (byte) ((RawData[0] & 0x9F) | (value << 5)); + } + + public ushort Sequence + { + get => BitConverter.ToUInt16(RawData, 1); + set => FastBitConverter.GetBytes(RawData, 1, value); + } + + public bool IsFragmented => (RawData[0] & 0x80) != 0; + + public void MarkFragmented() + { + RawData[0] |= 0x80; //set first bit + } + + public byte ChannelId + { + get => RawData[3]; + set => RawData[3] = value; + } + + public ushort FragmentId + { + get => BitConverter.ToUInt16(RawData, 4); + set => FastBitConverter.GetBytes(RawData, 4, value); + } + + public ushort FragmentPart + { + get => BitConverter.ToUInt16(RawData, 6); + set => FastBitConverter.GetBytes(RawData, 6, value); + } + + public ushort FragmentsTotal + { + get => BitConverter.ToUInt16(RawData, 8); + set => FastBitConverter.GetBytes(RawData, 8, value); + } + + //Data + public byte[] RawData; + public int Size; + + //Delivery + public object UserData; + + //Pool node + public NetPacket Next; + + public NetPacket(int size) + { + RawData = new byte[size]; + Size = size; + } + + public NetPacket(PacketProperty property, int size) + { + size += GetHeaderSize(property); + RawData = new byte[size]; + Property = property; + Size = size; + } + + public static int GetHeaderSize(PacketProperty property) + { + return HeaderSizes[(int)property]; + } + + public int GetHeaderSize() + { + return HeaderSizes[RawData[0] & 0x1F]; + } + + public bool Verify() + { + byte property = (byte)(RawData[0] & 0x1F); + if (property >= PropertiesCount) + return false; + int headerSize = HeaderSizes[property]; + bool fragmented = (RawData[0] & 0x80) != 0; + return Size >= headerSize && (!fragmented || Size >= headerSize + NetConstants.FragmentHeaderSize); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs.meta new file mode 100644 index 0000000..02838af --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7ddd322169be074f870f73db1a55255 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs new file mode 100644 index 0000000..922c720 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs @@ -0,0 +1,1405 @@ +#if DEBUG +#define STATS_ENABLED +#endif +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Threading; +using LiteNetLib.Utils; + +namespace LiteNetLib +{ + /// + /// Peer connection state + /// + [Flags] + public enum ConnectionState : byte + { + Outgoing = 1 << 1, + Connected = 1 << 2, + ShutdownRequested = 1 << 3, + Disconnected = 1 << 4, + EndPointChange = 1 << 5, + Any = Outgoing | Connected | ShutdownRequested | EndPointChange + } + + internal enum ConnectRequestResult + { + None, + P2PLose, //when peer connecting + Reconnection, //when peer was connected + NewConnection //when peer was disconnected + } + + internal enum DisconnectResult + { + None, + Reject, + Disconnect + } + + internal enum ShutdownResult + { + None, + Success, + WasConnected + } + + /// + /// Network peer. Main purpose is sending messages to specific peer. + /// + public class NetPeer + { + //Ping and RTT + private int _rtt; + private int _avgRtt; + private int _rttCount; + private double _resendDelay = 27.0; + private int _pingSendTimer; + private int _rttResetTimer; + private readonly Stopwatch _pingTimer = new Stopwatch(); + private int _timeSinceLastPacket; + private long _remoteDelta; + + //Common + private readonly object _shutdownLock = new object(); + + internal volatile NetPeer NextPeer; + internal NetPeer PrevPeer; + + internal byte ConnectionNum + { + get => _connectNum; + private set + { + _connectNum = value; + _mergeData.ConnectionNumber = value; + _pingPacket.ConnectionNumber = value; + _pongPacket.ConnectionNumber = value; + } + } + + //Channels + private readonly Queue _unreliableChannel; + private readonly ConcurrentQueue _channelSendQueue; + private readonly BaseChannel[] _channels; + + //MTU + private int _mtu; + private int _mtuIdx; + private bool _finishMtu; + private int _mtuCheckTimer; + private int _mtuCheckAttempts; + private const int MtuCheckDelay = 1000; + private const int MaxMtuCheckAttempts = 4; + private readonly object _mtuMutex = new object(); + + //Fragment + private class IncomingFragments + { + public NetPacket[] Fragments; + public int ReceivedCount; + public int TotalSize; + public byte ChannelId; + } + private int _fragmentId; + private readonly Dictionary _holdedFragments; + private readonly Dictionary _deliveredFragments; + + //Merging + private readonly NetPacket _mergeData; + private int _mergePos; + private int _mergeCount; + + //Connection + private IPEndPoint _remoteEndPoint; + private int _connectAttempts; + private int _connectTimer; + private long _connectTime; + private byte _connectNum; + private ConnectionState _connectionState; + private NetPacket _shutdownPacket; + private const int ShutdownDelay = 300; + private int _shutdownTimer; + private readonly NetPacket _pingPacket; + private readonly NetPacket _pongPacket; + private readonly NetPacket _connectRequestPacket; + private readonly NetPacket _connectAcceptPacket; + + /// + /// Peer ip address and port + /// + public IPEndPoint EndPoint => _remoteEndPoint; + + /// + /// Peer parent NetManager + /// + public readonly NetManager NetManager; + + /// + /// Current connection state + /// + public ConnectionState ConnectionState => _connectionState; + + /// + /// Connection time for internal purposes + /// + internal long ConnectTime => _connectTime; + + /// + /// Peer id can be used as key in your dictionary of peers + /// + public readonly int Id; + + /// + /// Id assigned from server + /// + public int RemoteId { get; private set; } + + /// + /// Current one-way ping (RTT/2) in milliseconds + /// + public int Ping => _avgRtt/2; + + /// + /// Round trip time in milliseconds + /// + public int RoundTripTime => _avgRtt; + + /// + /// Current MTU - Maximum Transfer Unit ( maximum udp packet size without fragmentation ) + /// + public int Mtu => _mtu; + + /// + /// Delta with remote time in ticks (not accurate) + /// positive - remote time > our time + /// + public long RemoteTimeDelta => _remoteDelta; + + /// + /// Remote UTC time (not accurate) + /// + public DateTime RemoteUtcTime => new DateTime(DateTime.UtcNow.Ticks + _remoteDelta); + + /// + /// Time since last packet received (including internal library packets) + /// + public int TimeSinceLastPacket => _timeSinceLastPacket; + + internal double ResendDelay => _resendDelay; + + /// + /// Application defined object containing data about the connection + /// + public object Tag; + + /// + /// Statistics of peer connection + /// + public readonly NetStatistics Statistics; + + //incoming connection constructor + internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) + { + Id = id; + Statistics = new NetStatistics(); + NetManager = netManager; + ResetMtu(); + _remoteEndPoint = remoteEndPoint; + _connectionState = ConnectionState.Connected; + _mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize); + _pongPacket = new NetPacket(PacketProperty.Pong, 0); + _pingPacket = new NetPacket(PacketProperty.Ping, 0) {Sequence = 1}; + + _unreliableChannel = new Queue(); + _holdedFragments = new Dictionary(); + _deliveredFragments = new Dictionary(); + + _channels = new BaseChannel[netManager.ChannelsCount * NetConstants.ChannelTypeCount]; + _channelSendQueue = new ConcurrentQueue(); + } + + internal void InitiateEndPointChange() + { + ResetMtu(); + _connectionState = ConnectionState.EndPointChange; + } + + internal void FinishEndPointChange(IPEndPoint newEndPoint) + { + if (_connectionState != ConnectionState.EndPointChange) + return; + _connectionState = ConnectionState.Connected; + _remoteEndPoint = newEndPoint; + } + + internal void ResetMtu() + { + _finishMtu = false; + if (NetManager.MtuOverride > 0) + OverrideMtu(NetManager.MtuOverride); + else if (NetManager.UseSafeMtu) + SetMtu(0); + else + SetMtu(1); + } + + private void SetMtu(int mtuIdx) + { + _mtuIdx = mtuIdx; + _mtu = NetConstants.PossibleMtu[mtuIdx] - NetManager.ExtraPacketSizeForLayer; + } + + private void OverrideMtu(int mtuValue) + { + _mtu = mtuValue; + _finishMtu = true; + } + + /// + /// Returns packets count in queue for reliable channel + /// + /// number of channel 0-63 + /// type of channel ReliableOrdered or ReliableUnordered + /// packets count in channel queue + public int GetPacketsCountInReliableQueue(byte channelNumber, bool ordered) + { + int idx = channelNumber * NetConstants.ChannelTypeCount + + (byte) (ordered ? DeliveryMethod.ReliableOrdered : DeliveryMethod.ReliableUnordered); + var channel = _channels[idx]; + return channel != null ? ((ReliableChannel)channel).PacketsInQueue : 0; + } + + /// + /// Create temporary packet (maximum size MTU - headerSize) to send later without additional copies + /// + /// Delivery method (reliable, unreliable, etc.) + /// Number of channel (from 0 to channelsCount - 1) + /// PooledPacket that you can use to write data starting from UserDataOffset + public PooledPacket CreatePacketFromPool(DeliveryMethod deliveryMethod, byte channelNumber) + { + //multithreaded variable + int mtu = _mtu; + var packet = NetManager.PoolGetPacket(mtu); + if (deliveryMethod == DeliveryMethod.Unreliable) + { + packet.Property = PacketProperty.Unreliable; + return new PooledPacket(packet, mtu, 0); + } + else + { + packet.Property = PacketProperty.Channeled; + return new PooledPacket(packet, mtu, (byte)(channelNumber * NetConstants.ChannelTypeCount + (byte)deliveryMethod)); + } + } + + /// + /// Sends pooled packet without data copy + /// + /// packet to send + /// size of user data you want to send + public void SendPooledPacket(PooledPacket packet, int userDataSize) + { + if (_connectionState != ConnectionState.Connected) + return; + packet._packet.Size = packet.UserDataOffset + userDataSize; + if (packet._packet.Property == PacketProperty.Channeled) + { + CreateChannel(packet._channelNumber).AddToQueue(packet._packet); + } + else + { + lock(_unreliableChannel) + _unreliableChannel.Enqueue(packet._packet); + } + } + + private BaseChannel CreateChannel(byte idx) + { + BaseChannel newChannel = _channels[idx]; + if (newChannel != null) + return newChannel; + switch ((DeliveryMethod)(idx % NetConstants.ChannelTypeCount)) + { + case DeliveryMethod.ReliableUnordered: + newChannel = new ReliableChannel(this, false, idx); + break; + case DeliveryMethod.Sequenced: + newChannel = new SequencedChannel(this, false, idx); + break; + case DeliveryMethod.ReliableOrdered: + newChannel = new ReliableChannel(this, true, idx); + break; + case DeliveryMethod.ReliableSequenced: + newChannel = new SequencedChannel(this, true, idx); + break; + } + BaseChannel prevChannel = Interlocked.CompareExchange(ref _channels[idx], newChannel, null); + if (prevChannel != null) + return prevChannel; + + return newChannel; + } + + //"Connect to" constructor + internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id, byte connectNum, NetDataWriter connectData) + : this(netManager, remoteEndPoint, id) + { + _connectTime = DateTime.UtcNow.Ticks; + _connectionState = ConnectionState.Outgoing; + ConnectionNum = connectNum; + + //Make initial packet + _connectRequestPacket = NetConnectRequestPacket.Make(connectData, remoteEndPoint.Serialize(), _connectTime, id); + _connectRequestPacket.ConnectionNumber = connectNum; + + //Send request + NetManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + + NetDebug.Write(NetLogLevel.Trace, $"[CC] ConnectId: {_connectTime}, ConnectNum: {connectNum}"); + } + + //"Accept" incoming constructor + internal NetPeer(NetManager netManager, ConnectionRequest request, int id) + : this(netManager, request.RemoteEndPoint, id) + { + _connectTime = request.InternalPacket.ConnectionTime; + ConnectionNum = request.InternalPacket.ConnectionNumber; + RemoteId = request.InternalPacket.PeerId; + + //Make initial packet + _connectAcceptPacket = NetConnectAcceptPacket.Make(_connectTime, ConnectionNum, id); + + //Make Connected + _connectionState = ConnectionState.Connected; + + //Send + NetManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + + NetDebug.Write(NetLogLevel.Trace, $"[CC] ConnectId: {_connectTime}"); + } + + //Reject + internal void Reject(NetConnectRequestPacket requestData, byte[] data, int start, int length) + { + _connectTime = requestData.ConnectionTime; + _connectNum = requestData.ConnectionNumber; + Shutdown(data, start, length, false); + } + + internal bool ProcessConnectAccept(NetConnectAcceptPacket packet) + { + if (_connectionState != ConnectionState.Outgoing) + return false; + + //check connection id + if (packet.ConnectionTime != _connectTime) + { + NetDebug.Write(NetLogLevel.Trace, $"[NC] Invalid connectId: {packet.ConnectionTime} != our({_connectTime})"); + return false; + } + //check connect num + ConnectionNum = packet.ConnectionNumber; + RemoteId = packet.PeerId; + + NetDebug.Write(NetLogLevel.Trace, "[NC] Received connection accept"); + Interlocked.Exchange(ref _timeSinceLastPacket, 0); + _connectionState = ConnectionState.Connected; + return true; + } + + /// + /// Gets maximum size of packet that will be not fragmented. + /// + /// Type of packet that you want send + /// size in bytes + public int GetMaxSinglePacketSize(DeliveryMethod options) + { + return _mtu - NetPacket.GetHeaderSize(options == DeliveryMethod.Unreliable ? PacketProperty.Unreliable : PacketProperty.Channeled); + } + + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Start of data + /// Length of data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(data, start, length, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(byte[] data, DeliveryMethod deliveryMethod) + { + SendInternal(data, 0, data.Length, 0, deliveryMethod, null); + } + + /// + /// Send data to peer (channel - 0) + /// + /// DataWriter with data + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod) + { + SendInternal(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod, null); + } + + /// + /// Send data to peer (channel - 0) + /// + /// Data + /// Start of data + /// Length of data + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(byte[] data, int start, int length, DeliveryMethod options) + { + SendInternal(data, start, length, 0, options, null); + } + + /// + /// Send data to peer + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod) + { + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, null); + } + + /// + /// Send data to peer + /// + /// DataWriter with data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod) + { + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, null); + } + + /// + /// Send data to peer + /// + /// Data + /// Start of data + /// Length of data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod) + { + SendInternal(data, start, length, channelNumber, deliveryMethod, null); + } + + private void SendInternal( + byte[] data, + int start, + int length, + byte channelNumber, + DeliveryMethod deliveryMethod, + object userData) + { + if (_connectionState != ConnectionState.Connected || channelNumber >= _channels.Length) + return; + + //Select channel + PacketProperty property; + BaseChannel channel = null; + + if (deliveryMethod == DeliveryMethod.Unreliable) + { + property = PacketProperty.Unreliable; + } + else + { + property = PacketProperty.Channeled; + channel = CreateChannel((byte)(channelNumber * NetConstants.ChannelTypeCount + (byte)deliveryMethod)); + } + + //Prepare + NetDebug.Write("[RS]Packet: " + property); + + //Check fragmentation + int headerSize = NetPacket.GetHeaderSize(property); + //Save mtu for multithread + int mtu = _mtu; + if (length + headerSize > mtu) + { + //if cannot be fragmented + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new TooBigPacketException("Unreliable or ReliableSequenced packet size exceeded maximum of " + (mtu - headerSize) + " bytes, Check allowed size by GetMaxSinglePacketSize()"); + + int packetFullSize = mtu - headerSize; + 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); + + if (totalPackets > ushort.MaxValue) + throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); + + ushort currentFragmentId = (ushort)Interlocked.Increment(ref _fragmentId); + + for(ushort partIdx = 0; partIdx < totalPackets; partIdx++) + { + int sendLength = length > packetDataSize ? packetDataSize : length; + + NetPacket p = NetManager.PoolGetPacket(headerSize + sendLength + NetConstants.FragmentHeaderSize); + p.Property = property; + p.UserData = userData; + p.FragmentId = currentFragmentId; + p.FragmentPart = partIdx; + p.FragmentsTotal = (ushort)totalPackets; + p.MarkFragmented(); + + Buffer.BlockCopy(data, start + partIdx * packetDataSize, p.RawData, NetConstants.FragmentedHeaderTotalSize, sendLength); + channel.AddToQueue(p); + + length -= sendLength; + } + return; + } + + //Else just send + NetPacket packet = NetManager.PoolGetPacket(headerSize + length); + packet.Property = property; + Buffer.BlockCopy(data, start, packet.RawData, headerSize, length); + packet.UserData = userData; + + if (channel == null) //unreliable + { + lock(_unreliableChannel) + _unreliableChannel.Enqueue(packet); + } + else + { + channel.AddToQueue(packet); + } + } + +#if LITENETLIB_SPANS || NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0 || NETSTANDARD2_1 + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(ReadOnlySpan data, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(data, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(ReadOnlySpan data, DeliveryMethod deliveryMethod) + { + SendInternal(data, 0, deliveryMethod, null); + } + + /// + /// Send data to peer + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// + /// If size exceeds maximum limit: + /// MTU - headerSize bytes for Unreliable + /// Fragment count exceeded ushort.MaxValue + /// + public void Send(ReadOnlySpan data, byte channelNumber, DeliveryMethod deliveryMethod) + { + SendInternal(data, channelNumber, deliveryMethod, null); + } + + private void SendInternal( + ReadOnlySpan data, + byte channelNumber, + DeliveryMethod deliveryMethod, + object userData) + { + if (_connectionState != ConnectionState.Connected || channelNumber >= _channels.Length) + return; + + //Select channel + PacketProperty property; + BaseChannel channel = null; + + if (deliveryMethod == DeliveryMethod.Unreliable) + { + property = PacketProperty.Unreliable; + } + else + { + property = PacketProperty.Channeled; + channel = CreateChannel((byte)(channelNumber * NetConstants.ChannelTypeCount + (byte)deliveryMethod)); + } + + //Prepare + NetDebug.Write("[RS]Packet: " + property); + + //Check fragmentation + int headerSize = NetPacket.GetHeaderSize(property); + //Save mtu for multithread + int mtu = _mtu; + int length = data.Length; + if (length + headerSize > mtu) + { + //if cannot be fragmented + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new TooBigPacketException("Unreliable or ReliableSequenced packet size exceeded maximum of " + (mtu - headerSize) + " bytes, Check allowed size by GetMaxSinglePacketSize()"); + + int packetFullSize = mtu - headerSize; + int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize; + int totalPackets = length / packetDataSize + (length % packetDataSize == 0 ? 0 : 1); + + if (totalPackets > ushort.MaxValue) + throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); + + ushort currentFragmentId = (ushort)Interlocked.Increment(ref _fragmentId); + + for (ushort partIdx = 0; partIdx < totalPackets; partIdx++) + { + int sendLength = length > packetDataSize ? packetDataSize : length; + + NetPacket p = NetManager.PoolGetPacket(headerSize + sendLength + NetConstants.FragmentHeaderSize); + p.Property = property; + p.UserData = userData; + p.FragmentId = currentFragmentId; + p.FragmentPart = partIdx; + p.FragmentsTotal = (ushort)totalPackets; + p.MarkFragmented(); + + data.Slice(partIdx * packetDataSize, sendLength).CopyTo(new Span(p.RawData, NetConstants.FragmentedHeaderTotalSize, sendLength)); + channel.AddToQueue(p); + + length -= sendLength; + } + return; + } + + //Else just send + NetPacket packet = NetManager.PoolGetPacket(headerSize + length); + packet.Property = property; + data.CopyTo(new Span(packet.RawData, headerSize, length)); + packet.UserData = userData; + + if (channel == null) //unreliable + { + lock(_unreliableChannel) + _unreliableChannel.Enqueue(packet); + } + else + { + channel.AddToQueue(packet); + } + } +#endif + + public void Disconnect(byte[] data) + { + NetManager.DisconnectPeer(this, data); + } + + public void Disconnect(NetDataWriter writer) + { + NetManager.DisconnectPeer(this, writer); + } + + public void Disconnect(byte[] data, int start, int count) + { + NetManager.DisconnectPeer(this, data, start, count); + } + + public void Disconnect() + { + NetManager.DisconnectPeer(this); + } + + internal DisconnectResult ProcessDisconnect(NetPacket packet) + { + if ((_connectionState == ConnectionState.Connected || _connectionState == ConnectionState.Outgoing) && + packet.Size >= 9 && + BitConverter.ToInt64(packet.RawData, 1) == _connectTime && + packet.ConnectionNumber == _connectNum) + { + return _connectionState == ConnectionState.Connected + ? DisconnectResult.Disconnect + : DisconnectResult.Reject; + } + return DisconnectResult.None; + } + + internal void AddToReliableChannelSendQueue(BaseChannel channel) + { + _channelSendQueue.Enqueue(channel); + } + + internal ShutdownResult Shutdown(byte[] data, int start, int length, bool force) + { + lock (_shutdownLock) + { + //trying to shutdown already disconnected + if (_connectionState == ConnectionState.Disconnected || + _connectionState == ConnectionState.ShutdownRequested) + { + return ShutdownResult.None; + } + + var result = _connectionState == ConnectionState.Connected + ? ShutdownResult.WasConnected + : ShutdownResult.Success; + + //don't send anything + if (force) + { + _connectionState = ConnectionState.Disconnected; + return result; + } + + //reset time for reconnect protection + Interlocked.Exchange(ref _timeSinceLastPacket, 0); + + //send shutdown packet + _shutdownPacket = new NetPacket(PacketProperty.Disconnect, length) {ConnectionNumber = _connectNum}; + FastBitConverter.GetBytes(_shutdownPacket.RawData, 1, _connectTime); + if (_shutdownPacket.Size >= _mtu) + { + //Drop additional data + NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU - 8!"); + } + else if (data != null && length > 0) + { + Buffer.BlockCopy(data, start, _shutdownPacket.RawData, 9, length); + } + _connectionState = ConnectionState.ShutdownRequested; + NetDebug.Write("[Peer] Send disconnect"); + NetManager.SendRaw(_shutdownPacket, _remoteEndPoint); + return result; + } + } + + private void UpdateRoundTripTime(int roundTripTime) + { + _rtt += roundTripTime; + _rttCount++; + _avgRtt = _rtt/_rttCount; + _resendDelay = 25.0 + _avgRtt * 2.1; // 25 ms + double rtt + } + + internal void AddReliablePacket(DeliveryMethod method, NetPacket p) + { + if (p.IsFragmented) + { + NetDebug.Write("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal); + //Get needed array from dictionary + ushort packetFragId = p.FragmentId; + byte packetChannelId = p.ChannelId; + if (!_holdedFragments.TryGetValue(packetFragId, out var incomingFragments)) + { + incomingFragments = new IncomingFragments + { + Fragments = new NetPacket[p.FragmentsTotal], + ChannelId = p.ChannelId + }; + _holdedFragments.Add(packetFragId, incomingFragments); + } + + //Cache + var fragments = incomingFragments.Fragments; + + //Error check + if (p.FragmentPart >= fragments.Length || + fragments[p.FragmentPart] != null || + p.ChannelId != incomingFragments.ChannelId) + { + NetManager.PoolRecycle(p); + NetDebug.WriteError("Invalid fragment packet"); + return; + } + //Fill array + fragments[p.FragmentPart] = p; + + //Increase received fragments count + incomingFragments.ReceivedCount++; + + //Increase total size + incomingFragments.TotalSize += p.Size - NetConstants.FragmentedHeaderTotalSize; + + //Check for finish + if (incomingFragments.ReceivedCount != fragments.Length) + return; + + //just simple packet + NetPacket resultingPacket = NetManager.PoolGetPacket(incomingFragments.TotalSize); + + int pos = 0; + for (int i = 0; i < incomingFragments.ReceivedCount; i++) + { + var fragment = fragments[i]; + int writtenSize = fragment.Size - NetConstants.FragmentedHeaderTotalSize; + + 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); + 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); + return; + } + + //Create resulting big packet + Buffer.BlockCopy( + fragment.RawData, + NetConstants.FragmentedHeaderTotalSize, + resultingPacket.RawData, + pos, + writtenSize); + pos += writtenSize; + + //Free memory + NetManager.PoolRecycle(fragment); + fragments[i] = null; + } + + //Clear memory + _holdedFragments.Remove(packetFragId); + + //Send to process + NetManager.CreateReceiveEvent(resultingPacket, method, (byte)(packetChannelId / NetConstants.ChannelTypeCount), 0, this); + } + else //Just simple packet + { + NetManager.CreateReceiveEvent(p, method, (byte)(p.ChannelId / NetConstants.ChannelTypeCount), NetConstants.ChanneledHeaderSize, this); + } + } + + private void ProcessMtuPacket(NetPacket packet) + { + //header + int + if (packet.Size < NetConstants.PossibleMtu[0]) + return; + + //first stage check (mtu check and mtu ok) + int receivedMtu = BitConverter.ToInt32(packet.RawData, 1); + 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); + return; + } + + if (packet.Property == PacketProperty.MtuCheck) + { + _mtuCheckAttempts = 0; + NetDebug.Write("[MTU] check. send back: " + receivedMtu); + packet.Property = PacketProperty.MtuOk; + NetManager.SendRawAndRecycle(packet, _remoteEndPoint); + } + else if(receivedMtu > _mtu && !_finishMtu) //MtuOk + { + //invalid packet + if (receivedMtu != NetConstants.PossibleMtu[_mtuIdx + 1] - NetManager.ExtraPacketSizeForLayer) + return; + + lock (_mtuMutex) + { + SetMtu(_mtuIdx+1); + } + //if maxed - finish. + if (_mtuIdx == NetConstants.PossibleMtu.Length - 1) + _finishMtu = true; + NetManager.PoolRecycle(packet); + NetDebug.Write("[MTU] ok. Increase to: " + _mtu); + } + } + + private void UpdateMtuLogic(int deltaTime) + { + if (_finishMtu) + return; + + _mtuCheckTimer += deltaTime; + if (_mtuCheckTimer < MtuCheckDelay) + return; + + _mtuCheckTimer = 0; + _mtuCheckAttempts++; + if (_mtuCheckAttempts >= MaxMtuCheckAttempts) + { + _finishMtu = true; + return; + } + + lock (_mtuMutex) + { + if (_mtuIdx >= NetConstants.PossibleMtu.Length - 1) + return; + + //Send increased packet + int newMtu = NetConstants.PossibleMtu[_mtuIdx + 1] - NetManager.ExtraPacketSizeForLayer; + var p = NetManager.PoolGetPacket(newMtu); + p.Property = PacketProperty.MtuCheck; + FastBitConverter.GetBytes(p.RawData, 1, newMtu); //place into start + FastBitConverter.GetBytes(p.RawData, p.Size - 4, newMtu);//and end of packet + + //Must check result for MTU fix + if (NetManager.SendRawAndRecycle(p, _remoteEndPoint) <= 0) + _finishMtu = true; + } + } + + internal ConnectRequestResult ProcessConnectRequest(NetConnectRequestPacket connRequest) + { + //current or new request + switch (_connectionState) + { + //P2P case + case ConnectionState.Outgoing: + //fast check + if (connRequest.ConnectionTime < _connectTime) + { + return ConnectRequestResult.P2PLose; + } + //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--) + { + byte rb = remoteBytes[i]; + if (rb == localBytes[i]) + continue; + if (rb < localBytes[i]) + return ConnectRequestResult.P2PLose; + } + } + break; + + case ConnectionState.Connected: + //Old connect request + if (connRequest.ConnectionTime == _connectTime) + { + //just reply accept + NetManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + } + //New connect request + else if (connRequest.ConnectionTime > _connectTime) + { + return ConnectRequestResult.Reconnection; + } + break; + + case ConnectionState.Disconnected: + case ConnectionState.ShutdownRequested: + if (connRequest.ConnectionTime >= _connectTime) + return ConnectRequestResult.NewConnection; + break; + } + return ConnectRequestResult.None; + } + + //Process incoming packet + internal void ProcessPacket(NetPacket packet) + { + //not initialized + if (_connectionState == ConnectionState.Outgoing || _connectionState == ConnectionState.Disconnected) + { + NetManager.PoolRecycle(packet); + return; + } + if (packet.Property == PacketProperty.ShutdownOk) + { + if (_connectionState == ConnectionState.ShutdownRequested) + _connectionState = ConnectionState.Disconnected; + NetManager.PoolRecycle(packet); + return; + } + if (packet.ConnectionNumber != _connectNum) + { + NetDebug.Write(NetLogLevel.Trace, "[RR]Old packet"); + NetManager.PoolRecycle(packet); + return; + } + Interlocked.Exchange(ref _timeSinceLastPacket, 0); + + NetDebug.Write("[RR]PacketProperty: {0}", packet.Property); + switch (packet.Property) + { + case PacketProperty.Merged: + int pos = NetConstants.HeaderSize; + while (pos < packet.Size) + { + ushort size = BitConverter.ToUInt16(packet.RawData, pos); + pos += 2; + if (packet.RawData.Length - pos < size) + break; + + NetPacket mergedPacket = NetManager.PoolGetPacket(size); + Buffer.BlockCopy(packet.RawData, pos, mergedPacket.RawData, 0, size); + mergedPacket.Size = size; + + if (!mergedPacket.Verify()) + break; + + pos += size; + ProcessPacket(mergedPacket); + } + NetManager.PoolRecycle(packet); + break; + //If we get ping, send pong + case PacketProperty.Ping: + if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pongPacket.Sequence) > 0) + { + NetDebug.Write("[PP]Ping receive, send pong"); + FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks); + _pongPacket.Sequence = packet.Sequence; + NetManager.SendRaw(_pongPacket, _remoteEndPoint); + } + NetManager.PoolRecycle(packet); + break; + + //If we get pong, calculate ping time and rtt + case PacketProperty.Pong: + if (packet.Sequence == _pingPacket.Sequence) + { + _pingTimer.Stop(); + int elapsedMs = (int)_pingTimer.ElapsedMilliseconds; + _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); + } + NetManager.PoolRecycle(packet); + break; + + case PacketProperty.Ack: + case PacketProperty.Channeled: + if (packet.ChannelId > _channels.Length) + { + NetManager.PoolRecycle(packet); + break; + } + var channel = _channels[packet.ChannelId] ?? (packet.Property == PacketProperty.Ack ? null : CreateChannel(packet.ChannelId)); + if (channel != null) + { + if (!channel.ProcessPacket(packet)) + NetManager.PoolRecycle(packet); + } + break; + + //Simple packet without acks + case PacketProperty.Unreliable: + NetManager.CreateReceiveEvent(packet, DeliveryMethod.Unreliable, 0, NetConstants.HeaderSize, this); + return; + + case PacketProperty.MtuCheck: + case PacketProperty.MtuOk: + ProcessMtuPacket(packet); + break; + + default: + NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property); + break; + } + } + + private void SendMerged() + { + if (_mergeCount == 0) + return; + int bytesSent; + if (_mergeCount > 1) + { + NetDebug.Write("[P]Send merged: " + _mergePos + ", count: " + _mergeCount); + bytesSent = NetManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, _remoteEndPoint); + } + else + { + //Send without length information and merging + bytesSent = NetManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, _remoteEndPoint); + } + + if (NetManager.EnableStatistics) + { + Statistics.IncrementPacketsSent(); + Statistics.AddBytesSent(bytesSent); + } + + _mergePos = 0; + _mergeCount = 0; + } + + internal void SendUserData(NetPacket packet) + { + packet.ConnectionNumber = _connectNum; + int mergedPacketSize = NetConstants.HeaderSize + packet.Size + 2; + const int sizeTreshold = 20; + if (mergedPacketSize + sizeTreshold >= _mtu) + { + NetDebug.Write(NetLogLevel.Trace, "[P]SendingPacket: " + packet.Property); + int bytesSent = NetManager.SendRaw(packet, _remoteEndPoint); + + if (NetManager.EnableStatistics) + { + Statistics.IncrementPacketsSent(); + Statistics.AddBytesSent(bytesSent); + } + + return; + } + if (_mergePos + mergedPacketSize > _mtu) + SendMerged(); + + FastBitConverter.GetBytes(_mergeData.RawData, _mergePos + NetConstants.HeaderSize, (ushort)packet.Size); + Buffer.BlockCopy(packet.RawData, 0, _mergeData.RawData, _mergePos + NetConstants.HeaderSize + 2, packet.Size); + _mergePos += packet.Size + 2; + _mergeCount++; + //DebugWriteForce("Merged: " + _mergePos + "/" + (_mtu - 2) + ", count: " + _mergeCount); + } + + internal void Update(int deltaTime) + { + Interlocked.Add(ref _timeSinceLastPacket, deltaTime); + switch (_connectionState) + { + case ConnectionState.Connected: + if (_timeSinceLastPacket > NetManager.DisconnectTimeout) + { + NetDebug.Write( + "[UPDATE] Disconnect by timeout: {0} > {1}", + _timeSinceLastPacket, + NetManager.DisconnectTimeout); + NetManager.DisconnectPeerForce(this, DisconnectReason.Timeout, 0, null); + return; + } + break; + + case ConnectionState.ShutdownRequested: + if (_timeSinceLastPacket > NetManager.DisconnectTimeout) + { + _connectionState = ConnectionState.Disconnected; + } + else + { + _shutdownTimer += deltaTime; + if (_shutdownTimer >= ShutdownDelay) + { + _shutdownTimer = 0; + NetManager.SendRaw(_shutdownPacket, _remoteEndPoint); + } + } + return; + + case ConnectionState.Outgoing: + _connectTimer += deltaTime; + if (_connectTimer > NetManager.ReconnectDelay) + { + _connectTimer = 0; + _connectAttempts++; + if (_connectAttempts > NetManager.MaxConnectAttempts) + { + NetManager.DisconnectPeerForce(this, DisconnectReason.ConnectionFailed, 0, null); + return; + } + + //else send connect again + NetManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + } + return; + + case ConnectionState.Disconnected: + return; + } + + //Send ping + _pingSendTimer += deltaTime; + if (_pingSendTimer >= NetManager.PingInterval) + { + NetDebug.Write("[PP] Send ping..."); + //reset timer + _pingSendTimer = 0; + //send ping + _pingPacket.Sequence++; + //ping timeout + if (_pingTimer.IsRunning) + UpdateRoundTripTime((int)_pingTimer.ElapsedMilliseconds); + _pingTimer.Restart(); + NetManager.SendRaw(_pingPacket, _remoteEndPoint); + } + + //RTT - round trip time + _rttResetTimer += deltaTime; + if (_rttResetTimer >= NetManager.PingInterval * 3) + { + _rttResetTimer = 0; + _rtt = _avgRtt; + _rttCount = 1; + } + + UpdateMtuLogic(deltaTime); + + //Pending send + int count = _channelSendQueue.Count; + while (count-- > 0) + { + if (!_channelSendQueue.TryDequeue(out var channel)) + break; + if (channel.SendAndCheckQueue()) + { + // still has something to send, re-add it to the send queue + _channelSendQueue.Enqueue(channel); + } + } + + lock (_unreliableChannel) + { + int unreliableCount = _unreliableChannel.Count; + for (int i = 0; i < unreliableCount; i++) + { + var packet = _unreliableChannel.Dequeue(); + SendUserData(packet); + NetManager.PoolRecycle(packet); + } + } + + SendMerged(); + } + + //For reliable channel + internal void RecycleAndDeliver(NetPacket packet) + { + if (packet.UserData != null) + { + if (packet.IsFragmented) + { + _deliveredFragments.TryGetValue(packet.FragmentId, out ushort fragCount); + fragCount++; + if (fragCount == packet.FragmentsTotal) + { + NetManager.MessageDelivered(this, packet.UserData); + _deliveredFragments.Remove(packet.FragmentId); + } + else + { + _deliveredFragments[packet.FragmentId] = fragCount; + } + } + else + { + NetManager.MessageDelivered(this, packet.UserData); + } + packet.UserData = null; + } + NetManager.PoolRecycle(packet); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs.meta new file mode 100644 index 0000000..7d06b87 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e1a9277334c51545b92369c8e4c6d74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs new file mode 100644 index 0000000..032e275 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs @@ -0,0 +1,81 @@ +using System.Threading; + +namespace LiteNetLib +{ + public sealed class NetStatistics + { + private long _packetsSent; + private long _packetsReceived; + private long _bytesSent; + private long _bytesReceived; + private long _packetLoss; + + public long PacketsSent => Interlocked.Read(ref _packetsSent); + public long PacketsReceived => Interlocked.Read(ref _packetsReceived); + public long BytesSent => Interlocked.Read(ref _bytesSent); + public long BytesReceived => Interlocked.Read(ref _bytesReceived); + public long PacketLoss => Interlocked.Read(ref _packetLoss); + + public long PacketLossPercent + { + get + { + long sent = PacketsSent, loss = PacketLoss; + + return sent == 0 ? 0 : loss * 100 / sent; + } + } + + public void Reset() + { + Interlocked.Exchange(ref _packetsSent, 0); + Interlocked.Exchange(ref _packetsReceived, 0); + Interlocked.Exchange(ref _bytesSent, 0); + Interlocked.Exchange(ref _bytesReceived, 0); + Interlocked.Exchange(ref _packetLoss, 0); + } + + public void IncrementPacketsSent() + { + Interlocked.Increment(ref _packetsSent); + } + + public void IncrementPacketsReceived() + { + Interlocked.Increment(ref _packetsReceived); + } + + public void AddBytesSent(long bytesSent) + { + Interlocked.Add(ref _bytesSent, bytesSent); + } + + public void AddBytesReceived(long bytesReceived) + { + Interlocked.Add(ref _bytesReceived, bytesReceived); + } + + public void IncrementPacketLoss() + { + Interlocked.Increment(ref _packetLoss); + } + + public void AddPacketLoss(long packetLoss) + { + Interlocked.Add(ref _packetLoss, packetLoss); + } + + public override string ToString() + { + return + string.Format( + "BytesReceived: {0}\nPacketsReceived: {1}\nBytesSent: {2}\nPacketsSent: {3}\nPacketLoss: {4}\nPacketLossPercent: {5}\n", + BytesReceived, + PacketsReceived, + BytesSent, + PacketsSent, + PacketLoss, + PacketLossPercent); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs.meta new file mode 100644 index 0000000..8d54a07 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetStatistics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15d4b62077bda58428b77d57fa4a9288 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs new file mode 100644 index 0000000..d162b2d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Net.NetworkInformation; + +namespace LiteNetLib +{ + /// + /// Address type that you want to receive from NetUtils.GetLocalIp method + /// + [Flags] + public enum LocalAddrType + { + IPv4 = 1, + IPv6 = 2, + All = IPv4 | IPv6 + } + + /// + /// Some specific network utilities + /// + public static class NetUtils + { + public static IPEndPoint MakeEndPoint(string hostStr, int port) + { + return new IPEndPoint(ResolveAddress(hostStr), port); + } + + public static IPAddress ResolveAddress(string hostStr) + { + if(hostStr == "localhost") + return IPAddress.Loopback; + + if (!IPAddress.TryParse(hostStr, out var ipAddress)) + { + if (NetManager.IPv6Support) + ipAddress = ResolveAddress(hostStr, AddressFamily.InterNetworkV6); + if (ipAddress == null) + ipAddress = ResolveAddress(hostStr, AddressFamily.InterNetwork); + } + if (ipAddress == null) + throw new ArgumentException("Invalid address: " + hostStr); + + return ipAddress; + } + + public static IPAddress ResolveAddress(string hostStr, AddressFamily addressFamily) + { + IPAddress[] addresses = Dns.GetHostEntry(hostStr).AddressList; + foreach (IPAddress ip in addresses) + { + if (ip.AddressFamily == addressFamily) + { + return ip; + } + } + return null; + } + + /// + /// Get all local ip addresses + /// + /// type of address (IPv4, IPv6 or both) + /// List with all local ip addresses + public static List GetLocalIpList(LocalAddrType addrType) + { + List targetList = new List(); + GetLocalIpList(targetList, addrType); + return targetList; + } + + /// + /// Get all local ip addresses (non alloc version) + /// + /// result list + /// type of address (IPv4, IPv6 or both) + public static void GetLocalIpList(IList targetList, LocalAddrType addrType) + { + bool ipv4 = (addrType & LocalAddrType.IPv4) == LocalAddrType.IPv4; + bool ipv6 = (addrType & LocalAddrType.IPv6) == LocalAddrType.IPv6; + try + { + foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) + { + //Skip loopback and disabled network interfaces + if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback || + ni.OperationalStatus != OperationalStatus.Up) + continue; + + var ipProps = ni.GetIPProperties(); + + //Skip address without gateway + if (ipProps.GatewayAddresses.Count == 0) + continue; + + foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses) + { + var address = ip.Address; + if ((ipv4 && address.AddressFamily == AddressFamily.InterNetwork) || + (ipv6 && address.AddressFamily == AddressFamily.InterNetworkV6)) + targetList.Add(address.ToString()); + } + } + + //Fallback mode (unity android) + if (targetList.Count == 0) + { + IPAddress[] addresses = Dns.GetHostEntry(Dns.GetHostName()).AddressList; + foreach (IPAddress ip in addresses) + { + if((ipv4 && ip.AddressFamily == AddressFamily.InterNetwork) || + (ipv6 && ip.AddressFamily == AddressFamily.InterNetworkV6)) + targetList.Add(ip.ToString()); + } + } + } + catch + { + //ignored + } + + if (targetList.Count == 0) + { + if(ipv4) + targetList.Add("127.0.0.1"); + if(ipv6) + targetList.Add("::1"); + } + } + + private static readonly List IpList = new List(); + /// + /// Get first detected local ip address + /// + /// type of address (IPv4, IPv6 or both) + /// IP address if available. Else - string.Empty + public static string GetLocalIp(LocalAddrType addrType) + { + lock (IpList) + { + IpList.Clear(); + GetLocalIpList(IpList, addrType); + return IpList.Count == 0 ? string.Empty : IpList[0]; + } + } + + // =========================================== + // Internal and debug log related stuff + // =========================================== + internal static void PrintInterfaceInfos() + { + NetDebug.WriteForce(NetLogLevel.Info, "IPv6Support: {0}", NetManager.IPv6Support); + try + { + foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) + { + foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) + { + if (ip.Address.AddressFamily == AddressFamily.InterNetwork || + ip.Address.AddressFamily == AddressFamily.InterNetworkV6) + { + NetDebug.WriteForce( + NetLogLevel.Info, + "Interface: {0}, Type: {1}, Ip: {2}, OpStatus: {3}", + ni.Name, + ni.NetworkInterfaceType.ToString(), + ip.Address.ToString(), + ni.OperationalStatus.ToString()); + } + } + } + } + catch (Exception e) + { + NetDebug.WriteForce(NetLogLevel.Info, "Error while getting interface infos: {0}", e.ToString()); + } + } + + internal static int RelativeSequenceNumber(int number, int expected) + { + return (number - expected + NetConstants.MaxSequence + NetConstants.HalfMaxSequence) % NetConstants.MaxSequence - NetConstants.HalfMaxSequence; + } + + internal static T[] AllocatePinnedUninitializedArray(int count) where T : unmanaged + { +#if NET5_0_OR_GREATER || NET5_0 + return GC.AllocateUninitializedArray(count, true); +#else + return new T[count]; +#endif + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs.meta new file mode 100644 index 0000000..0d039e7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab6438405a73f8c46ac22cd2f259a0e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs new file mode 100644 index 0000000..26ef7bd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs @@ -0,0 +1,32 @@ +namespace LiteNetLib +{ + public readonly ref struct PooledPacket + { + internal readonly NetPacket _packet; + internal readonly byte _channelNumber; + + /// + /// Maximum data size that you can put into such packet + /// + public readonly int MaxUserDataSize; + + /// + /// Offset for user data when writing to Data array + /// + public readonly int UserDataOffset; + + /// + /// Raw packet data. Do not modify header! Use UserDataOffset as start point for your data + /// + public byte[] Data => _packet.RawData; + + internal PooledPacket(NetPacket packet, int maxDataSize, byte channelNumber) + { + _packet = packet; + UserDataOffset = _packet.GetHeaderSize(); + _packet.Size = UserDataOffset; + MaxUserDataSize = maxDataSize - UserDataOffset; + _channelNumber = channelNumber; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs.meta new file mode 100644 index 0000000..8c3b978 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PooledPacket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76e47a542bb12e043b874c7180d98319 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs new file mode 100644 index 0000000..f825e37 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs @@ -0,0 +1,336 @@ +using System; + +namespace LiteNetLib +{ + internal sealed class ReliableChannel : BaseChannel + { + private struct PendingPacket + { + private NetPacket _packet; + private long _timeStamp; + private bool _isSent; + + public override string ToString() + { + return _packet == null ? "Empty" : _packet.Sequence.ToString(); + } + + public void Init(NetPacket packet) + { + _packet = packet; + _isSent = false; + } + + //Returns true if there is a pending packet inside + public bool TrySend(long currentTime, NetPeer peer) + { + if (_packet == null) + return false; + + if (_isSent) //check send time + { + double resendDelay = peer.ResendDelay * TimeSpan.TicksPerMillisecond; + double packetHoldTime = currentTime - _timeStamp; + if (packetHoldTime < resendDelay) + return true; + NetDebug.Write("[RC]Resend: {0} > {1}", (int)packetHoldTime, resendDelay); + } + _timeStamp = currentTime; + _isSent = true; + peer.SendUserData(_packet); + return true; + } + + public bool Clear(NetPeer peer) + { + if (_packet != null) + { + peer.RecycleAndDeliver(_packet); + _packet = null; + return true; + } + return false; + } + } + + private readonly NetPacket _outgoingAcks; //for send acks + private readonly PendingPacket[] _pendingPackets; //for unacked packets and duplicates + private readonly NetPacket[] _receivedPackets; //for order + private readonly bool[] _earlyReceived; //for unordered + + private int _localSeqence; + private int _remoteSequence; + private int _localWindowStart; + private int _remoteWindowStart; + + private bool _mustSendAcks; + + private readonly DeliveryMethod _deliveryMethod; + private readonly bool _ordered; + private readonly int _windowSize; + private const int BitsInByte = 8; + private readonly byte _id; + + public ReliableChannel(NetPeer peer, bool ordered, byte id) : base(peer) + { + _id = id; + _windowSize = NetConstants.DefaultWindowSize; + _ordered = ordered; + _pendingPackets = new PendingPacket[_windowSize]; + for (int i = 0; i < _pendingPackets.Length; i++) + _pendingPackets[i] = new PendingPacket(); + + if (_ordered) + { + _deliveryMethod = DeliveryMethod.ReliableOrdered; + _receivedPackets = new NetPacket[_windowSize]; + } + else + { + _deliveryMethod = DeliveryMethod.ReliableUnordered; + _earlyReceived = new bool[_windowSize]; + } + + _localWindowStart = 0; + _localSeqence = 0; + _remoteSequence = 0; + _remoteWindowStart = 0; + _outgoingAcks = new NetPacket(PacketProperty.Ack, (_windowSize - 1) / BitsInByte + 2) {ChannelId = id}; + } + + //ProcessAck in packet + private void ProcessAck(NetPacket packet) + { + if (packet.Size != _outgoingAcks.Size) + { + NetDebug.Write("[PA]Invalid acks packet size"); + return; + } + + ushort ackWindowStart = packet.Sequence; + int windowRel = NetUtils.RelativeSequenceNumber(_localWindowStart, ackWindowStart); + if (ackWindowStart >= NetConstants.MaxSequence || windowRel < 0) + { + NetDebug.Write("[PA]Bad window start"); + return; + } + + //check relevance + if (windowRel >= _windowSize) + { + NetDebug.Write("[PA]Old acks"); + return; + } + + byte[] acksData = packet.RawData; + lock (_pendingPackets) + { + for (int pendingSeq = _localWindowStart; + pendingSeq != _localSeqence; + pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence) + { + int rel = NetUtils.RelativeSequenceNumber(pendingSeq, ackWindowStart); + if (rel >= _windowSize) + { + NetDebug.Write("[PA]REL: " + rel); + break; + } + + int pendingIdx = pendingSeq % _windowSize; + int currentByte = NetConstants.ChanneledHeaderSize + pendingIdx / BitsInByte; + int currentBit = pendingIdx % BitsInByte; + if ((acksData[currentByte] & (1 << currentBit)) == 0) + { + if (Peer.NetManager.EnableStatistics) + { + Peer.Statistics.IncrementPacketLoss(); + Peer.NetManager.Statistics.IncrementPacketLoss(); + } + + //Skip false ack + NetDebug.Write("[PA]False ack: {0}", pendingSeq); + continue; + } + + if (pendingSeq == _localWindowStart) + { + //Move window + _localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence; + } + + //clear packet + if (_pendingPackets[pendingIdx].Clear(Peer)) + NetDebug.Write("[PA]Removing reliableInOrder ack: {0} - true", pendingSeq); + } + } + } + + protected override bool SendNextPackets() + { + if (_mustSendAcks) + { + _mustSendAcks = false; + NetDebug.Write("[RR]SendAcks"); + lock(_outgoingAcks) + Peer.SendUserData(_outgoingAcks); + } + + long currentTime = DateTime.UtcNow.Ticks; + bool hasPendingPackets = false; + + lock (_pendingPackets) + { + //get packets from queue + while (!OutgoingQueue.IsEmpty) + { + 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; + } + + //send + for (int pendingSeq = _localWindowStart; pendingSeq != _localSeqence; pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence) + { + // Please note: TrySend is invoked on a mutable struct, it's important to not extract it into a variable here + if (_pendingPackets[pendingSeq % _windowSize].TrySend(currentTime, Peer)) + hasPendingPackets = true; + } + } + + return hasPendingPackets || _mustSendAcks || !OutgoingQueue.IsEmpty; + } + + //Process incoming packet + public override bool ProcessPacket(NetPacket packet) + { + if (packet.Property == PacketProperty.Ack) + { + ProcessAck(packet); + return false; + } + int seq = packet.Sequence; + if (seq >= NetConstants.MaxSequence) + { + NetDebug.Write("[RR]Bad sequence"); + return false; + } + + int relate = NetUtils.RelativeSequenceNumber(seq, _remoteWindowStart); + int relateSeq = NetUtils.RelativeSequenceNumber(seq, _remoteSequence); + + if (relateSeq > _windowSize) + { + NetDebug.Write("[RR]Bad sequence"); + return false; + } + + //Drop bad packets + if (relate < 0) + { + //Too old packet doesn't ack + NetDebug.Write("[RR]ReliableInOrder too old"); + return false; + } + if (relate >= _windowSize * 2) + { + //Some very new packet + NetDebug.Write("[RR]ReliableInOrder too new"); + return false; + } + + //If very new - move window + int ackIdx; + int ackByte; + int ackBit; + lock (_outgoingAcks) + { + if (relate >= _windowSize) + { + //New window position + int newWindowStart = (_remoteWindowStart + relate - _windowSize + 1) % NetConstants.MaxSequence; + _outgoingAcks.Sequence = (ushort) newWindowStart; + + //Clean old data + while (_remoteWindowStart != newWindowStart) + { + ackIdx = _remoteWindowStart % _windowSize; + ackByte = NetConstants.ChanneledHeaderSize + ackIdx / BitsInByte; + ackBit = ackIdx % BitsInByte; + _outgoingAcks.RawData[ackByte] &= (byte) ~(1 << ackBit); + _remoteWindowStart = (_remoteWindowStart + 1) % NetConstants.MaxSequence; + } + } + + //Final stage - process valid packet + //trigger acks send + _mustSendAcks = true; + + ackIdx = seq % _windowSize; + ackByte = NetConstants.ChanneledHeaderSize + ackIdx / BitsInByte; + ackBit = ackIdx % BitsInByte; + if ((_outgoingAcks.RawData[ackByte] & (1 << ackBit)) != 0) + { + NetDebug.Write("[RR]ReliableInOrder duplicate"); + //because _mustSendAcks == true + AddToPeerChannelSendQueue(); + return false; + } + + //save ack + _outgoingAcks.RawData[ackByte] |= (byte) (1 << ackBit); + } + + AddToPeerChannelSendQueue(); + + //detailed check + if (seq == _remoteSequence) + { + NetDebug.Write("[RR]ReliableInOrder packet succes"); + Peer.AddReliablePacket(_deliveryMethod, packet); + _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence; + + if (_ordered) + { + NetPacket p; + while ((p = _receivedPackets[_remoteSequence % _windowSize]) != null) + { + //process holden packet + _receivedPackets[_remoteSequence % _windowSize] = null; + Peer.AddReliablePacket(_deliveryMethod, p); + _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence; + } + } + else + { + while (_earlyReceived[_remoteSequence % _windowSize]) + { + //process early packet + _earlyReceived[_remoteSequence % _windowSize] = false; + _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence; + } + } + return true; + } + + //holden packet + if (_ordered) + { + _receivedPackets[ackIdx] = packet; + } + else + { + _earlyReceived[ackIdx] = true; + Peer.AddReliablePacket(_deliveryMethod, packet); + } + return true; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs.meta new file mode 100644 index 0000000..55f9b0b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7e20c169333af54fa233b0d70b19a61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs new file mode 100644 index 0000000..a3763ee --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs @@ -0,0 +1,110 @@ +using System; + +namespace LiteNetLib +{ + internal sealed class SequencedChannel : BaseChannel + { + private int _localSequence; + private ushort _remoteSequence; + private readonly bool _reliable; + private NetPacket _lastPacket; + private readonly NetPacket _ackPacket; + private bool _mustSendAck; + private readonly byte _id; + private long _lastPacketSendTime; + + public SequencedChannel(NetPeer peer, bool reliable, byte id) : base(peer) + { + _id = id; + _reliable = reliable; + if (_reliable) + _ackPacket = new NetPacket(PacketProperty.Ack, 0) {ChannelId = id}; + } + + protected override bool SendNextPackets() + { + if (_reliable && OutgoingQueue.Count == 0) + { + long currentTime = DateTime.UtcNow.Ticks; + long packetHoldTime = currentTime - _lastPacketSendTime; + if (packetHoldTime >= Peer.ResendDelay * TimeSpan.TicksPerMillisecond) + { + var packet = _lastPacket; + if (packet != null) + { + _lastPacketSendTime = currentTime; + Peer.SendUserData(packet); + } + } + } + else + { + while (OutgoingQueue.TryDequeue(out var packet)) + { + _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 && _mustSendAck) + { + _mustSendAck = false; + _ackPacket.Sequence = _remoteSequence; + Peer.SendUserData(_ackPacket); + } + + return _lastPacket != null; + } + + public override bool ProcessPacket(NetPacket packet) + { + if (packet.IsFragmented) + return false; + if (packet.Property == PacketProperty.Ack) + { + if (_reliable && _lastPacket != null && packet.Sequence == _lastPacket.Sequence) + _lastPacket = null; + return false; + } + int relative = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence); + bool packetProcessed = false; + if (packet.Sequence < NetConstants.MaxSequence && relative > 0) + { + if (Peer.NetManager.EnableStatistics) + { + Peer.Statistics.AddPacketLoss(relative - 1); + Peer.NetManager.Statistics.AddPacketLoss(relative - 1); + } + + _remoteSequence = packet.Sequence; + Peer.NetManager.CreateReceiveEvent( + packet, + _reliable ? DeliveryMethod.ReliableSequenced : DeliveryMethod.Sequenced, + (byte)(packet.ChannelId / NetConstants.ChannelTypeCount), + NetConstants.ChanneledHeaderSize, + Peer); + packetProcessed = true; + } + + if (_reliable) + { + _mustSendAck = true; + AddToPeerChannelSendQueue(); + } + + return packetProcessed; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs.meta new file mode 100644 index 0000000..a6b7dba --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4e1f97908b70e642baea0fc22724282 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils.meta new file mode 100644 index 0000000..5c1f750 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c6e0e6809efaf74c8c6864f8129b89f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs new file mode 100644 index 0000000..7e85680 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs @@ -0,0 +1,150 @@ +#if NETCOREAPP3_0_OR_GREATER || NETCOREAPP3_1 || NET5_0 +using System; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +#endif +#if NET5_0_OR_GREATER || NET5_0 +using System.Runtime.Intrinsics.Arm; +#endif + +namespace LiteNetLib.Utils +{ + //Implementation from Crc32.NET + public static class CRC32C + { + public const int ChecksumSize = 4; + private const uint Poly = 0x82F63B78u; + private static readonly uint[] Table; + + static CRC32C() + { +#if NETCOREAPP3_0_OR_GREATER || NETCOREAPP3_1 || NET5_0 + if (Sse42.IsSupported) + return; +#endif +#if NET5_0_OR_GREATER || NET5_0 + if (Crc32.IsSupported) + return; +#endif + Table = NetUtils.AllocatePinnedUninitializedArray(16 * 256); + for (uint i = 0; i < 256; i++) + { + uint res = i; + for (int t = 0; t < 16; t++) + { + for (int k = 0; k < 8; k++) + res = (res & 1) == 1 ? Poly ^ (res >> 1) : (res >> 1); + Table[t * 256 + i] = res; + } + } + } + + /// + /// Compute CRC32C for data + /// + /// input data + /// offset + /// length + /// CRC32C checksum + public static uint Compute(byte[] input, int offset, int length) + { + uint crcLocal = uint.MaxValue; +#if NETCOREAPP3_0_OR_GREATER || NETCOREAPP3_1 || NET5_0 + if (Sse42.IsSupported) + { + var data = new ReadOnlySpan(input, offset, length); + int processed = 0; + if (Sse42.X64.IsSupported && data.Length > sizeof(ulong)) + { + processed = data.Length / sizeof(ulong) * sizeof(ulong); + var ulongs = MemoryMarshal.Cast(data.Slice(0, processed)); + ulong crclong = crcLocal; + for (int i = 0; i < ulongs.Length; i++) + { + crclong = Sse42.X64.Crc32(crclong, ulongs[i]); + } + + crcLocal = (uint)crclong; + } + else if (data.Length > sizeof(uint)) + { + processed = data.Length / sizeof(uint) * sizeof(uint); + var uints = MemoryMarshal.Cast(data.Slice(0, processed)); + for (int i = 0; i < uints.Length; i++) + { + crcLocal = Sse42.Crc32(crcLocal, uints[i]); + } + } + + for (int i = processed; i < data.Length; i++) + { + crcLocal = Sse42.Crc32(crcLocal, data[i]); + } + + return crcLocal ^ uint.MaxValue; + } +#endif +#if NET5_0_OR_GREATER || NET5_0 + if (Crc32.IsSupported) + { + var data = new ReadOnlySpan(input, offset, length); + int processed = 0; + if (Crc32.Arm64.IsSupported && data.Length > sizeof(ulong)) + { + processed = data.Length / sizeof(ulong) * sizeof(ulong); + var ulongs = MemoryMarshal.Cast(data.Slice(0, processed)); + for (int i = 0; i < ulongs.Length; i++) + { + crcLocal = Crc32.Arm64.ComputeCrc32C(crcLocal, ulongs[i]); + } + } + else if (data.Length > sizeof(uint)) + { + processed = data.Length / sizeof(uint) * sizeof(uint); + var uints = MemoryMarshal.Cast(data.Slice(0, processed)); + for (int i = 0; i < uints.Length; i++) + { + crcLocal = Crc32.ComputeCrc32C(crcLocal, uints[i]); + } + } + + for (int i = processed; i < data.Length; i++) + { + crcLocal = Crc32.ComputeCrc32C(crcLocal, data[i]); + } + + return crcLocal ^ uint.MaxValue; + } +#endif + while (length >= 16) + { + var a = Table[(3 * 256) + input[offset + 12]] + ^ Table[(2 * 256) + input[offset + 13]] + ^ Table[(1 * 256) + input[offset + 14]] + ^ Table[(0 * 256) + input[offset + 15]]; + + var b = Table[(7 * 256) + input[offset + 8]] + ^ Table[(6 * 256) + input[offset + 9]] + ^ Table[(5 * 256) + input[offset + 10]] + ^ Table[(4 * 256) + input[offset + 11]]; + + var c = Table[(11 * 256) + input[offset + 4]] + ^ Table[(10 * 256) + input[offset + 5]] + ^ Table[(9 * 256) + input[offset + 6]] + ^ Table[(8 * 256) + input[offset + 7]]; + + var d = Table[(15 * 256) + ((byte)crcLocal ^ input[offset])] + ^ Table[(14 * 256) + ((byte)(crcLocal >> 8) ^ input[offset + 1])] + ^ Table[(13 * 256) + ((byte)(crcLocal >> 16) ^ input[offset + 2])] + ^ Table[(12 * 256) + ((crcLocal >> 24) ^ input[offset + 3])]; + + crcLocal = d ^ c ^ b ^ a; + offset += 16; + length -= 16; + } + while (--length >= 0) + crcLocal = Table[(byte)(crcLocal ^ input[offset++])] ^ crcLocal >> 8; + return crcLocal ^ uint.MaxValue; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs.meta new file mode 100644 index 0000000..d42bd93 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/CRC32C.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 912ba506b0945b743be5c4129177024c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs new file mode 100644 index 0000000..3ecd10c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs @@ -0,0 +1,175 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LiteNetLib.Utils +{ + public static class FastBitConverter + { +#if (LITENETLIB_UNSAFE || LITENETLIB_UNSAFELIB || 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 + { + int size = sizeof(T); + if (bytes.Length < startIndex + size) + ThrowIndexOutOfRangeException(); +#if LITENETLIB_UNSAFELIB || NETCOREAPP3_1 || NET5_0 || NETCOREAPP3_0_OR_GREATER + Unsafe.As(ref bytes[startIndex]) = value; +#else + fixed (byte* ptr = &bytes[startIndex]) + { +#if UNITY_ANDROID + // On some android systems, assigning *(T*)ptr throws a NRE if + // the ptr isn't aligned (i.e. if Position is 1,2,3,5, etc.). + // Here we have to use memcpy. + // + // => we can't get a pointer of a struct in C# without + // marshalling allocations + // => instead, we stack allocate an array of type T and use that + // => stackalloc avoids GC and is very fast. it only works for + // value types, but all blittable types are anyway. + T* valueBuffer = stackalloc T[1] { value }; + UnsafeUtility.MemCpy(ptr, valueBuffer, size); +#else + *(T*)ptr = value; +#endif + } +#endif + } +#else + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, T value) where T : unmanaged + { + if (bytes.Length < startIndex + Unsafe.SizeOf()) + ThrowIndexOutOfRangeException(); + Unsafe.As(ref bytes[startIndex]) = value; + } +#endif + + private static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException(); +#else + [StructLayout(LayoutKind.Explicit)] + private struct ConverterHelperDouble + { + [FieldOffset(0)] + public ulong Along; + + [FieldOffset(0)] + public double Adouble; + } + + [StructLayout(LayoutKind.Explicit)] + private struct ConverterHelperFloat + { + [FieldOffset(0)] + public int Aint; + + [FieldOffset(0)] + public float Afloat; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteLittleEndian(byte[] buffer, int offset, ulong data) + { +#if BIGENDIAN + buffer[offset + 7] = (byte)(data); + buffer[offset + 6] = (byte)(data >> 8); + buffer[offset + 5] = (byte)(data >> 16); + buffer[offset + 4] = (byte)(data >> 24); + buffer[offset + 3] = (byte)(data >> 32); + buffer[offset + 2] = (byte)(data >> 40); + buffer[offset + 1] = (byte)(data >> 48); + buffer[offset ] = (byte)(data >> 56); +#else + buffer[offset] = (byte)(data); + buffer[offset + 1] = (byte)(data >> 8); + buffer[offset + 2] = (byte)(data >> 16); + buffer[offset + 3] = (byte)(data >> 24); + buffer[offset + 4] = (byte)(data >> 32); + buffer[offset + 5] = (byte)(data >> 40); + buffer[offset + 6] = (byte)(data >> 48); + buffer[offset + 7] = (byte)(data >> 56); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteLittleEndian(byte[] buffer, int offset, int data) + { +#if BIGENDIAN + buffer[offset + 3] = (byte)(data); + buffer[offset + 2] = (byte)(data >> 8); + buffer[offset + 1] = (byte)(data >> 16); + buffer[offset ] = (byte)(data >> 24); +#else + buffer[offset] = (byte)(data); + buffer[offset + 1] = (byte)(data >> 8); + buffer[offset + 2] = (byte)(data >> 16); + buffer[offset + 3] = (byte)(data >> 24); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteLittleEndian(byte[] buffer, int offset, short data) + { +#if BIGENDIAN + buffer[offset + 1] = (byte)(data); + buffer[offset ] = (byte)(data >> 8); +#else + buffer[offset] = (byte)(data); + buffer[offset + 1] = (byte)(data >> 8); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, double value) + { + ConverterHelperDouble ch = new ConverterHelperDouble { Adouble = value }; + WriteLittleEndian(bytes, startIndex, ch.Along); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, float value) + { + ConverterHelperFloat ch = new ConverterHelperFloat { Afloat = value }; + WriteLittleEndian(bytes, startIndex, ch.Aint); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, short value) + { + WriteLittleEndian(bytes, startIndex, value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, ushort value) + { + WriteLittleEndian(bytes, startIndex, (short)value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, int value) + { + WriteLittleEndian(bytes, startIndex, value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, uint value) + { + WriteLittleEndian(bytes, startIndex, (int)value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, long value) + { + WriteLittleEndian(bytes, startIndex, (ulong)value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(byte[] bytes, int startIndex, ulong value) + { + WriteLittleEndian(bytes, startIndex, value); + } +#endif + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs.meta new file mode 100644 index 0000000..784434c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21018f84ccfb8244e99b5ec22ceb91c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs new file mode 100644 index 0000000..92f14be --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs @@ -0,0 +1,8 @@ +namespace LiteNetLib.Utils +{ + public interface INetSerializable + { + void Serialize(NetDataWriter writer); + void Deserialize(NetDataReader reader); + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs.meta new file mode 100644 index 0000000..f055292 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/INetSerializable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c26b17a74d3fb8b498fc89d253f1742a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs new file mode 100644 index 0000000..7022265 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs @@ -0,0 +1,680 @@ +using System; +using System.Net; +using System.Text; + +namespace LiteNetLib.Utils +{ + public class NetDataReader + { + protected byte[] _data; + protected int _position; + 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 void SkipBytes(int count) + { + _position += count; + } + + public void SetPosition(int position) + { + _position = position; + } + + public void SetSource(NetDataWriter dataWriter) + { + _data = dataWriter.Data; + _position = 0; + _offset = 0; + _dataSize = dataWriter.Length; + } + + public void SetSource(byte[] source) + { + _data = source; + _position = 0; + _offset = 0; + _dataSize = source.Length; + } + + public void SetSource(byte[] source, int offset, int maxSize) + { + _data = source; + _position = offset; + _offset = offset; + _dataSize = maxSize; + } + + public NetDataReader() + { + + } + + public NetDataReader(NetDataWriter writer) + { + SetSource(writer); + } + + public NetDataReader(byte[] source) + { + SetSource(source); + } + + public NetDataReader(byte[] source, int offset, int maxSize) + { + SetSource(source, offset, maxSize); + } + + #region GetMethods + public IPEndPoint GetNetEndPoint() + { + string host = GetString(1000); + int port = GetInt(); + return NetUtils.MakeEndPoint(host, port); + } + + public byte GetByte() + { + byte res = _data[_position]; + _position += 1; + return res; + } + + public sbyte GetSByte() + { + var b = (sbyte)_data[_position]; + _position++; + return b; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + public string[] GetStringArray() + { + ushort arraySize = GetUShort(); + var arr = new string[arraySize]; + for (int i = 0; i < arraySize; i++) + { + arr[i] = GetString(); + } + return arr; + } + + public string[] GetStringArray(int maxStringLength) + { + ushort arraySize = GetUShort(); + var arr = new string[arraySize]; + for (int i = 0; i < arraySize; i++) + { + arr[i] = GetString(maxStringLength); + } + return arr; + } + + public bool GetBool() + { + bool res = _data[_position] > 0; + _position += 1; + return res; + } + + public char GetChar() + { + return (char)GetUShort(); + } + + public ushort GetUShort() + { + ushort result = BitConverter.ToUInt16(_data, _position); + _position += 2; + return result; + } + + public short GetShort() + { + short result = BitConverter.ToInt16(_data, _position); + _position += 2; + return result; + } + + public long GetLong() + { + long result = BitConverter.ToInt64(_data, _position); + _position += 8; + return result; + } + + public ulong GetULong() + { + ulong result = BitConverter.ToUInt64(_data, _position); + _position += 8; + return result; + } + + public int GetInt() + { + int result = BitConverter.ToInt32(_data, _position); + _position += 4; + return result; + } + + public uint GetUInt() + { + uint result = BitConverter.ToUInt32(_data, _position); + _position += 4; + return result; + } + + public float GetFloat() + { + float result = BitConverter.ToSingle(_data, _position); + _position += 4; + return result; + } + + public double GetDouble() + { + double result = BitConverter.ToDouble(_data, _position); + _position += 8; + return result; + } + + /// + /// Note that "maxLength" only limits the number of characters in a string, not its size in bytes. + /// + /// "string.Empty" if value > "maxLength" + public string GetString(int maxLength) + { + ushort size = GetUShort(); + if (size == 0) + { + return null; + } + + int actualSize = size - 1; + if (actualSize >= NetDataWriter.StringBufferMaxLength) + { + return null; + } + + ArraySegment data = GetBytesSegment(actualSize); + + return (maxLength > 0 && _uTF8Encoding.GetCharCount(data.Array, data.Offset, data.Count) > maxLength) ? + string.Empty : + _uTF8Encoding.GetString(data.Array, data.Offset, data.Count); + } + + public string GetString() + { + ushort size = GetUShort(); + if (size == 0) + { + return null; + } + + int actualSize = size - 1; + if (actualSize >= NetDataWriter.StringBufferMaxLength) + { + return null; + } + + ArraySegment data = GetBytesSegment(actualSize); + + return _uTF8Encoding.GetString(data.Array, data.Offset, data.Count); + } + + public ArraySegment GetBytesSegment(int count) + { + ArraySegment segment = new ArraySegment(_data, _position, count); + _position += count; + return segment; + } + + public ArraySegment GetRemainingBytesSegment() + { + ArraySegment segment = new ArraySegment(_data, _position, AvailableBytes); + _position = _data.Length; + return segment; + } + + public T Get() where T : INetSerializable, new() + { + var obj = new T(); + obj.Deserialize(this); + return obj; + } + + public byte[] GetRemainingBytes() + { + byte[] outgoingData = new byte[AvailableBytes]; + Buffer.BlockCopy(_data, _position, outgoingData, 0, AvailableBytes); + _position = _data.Length; + return outgoingData; + } + + public void GetBytes(byte[] destination, int start, int count) + { + Buffer.BlockCopy(_data, _position, destination, start, count); + _position += count; + } + + public void GetBytes(byte[] destination, int count) + { + Buffer.BlockCopy(_data, _position, destination, 0, count); + _position += count; + } + + public sbyte[] GetSBytesWithLength() + { + int length = GetInt(); + sbyte[] outgoingData = new sbyte[length]; + Buffer.BlockCopy(_data, _position, outgoingData, 0, length); + _position += length; + return outgoingData; + } + + public byte[] GetBytesWithLength() + { + int length = GetInt(); + byte[] outgoingData = new byte[length]; + Buffer.BlockCopy(_data, _position, outgoingData, 0, length); + _position += length; + return outgoingData; + } + #endregion + + #region PeekMethods + + public byte PeekByte() + { + return _data[_position]; + } + + public sbyte PeekSByte() + { + return (sbyte)_data[_position]; + } + + public bool PeekBool() + { + return _data[_position] > 0; + } + + public char PeekChar() + { + return (char)PeekUShort(); + } + + public ushort PeekUShort() + { + return BitConverter.ToUInt16(_data, _position); + } + + public short PeekShort() + { + return BitConverter.ToInt16(_data, _position); + } + + public long PeekLong() + { + return BitConverter.ToInt64(_data, _position); + } + + public ulong PeekULong() + { + return BitConverter.ToUInt64(_data, _position); + } + + public int PeekInt() + { + return BitConverter.ToInt32(_data, _position); + } + + public uint PeekUInt() + { + return BitConverter.ToUInt32(_data, _position); + } + + public float PeekFloat() + { + return BitConverter.ToSingle(_data, _position); + } + + public double PeekDouble() + { + return BitConverter.ToDouble(_data, _position); + } + + public string PeekString(int maxLength) + { + ushort size = PeekUShort(); + if (size == 0) + { + return null; + } + + int actualSize = size - 1; + if (actualSize >= NetDataWriter.StringBufferMaxLength) + { + return null; + } + + return (maxLength > 0 && _uTF8Encoding.GetCharCount(_data, _position + 2, actualSize) > maxLength) ? + string.Empty : + _uTF8Encoding.GetString(_data, _position + 2, actualSize); + } + + public string PeekString() + { + ushort size = PeekUShort(); + if (size == 0) + { + return null; + } + + int actualSize = size - 1; + if (actualSize >= NetDataWriter.StringBufferMaxLength) + { + return null; + } + + return _uTF8Encoding.GetString(_data, _position + 2, actualSize); + } + #endregion + + #region TryGetMethods + public bool TryGetByte(out byte result) + { + if (AvailableBytes >= 1) + { + result = GetByte(); + return true; + } + result = 0; + return false; + } + + public bool TryGetSByte(out sbyte result) + { + if (AvailableBytes >= 1) + { + result = GetSByte(); + return true; + } + result = 0; + return false; + } + + public bool TryGetBool(out bool result) + { + if (AvailableBytes >= 1) + { + result = GetBool(); + return true; + } + result = false; + return false; + } + + public bool TryGetChar(out char result) + { + if (!TryGetUShort(out ushort uShortValue)) + { + result = '\0'; + return false; + } + result = (char)uShortValue; + return true; + } + + public bool TryGetShort(out short result) + { + if (AvailableBytes >= 2) + { + result = GetShort(); + return true; + } + result = 0; + return false; + } + + public bool TryGetUShort(out ushort result) + { + if (AvailableBytes >= 2) + { + result = GetUShort(); + return true; + } + result = 0; + return false; + } + + public bool TryGetInt(out int result) + { + if (AvailableBytes >= 4) + { + result = GetInt(); + return true; + } + result = 0; + return false; + } + + public bool TryGetUInt(out uint result) + { + if (AvailableBytes >= 4) + { + result = GetUInt(); + return true; + } + result = 0; + return false; + } + + public bool TryGetLong(out long result) + { + if (AvailableBytes >= 8) + { + result = GetLong(); + return true; + } + result = 0; + return false; + } + + public bool TryGetULong(out ulong result) + { + if (AvailableBytes >= 8) + { + result = GetULong(); + return true; + } + result = 0; + return false; + } + + public bool TryGetFloat(out float result) + { + if (AvailableBytes >= 4) + { + result = GetFloat(); + return true; + } + result = 0; + return false; + } + + public bool TryGetDouble(out double result) + { + if (AvailableBytes >= 8) + { + result = GetDouble(); + return true; + } + result = 0; + return false; + } + + public bool TryGetString(out string result) + { + if (AvailableBytes >= 2) + { + ushort strSize = PeekUShort(); + if (AvailableBytes >= strSize + 1) + { + result = GetString(); + return true; + } + } + result = null; + return false; + } + + public bool TryGetStringArray(out string[] result) + { + ushort strArrayLength; + if (!TryGetUShort(out strArrayLength)) + { + result = null; + return false; + } + + result = new string[strArrayLength]; + for (int i = 0; i < strArrayLength; i++) + { + if (!TryGetString(out result[i])) + { + result = null; + return false; + } + } + + return true; + } + + public bool TryGetBytesWithLength(out byte[] result) + { + if (AvailableBytes >= 4) + { + var length = PeekInt(); + if (length >= 0 && AvailableBytes >= length + 4) + { + result = GetBytesWithLength(); + return true; + } + } + result = null; + return false; + } + #endregion + + public void Clear() + { + _position = 0; + _dataSize = 0; + _data = null; + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs.meta new file mode 100644 index 0000000..31be4dd --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2876e12b475627f448ca5a6850748bc3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs new file mode 100644 index 0000000..1c9d724 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs @@ -0,0 +1,379 @@ +using System; +using System.Net; +using System.Runtime.CompilerServices; +using System.Text; + +namespace LiteNetLib.Utils +{ + public class NetDataWriter + { + protected byte[] _data; + protected int _position; + private const int InitialSize = 64; + private readonly bool _autoResize; + + public int Capacity => _data.Length; + public byte[] Data => _data; + public int Length => _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 + private readonly byte[] _stringBuffer = new byte[StringBufferMaxLength]; + + public NetDataWriter() : this(true, InitialSize) + { + } + + public NetDataWriter(bool autoResize) : this(autoResize, InitialSize) + { + } + + public NetDataWriter(bool autoResize, int initialSize) + { + _data = new byte[initialSize]; + _autoResize = autoResize; + } + + /// + /// Creates NetDataWriter from existing ByteArray + /// + /// Source byte array + /// Copy array to new location or use existing + public static NetDataWriter FromBytes(byte[] bytes, bool copy) + { + if (copy) + { + var netDataWriter = new NetDataWriter(true, bytes.Length); + netDataWriter.Put(bytes); + return netDataWriter; + } + return new NetDataWriter(true, 0) {_data = bytes, _position = bytes.Length}; + } + + /// + /// Creates NetDataWriter from existing ByteArray (always copied data) + /// + /// Source byte array + /// Offset of array + /// Length of array + public static NetDataWriter FromBytes(byte[] bytes, int offset, int length) + { + var netDataWriter = new NetDataWriter(true, bytes.Length); + netDataWriter.Put(bytes, offset, length); + return netDataWriter; + } + + public static NetDataWriter FromString(string value) + { + var netDataWriter = new NetDataWriter(); + netDataWriter.Put(value); + return netDataWriter; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ResizeIfNeed(int newSize) + { + if (_data.Length < newSize) + { + Array.Resize(ref _data, Math.Max(newSize, _data.Length * 2)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureFit(int additionalSize) + { + if (_data.Length < _position + additionalSize) + { + Array.Resize(ref _data, Math.Max(_position + additionalSize, _data.Length * 2)); + } + } + + public void Reset(int size) + { + ResizeIfNeed(size); + _position = 0; + } + + public void Reset() + { + _position = 0; + } + + public byte[] CopyData() + { + byte[] resultData = new byte[_position]; + Buffer.BlockCopy(_data, 0, resultData, 0, _position); + return resultData; + } + + /// + /// Sets position of NetDataWriter to rewrite previous values + /// + /// new byte position + /// previous position of data writer + public int SetPosition(int position) + { + int prevPosition = _position; + _position = position; + return prevPosition; + } + + public void Put(float value) + { + if (_autoResize) + ResizeIfNeed(_position + 4); + FastBitConverter.GetBytes(_data, _position, value); + _position += 4; + } + + public void Put(double value) + { + if (_autoResize) + ResizeIfNeed(_position + 8); + FastBitConverter.GetBytes(_data, _position, value); + _position += 8; + } + + public void Put(long value) + { + if (_autoResize) + ResizeIfNeed(_position + 8); + FastBitConverter.GetBytes(_data, _position, value); + _position += 8; + } + + public void Put(ulong value) + { + if (_autoResize) + ResizeIfNeed(_position + 8); + FastBitConverter.GetBytes(_data, _position, value); + _position += 8; + } + + public void Put(int value) + { + if (_autoResize) + ResizeIfNeed(_position + 4); + FastBitConverter.GetBytes(_data, _position, value); + _position += 4; + } + + public void Put(uint value) + { + if (_autoResize) + ResizeIfNeed(_position + 4); + FastBitConverter.GetBytes(_data, _position, value); + _position += 4; + } + + public void Put(char value) + { + Put((ushort)value); + } + + public void Put(ushort value) + { + if (_autoResize) + ResizeIfNeed(_position + 2); + FastBitConverter.GetBytes(_data, _position, value); + _position += 2; + } + + public void Put(short value) + { + if (_autoResize) + ResizeIfNeed(_position + 2); + FastBitConverter.GetBytes(_data, _position, value); + _position += 2; + } + + public void Put(sbyte value) + { + if (_autoResize) + ResizeIfNeed(_position + 1); + _data[_position] = (byte)value; + _position++; + } + + public void Put(byte value) + { + if (_autoResize) + ResizeIfNeed(_position + 1); + _data[_position] = value; + _position++; + } + + public void Put(byte[] data, int offset, int length) + { + if (_autoResize) + ResizeIfNeed(_position + length); + Buffer.BlockCopy(data, offset, _data, _position, length); + _position += length; + } + + public void Put(byte[] data) + { + if (_autoResize) + ResizeIfNeed(_position + data.Length); + Buffer.BlockCopy(data, 0, _data, _position, data.Length); + _position += data.Length; + } + + public void PutSBytesWithLength(sbyte[] data, int offset, int length) + { + if (_autoResize) + ResizeIfNeed(_position + length + 4); + FastBitConverter.GetBytes(_data, _position, length); + Buffer.BlockCopy(data, offset, _data, _position + 4, length); + _position += length + 4; + } + + 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; + } + + public void PutBytesWithLength(byte[] data, int offset, int length) + { + if (_autoResize) + ResizeIfNeed(_position + length + 4); + FastBitConverter.GetBytes(_data, _position, length); + Buffer.BlockCopy(data, offset, _data, _position + 4, length); + _position += length + 4; + } + + 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; + } + + public void Put(bool value) + { + Put((byte)(value ? 1 : 0)); + } + + private void PutArray(Array arr, int sz) + { + ushort length = arr == null ? (ushort) 0 : (ushort)arr.Length; + sz *= length; + if (_autoResize) + ResizeIfNeed(_position + sz + 2); + FastBitConverter.GetBytes(_data, _position, length); + if (arr != null) + Buffer.BlockCopy(arr, 0, _data, _position + 2, sz); + _position += sz + 2; + } + + public void PutArray(float[] value) + { + PutArray(value, 4); + } + + public void PutArray(double[] value) + { + PutArray(value, 8); + } + + public void PutArray(long[] value) + { + PutArray(value, 8); + } + + public void PutArray(ulong[] value) + { + PutArray(value, 8); + } + + public void PutArray(int[] value) + { + PutArray(value, 4); + } + + public void PutArray(uint[] value) + { + PutArray(value, 4); + } + + public void PutArray(ushort[] value) + { + PutArray(value, 2); + } + + public void PutArray(short[] value) + { + PutArray(value, 2); + } + + public void PutArray(bool[] value) + { + PutArray(value, 1); + } + + public void PutArray(string[] value) + { + ushort strArrayLength = value == null ? (ushort)0 : (ushort)value.Length; + Put(strArrayLength); + for (int i = 0; i < strArrayLength; i++) + Put(value[i]); + } + + public void PutArray(string[] value, int strMaxLength) + { + ushort strArrayLength = value == null ? (ushort)0 : (ushort)value.Length; + Put(strArrayLength); + for (int i = 0; i < strArrayLength; i++) + Put(value[i], strMaxLength); + } + + public void Put(IPEndPoint endPoint) + { + Put(endPoint.Address.ToString()); + Put(endPoint.Port); + } + + public void Put(string value) + { + Put(value, 0); + } + + /// + /// Note that "maxLength" only limits the number of characters in a string, not its size in bytes. + /// + public void Put(string value, int maxLength) + { + if (value == null) + { + Put((ushort)0); + return; + } + + int length = maxLength > 0 && value.Length > maxLength ? maxLength : value.Length; + int size = _uTF8Encoding.GetBytes(value, 0, length, _stringBuffer, 0); + + if (size >= StringBufferMaxLength) + { + Put((ushort)0); + return; + } + + Put(checked((ushort)(size + 1))); + Put(_stringBuffer, 0, size); + } + + public void Put(T obj) where T : INetSerializable + { + obj.Serialize(this); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs.meta new file mode 100644 index 0000000..448549c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb3b55fb59ddd9044b1fd56b8543053b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs new file mode 100644 index 0000000..007d520 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; + +namespace LiteNetLib.Utils +{ + public class NetPacketProcessor + { + private static class HashCache + { + public static readonly ulong Id; + + //FNV-1 64 bit hash + static HashCache() + { + ulong hash = 14695981039346656037UL; //offset + string typeName = typeof(T).ToString(); + for (var i = 0; i < typeName.Length; i++) + { + hash ^= typeName[i]; + hash *= 1099511628211UL; //prime + } + Id = hash; + } + } + + 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() + { + _netSerializer = new NetSerializer(); + } + + public NetPacketProcessor(int maxStringLength) + { + _netSerializer = new NetSerializer(maxStringLength); + } + + protected virtual ulong GetHash() + { + return HashCache.Id; + } + + protected virtual SubscribeDelegate GetCallbackFromData(NetDataReader reader) + { + ulong hash = reader.GetULong(); + if (!_callbacks.TryGetValue(hash, out var action)) + { + throw new ParseException("Undefined packet in NetDataReader"); + } + return action; + } + + protected virtual void WriteHash(NetDataWriter writer) + { + writer.Put(GetHash()); + } + + /// + /// Register nested property type + /// + /// INetSerializable structure + public void RegisterNestedType() where T : struct, INetSerializable + { + _netSerializer.RegisterNestedType(); + } + + /// + /// Register nested property type + /// + /// + /// + public void RegisterNestedType(Action writeDelegate, Func readDelegate) + { + _netSerializer.RegisterNestedType(writeDelegate, readDelegate); + } + + /// + /// Register nested property type + /// + /// INetSerializable class + public void RegisterNestedType(Func constructor) where T : class, INetSerializable + { + _netSerializer.RegisterNestedType(constructor); + } + + /// + /// Reads all available data from NetDataReader and calls OnReceive delegates + /// + /// NetDataReader with packets data + public void ReadAllPackets(NetDataReader reader) + { + while (reader.AvailableBytes > 0) + ReadPacket(reader); + } + + /// + /// Reads all available data from NetDataReader and calls OnReceive delegates + /// + /// NetDataReader with packets data + /// Argument that passed to OnReceivedEvent + /// Malformed packet + public void ReadAllPackets(NetDataReader reader, object userData) + { + while (reader.AvailableBytes > 0) + ReadPacket(reader, userData); + } + + /// + /// Reads one packet from NetDataReader and calls OnReceive delegate + /// + /// NetDataReader with packet + /// Malformed packet + public void ReadPacket(NetDataReader reader) + { + 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() + { + WriteHash(writer); + _netSerializer.Serialize(writer, packet); + } + + public void WriteNetSerializable(NetDataWriter writer, ref T packet) where T : INetSerializable + { + WriteHash(writer); + packet.Serialize(writer); + } + + /// + /// Reads one packet from NetDataReader and calls OnReceive delegate + /// + /// NetDataReader with packet + /// Argument that passed to OnReceivedEvent + /// Malformed packet + public void ReadPacket(NetDataReader reader, object userData) + { + GetCallbackFromData(reader)(reader, userData); + } + + /// + /// Register and subscribe to packet receive event + /// + /// 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() + { + _netSerializer.Register(); + _callbacks[GetHash()] = (reader, userData) => + { + var reference = packetConstructor(); + _netSerializer.Deserialize(reader, reference); + onReceive(reference); + }; + } + + /// + /// Register and subscribe to packet receive event (with userData) + /// + /// 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() + { + _netSerializer.Register(); + _callbacks[GetHash()] = (reader, userData) => + { + var reference = packetConstructor(); + _netSerializer.Deserialize(reader, reference); + onReceive(reference, (TUserData)userData); + }; + } + + /// + /// Register and subscribe to packet receive event + /// This method will overwrite last received packet class on receive (less garbage) + /// + /// 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() + { + _netSerializer.Register(); + var reference = new T(); + _callbacks[GetHash()] = (reader, userData) => + { + _netSerializer.Deserialize(reader, reference); + onReceive(reference); + }; + } + + /// + /// Register and subscribe to packet receive event + /// This method will overwrite last received packet class on receive (less garbage) + /// + /// 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() + { + _netSerializer.Register(); + var reference = new T(); + _callbacks[GetHash()] = (reader, userData) => + { + _netSerializer.Deserialize(reader, reference); + onReceive(reference, (TUserData)userData); + }; + } + + public void SubscribeNetSerializable( + Action onReceive, + Func packetConstructor) where T : INetSerializable + { + _callbacks[GetHash()] = (reader, userData) => + { + var pkt = packetConstructor(); + pkt.Deserialize(reader); + onReceive(pkt, (TUserData)userData); + }; + } + + public void SubscribeNetSerializable( + Action onReceive, + Func packetConstructor) where T : INetSerializable + { + _callbacks[GetHash()] = (reader, userData) => + { + var pkt = packetConstructor(); + pkt.Deserialize(reader); + onReceive(pkt); + }; + } + + public void SubscribeNetSerializable( + Action onReceive) where T : INetSerializable, new() + { + var reference = new T(); + _callbacks[GetHash()] = (reader, userData) => + { + reference.Deserialize(reader); + onReceive(reference, (TUserData)userData); + }; + } + + public void SubscribeNetSerializable( + Action onReceive) where T : INetSerializable, new() + { + var reference = new T(); + _callbacks[GetHash()] = (reader, userData) => + { + reference.Deserialize(reader); + onReceive(reference); + }; + } + + /// + /// Remove any subscriptions by type + /// + /// Packet type + /// true if remove is success + public bool RemoveSubscription() + { + return _callbacks.Remove(GetHash()); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs.meta new file mode 100644 index 0000000..e076011 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0d5a653362556943a36db010a601057 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs new file mode 100644 index 0000000..63f6cd6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs @@ -0,0 +1,738 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; + +namespace LiteNetLib.Utils +{ + public class InvalidTypeException : ArgumentException + { + public InvalidTypeException(string message) : base(message) { } + } + + public class ParseException : Exception + { + public ParseException(string message) : base(message) { } + } + + public class NetSerializer + { + private enum CallType + { + Basic, + Array, + List + } + + private abstract class FastCall + { + public CallType Type; + public virtual void Init(MethodInfo getMethod, MethodInfo setMethod, CallType type) { Type = type; } + public abstract void Read(T inf, NetDataReader r); + public abstract void Write(T inf, NetDataWriter w); + public abstract void ReadArray(T inf, NetDataReader r); + public abstract void WriteArray(T inf, NetDataWriter w); + public abstract void ReadList(T inf, NetDataReader r); + public abstract void WriteList(T inf, NetDataWriter w); + } + + private abstract class FastCallSpecific : FastCall + { + protected Func Getter; + protected Action Setter; + protected Func GetterArr; + protected Action SetterArr; + protected Func> GetterList; + protected Action> SetterList; + + public override void ReadArray(TClass inf, NetDataReader r) { throw new InvalidTypeException("Unsupported type: " + typeof(TProperty) + "[]"); } + public override void WriteArray(TClass inf, NetDataWriter w) { throw new InvalidTypeException("Unsupported type: " + typeof(TProperty) + "[]"); } + public override void ReadList(TClass inf, NetDataReader r) { throw new InvalidTypeException("Unsupported type: List<" + typeof(TProperty) + ">"); } + public override void WriteList(TClass inf, NetDataWriter w) { throw new InvalidTypeException("Unsupported type: List<" + typeof(TProperty) + ">"); } + + protected TProperty[] ReadArrayHelper(TClass inf, NetDataReader r) + { + ushort count = r.GetUShort(); + var arr = GetterArr(inf); + arr = arr == null || arr.Length != count ? new TProperty[count] : arr; + SetterArr(inf, arr); + return arr; + } + + protected TProperty[] WriteArrayHelper(TClass inf, NetDataWriter w) + { + var arr = GetterArr(inf); + w.Put((ushort)arr.Length); + return arr; + } + + protected List ReadListHelper(TClass inf, NetDataReader r, out int len) + { + len = r.GetUShort(); + var list = GetterList(inf); + if (list == null) + { + list = new List(len); + SetterList(inf, list); + } + return list; + } + + protected List WriteListHelper(TClass inf, NetDataWriter w, out int len) + { + var list = GetterList(inf); + if (list == null) + { + len = 0; + w.Put(0); + return null; + } + len = list.Count; + w.Put((ushort)len); + return list; + } + + public override void Init(MethodInfo getMethod, MethodInfo setMethod, CallType type) + { + base.Init(getMethod, setMethod, type); + switch (type) + { + case CallType.Array: + GetterArr = (Func)Delegate.CreateDelegate(typeof(Func), getMethod); + SetterArr = (Action)Delegate.CreateDelegate(typeof(Action), setMethod); + break; + case CallType.List: + GetterList = (Func>)Delegate.CreateDelegate(typeof(Func>), getMethod); + SetterList = (Action>)Delegate.CreateDelegate(typeof(Action>), setMethod); + break; + default: + Getter = (Func)Delegate.CreateDelegate(typeof(Func), getMethod); + Setter = (Action)Delegate.CreateDelegate(typeof(Action), setMethod); + break; + } + } + } + + private abstract class FastCallSpecificAuto : FastCallSpecific + { + protected abstract void ElementRead(NetDataReader r, out TProperty prop); + protected abstract void ElementWrite(NetDataWriter w, ref TProperty prop); + + public override void Read(TClass inf, NetDataReader r) + { + ElementRead(r, out var elem); + Setter(inf, elem); + } + + public override void Write(TClass inf, NetDataWriter w) + { + var elem = Getter(inf); + ElementWrite(w, ref elem); + } + + public override void ReadArray(TClass inf, NetDataReader r) + { + var arr = ReadArrayHelper(inf, r); + for (int i = 0; i < arr.Length; i++) + ElementRead(r, out arr[i]); + } + + public override void WriteArray(TClass inf, NetDataWriter w) + { + var arr = WriteArrayHelper(inf, w); + for (int i = 0; i < arr.Length; i++) + ElementWrite(w, ref arr[i]); + } + } + + private sealed class FastCallStatic : FastCallSpecific + { + private readonly Action _writer; + private readonly Func _reader; + + public FastCallStatic(Action write, Func read) + { + _writer = write; + _reader = read; + } + + public override void Read(TClass inf, NetDataReader r) { Setter(inf, _reader(r)); } + public override void Write(TClass inf, NetDataWriter w) { _writer(w, Getter(inf)); } + + public override void ReadList(TClass inf, NetDataReader r) + { + var list = ReadListHelper(inf, r, out int len); + int listCount = list.Count; + for (int i = 0; i < len; i++) + { + if (i < listCount) + list[i] = _reader(r); + else + list.Add(_reader(r)); + } + if (len < listCount) + list.RemoveRange(len, listCount - len); + } + + public override void WriteList(TClass inf, NetDataWriter w) + { + var list = WriteListHelper(inf, w, out int len); + for (int i = 0; i < len; i++) + _writer(w, list[i]); + } + + public override void ReadArray(TClass inf, NetDataReader r) + { + var arr = ReadArrayHelper(inf, r); + int len = arr.Length; + for (int i = 0; i < len; i++) + arr[i] = _reader(r); + } + + public override void WriteArray(TClass inf, NetDataWriter w) + { + var arr = WriteArrayHelper(inf, w); + int len = arr.Length; + for (int i = 0; i < len; i++) + _writer(w, arr[i]); + } + } + + private sealed class FastCallStruct : FastCallSpecific where TProperty : struct, INetSerializable + { + private TProperty _p; + + public override void Read(TClass inf, NetDataReader r) + { + _p.Deserialize(r); + Setter(inf, _p); + } + + public override void Write(TClass inf, NetDataWriter w) + { + _p = Getter(inf); + _p.Serialize(w); + } + + public override void ReadList(TClass inf, NetDataReader r) + { + var list = ReadListHelper(inf, r, out int len); + int listCount = list.Count; + for (int i = 0; i < len; i++) + { + var itm = default(TProperty); + itm.Deserialize(r); + if(i < listCount) + list[i] = itm; + else + list.Add(itm); + } + if (len < listCount) + list.RemoveRange(len, listCount - len); + } + + public override void WriteList(TClass inf, NetDataWriter w) + { + var list = WriteListHelper(inf, w, out int len); + for (int i = 0; i < len; i++) + list[i].Serialize(w); + } + + public override void ReadArray(TClass inf, NetDataReader r) + { + var arr = ReadArrayHelper(inf, r); + int len = arr.Length; + for (int i = 0; i < len; i++) + arr[i].Deserialize(r); + } + + public override void WriteArray(TClass inf, NetDataWriter w) + { + var arr = WriteArrayHelper(inf, w); + int len = arr.Length; + for (int i = 0; i < len; i++) + arr[i].Serialize(w); + } + } + + private sealed class FastCallClass : FastCallSpecific where TProperty : class, INetSerializable + { + private readonly Func _constructor; + public FastCallClass(Func constructor) { _constructor = constructor; } + + public override void Read(TClass inf, NetDataReader r) + { + var p = _constructor(); + p.Deserialize(r); + Setter(inf, p); + } + + public override void Write(TClass inf, NetDataWriter w) + { + var p = Getter(inf); + p?.Serialize(w); + } + + public override void ReadList(TClass inf, NetDataReader r) + { + var list = ReadListHelper(inf, r, out int len); + int listCount = list.Count; + for (int i = 0; i < len; i++) + { + if (i < listCount) + { + list[i].Deserialize(r); + } + else + { + var itm = _constructor(); + itm.Deserialize(r); + list.Add(itm); + } + } + if (len < listCount) + list.RemoveRange(len, listCount - len); + } + + public override void WriteList(TClass inf, NetDataWriter w) + { + var list = WriteListHelper(inf, w, out int len); + for (int i = 0; i < len; i++) + list[i].Serialize(w); + } + + public override void ReadArray(TClass inf, NetDataReader r) + { + var arr = ReadArrayHelper(inf, r); + int len = arr.Length; + for (int i = 0; i < len; i++) + { + arr[i] = _constructor(); + arr[i].Deserialize(r); + } + } + + public override void WriteArray(TClass inf, NetDataWriter w) + { + var arr = WriteArrayHelper(inf, w); + int len = arr.Length; + for (int i = 0; i < len; i++) + arr[i].Serialize(w); + } + } + + private class IntSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetInt()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetIntArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class UIntSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetUInt()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetUIntArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class ShortSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetShort()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetShortArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class UShortSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetUShort()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetUShortArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class LongSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetLong()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetLongArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class ULongSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetULong()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetULongArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class ByteSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetByte()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetBytesWithLength()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutBytesWithLength(GetterArr(inf)); } + } + + private class SByteSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetSByte()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetSBytesWithLength()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutSBytesWithLength(GetterArr(inf)); } + } + + private class FloatSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetFloat()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetFloatArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class DoubleSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetDouble()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetDoubleArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class BoolSerializer : FastCallSpecific + { + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetBool()); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf)); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetBoolArray()); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf)); } + } + + private class CharSerializer : FastCallSpecificAuto + { + protected override void ElementWrite(NetDataWriter w, ref char prop) { w.Put(prop); } + protected override void ElementRead(NetDataReader r, out char prop) { prop = r.GetChar(); } + } + + private class IPEndPointSerializer : FastCallSpecificAuto + { + protected override void ElementWrite(NetDataWriter w, ref IPEndPoint prop) { w.Put(prop); } + protected override void ElementRead(NetDataReader r, out IPEndPoint prop) { prop = r.GetNetEndPoint(); } + } + + private class StringSerializer : FastCallSpecific + { + private readonly int _maxLength; + public StringSerializer(int maxLength) { _maxLength = maxLength > 0 ? maxLength : short.MaxValue; } + public override void Read(T inf, NetDataReader r) { Setter(inf, r.GetString(_maxLength)); } + public override void Write(T inf, NetDataWriter w) { w.Put(Getter(inf), _maxLength); } + public override void ReadArray(T inf, NetDataReader r) { SetterArr(inf, r.GetStringArray(_maxLength)); } + public override void WriteArray(T inf, NetDataWriter w) { w.PutArray(GetterArr(inf), _maxLength); } + } + + private class EnumByteSerializer : FastCall + { + protected readonly PropertyInfo Property; + protected readonly Type PropertyType; + public EnumByteSerializer(PropertyInfo property, Type propertyType) + { + Property = property; + PropertyType = propertyType; + } + public override void Read(T inf, NetDataReader r) { Property.SetValue(inf, Enum.ToObject(PropertyType, r.GetByte()), null); } + public override void Write(T inf, NetDataWriter w) { w.Put((byte)Property.GetValue(inf, null)); } + public override void ReadArray(T inf, NetDataReader r) { throw new InvalidTypeException("Unsupported type: Enum[]"); } + public override void WriteArray(T inf, NetDataWriter w) { throw new InvalidTypeException("Unsupported type: Enum[]"); } + public override void ReadList(T inf, NetDataReader r) { throw new InvalidTypeException("Unsupported type: List"); } + public override void WriteList(T inf, NetDataWriter w) { throw new InvalidTypeException("Unsupported type: List"); } + } + + private class EnumIntSerializer : EnumByteSerializer + { + public EnumIntSerializer(PropertyInfo property, Type propertyType) : base(property, propertyType) { } + public override void Read(T inf, NetDataReader r) { Property.SetValue(inf, Enum.ToObject(PropertyType, r.GetInt()), null); } + public override void Write(T inf, NetDataWriter w) { w.Put((int)Property.GetValue(inf, null)); } + } + + private sealed class ClassInfo + { + public static ClassInfo Instance; + private readonly FastCall[] _serializers; + private readonly int _membersCount; + + public ClassInfo(List> serializers) + { + _membersCount = serializers.Count; + _serializers = serializers.ToArray(); + } + + public void Write(T obj, NetDataWriter writer) + { + for (int i = 0; i < _membersCount; i++) + { + var s = _serializers[i]; + if (s.Type == CallType.Basic) + s.Write(obj, writer); + else if (s.Type == CallType.Array) + s.WriteArray(obj, writer); + else + s.WriteList(obj, writer); + } + } + + public void Read(T obj, NetDataReader reader) + { + for (int i = 0; i < _membersCount; i++) + { + var s = _serializers[i]; + if (s.Type == CallType.Basic) + s.Read(obj, reader); + else if(s.Type == CallType.Array) + s.ReadArray(obj, reader); + else + s.ReadList(obj, reader); + } + } + } + + private abstract class CustomType + { + public abstract FastCall Get(); + } + + private sealed class CustomTypeStruct : CustomType where TProperty : struct, INetSerializable + { + public override FastCall Get() { return new FastCallStruct(); } + } + + private sealed class CustomTypeClass : CustomType where TProperty : class, INetSerializable + { + private readonly Func _constructor; + public CustomTypeClass(Func constructor) { _constructor = constructor; } + public override FastCall Get() { return new FastCallClass(_constructor); } + } + + private sealed class CustomTypeStatic : CustomType + { + private readonly Action _writer; + private readonly Func _reader; + public CustomTypeStatic(Action writer, Func reader) + { + _writer = writer; + _reader = reader; + } + public override FastCall Get() { return new FastCallStatic(_writer, _reader); } + } + + /// + /// Register custom property type + /// + /// INetSerializable structure + public void RegisterNestedType() where T : struct, INetSerializable + { + _registeredTypes.Add(typeof(T), new CustomTypeStruct()); + } + + /// + /// Register custom property type + /// + /// INetSerializable class + public void RegisterNestedType(Func constructor) where T : class, INetSerializable + { + _registeredTypes.Add(typeof(T), new CustomTypeClass(constructor)); + } + + /// + /// Register custom property type + /// + /// Any packet + /// custom type writer + /// custom type reader + public void RegisterNestedType(Action writer, Func reader) + { + _registeredTypes.Add(typeof(T), new CustomTypeStatic(writer, reader)); + } + + private NetDataWriter _writer; + private readonly int _maxStringLength; + private readonly Dictionary _registeredTypes = new Dictionary(); + + public NetSerializer() : this(0) + { + } + + public NetSerializer(int maxStringLength) + { + _maxStringLength = maxStringLength; + } + + private ClassInfo RegisterInternal() + { + if (ClassInfo.Instance != null) + return ClassInfo.Instance; + + Type t = typeof(T); + var props = t.GetProperties( + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.GetProperty | + BindingFlags.SetProperty); + var serializers = new List>(); + for (int i = 0; i < props.Length; i++) + { + var property = props[i]; + var propertyType = property.PropertyType; + + var elementType = propertyType.IsArray ? propertyType.GetElementType() : propertyType; + var callType = propertyType.IsArray ? CallType.Array : CallType.Basic; + + if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>)) + { + elementType = propertyType.GetGenericArguments()[0]; + callType = CallType.List; + } + + if (Attribute.IsDefined(property, typeof(IgnoreDataMemberAttribute))) + continue; + + var getMethod = property.GetGetMethod(); + var setMethod = property.GetSetMethod(); + if (getMethod == null || setMethod == null) + continue; + + FastCall serialzer = null; + if (propertyType.IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(propertyType); + if (underlyingType == typeof(byte)) + serialzer = new EnumByteSerializer(property, propertyType); + else if (underlyingType == typeof(int)) + serialzer = new EnumIntSerializer(property, propertyType); + else + throw new InvalidTypeException("Not supported enum underlying type: " + underlyingType.Name); + } + else if (elementType == typeof(string)) + serialzer = new StringSerializer(_maxStringLength); + else if (elementType == typeof(bool)) + serialzer = new BoolSerializer(); + else if (elementType == typeof(byte)) + serialzer = new ByteSerializer(); + else if (elementType == typeof(sbyte)) + serialzer = new SByteSerializer(); + else if (elementType == typeof(short)) + serialzer = new ShortSerializer(); + else if (elementType == typeof(ushort)) + serialzer = new UShortSerializer(); + else if (elementType == typeof(int)) + serialzer = new IntSerializer(); + else if (elementType == typeof(uint)) + serialzer = new UIntSerializer(); + else if (elementType == typeof(long)) + serialzer = new LongSerializer(); + else if (elementType == typeof(ulong)) + serialzer = new ULongSerializer(); + else if (elementType == typeof(float)) + serialzer = new FloatSerializer(); + else if (elementType == typeof(double)) + serialzer = new DoubleSerializer(); + else if (elementType == typeof(char)) + serialzer = new CharSerializer(); + else if (elementType == typeof(IPEndPoint)) + serialzer = new IPEndPointSerializer(); + else + { + _registeredTypes.TryGetValue(elementType, out var customType); + if (customType != null) + serialzer = customType.Get(); + } + + if (serialzer != null) + { + serialzer.Init(getMethod, setMethod, callType); + serializers.Add(serialzer); + } + else + { + throw new InvalidTypeException("Unknown property type: " + propertyType.FullName); + } + } + ClassInfo.Instance = new ClassInfo(serializers); + return ClassInfo.Instance; + } + + /// 's fields are not supported, or it has no fields + public void Register() + { + RegisterInternal(); + } + + /// + /// Reads packet with known type + /// + /// 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() + { + var info = RegisterInternal(); + var result = new T(); + try + { + info.Read(result, reader); + } + catch + { + return null; + } + return result; + } + + /// + /// Reads packet with known type (non alloc variant) + /// + /// NetDataReader with packet + /// 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() + { + var info = RegisterInternal(); + try + { + info.Read(target, reader); + } + catch + { + return false; + } + return true; + } + + /// + /// Serialize object to NetDataWriter (fast) + /// + /// 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() + { + RegisterInternal().Write(obj, writer); + } + + /// + /// Serialize object to byte array + /// + /// Object to serialize + /// byte array with serialized data + public byte[] Serialize(T obj) where T : class, new() + { + if (_writer == null) + _writer = new NetDataWriter(); + _writer.Reset(); + Serialize(_writer, obj); + return _writer.CopyData(); + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs.meta new file mode 100644 index 0000000..87dacc8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 503136cdfd845ea439d6eb1e7fcfa924 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs new file mode 100644 index 0000000..1ba5210 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs @@ -0,0 +1,423 @@ +using System; + +namespace LiteNetLib.Utils +{ + /// + /// Represents RFC4330 SNTP packet used for communication to and from a network time server. + /// + /// + /// + /// Most applications should just use the property. + /// + /// + /// The same data structure represents both request and reply packets. + /// Request and reply differ in which properties are set and to what values. + /// + /// + /// The only real property is . + /// All other properties read from and write to the underlying byte array + /// with the exception of , + /// which is not part of the packet on network and it is instead set locally after receiving the packet. + /// + /// + /// Copied from GuerrillaNtp project + /// with permission from Robert Vazan (@robertvazan) under MIT license, see https://github.com/RevenantX/LiteNetLib/pull/236 + /// + /// + public class NtpPacket + { + private static readonly DateTime Epoch = new DateTime(1900, 1, 1); + + /// + /// Gets RFC4330-encoded SNTP packet. + /// + /// + /// Byte array containing RFC4330-encoded SNTP packet. It is at least 48 bytes long. + /// + /// + /// This is the only real property. All other properties except + /// read from or write to this byte array. + /// + public byte[] Bytes { get; } + + /// + /// Gets the leap second indicator. + /// + /// + /// Leap second warning, if any. Special value + /// indicates unsynchronized server clock. + /// Default is . + /// + /// + /// Only servers fill in this property. Clients can consult this property for possible leap second warning. + /// + public NtpLeapIndicator LeapIndicator => (NtpLeapIndicator)((Bytes[0] & 0xC0) >> 6); + + /// + /// Gets or sets protocol version number. + /// + /// + /// SNTP protocol version. Default is 4, which is the latest version at the time of this writing. + /// + /// + /// In request packets, clients should leave this property at default value 4. + /// Servers usually reply with the same protocol version. + /// + public int VersionNumber + { + get => (Bytes[0] & 0x38) >> 3; + private set => Bytes[0] = (byte)((Bytes[0] & ~0x38) | value << 3); + } + + /// + /// Gets or sets SNTP packet mode, i.e. whether this is client or server packet. + /// + /// + /// SNTP packet mode. Default is in newly created packets. + /// Server reply should have this property set to . + /// + public NtpMode Mode + { + get => (NtpMode)(Bytes[0] & 0x07); + private set => Bytes[0] = (byte)((Bytes[0] & ~0x07) | (int)value); + } + + /// + /// Gets server's distance from the reference clock. + /// + /// + /// + /// Distance from the reference clock. This property is set only in server reply packets. + /// Servers connected directly to reference clock hardware set this property to 1. + /// Statum number is incremented by 1 on every hop down the NTP server hierarchy. + /// + /// + /// Special value 0 indicates that this packet is a Kiss-o'-Death message + /// with kiss code stored in . + /// + /// + public int Stratum => Bytes[1]; + + /// + /// Gets server's preferred polling interval. + /// + /// + /// Polling interval in log2 seconds, e.g. 4 stands for 16s and 17 means 131,072s. + /// + public int Poll => Bytes[2]; + + /// + /// Gets the precision of server clock. + /// + /// + /// Clock precision in log2 seconds, e.g. -20 for microsecond precision. + /// + public int Precision => (sbyte)Bytes[3]; + + /// + /// Gets the total round-trip delay from the server to the reference clock. + /// + /// + /// Round-trip delay to the reference clock. Normally a positive value smaller than one second. + /// + public TimeSpan RootDelay => GetTimeSpan32(4); + + /// + /// Gets the estimated error in time reported by the server. + /// + /// + /// Estimated error in time reported by the server. Normally a positive value smaller than one second. + /// + public TimeSpan RootDispersion => GetTimeSpan32(8); + + /// + /// Gets the ID of the time source used by the server or Kiss-o'-Death code sent by the server. + /// + /// + /// + /// ID of server's time source or Kiss-o'-Death code. + /// Purpose of this property depends on value of property. + /// + /// + /// Stratum 1 servers write here one of several special values that describe the kind of hardware clock they use. + /// + /// + /// Stratum 2 and lower servers set this property to IPv4 address of their upstream server. + /// If upstream server has IPv6 address, the address is hashed, because it doesn't fit in this property. + /// + /// + /// When server sets to special value 0, + /// this property contains so called kiss code that instructs the client to stop querying the server. + /// + /// + public uint ReferenceId => GetUInt32BE(12); + + /// + /// Gets or sets the time when the server clock was last set or corrected. + /// + /// + /// Time when the server clock was last set or corrected or null when not specified. + /// + /// + /// This Property is usually set only by servers. It usually lags server's current time by several minutes, + /// so don't use this property for time synchronization. + /// + public DateTime? ReferenceTimestamp => GetDateTime64(16); + + /// + /// Gets or sets the time when the client sent its request. + /// + /// + /// This property is null in request packets. + /// In reply packets, it is the time when the client sent its request. + /// Servers copy this value from + /// that they find in received request packet. + /// + /// + /// + public DateTime? OriginTimestamp => GetDateTime64(24); + + /// + /// Gets or sets the time when the request was received by the server. + /// + /// + /// This property is null in request packets. + /// In reply packets, it is the time when the server received client request. + /// + /// + /// + public DateTime? ReceiveTimestamp => GetDateTime64(32); + + /// + /// Gets or sets the time when the packet was sent. + /// + /// + /// Time when the packet was sent. It should never be null. + /// Default value is . + /// + /// + /// This property must be set by both clients and servers. + /// + /// + /// + public DateTime? TransmitTimestamp { get { return GetDateTime64(40); } private set { SetDateTime64(40, value); } } + + /// + /// Gets or sets the time of reception of response SNTP packet on the client. + /// + /// + /// Time of reception of response SNTP packet on the client. It is null in request packets. + /// + /// + /// This property is not part of the protocol and has to be set when reply packet is received. + /// + /// + /// + public DateTime? DestinationTimestamp { get; private set; } + + /// + /// Gets the round-trip time to the server. + /// + /// + /// Time the request spent traveling to the server plus the time the reply spent traveling back. + /// This is calculated from timestamps in the packet as (t1 - t0) + (t3 - t2) + /// where t0 is , + /// t1 is , + /// t2 is , + /// and t3 is . + /// This property throws an exception in request packets. + /// + public TimeSpan RoundTripTime + { + get + { + CheckTimestamps(); + return (ReceiveTimestamp.Value - OriginTimestamp.Value) + (DestinationTimestamp.Value - TransmitTimestamp.Value); + } + } + + /// + /// Gets the offset that should be added to local time to synchronize it with server time. + /// + /// + /// Time difference between server and client. It should be added to local time to get server time. + /// It is calculated from timestamps in the packet as 0.5 * ((t1 - t0) - (t3 - t2)) + /// where t0 is , + /// t1 is , + /// t2 is , + /// and t3 is . + /// This property throws an exception in request packets. + /// + public TimeSpan CorrectionOffset + { + get + { + CheckTimestamps(); + return TimeSpan.FromTicks(((ReceiveTimestamp.Value - OriginTimestamp.Value) - (DestinationTimestamp.Value - TransmitTimestamp.Value)).Ticks / 2); + } + } + + /// + /// Initializes default request packet. + /// + /// + /// Properties and + /// are set appropriately for request packet. Property + /// is set to . + /// + public NtpPacket() : this(new byte[48]) + { + Mode = NtpMode.Client; + VersionNumber = 4; + TransmitTimestamp = DateTime.UtcNow; + } + + /// + /// Initializes packet from received data. + /// + internal NtpPacket(byte[] bytes) + { + if (bytes.Length < 48) + throw new ArgumentException("SNTP reply packet must be at least 48 bytes long.", "bytes"); + Bytes = bytes; + } + + /// + /// Initializes packet from data received from a server. + /// + /// Data received from the server. + /// Utc time of reception of response SNTP packet on the client. + /// + public static NtpPacket FromServerResponse(byte[] bytes, DateTime destinationTimestamp) + { + return new NtpPacket(bytes) { DestinationTimestamp = destinationTimestamp }; + } + + internal void ValidateRequest() + { + if (Mode != NtpMode.Client) + throw new InvalidOperationException("This is not a request SNTP packet."); + if (VersionNumber == 0) + throw new InvalidOperationException("Protocol version of the request is not specified."); + if (TransmitTimestamp == null) + throw new InvalidOperationException("TransmitTimestamp must be set in request packet."); + } + + internal void ValidateReply() + { + if (Mode != NtpMode.Server) + throw new InvalidOperationException("This is not a reply SNTP packet."); + if (VersionNumber == 0) + throw new InvalidOperationException("Protocol version of the reply is not specified."); + if (Stratum == 0) + throw new InvalidOperationException(string.Format("Received Kiss-o'-Death SNTP packet with code 0x{0:x}.", ReferenceId)); + if (LeapIndicator == NtpLeapIndicator.AlarmCondition) + throw new InvalidOperationException("SNTP server has unsynchronized clock."); + CheckTimestamps(); + } + + private void CheckTimestamps() + { + if (OriginTimestamp == null) + throw new InvalidOperationException("Origin timestamp is missing."); + if (ReceiveTimestamp == null) + throw new InvalidOperationException("Receive timestamp is missing."); + if (TransmitTimestamp == null) + throw new InvalidOperationException("Transmit timestamp is missing."); + if (DestinationTimestamp == null) + throw new InvalidOperationException("Destination timestamp is missing."); + } + + private DateTime? GetDateTime64(int offset) + { + var field = GetUInt64BE(offset); + if (field == 0) + return null; + return new DateTime(Epoch.Ticks + Convert.ToInt64(field * (1.0 / (1L << 32) * 10000000.0))); + } + + private void SetDateTime64(int offset, DateTime? value) + { + SetUInt64BE(offset, value == null ? 0 : Convert.ToUInt64((value.Value.Ticks - Epoch.Ticks) * (0.0000001 * (1L << 32)))); + } + + private TimeSpan GetTimeSpan32(int offset) + { + return TimeSpan.FromSeconds(GetInt32BE(offset) / (double)(1 << 16)); + } + + private ulong GetUInt64BE(int offset) + { + return SwapEndianness(BitConverter.ToUInt64(Bytes, offset)); + } + + private void SetUInt64BE(int offset, ulong value) + { + FastBitConverter.GetBytes(Bytes, offset, SwapEndianness(value)); + } + + private int GetInt32BE(int offset) + { + return (int)GetUInt32BE(offset); + } + + private uint GetUInt32BE(int offset) + { + return SwapEndianness(BitConverter.ToUInt32(Bytes, offset)); + } + + private static uint SwapEndianness(uint x) + { + return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24); + } + + private static ulong SwapEndianness(ulong x) + { + return ((ulong)SwapEndianness((uint)x) << 32) | SwapEndianness((uint)(x >> 32)); + } + } + + /// + /// Represents leap second warning from the server that instructs the client to add or remove leap second. + /// + /// + public enum NtpLeapIndicator + { + /// + /// No leap second warning. No action required. + /// + NoWarning, + + /// + /// Warns the client that the last minute of the current day has 61 seconds. + /// + LastMinuteHas61Seconds, + + /// + /// Warns the client that the last minute of the current day has 59 seconds. + /// + LastMinuteHas59Seconds, + + /// + /// Special value indicating that the server clock is unsynchronized and the returned time is unreliable. + /// + AlarmCondition + } + + /// + /// Describes SNTP packet mode, i.e. client or server. + /// + /// + public enum NtpMode + { + /// + /// Identifies client-to-server SNTP packet. + /// + Client = 3, + + /// + /// Identifies server-to-client SNTP packet. + /// + Server = 4, + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs.meta new file mode 100644 index 0000000..fdbbe00 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpPacket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: daf31cf4ab8132943b2c8ca301fc919a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs new file mode 100644 index 0000000..bd7f74f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs @@ -0,0 +1,42 @@ +using System.Net; +using System.Net.Sockets; + +namespace LiteNetLib.Utils +{ + internal sealed class NtpRequest + { + private const int ResendTimer = 1000; + private const int KillTimer = 10000; + public const int DefaultPort = 123; + private readonly IPEndPoint _ntpEndPoint; + private int _resendTime = ResendTimer; + private int _killTime = 0; + + public NtpRequest(IPEndPoint endPoint) + { + _ntpEndPoint = endPoint; + } + + public bool NeedToKill => _killTime >= KillTimer; + + public bool Send(Socket socket, int time) + { + _resendTime += time; + _killTime += time; + if (_resendTime < ResendTimer) + { + return false; + } + var packet = new NtpPacket(); + try + { + int sendCount = socket.SendTo(packet.Bytes, 0, packet.Bytes.Length, SocketFlags.None, _ntpEndPoint); + return sendCount == packet.Bytes.Length; + } + catch + { + return false; + } + } + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs.meta new file mode 100644 index 0000000..aa80855 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NtpRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3fa3bfbb02dd944e939070e3cf0638c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs new file mode 100644 index 0000000..2497e8f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs @@ -0,0 +1,509 @@ +using FishNet.Managing; +using FishNet.Managing.Logging; +using FishNet.Managing.Transporting; +using LiteNetLib; +using LiteNetLib.Layers; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Transporting.Tugboat +{ + [DisallowMultipleComponent] + [AddComponentMenu("FishNet/Transport/Tugboat")] + public class Tugboat : Transport + { + + #region Serialized. + [Header("Channels")] + /// + /// Maximum transmission unit for the unreliable channel. + /// + [Tooltip("Maximum transmission unit for the unreliable channel.")] + [Range(MINIMUM_UDP_MTU, MAXIMUM_UDP_MTU)] + [SerializeField] + private int _unreliableMTU = 1023; + + [Header("Server")] + /// + /// IPv4 address to bind server to. + /// + [Tooltip("IPv4 Address to bind server to.")] + [SerializeField] + private string _ipv4BindAddress; + /// + /// IPv6 address to bind server to. + /// + [Tooltip("IPv6 Address to bind server to.")] + [SerializeField] + private string _ipv6BindAddress; + /// + /// Port to use. + /// + [Tooltip("Port to use.")] + [SerializeField] + private ushort _port = 7770; + /// + /// Maximum number of players which may be connected at once. + /// + [Tooltip("Maximum number of players which may be connected at once.")] + [Range(1, 9999)] + [SerializeField] + private int _maximumClients = 4095; + + + [Header("Client")] + /// + /// Address to connect. + /// + [Tooltip("Address to connect.")] + [SerializeField] + private string _clientAddress = "localhost"; + + [Header("Misc")] + /// + /// How long in seconds until either the server or client socket must go without data before being timed out. Use 0f to disable timing out. + /// + [Tooltip("How long in seconds until either the server or client socket must go without data before being timed out. Use 0f to disable timing out.")] + [Range(0, MAX_TIMEOUT_SECONDS)] + [SerializeField] + private ushort _timeout = 15; + #endregion + + #region Private. + /// + /// PacketLayer to use with LiteNetLib. + /// + private PacketLayerBase _packetLayer; + /// + /// Server socket and handler. + /// + private Server.ServerSocket _server = new Server.ServerSocket(); + /// + /// Client socket and handler. + /// + private Client.ClientSocket _client = new Client.ClientSocket(); + #endregion + + #region Const. + private const ushort MAX_TIMEOUT_SECONDS = 1800; + /// + /// Minimum UDP packet size allowed. + /// + private const int MINIMUM_UDP_MTU = 576; + /// + /// Maximum UDP packet size allowed. + /// + private const int MAXIMUM_UDP_MTU = 1023; + #endregion + + #region Initialization and unity. + public override void Initialize(NetworkManager networkManager, int transportIndex) + { + base.Initialize(networkManager, transportIndex); + } + + protected void OnDestroy() + { + Shutdown(); + } + #endregion + + #region ConnectionStates. + /// + /// Gets the address of a remote connection Id. + /// + /// + /// + public override string GetConnectionAddress(int connectionId) + { + return _server.GetConnectionAddress(connectionId); + } + /// + /// 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. + /// + /// True if getting ConnectionState for the server. + public override LocalConnectionState GetConnectionState(bool server) + { + if (server) + return _server.GetConnectionState(); + else + return _client.GetConnectionState(); + } + /// + /// 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) + { + OnClientConnectionState?.Invoke(connectionStateArgs); + } + /// + /// Handles a ConnectionStateArgs for the local server. + /// + /// + public override void HandleServerConnectionState(ServerConnectionStateArgs connectionStateArgs) + { + OnServerConnectionState?.Invoke(connectionStateArgs); + UpdateTimeout(); + } + /// + /// Handles a ConnectionStateArgs for a remote client. + /// + /// + public override void HandleRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs) + { + 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) + { + if (server) + _server.IterateIncoming(); + else + _client.IterateIncoming(); + } + + /// + /// Processes data to be sent by the socket. + /// + /// True to process data received on the server. + public override void IterateOutgoing(bool server) + { + if (server) + _server.IterateOutgoing(); + else + _client.IterateOutgoing(); + } + #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. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void SendToServer(byte channelId, ArraySegment segment) + { + SanitizeChannel(ref channelId); + _client.SendToServer(channelId, segment); + } + /// + /// Sends data to a client. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void SendToClient(byte channelId, ArraySegment segment, int connectionId) + { + SanitizeChannel(ref channelId); + _server.SendToClient(channelId, segment, connectionId); + } + #endregion + + #region Configuration. + /// + /// Sets which PacketLayer to use with LiteNetLib. + /// + /// + public void SetPacketLayer(PacketLayerBase packetLayer) + { + _packetLayer = packetLayer; + if (GetConnectionState(true) != LocalConnectionState.Stopped) + base.NetworkManager.LogWarning("PacketLayer is set but will not be applied until the server stops."); + if (GetConnectionState(false) != LocalConnectionState.Stopped) + base.NetworkManager.LogWarning("PacketLayer is set but will not be applied until the client stops."); + + _server.Initialize(this, _unreliableMTU, _packetLayer); + _client.Initialize(this, _unreliableMTU, _packetLayer); + } + /// + /// How long in seconds until either the server or client socket must go without data before being timed out. + /// + /// True to get the timeout for the server socket, false for the client socket. + /// + public override float GetTimeout(bool asServer) + { + //Server and client uses the same timeout. + return (float)_timeout; + } + /// + /// Sets how long in seconds until either the server or client socket must go without data before being timed out. + /// + /// True to set the timeout for the server socket, false for the client socket. + public override void SetTimeout(float value, bool asServer) + { + _timeout = (ushort)value; + } + /// + /// 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 _server.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. + /// + /// + public override void SetMaximumClients(int value) + { + if (_server.GetConnectionState() != LocalConnectionState.Stopped) + { + if (base.NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Cannot set maximum clients when server is running."); + } + else + { + _maximumClients = value; + } + } + /// + /// Sets which address the client will connect to. + /// + /// + public override void SetClientAddress(string address) + { + _clientAddress = address; + } + /// + /// Gets which address the client will connect to. + /// + public override string GetClientAddress() + { + return _clientAddress; + } + + /// + /// Sets which address the server will bind to. + /// + /// + public override void SetServerBindAddress(string address, IPAddressType addressType) + { + if (addressType == IPAddressType.IPv4) + _ipv4BindAddress = address; + else + _ipv6BindAddress = address; + } + /// + /// Gets which address the server will bind to. + /// + /// + public override string GetServerBindAddress(IPAddressType addressType) + { + if (addressType == IPAddressType.IPv4) + return _ipv4BindAddress; + else + return _ipv6BindAddress; + } + /// + /// Sets which port to use. + /// + /// + public override void SetPort(ushort port) + { + _port = port; + } + /// + /// Gets which port to use. + /// + /// + public override ushort GetPort() + { + return _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(_clientAddress); + } + + /// + /// 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 stop the client socket. The technique used to accomplish immediate disconnects may vary depending on the transport. + /// When not using immediate disconnects it's recommended to perform disconnects using the ServerManager rather than accessing the transport directly. + /// + public override bool StopConnection(int connectionId, bool immediately) + { + return _server.StopConnection(connectionId); + } + + /// + /// Stops both client and server. + /// + public override void Shutdown() + { + //Stops client then server connections. + StopConnection(false); + StopConnection(true); + } + + #region Privates. + /// + /// Starts server. + /// + private bool StartServer() + { + _server.Initialize(this, _unreliableMTU, _packetLayer); + UpdateTimeout(); + return _server.StartConnection(_port, _maximumClients, _ipv4BindAddress, _ipv6BindAddress); + } + + /// + /// Stops server. + /// + private bool StopServer() + { + return _server.StopConnection(); + } + + /// + /// Starts the client. + /// + /// + private bool StartClient(string address) + { + _client.Initialize(this, _unreliableMTU, _packetLayer); + UpdateTimeout(); + return _client.StartConnection(address, _port); + } + + /// + /// Updates clients timeout values. + /// + private void UpdateTimeout() + { + //If server is running set timeout to max. This is for host only. + //int timeout = (GetConnectionState(true) != LocalConnectionState.Stopped) ? MAX_TIMEOUT_SECONDS : _timeout; + int timeout = (Application.isEditor) ? MAX_TIMEOUT_SECONDS : _timeout; + _client.UpdateTimeout(timeout); + _server.UpdateTimeout(timeout); + } + /// + /// Stops the client. + /// + private bool StopClient() + { + return _client.StopConnection(); + } + #endregion + #endregion + + #region Channels. + /// + /// If channelId is invalid then channelId becomes forced to reliable. + /// + /// + private void SanitizeChannel(ref byte channelId) + { + if (channelId < 0 || channelId >= TransportManager.CHANNEL_COUNT) + { + if (NetworkManager.CanLog(LoggingType.Warning)) + Debug.LogWarning($"Channel of {channelId} is out of range of supported channels. Channel will be defaulted to reliable."); + channelId = 0; + } + } + /// + /// 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 _unreliableMTU; + } + #endregion + + #region Editor. +#if UNITY_EDITOR + private void OnValidate() + { + if (_unreliableMTU < 0) + _unreliableMTU = MINIMUM_UDP_MTU; + else if (_unreliableMTU > MAXIMUM_UDP_MTU) + _unreliableMTU = MAXIMUM_UDP_MTU; + } +#endif + #endregion + } +} diff --git a/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs.meta b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs.meta new file mode 100644 index 0000000..cb42e47 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Tugboat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f48f002b825cbd45a19bd96d90f9edb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility.meta b/UnityProject/Assets/FishNet/Runtime/Utility.meta new file mode 100644 index 0000000..8cca6c1 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b01cb2614bcfb9249b6c78abcf482943 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs b/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs new file mode 100644 index 0000000..1efa14b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs @@ -0,0 +1,64 @@ +using FishNet.Utility.Constant; +using System.Runtime.CompilerServices; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + + + +namespace FishNet.Utility +{ +#if UNITY_EDITOR + [InitializeOnLoad] +#endif + public static class ApplicationState + { + +#if !UNITY_EDITOR + /// + /// True if application is quitting. + /// + private static bool _isQuitting; +#endif + static ApplicationState() + { +#if !UNITY_EDITOR + _isQuitting = false; +#endif + Application.quitting -= Application_quitting; + Application.quitting += Application_quitting; + } + + private static void Application_quitting() + { +#if !UNITY_EDITOR + _isQuitting = true; +#endif + } + + public static bool IsQuitting() + { +#if UNITY_EDITOR + if (!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying) + return true; + else + return false; +#else + return _isQuitting; +#endif + } + + public static bool IsPlaying() + { +#if UNITY_EDITOR + return EditorApplication.isPlaying; +#else + return Application.isPlaying; +#endif + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs.meta new file mode 100644 index 0000000..7861977 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/ApplicationState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54eb82a57a65e8548b57f5ca2a62bb76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs new file mode 100644 index 0000000..f9019dc --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs @@ -0,0 +1,11 @@ +namespace FishNet.Utility.Constant +{ + internal static class UtilityConstants + { + public const string CODEGEN_ASSEMBLY_NAME = "Unity.FishNet.CodeGen"; + public const string GENERATED_ASSEMBLY_NAME = "FishNet.Generated"; + public const string TEST_ASSEMBLY_NAME = "FishNet.Test"; + public const string RUNTIME_ASSEMBLY_NAME = "FishNet.Runtime"; + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs.meta new file mode 100644 index 0000000..ef98347 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Constants.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f2a3c23b44e4ef4e9783ef53ec0d5da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs b/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs new file mode 100644 index 0000000..4c0118c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +namespace FishNet.Utility +{ + + + public class DDOLFinder : MonoBehaviour + { + #region Public. + /// + /// Singleton instance of this class. + /// + public static DDOLFinder Instance { get; private set; } + #endregion + + private void Awake() + { + FirstInitialize(); + } + + /// + /// Initializes this script for use. Should only be completed once. + /// + private void FirstInitialize() + { + if (Instance != null && Instance != this) + { + Debug.LogError("Multiple DDOL scripts found. There should be only one."); + return; + } + else + { + Instance = this; + gameObject.name = "DDOLFinder"; + DontDestroyOnLoad(gameObject); + } + } + + /// + /// Returns the current DDOL or creates one if not yet created. + /// + public static DDOLFinder GetDDOL() + { + //Not yet made. + if (Instance == null) + { + GameObject obj = new GameObject(); + DDOLFinder ddol = obj.AddComponent(); + return ddol; + } + //Already made. + else + { + return Instance; + } + } + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs.meta new file mode 100644 index 0000000..bf2dcdb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/DDOLFinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47bed61fc24f71942a7437612621bbfd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Editor.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Editor.meta new file mode 100644 index 0000000..3d5a891 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66122940cd5d35e49908ec08d1daf7db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs new file mode 100644 index 0000000..80edf9a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs @@ -0,0 +1 @@ +//remove on 2023/01/01 \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs.meta new file mode 100644 index 0000000..f73e1f7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/MiscMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49475a95daed9f84d86f058997eb4157 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs new file mode 100644 index 0000000..147a9b4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Utility.Editing +{ + /* Source https://forum.unity.com/threads/how-to-link-scenes-in-the-inspector.383140/ */ + + [CustomPropertyDrawer(typeof(SceneAttribute))] + public class SceneDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType == SerializedPropertyType.String) + { + SceneAsset sceneObject = AssetDatabase.LoadAssetAtPath(property.stringValue); + + if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue)) + { + // try to load it from the build settings for legacy compatibility + sceneObject = GetBuildSettingsSceneObject(property.stringValue); + } + if (sceneObject == null && !string.IsNullOrEmpty(property.stringValue)) + { + Debug.Log($"Could not find scene {property.stringValue} in {property.propertyPath}, assign the proper scenes in your NetworkManager"); + } + SceneAsset scene = (SceneAsset)EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true); + + property.stringValue = AssetDatabase.GetAssetPath(scene); + } + else + { + EditorGUI.LabelField(position, label.text, "Use [Scene] with strings."); + } + } + + protected SceneAsset GetBuildSettingsSceneObject(string sceneName) + { + foreach (EditorBuildSettingsScene buildScene in EditorBuildSettings.scenes) + { + SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath(buildScene.path); + if (sceneAsset != null && sceneAsset.name == sceneName) + { + return sceneAsset; + } + } + return null; + } + } +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs.meta new file mode 100644 index 0000000..8f3c47d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Editor/SceneDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b2c813205b39ed46953611f7a5659fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension.meta new file mode 100644 index 0000000..bb462bb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f30057a48bb0104d8a7813443607804 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs new file mode 100644 index 0000000..f1c2ae2 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace FishNet.Utility.Extension +{ + public static class CollectionFN + { + /// + /// Random for shuffling. + /// + private static Random _random = new Random(); + + /// + /// Shuffle based on Fisher-Yates shuffle. + /// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + /// https://stackoverflow.com/questions/273313/randomize-a-listt + /// + public static void Shuffle(this IList lst) + { + int n = lst.Count; + while (n > 1) + { + n--; + int k = _random.Next(n + 1); + T value = lst[k]; + lst[k] = lst[n]; + lst[n] = value; + } + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs.meta new file mode 100644 index 0000000..0fa0ef3 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Collection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a6539089deb687469d1abdc1b8964a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs new file mode 100644 index 0000000..4f9a5f4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs @@ -0,0 +1,35 @@ +using FishNet.Documenting; +using System.Collections.Generic; + +namespace FishNet.Utility.Extension +{ + [APIExclude] + public static class DictionaryFN + { + + /// + /// Uses a hacky way to TryGetValue on a dictionary when using IL2CPP and on mobile. + /// This is to support older devices that don't properly handle IL2CPP builds. + /// + public static bool TryGetValueIL2CPP(this IDictionary dict, TKey key, out TValue value) + { +#if ENABLE_IL2CPP && UNITY_IOS || UNITY_ANDROID + if (dict.ContainsKey(key)) + { + value = dict[key]; + return true; + } + else + { + value = default; + return false; + } +#else + return dict.TryGetValue(key, out value); +#endif + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs.meta new file mode 100644 index 0000000..67297e5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Dictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d286695e7464ce943bc321215aaa2ee1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs new file mode 100644 index 0000000..f2fa102 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs @@ -0,0 +1,31 @@ +using System; + +namespace FishNet.Utility.Extension +{ + public static class EnumFN + { + + /// + /// Returns the highest numeric value for T. + /// + internal static int GetHighestValue() + { + Type enumType = typeof(T); + /* Brute force enum values. + * Linq Last/Max lookup throws for IL2CPP. */ + int highestValue = 0; + Array pidValues = Enum.GetValues(enumType); + foreach (T pid in pidValues) + { + object obj = Enum.Parse(enumType, pid.ToString()); + int value = Convert.ToInt32(obj); + highestValue = Math.Max(highestValue, value); + } + + return highestValue; + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs.meta new file mode 100644 index 0000000..d4b39d4 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Enum.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f58b410f20b8e694aa852d2ea5240626 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs new file mode 100644 index 0000000..84d97e6 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs @@ -0,0 +1,34 @@ +namespace FishNet.Utility.Extension +{ + + public static class MathFN + { + + /// + /// Returns a clamped SBytte. + /// + public static sbyte ClampSByte(long value, sbyte min, sbyte max) + { + if (value < min) + return min; + else if (value > max) + return max; + else + return (sbyte)value; + } + + /// + /// Returns a clamped double. + /// + public static double ClampDouble(double value, double min, double max) + { + if (value < min) + return min; + else if (value > max) + return max; + else + return value; + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs.meta new file mode 100644 index 0000000..2df9023 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Math.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: feb978e97a6aa6b4cbb99481d925c00c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs new file mode 100644 index 0000000..5efb900 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs @@ -0,0 +1,28 @@ +using FishNet.Connection; +using FishNet.Object; +using UnityEngine; + +namespace FishNet.Utility.Extension +{ + + public static class ObjectFN + { + /// + /// Spawns an object over the network using InstanceFinder. Only call from the server. + /// + public static void Spawn(this NetworkObject nob, NetworkConnection owner = null) + { + InstanceFinder.ServerManager.Spawn(nob, owner); + } + /// + /// Spawns an object over the network using InstanceFinder. Only call from the server. + /// + public static void Spawn(this GameObject go, NetworkConnection owner = null) + { + InstanceFinder.ServerManager.Spawn(go, owner); + } + + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs.meta new file mode 100644 index 0000000..6d573f8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Object.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d1cdee4c45e73a4fa9adba1177483ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs new file mode 100644 index 0000000..77257cb --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs @@ -0,0 +1,44 @@ +using FishNet.Documenting; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Utility.Extension +{ + [APIExclude] + public static class QuaterionFN + { + + /// + /// Returns if two quaternions match. + /// + /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return a match even when not true due to error tolerance. + /// + public static bool Matches(this Quaternion a, Quaternion b, bool precise = false) + { + if (!precise) + return (a == b); + else + return (a.w == b.w && a.x == b.x && a.y == b.y && a.z == b.z); + } + + /// + /// Returns the angle between two quaterions. + /// + /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference. + /// + public static float Angle(this Quaternion a, Quaternion b, bool precise = false) + { + if (precise) + { + return Quaternion.Angle(a, b); + } + else + { + //This is run Unitys implementation without the error tolerance. + float dot = (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w); + return (Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1f)) * 2f * 57.29578f); + } + } + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs.meta new file mode 100644 index 0000000..4bdf137 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Quaternion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b8122e8a7592784896b4173707188ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs new file mode 100644 index 0000000..1ea499b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs @@ -0,0 +1,76 @@ +using FishNet.Object; +using FishNet.Utility.Performance; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace FishNet.Utility.Extension +{ + + public static class SceneFN + { + #region Private. + + /// + /// Used for performance gains when getting objects. + /// + private static List _gameObjectList = new List(); + /// + /// List for NetworkObjects. + /// + private static List _networkObjectListA = new List(); + /// + /// List for NetworkObjects. + /// + private static List _networkObjectListB = new List(); + #endregion + + /// + /// Gets all NetworkObjects in a scene. + /// + /// Scene to get objects in. + /// True to only return the first NetworkObject within an object chain. False will return nested NetworkObjects. + /// ListCache of found NetworkObjects. + /// + public static void GetSceneNetworkObjects(Scene s, bool firstOnly, out ListCache nobCache) + { + nobCache = ListCaches.GetNetworkObjectCache(); + //Iterate all root objects for the scene. + s.GetRootGameObjects(_gameObjectList); + foreach (GameObject go in _gameObjectList) + { + + //Get NetworkObjects within children of each root. + go.GetComponentsInChildren(true, _networkObjectListA); + //If network objects are found. + if (_networkObjectListA.Count > 0) + { + //Add only the first networkobject + if (firstOnly) + { + /* The easiest way to see if a nob is nested is to + * get nobs in parent and if the count is greater than 1, then + * it is nested. The technique used here isn't exactly fast but + * it will only occur during scene loads, so I'm trading off speed + * for effort and readability. */ + foreach (NetworkObject nob in _networkObjectListA) + { + nob.GetComponentsInParent(true, _networkObjectListB); + //No extra nobs, only this one. + if (_networkObjectListB.Count == 1) + nobCache.AddValue(nob); + } + } + //Not first only, add them all. + else + { + nobCache.AddValues(_networkObjectListA); + } + + } + } + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs.meta new file mode 100644 index 0000000..e079485 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Scene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a02f3d03f737e304e9854278f4e9211d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs new file mode 100644 index 0000000..65c2330 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs @@ -0,0 +1,2 @@ +//This file is no longer needed. +//Remove on 2023/01/01. \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs.meta new file mode 100644 index 0000000..96890af --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0290072767907ed46bf842ddff98770e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs new file mode 100644 index 0000000..2cc512c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs @@ -0,0 +1,30 @@ +using FishNet.Documenting; +using UnityEngine; + +namespace FishNet.Utility.Extension +{ + [APIExclude] + public static class TransformFN + { + + /// + /// Sets local position and rotation for a transform. + /// + public static void SetLocalPositionAndRotation(this Transform t, Vector3 pos, Quaternion rot) + { + t.localPosition = pos; + t.localRotation = rot; + } + /// + /// Sets local position, rotation, and scale for a transform. + /// + public static void SetLocalPositionRotationAndScale(this Transform t, Vector3 pos, Quaternion rot, Vector3 scale) + { + t.localPosition = pos; + t.localRotation = rot; + t.localScale = scale; + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs.meta new file mode 100644 index 0000000..bdee36b --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d311fc1bf09b9e4fbc5a17a9c50ab0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Performance.meta new file mode 100644 index 0000000..d114a4d --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c297487b42ef1b640a26b7c41fef6e27 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs new file mode 100644 index 0000000..235920a --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +namespace FishNet.Utility.Performance +{ + + /// + /// Retrieves and stores byte arrays using a pooling system. + /// + public static class ByteArrayPool + { + /// + /// Stored byte arrays. + /// + private static Queue _byteArrays = new Queue(); + + /// + /// Returns a byte array which will be of at lesat minimum length. The returns array must manually be stored. + /// + public static byte[] Retrieve(int minimumLength) + { + byte[] result = null; + + if (_byteArrays.Count > 0) + result = _byteArrays.Dequeue(); + + int doubleMinimumLength = (minimumLength * 2); + if (result == null) + result = new byte[doubleMinimumLength]; + else if (result.Length < minimumLength) + Array.Resize(ref result, doubleMinimumLength); + + return result; + } + + /// + /// Stores a byte array for re-use. + /// + public static void Store(byte[] buffer) + { + /* Holy cow that's a lot of buffered + * buffers. This wouldn't happen under normal + * circumstances but if the user is stress + * testing connections in one executable perhaps. */ + if (_byteArrays.Count > 300) + return; + _byteArrays.Enqueue(buffer); + } + + } + + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs.meta new file mode 100644 index 0000000..4c5401f --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ByteArrayPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7620a5e6fedc18408f8f04821b35bbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs new file mode 100644 index 0000000..fca4d97 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs @@ -0,0 +1,277 @@ +using FishNet.Connection; +using FishNet.Object; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Utility.Performance +{ + /// + /// Various ListCache instances that may be used on the Unity thread. + /// + public static class ListCaches + { + + /// + /// Cache collection for NetworkObjects. + /// + private static Stack> _networkObjectCaches = new Stack>(); + /// + /// Cache for NetworkObjects. + /// + [Obsolete("Use GetNetworkObjectCache instead.")] //Remove on 2023/01/01 + public static ListCache NetworkObjectCache = new ListCache(); + /// + /// Cache collection for NetworkObjects. + /// + private static Stack> _networkBehaviourCaches = new Stack>(); + /// + /// Cache for NetworkBehaviours. + /// + [Obsolete("Use GetNetworkBehaviourCache instead.")] //Remove on 2023/01/01 + public static ListCache NetworkBehaviourCache = new ListCache(); + /// + /// Cache collection for NetworkObjects. + /// + private static Stack> _transformCaches = new Stack>(); + /// + /// Cache for Transforms. + /// + [Obsolete("Use GetTransformCache instead.")] //Remove on 2023/01/01 + public static ListCache TransformCache = new ListCache(); + /// + /// Cache collection for NetworkConnections. + /// + private static Stack> _networkConnectionCaches = new Stack>(); + /// + /// Cache for NetworkConnectios. + /// + [Obsolete("Use GetNetworkConnectionCache instead.")] //Remove on 2023/01/01 + public static ListCache NetworkConnectionCache = new ListCache(); + /// + /// Cache for ints. + /// + public static ListCache IntCache = new ListCache(); + + + #region GetCache. + /// + /// Returns a NetworkObject cache. Use StoreCache to return the cache. + /// + /// + public static ListCache GetNetworkObjectCache() + { + ListCache result; + if (_networkObjectCaches.Count == 0) + result = new ListCache(); + else + result = _networkObjectCaches.Pop(); + + return result; + } + /// + /// Returns a NetworkConnection cache. Use StoreCache to return the cache. + /// + /// + public static ListCache GetNetworkConnectionCache() + { + ListCache result; + if (_networkConnectionCaches.Count == 0) + result = new ListCache(); + else + result = _networkConnectionCaches.Pop(); + + return result; + } + /// + /// Returns a Transform cache. Use StoreCache to return the cache. + /// + /// + public static ListCache GetTransformCache() + { + ListCache result; + if (_transformCaches.Count == 0) + result = new ListCache(); + else + result = _transformCaches.Pop(); + + return result; + } + /// + /// Returns a NetworkBehaviour cache. Use StoreCache to return the cache. + /// + /// + public static ListCache GetNetworkBehaviourCache() + { + ListCache result; + if (_networkBehaviourCaches.Count == 0) + result = new ListCache(); + else + result = _networkBehaviourCaches.Pop(); + + return result; + } + #endregion + + + #region StoreCache. + /// + /// Stores a NetworkObject cache. + /// + /// + public static void StoreCache(ListCache cache) + { + cache.Reset(); + _networkObjectCaches.Push(cache); + } + /// + /// Stores a NetworkConnection cache. + /// + /// + public static void StoreCache(ListCache cache) + { + cache.Reset(); + _networkConnectionCaches.Push(cache); + } + /// + /// Stores a Transform cache. + /// + /// + public static void StoreCache(ListCache cache) + { + cache.Reset(); + _transformCaches.Push(cache); + } + /// + /// Stores a NetworkBehaviour cache. + /// + /// + public static void StoreCache(ListCache cache) + { + cache.Reset(); + _networkBehaviourCaches.Push(cache); + } + #endregion + + } + + /// + /// Creates a reusable cache of T which auto expands. + /// + public class ListCache + { + #region Public. + /// + /// Collection cache is for. + /// + public List Collection; + /// + /// Entries currently written. + /// + public int Written { get; private set; } + #endregion + + public ListCache() + { + Collection = new List(); + } + public ListCache(int capacity) + { + Collection = new List(capacity); + } + + /// + /// Adds a new value to Collection and returns it. + /// + /// + public T AddReference() + { + if (Collection.Count <= Written) + { + T next = Activator.CreateInstance(); + Collection.Add(next); + Written++; + return next; + } + else + { + T next = Collection[Written]; + Written++; + return next; + } + } + + + /// + /// Adds value to Collection. + /// + /// + public void AddValue(T value) + { + if (Collection.Count <= Written) + Collection.Add(value); + else + Collection[Written] = value; + + Written++; + } + + /// + /// Adds values to Collection. + /// + /// + public void AddValues(T[] values) + { + for (int i = 0; i < values.Length; i++) + AddValue(values[i]); + } + /// + /// Adds values to Collection. + /// + /// + public void AddValues(List values) + { + for (int i = 0; i < values.Count; i++) + AddValue(values[i]); + } + /// + /// Adds values to Collection. + /// + /// + public void AddValues(HashSet values) + { + foreach (T item in values) + AddValue(item); + } + /// + /// Adds values to Collection. + /// + /// + public void AddValues(ISet values) + { + foreach (T item in values) + AddValue(item); + } + + /// + /// Adds values to Collection. + /// + /// + public void AddValues(IReadOnlyCollection values) + { + foreach (T item in values) + AddValue(item); + } + + + /// + /// Resets cache. + /// + public void Reset() + { + Written = 0; + } + } + + +} diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs.meta new file mode 100644 index 0000000..4b13d4c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/ListCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 488b0788adfd9ee43977abd5d0280124 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs new file mode 100644 index 0000000..a978922 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs @@ -0,0 +1,2 @@ +//This file is no longer needed. +//Remove on 2023/01/01 \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs.meta new file mode 100644 index 0000000..49599ec --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eddbe8b834edd0842b18e08301d92d0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs new file mode 100644 index 0000000..59eb1a5 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs @@ -0,0 +1,39 @@ +using FishNet.Object; +using System.Collections.Generic; +using UnityEngine; + +namespace FishNet.Utility.Performance +{ + + public static class GetNonAlloc + { + /// + /// + /// + private static List _transformList = new List(); + /// + /// + /// + private static List _networkBehavioursList = new List(); + + /// + /// Gets all NetworkBehaviours on a transform. + /// + public static List GetNetworkBehaviours(this Transform t) + { + t.GetComponents(_networkBehavioursList); + return _networkBehavioursList; + } + + /// + /// Gets all transforms on transform and it's children. + /// + public static List GetTransformsInChildrenNonAlloc(this Transform t, bool includeInactive = false) + { + t.GetComponentsInChildren(includeInactive, _transformList); + return _transformList; + } + + } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs.meta new file mode 100644 index 0000000..b2bc83c --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/Performance/Transforms.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d0740f919077254c8ffb131b9587407 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs b/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs new file mode 100644 index 0000000..dd343a7 --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace FishNet.Utility +{ + /* Source https://forum.unity.com/threads/how-to-link-scenes-in-the-inspector.383140/ */ + + /// + /// Converts a string property into a Scene property in the inspector + /// + public class SceneAttribute : PropertyAttribute { } + +} \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs.meta b/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs.meta new file mode 100644 index 0000000..5d3afce --- /dev/null +++ b/UnityProject/Assets/FishNet/Runtime/Utility/SceneAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3684fb9a5dec7454b8ad791f5ef19164 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md b/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md new file mode 100644 index 0000000..343ab60 --- /dev/null +++ b/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md @@ -0,0 +1,82 @@ +This package contains third-party software components governed by the license(s) indicated below: + +Component Name: LiteNetLib +License Type: MIT +Copyright (c) 2020 Ruslan Pyrch +Copyright (c) 2021, Benjamin Berwick of FirstGearGames LLC, registered 2018, North Carolina. + +Paths: FishNet\Runtime\Transporting\Transports\Tugboat\LiteNetLib + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +Component Name: CodeGen Helpers(extensions). +License Type: MIT +Copyright (c) 2015, Unity Technologies +Copyright (c) 2019, vis2k, Paul and Contributors +Copyright (c) 2021, Benjamin Berwick of FirstGearGames LLC, registered 2018, North Carolina. + +Paths: FishNet/CodeGenerating/Helpers/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +Component Name: MonoCecil +License Type: MIT +Copyright (c) 2008 - 2015 Jb Evain +Copyright (c) 2008 - 2011 Novell, Inc. + +Paths: FishNet/CodeGenerating/cecil-xxxxx + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md.meta b/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md.meta new file mode 100644 index 0000000..f9ad4bb --- /dev/null +++ b/UnityProject/Assets/FishNet/THIRD PARTY NOTICE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6ee8e3f1530d3594488bfe438dced5ea +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Upgrading.meta b/UnityProject/Assets/FishNet/Upgrading.meta new file mode 100644 index 0000000..96ab21b --- /dev/null +++ b/UnityProject/Assets/FishNet/Upgrading.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45e9a7bff88078f49ae15609740702eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs b/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs new file mode 100644 index 0000000..feea582 --- /dev/null +++ b/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs @@ -0,0 +1,438 @@ +#if UNITY_EDITOR && MIRROR +using UnityEditor; +using UnityEngine; +using FishNet.Object; +using FishNet.Documenting; +using System.Collections.Generic; +using FNNetworkTransform = FishNet.Component.Transforming.NetworkTransform; +using FNNetworkAnimator = FishNet.Component.Animating.NetworkAnimator; +using FNNetworkObserver = FishNet.Observing.NetworkObserver; +using FishNet.Observing; +using FishNet.Component.Observing; +using FishNet.Editing; +using System.IO; +using System.Collections; +using Mirror; +using MirrorExperimentalNetworkTransformBase = Mirror.Experimental.NetworkTransformBase; +using MirrorExperimentalNetworkTransformChild = Mirror.Experimental.NetworkTransformChild; +using MirrorNetworkTransformBase = Mirror.NetworkTransformBase; +using MirrorNetworkTransformChild = Mirror.NetworkTransformChild; +using MirrorNetworkAnimator = Mirror.NetworkAnimator; +#if !MIRROR_57_0_OR_NEWER +using MirrorNetworkProximityChecker = Mirror.NetworkProximityChecker; +using MirrorNetworkSceneChecker = Mirror.NetworkSceneChecker; +#endif + +#if FGG_ASSETS +using FlexNetworkAnimator = FirstGearGames.Mirrors.Assets.FlexNetworkAnimators.FlexNetworkAnimator; +using FlexNetworkTransformBase = FirstGearGames.Mirrors.Assets.FlexNetworkTransforms.FlexNetworkTransformBase; +using FastProximityChecker = FirstGearGames.Mirrors.Assets.NetworkProximities.FastProximityChecker; +#endif + +#if FGG_PROJECTS +using FlexSceneChecker = FirstGearGames.FlexSceneManager.FlexSceneChecker; +#endif + +namespace FishNet.Upgrading.Mirror.Editing +{ + + /* IMPORTANT IMPORTANT IMPORTANT IMPORTANT + * If you receive errors about missing Mirror components, + * such as NetworkIdentity, then remove MIRROR and any other + * MIRROR defines. + * Project Settings -> Player -> Other -> Scripting Define Symbols. + * + * If you are also using my assets add FGG_ASSETS to the defines, and + * then remove it after running this script. */ + [APIExclude] + [ExecuteInEditMode] + [InitializeOnLoad] + public class MirrorUpgrade : MonoBehaviour + { + /// + /// SceneCondition within FishNet. + /// + private SceneCondition _sceneCondition = null; + /// + /// DistanceCondition created for the user. + /// + private DistanceCondition _distanceCondition = null; + /// + /// + /// + private int _replacedNetworkTransforms; + /// + /// + /// + private int _replacedNetworkAnimators; + /// + /// + /// + private int _replacedNetworkIdentities; + /// + /// + /// + private int _replacedSceneCheckers; + /// + /// + /// + private int _replacedProximityCheckers; + /// + /// True if anything was changed. + /// + private bool _changed; + /// + /// Index in gameObjects to iterate. + /// + private int _goIndex = -1; + /// + /// Found gameObjects to iterate. + /// + private List _gameObjects = new List(); + /// + /// True if initialized. + /// + private bool _initialized; + + + private const string OBJECT_NAME_PREFIX = "MirrorUpgrade"; + + + private void Awake() + { + gameObject.name = OBJECT_NAME_PREFIX; + Debug.Log($"{gameObject.name} is working. Please wait until this object is removed from your hierarchy."); + EditorApplication.update += EditorUpdate; + } + + private void OnDestroy() + { + EditorApplication.update -= EditorUpdate; + } + + private void EditorUpdate() + { + if (!_initialized) + { + FindConditions(true); + _gameObjects = Finding.GetGameObjects(true, false, true, new string[] { "/Mirror/" }); + _goIndex = 0; + _initialized = true; + } + + if (_goIndex == -1) + return; + if (_goIndex >= _gameObjects.Count) + { + gameObject.name = $"{OBJECT_NAME_PREFIX} - 100%"; + Debug.Log($"Switched {_replacedNetworkTransforms} NetworkTransforms."); + Debug.Log($"Switched {_replacedNetworkAnimators} NetworkAnimators."); + Debug.Log($"Switched {_replacedSceneCheckers} SceneCheckers."); + Debug.Log($"Switched {_replacedProximityCheckers} ProximityCheckers."); + Debug.Log($"Switched {_replacedNetworkIdentities} NetworkIdentities."); + + if (_changed) + PrintSaveWarning(); + + DestroyImmediate(gameObject); + return; + } + + float percentFloat = ((float)_goIndex / (float)_gameObjects.Count) * 100f; + int percentInt = Mathf.FloorToInt(percentFloat); + gameObject.name = $"{OBJECT_NAME_PREFIX} - {percentInt}%"; + + GameObject go = _gameObjects[_goIndex]; + _goIndex++; + //Go went empty? + if (go == null) + return; + + /* When a component is removed + * changed is set true and remove count is increased. + * _goIndex is also returned before exiting the method. + * This will cause the same gameObject to iterate + * next update. This is important because the components + * must be Switched in order, and I can only remove one + * component per frame without Unity throwing a fit and + * freezing. A while loop doesn't let Unity recognize the component + * is gone(weird right? maybe editor thing), and a coroutine + * doesn't show errors well, they just fail silently. */ + + bool changedThisFrame = false; + if (IterateNetworkTransform(go)) + { + changedThisFrame = true; + _changed = true; + _replacedNetworkTransforms++; + } + if (IterateNetworkAnimator(go)) + { + changedThisFrame = true; + _changed = true; + _replacedNetworkAnimators++; + } + + if (IterateSceneChecker(go)) + { + changedThisFrame = true; + _changed = true; + _replacedSceneCheckers++; + } + if (IterateProximityChecker(go)) + { + changedThisFrame = true; + _changed = true; + _replacedProximityCheckers++; + } + if (changedThisFrame) + { + _goIndex--; + return; + } + //NetworkIdentity must be done last. + if (IterateNetworkIdentity(go)) + { + _changed = true; + _replacedNetworkIdentities++; + } + } + + + /// + /// Finds Condition scripts to be used with NetworkObserver. + /// + /// + private void FindConditions(bool error) + { + List scriptableObjects; + + if (_sceneCondition == null) + { + scriptableObjects = Finding.GetScriptableObjects(true, true); + //Use the first found scene condition, there should be only one. + if (scriptableObjects.Count > 0) + _sceneCondition = (SceneCondition)scriptableObjects[0]; + + if (_sceneCondition == null && error) + Debug.LogError("SceneCondition could not be found. Upgrading scene checker components will not function."); + } + + if (_distanceCondition == null) + { + scriptableObjects = Finding.GetScriptableObjects(false, true); + if (scriptableObjects.Count > 0) + { + _distanceCondition = (DistanceCondition)scriptableObjects[0]; + } + else + { + DistanceCondition dc = ScriptableObject.CreateInstance(); + string savePath = "Assets"; + AssetDatabase.CreateAsset(dc, Path.Combine(savePath, $"CreatedDistanceCondition.asset")); + Debug.LogWarning($"DistanceCondition has been created at {savePath}. Place this file somewhere within your project and change settings to your liking."); + } + + if (_distanceCondition == null && error) + Debug.LogError("DistanceCondition could not be found. Upgrading proximity checker components will not function."); + } + } + + + private bool IterateNetworkTransform(GameObject go) + { + if (go.TryGetComponent(out MirrorNetworkTransformBase nt1)) + { + Transform target; + if (nt1 is MirrorNetworkTransformChild mc1) + target = mc1.target; + else + target = go.transform; + Replace(nt1, target); + return true; + } + if (go.TryGetComponent(out MirrorExperimentalNetworkTransformBase nt2)) + { + Transform target; + if (nt2 is MirrorExperimentalNetworkTransformChild mc1) + target = mc1.target; + else + target = go.transform; + Replace(nt2, target); + return true; + } +#if FGG_ASSETS + if (go.TryGetComponent(out FlexNetworkTransformBase fntb)) + { + Replace(fntb, fntb.TargetTransform); + return true; + } +#endif + + void Replace(UnityEngine.Component component, Transform target) + { + EditorUtility.SetDirty(go); + DestroyImmediate(component, true); + + if (target != null && !target.TryGetComponent(out _)) + target.gameObject.AddComponent(); + } + + //Fall through, nothing was replaced. + return false; + } + + private bool IterateNetworkAnimator(GameObject go) + { + if (go.TryGetComponent(out MirrorNetworkAnimator mna)) + { + Replace(mna, mna.transform); + return true; + } +#if FGG_ASSETS + if (go.TryGetComponent(out FlexNetworkAnimator fna)) + { + Replace(fna, fna.transform); + return true; + } +#endif + + void Replace(UnityEngine.Component component, Transform target) + { + EditorUtility.SetDirty(go); + DestroyImmediate(component, true); + + if (target == null) + return; + if (!target.TryGetComponent(out _)) + target.gameObject.AddComponent(); + } + + return false; + } + + + private bool IterateSceneChecker(GameObject go) + { +#if !MIRROR_57_0_OR_NEWER + if (_sceneCondition == null) + return false; + + if (go.TryGetComponent(out MirrorNetworkSceneChecker msc)) + { + Replace(msc); + return true; + } +#if FGG_PROJECTS + if (go.TryGetComponent(out FlexSceneChecker fsc)) + { + Replace(fsc); + return true; + } +#endif + + void Replace(UnityEngine.Component component) + { + EditorUtility.SetDirty(go); + DestroyImmediate(component, true); + + FNNetworkObserver networkObserver; + if (!go.TryGetComponent(out networkObserver)) + networkObserver = go.AddComponent(); + + bool conditionFound = false; + foreach (ObserverCondition condition in networkObserver.ObserverConditions) + { + if (condition.GetType() == typeof(SceneCondition)) + { + conditionFound = true; + break; + } + } + + //If not able to find scene condition then add one. + if (!conditionFound) + networkObserver.ObserverConditionsInternal.Add(_sceneCondition); + } + +#endif + return false; + } + + + + private bool IterateProximityChecker(GameObject go) + { +#if !MIRROR_57_0_OR_NEWER + if (_distanceCondition == null) + return false; + + if (go.TryGetComponent(out MirrorNetworkProximityChecker mnpc)) + { + Replace(mnpc); + return true; + } +#if FGG_PROJECTS + if (go.TryGetComponent(out FastProximityChecker fpc)) + { + Replace(fpc); + return true; + } +#endif + + void Replace(UnityEngine.Component component) + { + EditorUtility.SetDirty(go); + DestroyImmediate(component, true); + + FNNetworkObserver networkObserver; + if (!go.TryGetComponent(out networkObserver)) + networkObserver = go.AddComponent(); + + bool conditionFound = false; + foreach (ObserverCondition condition in networkObserver.ObserverConditions) + { + if (condition.GetType() == typeof(DistanceCondition)) + { + conditionFound = true; + break; + } + } + + //If not able to find scene condition then add one. + if (!conditionFound) + networkObserver.ObserverConditionsInternal.Add(_distanceCondition); + } +#endif + + return false; + } + + + private bool IterateNetworkIdentity(GameObject go) + { + if (go.TryGetComponent(out NetworkIdentity netIdentity)) + { + EditorUtility.SetDirty(go); + DestroyImmediate(netIdentity, true); + + //Add nob if doesn't exist. + if (!go.TryGetComponent(out _)) + go.AddComponent(); + + return true; + } + + return false; + } + + + private static void PrintSaveWarning() + { + Debug.LogWarning("You must File -> Save for changes to complete."); + } + } + + +} +#endif \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs.meta b/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs.meta new file mode 100644 index 0000000..b1d33a8 --- /dev/null +++ b/UnityProject/Assets/FishNet/Upgrading/MirrorUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 491b9891492df1444937419bc0e39642 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs b/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs new file mode 100644 index 0000000..5d77c2b --- /dev/null +++ b/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs @@ -0,0 +1,75 @@ +#if UNITY_EDITOR +using FishNet.Documenting; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace FishNet.Upgrading.Mirror.Editing +{ + + /* IMPORTANT IMPORTANT IMPORTANT IMPORTANT + * If you receive errors about missing Mirror components, + * such as NetworkIdentity, then remove MIRROR and any other + * MIRROR defines. + * Project Settings -> Player -> Other -> Scripting Define Symbols. + * + * If you are also using my assets add FGG_ASSETS to the defines, and + * then remove it after running this script. */ + [APIExclude] + public class UpgradeFromMirrorMenu : MonoBehaviour + { + + /// + /// Replaces all components. + /// + [MenuItem("Fish-Networking/Upgrading/From Mirror/Replace Components", false,2)] + private static void ReplaceComponents() + { +#if MIRROR + MirrorUpgrade result = GameObject.FindObjectOfType(); + if (result != null) + { + Debug.LogError("MirrorUpgrade already exist in the scene. This suggests an operation is currently running."); + return; + } + + GameObject iteratorGo = new GameObject(); + iteratorGo.AddComponent(); +#else + Debug.LogError("Mirror must be imported to perform this function."); +#endif + } + + [MenuItem("Fish-Networking/Upgrading/From Mirror/Remove Defines", false, 2)] + private static void RemoveDefines() + { + string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + /* Convert current defines into a hashset. This is so we can + * determine if any of our defines were added. Only save playersettings + * when a define is added. */ + HashSet definesHs = new HashSet(); + string[] currentArr = currentDefines.Split(';'); + + bool removed = false; + //Add any define which doesn't contain MIRROR. + foreach (string item in currentArr) + { + string itemLower = item.ToLower(); + if (itemLower != "mirror" && !itemLower.StartsWith("mirror_")) + definesHs.Add(item); + else + removed = true; + } + + if (removed) + { + Debug.Log("Removed Mirror defines to player settings."); + string changedDefines = string.Join(";", definesHs); + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, changedDefines); + } + } + + + } +} +#endif diff --git a/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs.meta b/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs.meta new file mode 100644 index 0000000..726fd8d --- /dev/null +++ b/UnityProject/Assets/FishNet/Upgrading/UpgradeFromMirrorMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55cd1de3399bf564a9545f089421a88d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNet/VERSION.txt b/UnityProject/Assets/FishNet/VERSION.txt new file mode 100644 index 0000000..e9c666f --- /dev/null +++ b/UnityProject/Assets/FishNet/VERSION.txt @@ -0,0 +1 @@ +2.3.12.Pro \ No newline at end of file diff --git a/UnityProject/Assets/FishNet/VERSION.txt.meta b/UnityProject/Assets/FishNet/VERSION.txt.meta new file mode 100644 index 0000000..fbab156 --- /dev/null +++ b/UnityProject/Assets/FishNet/VERSION.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 84a91b39bff26504e9cf03f8aa4fe3ab +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/FishNetworkManager.prefab b/UnityProject/Assets/FishNetworkManager.prefab new file mode 100644 index 0000000..ea2081a --- /dev/null +++ b/UnityProject/Assets/FishNetworkManager.prefab @@ -0,0 +1,707 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &225435927466029604 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2737543991059065802} + - component: {fileID: 525349609959503779} + - component: {fileID: 8544898160630127577} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2737543991059065802 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 225435927466029604} + 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: 9037581618969920970} + 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!222 &525349609959503779 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 225435927466029604} + m_CullTransparentMesh: 0 +--- !u!114 &8544898160630127577 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 225435927466029604} + 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 &2796818760573100368 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2796818760573100370} + - component: {fileID: 2796818760573100369} + - component: {fileID: 4727661587256721527} + - component: {fileID: 2796818760573100383} + - component: {fileID: 4727661587256721528} + - component: {fileID: 4727661587256721529} + - component: {fileID: 4727661587256721526} + m_Layer: 0 + m_Name: FishNetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2796818760573100370 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + 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: 9037581618579610991} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2796818760573100369 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} + m_Name: + m_EditorClassIdentifier: + _refreshDefaultPrefabs: 0 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 + _logging: {fileID: 0} + _spawnablePrefabs: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, type: 2} +--- !u!114 &4727661587256721527 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} + m_Name: + m_EditorClassIdentifier: + _updateHostVisibility: 1 + _defaultConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!114 &2796818760573100383 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + 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!114 &4727661587256721528 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34e4a322dca349547989b14021da4e23, type: 3} + m_Name: + m_EditorClassIdentifier: + Transport: {fileID: 4727661587256721526} + _latencySimulator: + _enabled: 0 + _simulateHost: 1 + _latency: 0 + _outOfOrder: 0 + _packetLoss: 0 +--- !u!114 &4727661587256721529 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + 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: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!114 &4727661587256721526 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2796818760573100368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37bf248b7e575fe4592c1ec247b10573, type: 3} + m_Name: + m_EditorClassIdentifier: + transport: {fileID: 4727661587256721529} + serverIP: + serverPort: 7777 + endpointServerPort: 8080 + heartBeatInterval: 3 + connectOnAwake: 1 + authenticationKey: Secret Auth Key + disconnectedFromRelay: + m_PersistentCalls: + m_Calls: [] + connectedToRelay: + m_PersistentCalls: + m_Calls: [] + useNATPunch: 0 + NATPunchtroughPort: -1 + useLoadBalancer: 0 + loadBalancerPort: 7070 + loadBalancerAddress: + serverName: My awesome server! + extraServerData: Map 1 + maxServerPlayers: 10 + isPublicServer: 1 + serverListUpdated: + m_PersistentCalls: + m_Calls: [] + serverStatus: Not Started. + serverId: + region: 1 +--- !u!1 &7203432629568778042 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4560820041013854248} + - component: {fileID: 2018194202920540960} + - component: {fileID: 5935525483625793491} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4560820041013854248 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203432629568778042} + 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: 9037581619120599114} + 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!222 &2018194202920540960 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203432629568778042} + m_CullTransparentMesh: 0 +--- !u!114 &5935525483625793491 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203432629568778042} + 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 &9037581618579610994 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9037581618579610991} + - component: {fileID: 9037581618579610995} + - component: {fileID: 9037581618579610990} + - component: {fileID: 9037581618579610989} + - component: {fileID: 9037581618579610988} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9037581618579610991 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618579610994} + 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: 9037581618969920970} + - {fileID: 9037581619120599114} + m_Father: {fileID: 2796818760573100370} + 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 &9037581618579610995 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618579610994} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + _autoStartType: 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} + _serverIndicator: {fileID: 8544898160630127577} + _clientIndicator: {fileID: 5935525483625793491} +--- !u!223 &9037581618579610990 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618579610994} + 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!114 &9037581618579610989 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618579610994} + 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!114 &9037581618579610988 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618579610994} + 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!1 &9037581618969920969 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9037581618969920970} + - component: {fileID: 9037581618969920965} + - component: {fileID: 9037581618969920964} + - component: {fileID: 9037581618969920971} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9037581618969920970 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618969920969} + 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: 2737543991059065802} + m_Father: {fileID: 9037581618579610991} + 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!222 &9037581618969920965 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618969920969} + m_CullTransparentMesh: 0 +--- !u!114 &9037581618969920964 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618969920969} + 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!114 &9037581618969920971 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581618969920969} + 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: 9037581618969920964} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 9037581618579610995} + 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 &9037581619120599113 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9037581619120599114} + - component: {fileID: 9037581619120599109} + - component: {fileID: 9037581619120599108} + - component: {fileID: 9037581619120599115} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9037581619120599114 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581619120599113} + 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: 4560820041013854248} + m_Father: {fileID: 9037581618579610991} + 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!222 &9037581619120599109 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581619120599113} + m_CullTransparentMesh: 0 +--- !u!114 &9037581619120599108 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581619120599113} + 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!114 &9037581619120599115 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9037581619120599113} + 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: 9037581619120599108} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 9037581618579610995} + 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 diff --git a/UnityProject/Assets/FishNetworkManager.prefab.meta b/UnityProject/Assets/FishNetworkManager.prefab.meta new file mode 100644 index 0000000..82f6858 --- /dev/null +++ b/UnityProject/Assets/FishNetworkManager.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aa4437dd870fb36468ec6b1d5a59925f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab b/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab deleted file mode 100644 index 84b8f93..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariBall.prefab +++ /dev/null @@ -1,188 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &1080679924113744 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4700925592147096} - - component: {fileID: 212107498293566416} - - component: {fileID: 61279514624852186} - - component: {fileID: 50354248948880112} - - component: {fileID: 114290021321007948} - - component: {fileID: 2590138469697868697} - - component: {fileID: 114121325390084138} - m_Layer: 0 - m_Name: AtariBall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &4700925592147096 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -3, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!212 &212107498293566416 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 4b66f21097323d44ab40669b2fb9c53d, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!61 &61279514624852186 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 6200000, guid: 97a3e4cddb8635c4eba1265f44d106bf, type: 2} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 1, y: 1} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 1, y: 1} - m_EdgeRadius: 0 ---- !u!50 &50354248948880112 -Rigidbody2D: - serializedVersion: 4 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_BodyType: 0 - m_Simulated: 0 - m_UseFullKinematicContacts: 0 - m_UseAutoMass: 0 - m_Mass: 0.0001 - m_LinearDrag: 0 - m_AngularDrag: 0.05 - m_GravityScale: 0 - m_Material: {fileID: 0} - m_Interpolate: 0 - m_SleepingMode: 1 - m_CollisionDetection: 0 - m_Constraints: 4 ---- !u!114 &114290021321007948 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!114 &2590138469697868697 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2a08d5ab1f59230458264367f00c54d8, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - speed: 100 ---- !u!114 &114121325390084138 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1080679924113744} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0 - clientAuthority: 0 - localPositionSensitivity: 0.01 - localRotationSensitivity: 0.01 - localScaleSensitivity: 0.01 - compressRotation: 1 - interpolateScale: 0 - syncScale: 0 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab b/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab deleted file mode 100644 index 44aaae1..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/AtariRacket.prefab +++ /dev/null @@ -1,188 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &1240244544407914 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4118252415362944} - - component: {fileID: 212641192162007874} - - component: {fileID: 61279767645666242} - - component: {fileID: 50389918509199184} - - component: {fileID: 114104497298166850} - - component: {fileID: -4874889082967523790} - - component: {fileID: 114398896143473162} - m_Layer: 0 - m_Name: AtariRacket - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &4118252415362944 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - 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: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!212 &212641192162007874 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 619ccff3ba2f2a04f9ddd19c264a1ecd, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!61 &61279767645666242 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 2, y: 4} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 2, y: 4} - m_EdgeRadius: 0 ---- !u!50 &50389918509199184 -Rigidbody2D: - serializedVersion: 4 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_BodyType: 0 - m_Simulated: 1 - m_UseFullKinematicContacts: 0 - m_UseAutoMass: 0 - m_Mass: 1 - m_LinearDrag: 0 - m_AngularDrag: 0.05 - m_GravityScale: 0 - m_Material: {fileID: 0} - m_Interpolate: 1 - m_SleepingMode: 1 - m_CollisionDetection: 1 - m_Constraints: 4 ---- !u!114 &114104497298166850 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!114 &-4874889082967523790 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b68eb08343b29a54dbd5ed7830fb9211, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - speed: 1500 ---- !u!114 &114398896143473162 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1240244544407914} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0 - clientAuthority: 1 - localPositionSensitivity: 0.01 - localRotationSensitivity: 0.01 - localScaleSensitivity: 0.01 - compressRotation: 1 - interpolateScale: 0 - syncScale: 0 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity b/UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity deleted file mode 100644 index bbaa0a4..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Demo.unity +++ /dev/null @@ -1,1166 +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: 3 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 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, g: 0, b: 0, a: 1} - m_UseRadianceAmbientProbe: 0 ---- !u!157 &4 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 11 - m_GIWorkflowMode: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 0 - m_EnableRealtimeLightmaps: 0 - m_LightmapEditorSettings: - serializedVersion: 12 - m_Resolution: 2 - m_BakeResolution: 40 - m_AtlasSize: 1024 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 0 - 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: 1024 - m_ReflectionCompression: 2 - m_MixedBakeMode: 1 - m_BakeBackend: 0 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVRBounces: 2 - m_PVREnvironmentSampleCount: 500 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 0 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 0 - 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_UseShadowmask: 0 ---- !u!196 &5 -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 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &289876230 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 289876232} - - component: {fileID: 289876231} - m_Layer: 0 - m_Name: DottedLine - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!212 &289876231 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 289876230} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 4294967295 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 75254f20e37ff3640beccde38f796fed, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!4 &289876232 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 289876230} - 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: [] - m_Father: {fileID: 1607538195} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &473997959 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 473997961} - - component: {fileID: 473997960} - m_Layer: 0 - m_Name: RacketSpawnLeft - m_TagString: Untagged - m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &473997960 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 473997959} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!4 &473997961 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 473997959} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -20, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 5 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &753891880 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 753891882} - - component: {fileID: 753891881} - - component: {fileID: 753891883} - m_Layer: 0 - m_Name: WallBottom - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!212 &753891881 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 753891880} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 4294967295 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 51f6a08479c829a49b6a15df6849e727, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!4 &753891882 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 753891880} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: -16, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1607538195} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!61 &753891883 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 753891880} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 50, y: 1} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 50, y: 1} - m_EdgeRadius: 0 ---- !u!1 &1212086918 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1212086921} - - component: {fileID: 1212086920} - - component: {fileID: 1212086919} - m_Layer: 0 - m_Name: EventSystem - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1212086919 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1212086918} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &1212086920 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1212086918} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} - m_Name: - m_EditorClassIdentifier: - m_FirstSelected: {fileID: 0} - m_sendNavigationEvents: 1 - m_DragThreshold: 10 ---- !u!4 &1212086921 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1212086918} - 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: [] - m_Father: {fileID: 0} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1278075347 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1278075350} - - component: {fileID: 1278075348} - - component: {fileID: 1278075349} - m_Layer: 0 - m_Name: Timer - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1278075348 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1278075347} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d0996ec573094c24890a4d4233ee871e, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 ---- !u!114 &1278075349 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1278075347} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 3073769009 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!4 &1278075350 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1278075347} - 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: [] - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1346799726 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1346799731} - - component: {fileID: 1346799730} - - component: {fileID: 1346799728} - - component: {fileID: 1346799727} - 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 &1346799727 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1346799726} - m_Enabled: 1 ---- !u!124 &1346799728 -Behaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1346799726} - m_Enabled: 1 ---- !u!20 &1346799730 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1346799726} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0.019607844} - 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: 1 - orthographic size: 40 - 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: 0 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &1346799731 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1346799726} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1352350029 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1352350031} - - component: {fileID: 1352350030} - - component: {fileID: 1352350032} - m_Layer: 0 - m_Name: WallLeft - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!212 &1352350030 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1352350029} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 4294967295 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: b41679787bea72d419d10a6df7dc137f, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!4 &1352350031 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1352350029} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -24.5, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1607538195} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!61 &1352350032 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1352350029} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 1, y: 32} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 1, y: 32} - m_EdgeRadius: 0 ---- !u!1 &1368547944 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1368547946} - - component: {fileID: 1368547945} - - component: {fileID: 1368547947} - m_Layer: 0 - m_Name: WallTop - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!212 &1368547945 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1368547944} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 4294967295 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 51f6a08479c829a49b6a15df6849e727, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!4 &1368547946 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1368547944} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 16, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1607538195} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!61 &1368547947 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1368547944} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 50, y: 1} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 50, y: 1} - m_EdgeRadius: 0 ---- !u!1 &1397990094 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1397990096} - - component: {fileID: 1397990095} - m_Layer: 0 - m_Name: RacketSpawnRight - m_TagString: Untagged - m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1397990095 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1397990094} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!4 &1397990096 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1397990094} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 20, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1575697329 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1575697331} - - component: {fileID: 1575697330} - - component: {fileID: 1575697332} - m_Layer: 0 - m_Name: WallRight - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!212 &1575697330 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1575697329} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 4294967295 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: b41679787bea72d419d10a6df7dc137f, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!4 &1575697331 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1575697329} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 24.5, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1607538195} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!61 &1575697332 -BoxCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1575697329} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - m_SpriteTilingProperty: - border: {x: 0, y: 0, z: 0, w: 0} - pivot: {x: 0.5, y: 0.5} - oldSize: {x: 1, y: 32} - newSize: {x: 1, y: 1} - adaptiveTilingThreshold: 0.5 - drawMode: 0 - adaptiveTiling: 0 - m_AutoTiling: 0 - serializedVersion: 2 - m_Size: {x: 1, y: 32} - m_EdgeRadius: 0 ---- !u!1 &1607538194 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1607538195} - m_Layer: 0 - m_Name: Table - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1607538195 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1607538194} - 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: 1368547946} - - {fileID: 753891882} - - {fileID: 1575697331} - - {fileID: 1352350031} - - {fileID: 289876232} - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1886246549 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1886246550} - - component: {fileID: 1886246552} - - component: {fileID: 1886246551} - - component: {fileID: 1886246553} - m_Layer: 0 - m_Name: NetworkManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1886246550 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1886246549} - 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: [] - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1886246551 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1886246549} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} - m_Name: - m_EditorClassIdentifier: - showGUI: 1 - offsetX: 0 - offsetY: 0 ---- !u!114 &1886246552 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1886246549} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} - m_Name: - m_EditorClassIdentifier: - dontDestroyOnLoad: 1 - PersistNetworkManagerToOfflineScene: 0 - runInBackground: 1 - autoStartServerBuild: 1 - serverTickRate: 60 - serverBatching: 0 - serverBatchInterval: 0 - offlineScene: - onlineScene: - transport: {fileID: 1886246553} - networkAddress: localhost - maxConnections: 4 - disconnectInactiveConnections: 0 - disconnectInactiveTimeout: 60 - authenticator: {fileID: 0} - playerPrefab: {fileID: 1240244544407914, guid: a85b24263182aae4bbc1829bb2b73d7a, - type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: [] ---- !u!114 &1886246553 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1886246549} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 872fa23ef6e77334ca452ce16f6cd091, type: 3} - m_Name: - m_EditorClassIdentifier: - port: 7777 - LogType: 1 - DebugDisplay: 0 - serverBindsAll: 1 - serverBindAddress: - serverMaxPeerCapacity: 50 - serverMaxNativeWaitTime: 1 - clientMaxNativeWaitTime: 3 - clientStatusUpdateInterval: 3 - Channels: 0100000002000000 - PacketBufferCapacity: 4096 - MaxAllowedPacketSize: 33554432 ---- !u!1001 &543632697568170294 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 440601958556739609, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: sceneId - value: 1882393603 - objectReference: {fileID: 0} - - target: {fileID: 440601958556739609, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_AssetId - value: 5339554c46006dd4e91cae9ff34c095d - objectReference: {fileID: 0} - - target: {fileID: 542835289192032773, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_Name - value: Ball - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_RootOrder - value: 4 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 548291784780898253, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 5995301680282788937, guid: 5339554c46006dd4e91cae9ff34c095d, - type: 3} - propertyPath: speed - value: 60 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 5339554c46006dd4e91cae9ff34c095d, type: 3} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs b/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs deleted file mode 100644 index a0e43c2..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs +++ /dev/null @@ -1,67 +0,0 @@ -using UnityEngine; -using Mirror; - -namespace Ignorance.Examples.PongChamp -{ - public class AtariPongBall : NetworkBehaviour - { - public float speed = 100; - private Rigidbody2D rigidbody2d; - - private void Awake() - { - rigidbody2d = GetComponent(); - } - - public override void OnStartServer() - { - base.OnStartServer(); - - // only simulate ball physics on server - rigidbody2d.simulated = true; - - // Serve the ball from left player - rigidbody2d.velocity = Vector2.right * speed; - } - - float HitFactor(Vector2 ballPos, Vector2 racketPos, float racketHeight) - { - // ascii art: - // || 1 <- at the top of the racket - // || - // || 0 <- at the middle of the racket - // || - // || -1 <- at the bottom of the racket - return (ballPos.y - racketPos.y) / racketHeight; - } - - // only call this on server - [ServerCallback] - void OnCollisionEnter2D(Collision2D col) - { - // Note: 'col' holds the collision information. If the - // Ball collided with a racket, then: - // col.gameObject is the racket - // col.transform.position is the racket's position - // col.collider is the racket's collider - - // did we hit a racket? then we need to calculate the hit factor - if (col.transform.GetComponent()) - { - // Calculate y direction via hit Factor - float y = HitFactor(transform.position, - col.transform.position, - col.collider.bounds.size.y); - - // Calculate x direction via opposite collision - float x = col.relativeVelocity.x > 0 ? 1 : -1; - - // Calculate direction, make length=1 via .normalized - Vector2 dir = new Vector2(x, y).normalized; - - // Set Velocity with dir * speed - rigidbody2d.velocity = dir * speed; - } - } - } -} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs.meta b/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs.meta deleted file mode 100644 index 951bb58..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongBall.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 2a08d5ab1f59230458264367f00c54d8 -timeCreated: 1426602353 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs b/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs deleted file mode 100644 index 75f9d93..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs +++ /dev/null @@ -1,25 +0,0 @@ -using UnityEngine; -using Mirror; - -namespace Ignorance.Examples.PongChamp -{ - public class AtariPongRacket : NetworkBehaviour - { - public float speed = 1500; - private Rigidbody2D rigidbody2d; - - private void Awake() - { - rigidbody2d = GetComponent(); - } - - // need to use FixedUpdate for rigidbody - void FixedUpdate() - { - // only let the local player control the racket. - // don't control other player's rackets - if (isLocalPlayer) - rigidbody2d.velocity = new Vector2(0, Input.GetAxisRaw("Vertical")) * speed * Time.fixedDeltaTime; - } - } -} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs.meta b/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs.meta deleted file mode 100644 index f0168bc..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/AtariPongRacket.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: b68eb08343b29a54dbd5ed7830fb9211 -timeCreated: 1426597826 -licenseType: Store -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs b/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs deleted file mode 100644 index 6f76470..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Scripts/OnlineTimer.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using Mirror; -using System.Diagnostics; -using Debug = UnityEngine.Debug; - -public class OnlineTimer : NetworkBehaviour -{ - private Stopwatch stopwatch; - - // Start is called before the first frame update - private void Awake() - { - stopwatch = new Stopwatch(); - } - - public override void OnStartClient() - { - stopwatch.Reset(); - stopwatch.Start(); - - Debug.Log("Stopwatch started!"); - - base.OnStartClient(); - } - - public void OnDisable() - { - if(stopwatch.IsRunning) - { - System.TimeSpan ts = stopwatch.Elapsed; - stopwatch.Stop(); - - Debug.Log("Stopwatch stopped: duration " + string.Format("{0:00}:{1:00}:{2:00}.{3:00}", - ts.Hours, ts.Minutes, ts.Seconds, - ts.Milliseconds / 10)); - } - } - - private void OnGUI() - { - if (!stopwatch.IsRunning) return; - - GUI.Box(new Rect(new Vector2(2, Screen.height - 36), new Vector2(320, 32)), "ONLINE TIME: " + string.Format("{0:00}:{1:00}:{2:00}.{3:00}", - stopwatch.Elapsed.Hours, stopwatch.Elapsed.Minutes, stopwatch.Elapsed.Seconds, - stopwatch.Elapsed.Milliseconds / 10)); - } -} diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab b/UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab deleted file mode 100644 index cec29bc..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/TenryuuBall.prefab +++ /dev/null @@ -1,178 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &542835289192032773 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 548291784780898253} - - component: {fileID: 394858453892616325} - - component: {fileID: 520653813702449573} - - component: {fileID: 440601958556739609} - - component: {fileID: 440842259441939327} - - component: {fileID: 8881572407762724401} - - component: {fileID: 5995301680282788937} - m_Layer: 0 - m_Name: TenryuuBall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &548291784780898253 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -3, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!212 &394858453892616325 -SpriteRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10754, 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: 0 - m_SelectedEditorRenderState: 0 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_Sprite: {fileID: 21300000, guid: 824ee62c0fc357b4081855e43253a948, type: 3} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_FlipX: 0 - m_FlipY: 0 - m_DrawMode: 0 - m_Size: {x: 1, y: 1} - m_AdaptiveModeThreshold: 0.5 - m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 - m_SpriteSortPoint: 0 ---- !u!50 &520653813702449573 -Rigidbody2D: - serializedVersion: 4 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_BodyType: 0 - m_Simulated: 1 - m_UseFullKinematicContacts: 0 - m_UseAutoMass: 0 - m_Mass: 0.0001 - m_LinearDrag: 0 - m_AngularDrag: 0 - m_GravityScale: 0 - m_Material: {fileID: 6200000, guid: 97a3e4cddb8635c4eba1265f44d106bf, type: 2} - m_Interpolate: 2 - m_SleepingMode: 1 - m_CollisionDetection: 1 - m_Constraints: 4 ---- !u!114 &440601958556739609 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} - m_Name: - m_EditorClassIdentifier: - sceneId: 0 - serverOnly: 0 - visible: 0 - m_AssetId: - hasSpawned: 0 ---- !u!114 &440842259441939327 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2f74aedd71d9a4f55b3ce499326d45fb, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - clientAuthority: 0 - localPositionSensitivity: 0.01 - localRotationSensitivity: 0.01 - localScaleSensitivity: 0.01 - compressRotation: 0 - interpolateScale: 1 - syncScale: 1 ---- !u!58 &8881572407762724401 -CircleCollider2D: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_Enabled: 1 - m_Density: 1 - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_UsedByEffector: 0 - m_UsedByComposite: 0 - m_Offset: {x: 0, y: 0} - serializedVersion: 2 - m_Radius: 1.28 ---- !u!114 &5995301680282788937 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 542835289192032773} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2a08d5ab1f59230458264367f00c54d8, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - speed: 70 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png b/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/PoutRyuu.png deleted file mode 100644 index 9db08b5726efc3889101f0be0b7d55af21625f51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30056 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 P00000NkvXXu0mjf+uI7) diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites.meta b/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites.meta deleted file mode 100644 index a6798fb..0000000 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0dbfc247338e79a4dbe7474f69b46503 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png b/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png deleted file mode 100644 index 20c4387c8b1306491974318a9d601c60207d069f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2791 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

b#YhU6FQuwV<4LVzi4zU4fe-q6`=WA@}z| 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 G#Qy data, int channel) { +#if MIRROR_40_0_OR_NEWER directConnectTransport.ServerSend(clientID, data, channel); +#else + directConnectTransport.ServerSend(clientID, channel, data); +#endif } public void ClientSend(ArraySegment data, int channel) { +#if MIRROR_40_0_OR_NEWER directConnectTransport.ClientSend(data, channel); +#else + directConnectTransport.ClientSend(channel, data); +#endif } #region Transport Callbacks diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMDirectConnectModule.cs.meta b/UnityProject/Assets/LRM/LRMDirectConnectModule.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMDirectConnectModule.cs.meta rename to UnityProject/Assets/LRM/LRMDirectConnectModule.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTools.cs b/UnityProject/Assets/LRM/LRMTools.cs similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTools.cs rename to UnityProject/Assets/LRM/LRMTools.cs diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTools.cs.meta b/UnityProject/Assets/LRM/LRMTools.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTools.cs.meta rename to UnityProject/Assets/LRM/LRMTools.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport.meta b/UnityProject/Assets/LRM/LRMTransport.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport.meta rename to UnityProject/Assets/LRM/LRMTransport.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportDirectConnect.cs b/UnityProject/Assets/LRM/LRMTransport/LRMTransportDirectConnect.cs similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportDirectConnect.cs rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportDirectConnect.cs diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportDirectConnect.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LRMTransportDirectConnect.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportDirectConnect.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportDirectConnect.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportNATPuncher.cs b/UnityProject/Assets/LRM/LRMTransport/LRMTransportNATPuncher.cs similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportNATPuncher.cs rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportNATPuncher.cs diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportNATPuncher.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LRMTransportNATPuncher.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportNATPuncher.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportNATPuncher.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportOverrides.cs b/UnityProject/Assets/LRM/LRMTransport/LRMTransportOverrides.cs similarity index 80% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportOverrides.cs rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportOverrides.cs index a34d7f4..305701f 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportOverrides.cs +++ b/UnityProject/Assets/LRM/LRMTransport/LRMTransportOverrides.cs @@ -86,11 +86,19 @@ namespace LightReflectiveMirror } else { - _clientSendBuffer.WriteString(ref pos, GetLocalIp() ?? "0.0.0.0"); + if (GetLocalIp() == null) + _clientSendBuffer.WriteString(ref pos, "0.0.0.0"); + else + _clientSendBuffer.WriteString(ref pos, GetLocalIp()); } _isClient = true; - clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#if MIRROR_40_0_OR_NEWER + clientToServerTransport.ClientSend(new System.ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new System.ArraySegment(_clientSendBuffer, 0, pos)); +#endif + } else { @@ -107,15 +115,23 @@ namespace LightReflectiveMirror { int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.LeaveRoom); - +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } if (_directConnectModule != null) _directConnectModule.ClientDisconnect(); } +#if MIRROR_40_0_OR_NEWER public override void ClientSend(ArraySegment segment, int channelId) +#else + public override void ClientSend(int channelId, ArraySegment segment) + +#endif { if (_directConnected) { @@ -127,11 +143,35 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.SendData); _clientSendBuffer.WriteBytes(ref pos, segment.Array.Take(segment.Count).ToArray()); _clientSendBuffer.WriteInt(ref pos, 0); - +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), channelId); +#else + clientToServerTransport.ClientSend(channelId, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } +#if !MIRROR_37_0_OR_NEWER + + public override bool ServerDisconnect(int connectionId) + { + if (_connectedRelayClients.TryGetBySecond(connectionId, out int relayId)) + { + int pos = 0; + _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.KickPlayer); + _clientSendBuffer.WriteInt(ref pos, relayId); + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); + return true; + } + + if (_connectedDirectClients.TryGetBySecond(connectionId, out int directId)) + return _directConnectModule.KickClient(directId); + + return false; + } + +#else + public override void ServerDisconnect(int connectionId) { if (_connectedRelayClients.TryGetBySecond(connectionId, out int relayId)) @@ -147,7 +187,13 @@ namespace LightReflectiveMirror _directConnectModule.KickClient(directId); } +#endif + +#if MIRROR_40_0_OR_NEWER public override void ServerSend(int connectionId, ArraySegment segment, int channelId) +#else + public override void ServerSend(int connectionId, int channelId, ArraySegment segment) +#endif { if (_directConnectModule != null && _connectedDirectClients.TryGetBySecond(connectionId, out int directId)) { @@ -159,8 +205,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.SendData); _clientSendBuffer.WriteBytes(ref pos, segment.Array.Take(segment.Count).ToArray()); _clientSendBuffer.WriteInt(ref pos, _connectedRelayClients.GetBySecond(connectionId)); - +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), channelId); +#else + clientToServerTransport.ClientSend(channelId, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } @@ -193,16 +242,14 @@ namespace LightReflectiveMirror int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.CreateRoom); - _clientSendBuffer.WriteInt(ref pos, maxServerPlayers); _clientSendBuffer.WriteString(ref pos, serverName); _clientSendBuffer.WriteBool(ref pos, isPublicServer); _clientSendBuffer.WriteString(ref pos, extraServerData); - // If we have direct connect module, and our local IP isnt null, tell server. Only time local IP is null is on cellular networks, such as IOS and Android. - _clientSendBuffer.WriteBool(ref pos, _directConnectModule != null ? GetLocalIp() != null : false); + _clientSendBuffer.WriteBool(ref pos, _directConnectModule != null ? GetLocalIp() != null ? true : false : false); - if (_directConnectModule != null && GetLocalIp() != null && useNATPunch) + if (_directConnectModule != null && GetLocalIp() != null) { _clientSendBuffer.WriteString(ref pos, GetLocalIp()); // Transport port will be NAT port + 1 for the proxy connections. @@ -221,8 +268,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteBool(ref pos, false); _clientSendBuffer.WriteInt(ref pos, _directConnectModule == null ? 1 : _directConnectModule.SupportsNATPunch() ? _directConnectModule.GetTransportPort() : 1); } - +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } public override void ServerStop() @@ -233,7 +283,11 @@ namespace LightReflectiveMirror int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.LeaveRoom); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif if (_directConnectModule != null) _directConnectModule.StopServer(); diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportOverrides.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LRMTransportOverrides.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportOverrides.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportOverrides.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportRequests.cs b/UnityProject/Assets/LRM/LRMTransport/LRMTransportRequests.cs similarity index 98% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportRequests.cs rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportRequests.cs index f805f4e..5ddd899 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportRequests.cs +++ b/UnityProject/Assets/LRM/LRMTransport/LRMTransportRequests.cs @@ -115,7 +115,11 @@ namespace LightReflectiveMirror _isClient = true; +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new System.ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new System.ArraySegment(_clientSendBuffer, 0, pos)); +#endif } IEnumerator GetServerList(LRMRegions region) diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportRequests.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LRMTransportRequests.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportRequests.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportRequests.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportVariables.cs b/UnityProject/Assets/LRM/LRMTransport/LRMTransportVariables.cs similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportVariables.cs rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportVariables.cs diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportVariables.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LRMTransportVariables.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LRMTransportVariables.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LRMTransportVariables.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LightReflectiveMirrorTransport.cs b/UnityProject/Assets/LRM/LRMTransport/LightReflectiveMirrorTransport.cs similarity index 95% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LightReflectiveMirrorTransport.cs rename to UnityProject/Assets/LRM/LRMTransport/LightReflectiveMirrorTransport.cs index 5706909..5e9bab3 100644 --- a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LightReflectiveMirrorTransport.cs +++ b/UnityProject/Assets/LRM/LRMTransport/LightReflectiveMirrorTransport.cs @@ -127,9 +127,14 @@ namespace LightReflectiveMirror int pos = 0; _clientSendBuffer.WriteByte(ref pos, 200); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif // If NAT Puncher is initialized, send heartbeat on that as well. + try { if (_NATPuncher != null) @@ -195,7 +200,7 @@ namespace LightReflectiveMirror break; case OpCodes.ServerLeft: - // Called when server was closed. + // Called when we were kicked, or server was closed. if (_isClient) { _isClient = false; @@ -343,7 +348,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteBool(ref pos, false); _clientSendBuffer.WriteBool(ref pos, false); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } @@ -359,8 +368,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteString(ref pos, newServerData); _clientSendBuffer.WriteBool(ref pos, false); _clientSendBuffer.WriteBool(ref pos, false); - +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } @@ -377,7 +389,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteBool(ref pos, isPublic); _clientSendBuffer.WriteBool(ref pos, false); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } @@ -394,7 +410,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteBool(ref pos, true); _clientSendBuffer.WriteInt(ref pos, maxPlayers); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } } @@ -415,7 +435,11 @@ namespace LightReflectiveMirror _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.AuthenticationResponse); _clientSendBuffer.WriteString(ref pos, authenticationKey); +#if MIRROR_40_0_OR_NEWER clientToServerTransport.ClientSend(new ArraySegment(_clientSendBuffer, 0, pos), 0); +#else + clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); +#endif } public enum OpCodes diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LightReflectiveMirrorTransport.cs.meta b/UnityProject/Assets/LRM/LRMTransport/LightReflectiveMirrorTransport.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/LRMTransport/LightReflectiveMirrorTransport.cs.meta rename to UnityProject/Assets/LRM/LRMTransport/LightReflectiveMirrorTransport.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources.meta b/UnityProject/Assets/LRM/Resources.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources.meta rename to UnityProject/Assets/LRM/Resources.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources/LRM.png b/UnityProject/Assets/LRM/Resources/LRM.png similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources/LRM.png rename to UnityProject/Assets/LRM/Resources/LRM.png diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources/LRM.png.meta b/UnityProject/Assets/LRM/Resources/LRM.png.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/Resources/LRM.png.meta rename to UnityProject/Assets/LRM/Resources/LRM.png.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/SocketProxy.cs b/UnityProject/Assets/LRM/SocketProxy.cs similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/SocketProxy.cs rename to UnityProject/Assets/LRM/SocketProxy.cs diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/SocketProxy.cs.meta b/UnityProject/Assets/LRM/SocketProxy.cs.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/SocketProxy.cs.meta rename to UnityProject/Assets/LRM/SocketProxy.cs.meta diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/package.json b/UnityProject/Assets/LRM/package.json similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/package.json rename to UnityProject/Assets/LRM/package.json diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/LRM/package.json.meta b/UnityProject/Assets/LRM/package.json.meta similarity index 100% rename from UnityProject/Assets/Mirror/Runtime/Transport/LRM/package.json.meta rename to UnityProject/Assets/LRM/package.json.meta diff --git a/UnityProject/Assets/LRMFunctionTester.unity b/UnityProject/Assets/LRMFunctionTester.unity index 58c39a5..c96ddf9 100644 --- a/UnityProject/Assets/LRMFunctionTester.unity +++ b/UnityProject/Assets/LRMFunctionTester.unity @@ -38,12 +38,12 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 11 + serializedVersion: 12 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 @@ -98,7 +98,7 @@ LightmapSettings: m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 1 + m_LightingSettings: {fileID: 0} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -118,6 +118,8 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} @@ -200,6 +202,7 @@ Transform: 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: 0} m_RootOrder: 0 @@ -232,6 +235,7 @@ 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: [] m_Father: {fileID: 1172724429} m_RootOrder: 0 @@ -256,6 +260,7 @@ 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: @@ -358,6 +363,7 @@ Light: 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 &539119553 @@ -370,6 +376,7 @@ Transform: 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: 0} m_RootOrder: 1 @@ -436,6 +443,7 @@ Transform: 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: 0} m_RootOrder: 4 @@ -472,6 +480,7 @@ MonoBehaviour: Port: 7777 NoDelay: 1 Interval: 10 + Timeout: 10000 FastResend: 2 CongestionWindow: 0 SendWindowSize: 4096 @@ -489,6 +498,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0.2683339, y: 0.5533862, z: -0.71634865} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1013063541} m_RootOrder: 0 @@ -510,7 +520,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!114 &1013063539 MonoBehaviour: m_ObjectHideFlags: 0 @@ -524,13 +534,16 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: clientToServerTransport: {fileID: 978065553} - serverIP: 127.0.0.1 + serverIP: 129.151.223.167 serverPort: 7777 endpointServerPort: 8080 heartBeatInterval: 3 connectOnAwake: 1 authenticationKey: Secret Auth Key - diconnectedFromRelay: + disconnectedFromRelay: + m_PersistentCalls: + m_Calls: [] + connectedToRelay: m_PersistentCalls: m_Calls: [] useNATPunch: 0 @@ -566,7 +579,6 @@ MonoBehaviour: autoStartServerBuild: 1 serverTickRate: 30 serverBatching: 1 - serverBatchInterval: 0 offlineScene: onlineScene: transport: {fileID: 1013063539} @@ -589,11 +601,63 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: -0.2683339, y: -0.5533862, z: 0.71634865} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: - {fileID: 978065554} m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1094339529 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1094339531} + - component: {fileID: 1094339530} + m_Layer: 0 + m_Name: FishBait - Connector + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1094339530 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1094339529} + 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: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!4 &1094339531 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1094339529} + 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: 1516572637330113619} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1172724428 GameObject: m_ObjectHideFlags: 0 @@ -622,6 +686,7 @@ 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: 278665275} m_Father: {fileID: 1251691190} @@ -647,6 +712,7 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -728,6 +794,7 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 --- !u!223 &1251691189 Canvas: m_ObjectHideFlags: 0 @@ -759,6 +826,7 @@ 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: 1172724429} m_Father: {fileID: 0} @@ -782,3 +850,757 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: functionDisplay: {fileID: 278665276} +--- !u!1 &1287384425 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1287384427} + - component: {fileID: 1287384426} + m_Layer: 0 + m_Name: FishBait - Direct Connect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1287384426 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1287384425} + 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: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!4 &1287384427 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1287384425} + 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: 1516572637330113619} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!224 &905488192866952489 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5776995517907044923} + 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: 5670112770959365451} + 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!114 &1516572637330113616 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} + m_Name: + m_EditorClassIdentifier: + _refreshDefaultPrefabs: 0 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 + _logging: {fileID: 0} + _spawnablePrefabs: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, type: 2} +--- !u!1 &1516572637330113617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1516572637330113619} + - component: {fileID: 1516572637330113616} + - component: {fileID: 8234759579310384502} + - component: {fileID: 1516572637330113630} + - component: {fileID: 8234759579310384505} + - component: {fileID: 8234759579310384507} + - component: {fileID: 8234759579310384506} + m_Layer: 0 + m_Name: FishNetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1516572637330113619 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + 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: 5670112771492132974} + - {fileID: 1287384427} + - {fileID: 1094339531} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1516572637330113630 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + 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!224 &1595977265591389899 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3529504718462195493} + 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: 5670112771043582155} + 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!222 &3447973838823685665 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5776995517907044923} + m_CullTransparentMesh: 0 +--- !u!1 &3529504718462195493 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1595977265591389899} + - component: {fileID: 3788041517377950370} + - component: {fileID: 4993975790925741784} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &3788041517377950370 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3529504718462195493} + m_CullTransparentMesh: 0 +--- !u!114 &4993975790925741784 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3529504718462195493} + 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!222 &5670112770959365444 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112770959365448} + m_CullTransparentMesh: 0 +--- !u!114 &5670112770959365445 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112770959365448} + 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!1 &5670112770959365448 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5670112770959365451} + - component: {fileID: 5670112770959365444} + - component: {fileID: 5670112770959365445} + - component: {fileID: 5670112770959365450} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &5670112770959365450 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112770959365448} + 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: 5670112770959365445} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 5670112771492132978} + 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!224 &5670112770959365451 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112770959365448} + 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: 905488192866952489} + m_Father: {fileID: 5670112771492132974} + 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!222 &5670112771043582148 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771043582152} + m_CullTransparentMesh: 0 +--- !u!114 &5670112771043582149 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771043582152} + 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!1 &5670112771043582152 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5670112771043582155} + - component: {fileID: 5670112771043582148} + - component: {fileID: 5670112771043582149} + - component: {fileID: 5670112771043582154} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &5670112771043582154 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771043582152} + 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: 5670112771043582149} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 5670112771492132978} + 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!224 &5670112771043582155 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771043582152} + 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: 1595977265591389899} + m_Father: {fileID: 5670112771492132974} + 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 &5670112771492132972 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771492132979} + 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!114 &5670112771492132973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771492132979} + 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!224 &5670112771492132974 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771492132979} + 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: 5670112771043582155} + - {fileID: 5670112770959365451} + m_Father: {fileID: 1516572637330113619} + 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!223 &5670112771492132975 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771492132979} + 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!114 &5670112771492132978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5670112771492132979} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + _autoStartType: 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} + _serverIndicator: {fileID: 4993975790925741784} + _clientIndicator: {fileID: 7026884142372709074} +--- !u!1 &5670112771492132979 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5670112771492132974} + - component: {fileID: 5670112771492132978} + - component: {fileID: 5670112771492132975} + - component: {fileID: 5670112771492132972} + - component: {fileID: 5670112771492132973} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &5776995517907044923 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 905488192866952489} + - component: {fileID: 3447973838823685665} + - component: {fileID: 7026884142372709074} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &7026884142372709074 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5776995517907044923} + 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 &8234759579310384502 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} + m_Name: + m_EditorClassIdentifier: + _updateHostVisibility: 1 + _defaultConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!114 &8234759579310384505 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34e4a322dca349547989b14021da4e23, type: 3} + m_Name: + m_EditorClassIdentifier: + Transport: {fileID: 8234759579310384507} + _latencySimulator: + _enabled: 0 + _simulateHost: 1 + _latency: 0 + _outOfOrder: 0 + _packetLoss: 0 +--- !u!114 &8234759579310384506 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 21eba6e2b0a7e964eb29db14a4eae4d6, type: 3} + m_Name: + m_EditorClassIdentifier: + directConnectTransport: {fileID: 1287384426} + showDebugLogs: 0 +--- !u!114 &8234759579310384507 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516572637330113617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37bf248b7e575fe4592c1ec247b10573, type: 3} + m_Name: + m_EditorClassIdentifier: + transport: {fileID: 1094339530} + transportHolder: {fileID: 0} + serverIP: 172.105.109.117 + serverPort: 7777 + endpointServerPort: 8080 + heartBeatInterval: 3 + connectOnAwake: 1 + authenticationKey: Secret Auth Key + disconnectedFromRelay: + m_PersistentCalls: + m_Calls: [] + connectedToRelay: + m_PersistentCalls: + m_Calls: [] + useNATPunch: 1 + NATPunchtroughPort: 1 + useLoadBalancer: 0 + loadBalancerPort: 7070 + loadBalancerAddress: 127.0.0.1 + serverName: My awesome server! + extraServerData: Map 1 + maxServerPlayers: 10 + isPublicServer: 1 + serverListUpdated: + m_PersistentCalls: + m_Calls: [] + serverStatus: Not Started. + serverId: + region: 1 diff --git a/UnityProject/Assets/LRMTestScene.unity b/UnityProject/Assets/LRMTestScene.unity index 5379b75..9df0999 100644 --- a/UnityProject/Assets/LRMTestScene.unity +++ b/UnityProject/Assets/LRMTestScene.unity @@ -43,7 +43,7 @@ RenderSettings: --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 11 + serializedVersion: 12 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 @@ -98,7 +98,7 @@ LightmapSettings: m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 1 + m_LightingSettings: {fileID: 1263934456} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -118,6 +118,8 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} @@ -191,6 +193,7 @@ Transform: m_LocalRotation: {x: 0, y: 0.92387956, z: -0.38268343, w: 0} m_LocalPosition: {x: 0, y: 6.5, z: 8} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -224,6 +227,7 @@ 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: 2007463783} m_Father: {fileID: 1933302372} @@ -248,6 +252,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 + m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -278,6 +283,7 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 1933302373} + m_TargetAssemblyTypeName: m_MethodName: RequestServerList m_Mode: 1 m_Arguments: @@ -303,6 +309,7 @@ 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: @@ -352,6 +359,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 3, y: 0, z: 3} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 6 @@ -395,6 +403,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 3, y: 0, z: -3} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 4 @@ -411,61 +420,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!1 &627350787 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 627350789} - - component: {fileID: 627350788} - m_Layer: 0 - m_Name: LRM - Connector - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &627350788 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 627350787} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 872fa23ef6e77334ca452ce16f6cd091, type: 3} - m_Name: - m_EditorClassIdentifier: - port: 7778 - LogType: 1 - DebugDisplay: 0 - serverBindsAll: 1 - serverBindAddress: - serverMaxPeerCapacity: 50 - serverMaxNativeWaitTime: 1 - clientMaxNativeWaitTime: 3 - clientStatusUpdateInterval: -1 - Channels: 0100000002000000 - PacketBufferCapacity: 4096 - MaxAllowedPacketSize: 33554432 ---- !u!4 &627350789 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 627350787} - 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: [] - m_Father: {fileID: 1282001518} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &664671251 GameObject: m_ObjectHideFlags: 0 @@ -495,6 +449,7 @@ 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: 1203620976} m_Father: {fileID: 816919830} @@ -519,6 +474,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 + m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -568,6 +524,7 @@ 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: @@ -618,6 +575,7 @@ 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: [] m_Father: {fileID: 1600541101} m_RootOrder: 0 @@ -694,6 +652,7 @@ 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: 952924772} m_Father: {fileID: 816919830} @@ -718,6 +677,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 + m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -767,6 +727,7 @@ 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: @@ -818,6 +779,7 @@ 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: 1600541101} - {fileID: 716818609} @@ -875,6 +837,7 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 0.392} m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -923,6 +886,7 @@ 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: 1862319968} m_Father: {fileID: 716818609} @@ -963,10 +927,12 @@ MeshRenderer: 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: 4294967295 m_RendererPriority: 0 m_Materials: @@ -991,6 +957,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!64 &1107091654 MeshCollider: m_ObjectHideFlags: 0 @@ -1023,6 +990,7 @@ Transform: 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: 0} m_RootOrder: 1 @@ -1089,6 +1057,7 @@ Transform: 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: 0} m_RootOrder: 9 @@ -1119,6 +1088,7 @@ 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: 1996275865} m_Father: {fileID: 664671252} @@ -1179,10 +1149,73 @@ Transform: 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: 1282001518} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!850595691 &1263934456 +LightingSettings: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Settings.lighting + serializedVersion: 4 + m_GIWorkflowMode: 1 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_RealtimeEnvironmentLighting: 1 + m_BounceScale: 1 + m_AlbedoBoost: 1 + m_IndirectOutputScale: 1 + m_UsingShadowmask: 1 + m_BakeBackend: 0 + m_LightmapMaxSize: 1024 + m_BakeResolution: 40 + m_Padding: 2 + m_LightmapCompression: 3 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAO: 0 + m_MixedBakeMode: 2 + m_LightmapsBakeMode: 1 + m_FilterMode: 1 + m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_RealtimeResolution: 2 + m_ForceWhiteAlbedo: 0 + m_ForceUpdates: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 256 + m_FinalGatherFiltering: 1 + m_PVRCulling: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_LightProbeSampleCountMultiplier: 4 + m_PVRBounces: 2 + m_PVRMinBounces: 2 + m_PVREnvironmentMIS: 0 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_PVRTiledBaking: 0 --- !u!1 &1282001517 GameObject: m_ObjectHideFlags: 0 @@ -1202,7 +1235,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!4 &1282001518 Transform: m_ObjectHideFlags: 0 @@ -1213,9 +1246,10 @@ Transform: 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: 1226094909} - - {fileID: 627350789} + - {fileID: 1521806212} m_Father: {fileID: 0} m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1292,8 +1326,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 7064b1b1d0671194baf55fa8d5f564d6, type: 3} m_Name: m_EditorClassIdentifier: - clientToServerTransport: {fileID: 627350788} - serverIP: 127.0.0.1 + clientToServerTransport: {fileID: 1521806211} + serverIP: 129.151.223.167 serverPort: 7777 endpointServerPort: 8080 heartBeatInterval: 3 @@ -1305,7 +1339,7 @@ MonoBehaviour: connectedToRelay: m_PersistentCalls: m_Calls: [] - useNATPunch: 0 + useNATPunch: 1 NATPunchtroughPort: 1 useLoadBalancer: 0 loadBalancerPort: 7070 @@ -1347,6 +1381,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: -3, y: 0, z: 3} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 7 @@ -1390,6 +1425,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: -3, y: 0, z: -3} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 5 @@ -1406,6 +1442,61 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!1 &1521806210 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1521806212} + - component: {fileID: 1521806211} + m_Layer: 0 + m_Name: LRM - Connector + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1521806211 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1521806210} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!4 &1521806212 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1521806210} + 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: 1282001518} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1600541100 GameObject: m_ObjectHideFlags: 0 @@ -1435,6 +1526,7 @@ 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: 668534521} m_Father: {fileID: 816919830} @@ -1473,6 +1565,7 @@ 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: @@ -1523,6 +1616,7 @@ 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: [] m_Father: {fileID: 952924772} m_RootOrder: 0 @@ -1547,6 +1641,7 @@ 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: @@ -1628,6 +1723,7 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 --- !u!223 &1933302371 Canvas: m_ObjectHideFlags: 0 @@ -1659,6 +1755,7 @@ 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: 171810014} - {fileID: 816919830} @@ -1713,6 +1810,7 @@ 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: [] m_Father: {fileID: 1203620976} m_RootOrder: 0 @@ -1737,6 +1835,7 @@ 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: @@ -1787,6 +1886,7 @@ 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: [] m_Father: {fileID: 171810014} m_RootOrder: 0 @@ -1811,6 +1911,7 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1913,6 +2014,7 @@ Light: 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 &2054208276 @@ -1925,7 +2027,718 @@ Transform: m_LocalRotation: {x: 0.10938167, y: 0.8754261, z: -0.40821788, w: 0.23456976} m_LocalPosition: {x: 0, y: 10, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 50, y: 150, z: 0} +--- !u!222 &257649730695299973 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 574729534439294466} + m_CullTransparentMesh: 0 +--- !u!1 &574729534439294466 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2388179379349069804} + - component: {fileID: 257649730695299973} + - component: {fileID: 8236136101642268671} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &1791061905344032518 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7435032252216548124} + m_CullTransparentMesh: 0 +--- !u!224 &2388179379349069804 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 574729534439294466} + 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: 8769283793889161708} + 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 &2452626056005064052 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + 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: 8769283793969129801} + m_Father: {fileID: 0} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2452626056005064054 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2452626056005064052} + - component: {fileID: 2452626056005064055} + - component: {fileID: 4991455776135803985} + - component: {fileID: 2452626056005064057} + - component: {fileID: 4991455776135803998} + - component: {fileID: 4991455776135803999} + - component: {fileID: 4991455776135803984} + m_Layer: 0 + m_Name: FishNetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2452626056005064055 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} + m_Name: + m_EditorClassIdentifier: + _refreshDefaultPrefabs: 0 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 + _logging: {fileID: 0} + _spawnablePrefabs: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, type: 2} +--- !u!114 &2452626056005064057 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} + m_Name: + m_EditorClassIdentifier: + _playerPrefab: {fileID: 1022466107096954536, guid: 3b6afe29d22f1fc458cbbcaa766322ac, + type: 3} + _addToDefaultScene: 1 + Spawns: + - {fileID: 535739936} + - {fileID: 1501912663} + - {fileID: 251893065} + - {fileID: 1458789073} +--- !u!224 &4292625434128561166 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7435032252216548124} + 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: 8769283793436492908} + 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!114 &4991455776135803984 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37bf248b7e575fe4592c1ec247b10573, type: 3} + m_Name: + m_EditorClassIdentifier: + transport: {fileID: 4991455776135803999} + serverIP: + serverPort: 7777 + endpointServerPort: 8080 + heartBeatInterval: 3 + connectOnAwake: 1 + authenticationKey: Secret Auth Key + disconnectedFromRelay: + m_PersistentCalls: + m_Calls: [] + connectedToRelay: + m_PersistentCalls: + m_Calls: [] + useNATPunch: 0 + NATPunchtroughPort: -1 + useLoadBalancer: 0 + loadBalancerPort: 7070 + loadBalancerAddress: + serverName: My awesome server! + extraServerData: Map 1 + maxServerPlayers: 10 + isPublicServer: 1 + serverListUpdated: + m_PersistentCalls: + m_Calls: [] + serverStatus: Not Started. + serverId: + region: 1 +--- !u!114 &4991455776135803985 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} + m_Name: + m_EditorClassIdentifier: + _updateHostVisibility: 1 + _defaultConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!114 &4991455776135803998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34e4a322dca349547989b14021da4e23, type: 3} + m_Name: + m_EditorClassIdentifier: + Transport: {fileID: 4991455776135803984} + _latencySimulator: + _enabled: 0 + _simulateHost: 1 + _latency: 0 + _outOfOrder: 0 + _packetLoss: 0 +--- !u!114 &4991455776135803999 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2452626056005064054} + 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: 4095 + _clientAddress: localhost + _timeout: 15 +--- !u!114 &6234680929065661429 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7435032252216548124} + 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 &7435032252216548124 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4292625434128561166} + - component: {fileID: 1791061905344032518} + - component: {fileID: 6234680929065661429} + m_Layer: 5 + m_Name: Indicator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &8236136101642268671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 574729534439294466} + 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 &8769283793436492898 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793436492911} + 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 &8769283793436492899 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793436492911} + m_CullTransparentMesh: 0 +--- !u!224 &8769283793436492908 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793436492911} + 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: 4292625434128561166} + m_Father: {fileID: 8769283793969129801} + 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 &8769283793436492909 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793436492911} + 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: 8769283793436492898} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 8769283793969129813} + 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 &8769283793436492911 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8769283793436492908} + - component: {fileID: 8769283793436492899} + - component: {fileID: 8769283793436492898} + - component: {fileID: 8769283793436492909} + m_Layer: 5 + m_Name: Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &8769283793889161698 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793889161711} + 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 &8769283793889161699 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793889161711} + m_CullTransparentMesh: 0 +--- !u!224 &8769283793889161708 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793889161711} + 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: 2388179379349069804} + m_Father: {fileID: 8769283793969129801} + 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 &8769283793889161709 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793889161711} + 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: 8769283793889161698} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 8769283793969129813} + 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 &8769283793889161711 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8769283793889161708} + - component: {fileID: 8769283793889161699} + - component: {fileID: 8769283793889161698} + - component: {fileID: 8769283793889161709} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!223 &8769283793969129800 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793969129812} + 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 &8769283793969129801 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793969129812} + 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: 8769283793889161708} + - {fileID: 8769283793436492908} + m_Father: {fileID: 2452626056005064052} + 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 &8769283793969129802 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793969129812} + 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 &8769283793969129803 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793969129812} + 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 &8769283793969129812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8769283793969129801} + - component: {fileID: 8769283793969129813} + - component: {fileID: 8769283793969129800} + - component: {fileID: 8769283793969129803} + - component: {fileID: 8769283793969129802} + m_Layer: 5 + m_Name: NetworkHudCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &8769283793969129813 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8769283793969129812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} + m_Name: + m_EditorClassIdentifier: + _autoStartType: 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} + _serverIndicator: {fileID: 8236136101642268671} + _clientIndicator: {fileID: 6234680929065661429} diff --git a/UnityProject/Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta b/UnityProject/Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta index bf2d3b6..ce1eb3f 100644 --- a/UnityProject/Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta +++ b/UnityProject/Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 guid: 97a3e4cddb8635c4eba1265f44d106bf timeCreated: 1426602119 -licenseType: Store +licenseType: Free NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta b/UnityProject/Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta index 47b9fc8..cc68660 100644 --- a/UnityProject/Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta +++ b/UnityProject/Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta @@ -77,12 +77,12 @@ TextureImporter: bones: [] spriteID: 09819c66a21defd49b2cfc87fea685d2 vertices: [] - indices: + indices: '' edges: [] weights: [] - spritePackingTag: + spritePackingTag: '' pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Mirror/Runtime/NetworkIdentity.cs b/UnityProject/Assets/Mirror/Runtime/NetworkIdentity.cs index b796580..f78f2f2 100644 --- a/UnityProject/Assets/Mirror/Runtime/NetworkIdentity.cs +++ b/UnityProject/Assets/Mirror/Runtime/NetworkIdentity.cs @@ -7,7 +7,7 @@ using UnityEngine.Serialization; #if UNITY_EDITOR using UnityEditor; #if UNITY_2018_3_OR_NEWER -using UnityEditor.Experimental.SceneManagement; + #endif #endif @@ -478,7 +478,7 @@ namespace Mirror // assign a sceneId and clear the assetId would still be // triggered for prefabs. in other words: if we are in prefab // stage, do not bother with anything else ever! - else if (PrefabStageUtility.GetCurrentPrefabStage() != null) + else if (UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null) { // when modifying a prefab in prefab stage, Unity calls // OnValidate for that prefab and for all scene objects based on @@ -488,7 +488,7 @@ namespace Mirror // scene object based on the prefab? // * GetCurrentPrefabStage = 'are we editing ANY prefab?' // * GetPrefabStage(go) = 'are we editing THIS prefab?' - if (PrefabStageUtility.GetPrefabStage(gameObject) != null) + if (UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage(gameObject) != null) { // force 0 for prefabs sceneId = 0; @@ -496,7 +496,7 @@ namespace Mirror // NOTE: might make sense to use GetPrefabStage for asset // path, but let's not touch it while it works. #if UNITY_2020_1_OR_NEWER - string path = PrefabStageUtility.GetCurrentPrefabStage().assetPath; + string path = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage().assetPath; #else string path = PrefabStageUtility.GetCurrentPrefabStage().prefabAssetPath; #endif diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance.meta deleted file mode 100644 index b56e66c..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: cc98cd95e3fb22b4eb88082706967357 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs deleted file mode 100644 index 2542fd4..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceClient.cs +++ /dev/null @@ -1,296 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. - -using ENet; -// using NetStack.Buffers; -using System; -using System.Collections.Concurrent; -using System.Threading; -using UnityEngine; -using Event = ENet.Event; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using EventType = ENet.EventType; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using Object = System.Object; // fixes CS0104 ambigous reference between the same thing in UnityEngine - -namespace IgnoranceTransport -{ - public class IgnoranceClient - { - // Client connection address and port - public string ConnectAddress = "127.0.0.1"; - public int ConnectPort = 7777; - // How many channels are expected - public int ExpectedChannels = 2; - // Native poll waiting time - public int PollTime = 1; - // Maximum Packet Size - public int MaximumPacketSize = 33554432; - // General Verbosity by default. - public int Verbosity = 1; - - // Queues - public ConcurrentQueue Incoming = new ConcurrentQueue(); - public ConcurrentQueue Outgoing = new ConcurrentQueue(); - public ConcurrentQueue Commands = new ConcurrentQueue(); - public ConcurrentQueue ConnectionEvents = new ConcurrentQueue(); - public ConcurrentQueue StatusUpdates = new ConcurrentQueue(); - - public bool IsAlive => WorkerThread != null && WorkerThread.IsAlive; - - private volatile bool CeaseOperation = false; - private Thread WorkerThread; - - public void Start() - { - Debug.Log("IgnoranceClient.Start()"); - - if (WorkerThread != null && WorkerThread.IsAlive) - { - // Cannot do that. - Debug.LogError("A worker thread is already running. Cannot start another."); - return; - } - - CeaseOperation = false; - ThreadParamInfo threadParams = new ThreadParamInfo() - { - Address = ConnectAddress, - Port = ConnectPort, - Channels = ExpectedChannels, - PollTime = PollTime, - PacketSizeLimit = MaximumPacketSize, - Verbosity = Verbosity - }; - - // Drain queues. - if (Incoming != null) while (Incoming.TryDequeue(out _)) ; - if (Outgoing != null) while (Outgoing.TryDequeue(out _)) ; - if (Commands != null) while (Commands.TryDequeue(out _)) ; - if (ConnectionEvents != null) while (ConnectionEvents.TryDequeue(out _)) ; - if (StatusUpdates != null) while (StatusUpdates.TryDequeue(out _)) ; - - WorkerThread = new Thread(ThreadWorker); - WorkerThread.Start(threadParams); - - Debug.Log("Client has dispatched worker thread."); - } - - public void Stop() - { - Debug.Log("Telling client thread to stop, this may take a while depending on network load"); - CeaseOperation = true; - } - - // This runs in a seperate thread, be careful accessing anything outside of it's thread - // or you may get an AccessViolation/crash. - private void ThreadWorker(Object parameters) - { - if (Verbosity > 0) - Debug.Log("Ignorance Client: Initializing. Please stand by..."); - - ThreadParamInfo setupInfo; - Address clientAddress = new Address(); - Peer clientPeer; - Host clientENetHost; - Event clientENetEvent; - IgnoranceClientStats icsu = default; - - // Grab the setup information. - if (parameters.GetType() == typeof(ThreadParamInfo)) - { - setupInfo = (ThreadParamInfo)parameters; - } - else - { - Debug.LogError("Ignorance Client: Startup failure: Invalid thread parameters. Aborting."); - return; - } - - // Attempt to initialize ENet inside the thread. - if (Library.Initialize()) - { - Debug.Log("Ignorance Client: ENet initialized."); - } - else - { - Debug.LogError("Ignorance Client: Failed to initialize ENet. This threads' fucked."); - return; - } - - // Attempt to connect to our target. - clientAddress.SetHost(setupInfo.Address); - clientAddress.Port = (ushort)setupInfo.Port; - - using (clientENetHost = new Host()) - { - // TODO: Maybe try catch this - clientENetHost.Create(); - clientPeer = clientENetHost.Connect(clientAddress, setupInfo.Channels); - - while (!CeaseOperation) - { - bool pollComplete = false; - - // Step 0: Handle commands. - while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) - { - switch (commandPacket.Type) - { - default: - break; - - case IgnoranceCommandType.ClientWantsToStop: - CeaseOperation = true; - break; - - case IgnoranceCommandType.ClientRequestsStatusUpdate: - // Respond with statistics so far. - if (!clientPeer.IsSet) - break; - - icsu.RTT = clientPeer.RoundTripTime; - - icsu.BytesReceived = clientPeer.BytesReceived; - icsu.BytesSent = clientPeer.BytesSent; - - icsu.PacketsReceived = clientENetHost.PacketsReceived; - icsu.PacketsSent = clientPeer.PacketsSent; - icsu.PacketsLost = clientPeer.PacketsLost; - - StatusUpdates.Enqueue(icsu); - break; - } - } - // Step 1: Send out data. - // ---> Sending to Server - while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) - { - // TODO: Revise this, could we tell the Peer to disconnect right here? - // Stop early if we get a client stop packet. - // if (outgoingPacket.Type == IgnorancePacketType.ClientWantsToStop) break; - - int ret = clientPeer.Send(outgoingPacket.Channel, ref outgoingPacket.Payload); - - if (ret < 0 && setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Client: ENet error code {ret} while sending packet to Peer {outgoingPacket.NativePeerId}."); - } - - // Step 2: - // <----- Receive Data packets - // This loops until polling is completed. It may take a while, if it's - // a slow networking day. - while (!pollComplete) - { - Packet incomingPacket; - Peer incomingPeer; - int incomingPacketLength; - - // Any events worth checking out? - if (clientENetHost.CheckEvents(out clientENetEvent) <= 0) - { - // If service time is met, break out of it. - if (clientENetHost.Service(setupInfo.PollTime, out clientENetEvent) <= 0) break; - - // Poll is done. - pollComplete = true; - } - - // Setup the packet references. - incomingPeer = clientENetEvent.Peer; - - // Now, let's handle those events. - switch (clientENetEvent.Type) - { - case EventType.None: - default: - break; - - case EventType.Connect: - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - NativePeerId = incomingPeer.ID, - IP = incomingPeer.IP, - Port = incomingPeer.Port - }); - break; - - case EventType.Disconnect: - case EventType.Timeout: - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - WasDisconnect = true - }); - break; - - - case EventType.Receive: - // Receive event type usually includes a packet; so cache its reference. - incomingPacket = clientENetEvent.Packet; - - if (!incomingPacket.IsSet) - { - if (setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Client: A receive event did not supply us with a packet to work with. This should never happen."); - break; - } - - incomingPacketLength = incomingPacket.Length; - - // Never consume more than we can have capacity for. - if (incomingPacketLength > setupInfo.PacketSizeLimit) - { - if (setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Client: Incoming packet is too big. My limit is {setupInfo.PacketSizeLimit} byte(s) whilest this packet is {incomingPacketLength} bytes."); - - incomingPacket.Dispose(); - break; - } - - IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket - { - Channel = clientENetEvent.ChannelID, - NativePeerId = incomingPeer.ID, - Payload = incomingPacket - }; - - Incoming.Enqueue(incomingQueuePacket); - break; - } - } - } - - Debug.Log("Ignorance Server: Shutdown commencing, disconnecting and flushing connection."); - - // Flush the client and disconnect. - clientPeer.Disconnect(0); - clientENetHost.Flush(); - - // Fix for client stuck in limbo, since the disconnection event may not be fired until next loop. - ConnectionEvents.Enqueue(new IgnoranceConnectionEvent() - { - WasDisconnect = true - }); - } - - // Deinitialize - Library.Deinitialize(); - if (setupInfo.Verbosity > 0) - Debug.Log("Ignorance Client: Shutdown complete."); - } - - - private struct ThreadParamInfo - { - public int Channels; - public int PollTime; - public int Port; - public int PacketSizeLimit; - public int Verbosity; - public string Address; - } - } -} diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs deleted file mode 100644 index 4f71947..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Core/IgnoranceServer.cs +++ /dev/null @@ -1,328 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. - -using ENet; -// using NetStack.Buffers; -using System.Collections.Concurrent; -using System.Threading; -using UnityEngine; -using Event = ENet.Event; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using EventType = ENet.EventType; // fixes CS0104 ambigous reference between the same thing in UnityEngine -using Object = System.Object; // fixes CS0104 ambigous reference between the same thing in UnityEngine - -namespace IgnoranceTransport -{ - public class IgnoranceServer - { - // Server Properties - // - Bind Settings - public string BindAddress = "127.0.0.1"; - public int BindPort = 7777; - // - Maximum allowed channels, peers, etc. - public int MaximumChannels = 2; - public int MaximumPeers = 100; - public int MaximumPacketSize = 33554432; // ENet.cs: uint maxPacketSize = 32 * 1024 * 1024 = 33554432 - // - Native poll waiting time - public int PollTime = 1; - public int Verbosity = 1; - - public bool IsAlive => WorkerThread != null && WorkerThread.IsAlive; - - private volatile bool CeaseOperation = false; - - // Queues - public ConcurrentQueue Incoming = new ConcurrentQueue(); - public ConcurrentQueue Outgoing = new ConcurrentQueue(); - public ConcurrentQueue Commands = new ConcurrentQueue(); - public ConcurrentQueue ConnectionEvents = new ConcurrentQueue(); - public ConcurrentQueue DisconnectionEvents = new ConcurrentQueue(); - - // Thread - private Thread WorkerThread; - - public void Start() - { - if (WorkerThread != null && WorkerThread.IsAlive) - { - // Cannot do that. - Debug.LogError("A worker thread is already running. Cannot start another."); - return; - } - - CeaseOperation = false; - ThreadParamInfo threadParams = new ThreadParamInfo() - { - Address = BindAddress, - Port = BindPort, - Peers = MaximumPeers, - Channels = MaximumChannels, - PollTime = PollTime, - PacketSizeLimit = MaximumPacketSize, - Verbosity = Verbosity - }; - - // Drain queues. - if (Incoming != null) while (Incoming.TryDequeue(out _)) ; - if (Outgoing != null) while (Outgoing.TryDequeue(out _)) ; - if (Commands != null) while (Commands.TryDequeue(out _)) ; - if (ConnectionEvents != null) while (ConnectionEvents.TryDequeue(out _)) ; - if (DisconnectionEvents != null) while (DisconnectionEvents.TryDequeue(out _)) ; - - WorkerThread = new Thread(ThreadWorker); - WorkerThread.Start(threadParams); - - // Announce - if (Verbosity > 0) - Debug.Log("Server has dispatched worker thread."); - } - - public void Stop() - { - if (Verbosity > 0) - Debug.Log("Telling server thread to stop, this may take a while depending on network load"); - CeaseOperation = true; - } - - private void ThreadWorker(Object parameters) - { - if (Verbosity > 0) - Debug.Log("Ignorance Server: Initializing. Please stand by..."); - - // Thread cache items - ThreadParamInfo setupInfo; - Address serverAddress = new Address(); - Host serverENetHost; - Event serverENetEvent; - - Peer[] serverPeerArray; - - // Grab the setup information. - if (parameters.GetType() == typeof(ThreadParamInfo)) - { - setupInfo = (ThreadParamInfo)parameters; - } - else - { - Debug.LogError("Ignorance Server: Startup failure: Invalid thread parameters. Aborting."); - return; - } - - // Attempt to initialize ENet inside the thread. - if (Library.Initialize()) - { - Debug.Log("Ignorance Server: ENet initialized."); - } - else - { - Debug.LogError("Ignorance Server: Failed to initialize ENet. This threads' fucked."); - return; - } - - // Configure the server address. - serverAddress.SetHost(setupInfo.Address); - serverAddress.Port = (ushort)setupInfo.Port; - serverPeerArray = new Peer[setupInfo.Peers]; - - using (serverENetHost = new Host()) - { - // Create the server object. - serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels); - - // Loop until we're told to cease operations. - while (!CeaseOperation) - { - // Intermission: Command Handling - while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) - { - switch (commandPacket.Type) - { - default: - break; - - // Boot a Peer off the Server. - case IgnoranceCommandType.ServerKickPeer: - uint targetPeer = commandPacket.PeerId; - - if (!serverPeerArray[targetPeer].IsSet) continue; - if (setupInfo.Verbosity > 0) - Debug.Log($"Ignorance Server: Booting Peer {targetPeer} off this server instance."); - - IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() - { - WasDisconnect = true, - NativePeerId = targetPeer - }; - - DisconnectionEvents.Enqueue(iced); - - // Disconnect and reset the peer array's entry for that peer. - serverPeerArray[targetPeer].DisconnectNow(0); - serverPeerArray[targetPeer] = default; - break; - } - } - - // Step One: - // ---> Sending to peers - while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) - { - // Only create a packet if the server knows the peer. - if (serverPeerArray[outgoingPacket.NativePeerId].IsSet) - { - int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload); - - if (ret < 0 && setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Server: ENet error code {ret} while sending packet to Peer {outgoingPacket.NativePeerId}."); - } - else - { - // A peer might have disconnected, this is OK - just log the packet if set to paranoid. - if (setupInfo.Verbosity > 1) - Debug.LogWarning("Ignorance Server: Can't send packet, a native peer object is not set. This may be normal if the Peer has disconnected before this send cycle."); - } - - } - - // Step 2 - // <--- Receiving from peers - bool pollComplete = false; - - while (!pollComplete) - { - Packet incomingPacket; - Peer incomingPeer; - int incomingPacketLength; - - // Any events happening? - if (serverENetHost.CheckEvents(out serverENetEvent) <= 0) - { - // If service time is met, break out of it. - if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0) break; - - pollComplete = true; - } - - // Setup the packet references. - incomingPeer = serverENetEvent.Peer; - - switch (serverENetEvent.Type) - { - // Idle. - case EventType.None: - default: - break; - - // Connection Event. - case EventType.Connect: - if (setupInfo.Verbosity > 1) - Debug.Log("Ignorance Server: Here comes a new Peer connection."); - - IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent() - { - NativePeerId = incomingPeer.ID, - IP = incomingPeer.IP, - Port = incomingPeer.Port - }; - - ConnectionEvents.Enqueue(ice); - - // Assign a reference to the Peer. - serverPeerArray[incomingPeer.ID] = incomingPeer; - break; - - // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together. - case EventType.Disconnect: - case EventType.Timeout: - if (!serverPeerArray[incomingPeer.ID].IsSet) break; - - if (setupInfo.Verbosity > 1) - Debug.Log("Ignorance Server: Peer disconnection."); - - IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() - { - WasDisconnect = true, - NativePeerId = incomingPeer.ID - }; - - DisconnectionEvents.Enqueue(iced); - - // Reset the peer array's entry for that peer. - serverPeerArray[incomingPeer.ID] = default; - break; - - case EventType.Receive: - // Receive event type usually includes a packet; so cache its reference. - incomingPacket = serverENetEvent.Packet; - if (!incomingPacket.IsSet) - { - if (setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Server: A receive event did not supply us with a packet to work with. This should never happen."); - break; - } - - incomingPacketLength = incomingPacket.Length; - - // Firstly check if the packet is too big. If it is, do not process it - drop it. - if (incomingPacketLength > setupInfo.PacketSizeLimit) - { - if (setupInfo.Verbosity > 0) - Debug.LogWarning($"Ignorance Server: Incoming packet is too big. My limit is {setupInfo.PacketSizeLimit} byte(s) whilest this packet is {incomingPacketLength} bytes."); - - incomingPacket.Dispose(); - break; - } - - IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket - { - Channel = serverENetEvent.ChannelID, - NativePeerId = incomingPeer.ID, - Payload = incomingPacket, - }; - - // Enqueue. - Incoming.Enqueue(incomingQueuePacket); - break; - } - } - } - - if (Verbosity > 0) - Debug.Log("Ignorance Server: Shutdown commencing, flushing connections."); - - // Cleanup and flush everything. - serverENetHost.Flush(); - - // Kick everyone. - for (int i = 0; i < serverPeerArray.Length; i++) - { - if (!serverPeerArray[i].IsSet) continue; - serverPeerArray[i].DisconnectNow(0); - } - } - - // Flush again to ensure ENet gets those Disconnection stuff out. - // May not be needed; better to err on side of caution - - if (setupInfo.Verbosity > 0) - Debug.Log("Ignorance Server: Shutdown complete."); - - Library.Deinitialize(); - } - - private struct ThreadParamInfo - { - public int Channels; - public int Peers; - public int PollTime; - public int Port; - public int PacketSizeLimit; - public int Verbosity; - public string Address; - } - } -} diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies.meta deleted file mode 100644 index 565dc3b..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 12f903db684732e45b130ad56f7c86c1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs deleted file mode 100644 index cf4336c..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Dependencies/ENet.cs +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * Managed C# wrapper for an extended version of ENet - * This is a fork from upstream and is available at http://github.com/SoftwareGuy/ENet-CSharp - * - * Copyright (c) 2019 Matt Coburn (SoftwareGuy/Coburn64), Chris Burns (c6burns) - * Copyright (c) 2013 James Bellinger, 2016 Nate Shoffner, 2018 Stanislav Denisov - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -using System; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -namespace ENet -{ - [Flags] - public enum PacketFlags - { - None = 0, - Reliable = 1 << 0, - Unsequenced = 1 << 1, - NoAllocate = 1 << 2, - UnreliableFragmented = 1 << 3, - Instant = 1 << 4, - Unthrottled = 1 << 5, - Sent = 1 << 8 - } - - public enum EventType - { - None = 0, - Connect = 1, - Disconnect = 2, - Receive = 3, - Timeout = 4 - } - - public enum PeerState - { - Uninitialized = -1, - Disconnected = 0, - Connecting = 1, - AcknowledgingConnect = 2, - ConnectionPending = 3, - ConnectionSucceeded = 4, - Connected = 5, - DisconnectLater = 6, - Disconnecting = 7, - AcknowledgingDisconnect = 8, - Zombie = 9 - } - - [StructLayout(LayoutKind.Explicit, Size = 18)] - internal struct ENetAddress - { - [FieldOffset(16)] - public ushort port; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ENetEvent - { - public EventType type; - public IntPtr peer; - public byte channelID; - public uint data; - public IntPtr packet; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ENetCallbacks - { - public AllocCallback malloc; - public FreeCallback free; - public NoMemoryCallback noMemory; - } - - public delegate IntPtr AllocCallback(IntPtr size); - public delegate void FreeCallback(IntPtr memory); - public delegate void NoMemoryCallback(); - public delegate void PacketFreeCallback(Packet packet); - public delegate int InterceptCallback(ref Event @event, ref Address address, IntPtr receivedData, int receivedDataLength); - public delegate ulong ChecksumCallback(IntPtr buffers, int bufferCount); - - internal static class ArrayPool - { - [ThreadStatic] - private static byte[] byteBuffer; - [ThreadStatic] - private static IntPtr[] pointerBuffer; - - public static byte[] GetByteBuffer() - { - if (byteBuffer == null) - byteBuffer = new byte[64]; - - return byteBuffer; - } - - public static IntPtr[] GetPointerBuffer() - { - if (pointerBuffer == null) - pointerBuffer = new IntPtr[Library.maxPeers]; - - return pointerBuffer; - } - } - - public struct Address - { - private ENetAddress nativeAddress; - - internal ENetAddress NativeData - { - get - { - return nativeAddress; - } - - set - { - nativeAddress = value; - } - } - - internal Address(ENetAddress address) - { - nativeAddress = address; - } - - public ushort Port - { - get - { - return nativeAddress.port; - } - - set - { - nativeAddress.port = value; - } - } - - public string GetIP() - { - StringBuilder ip = new StringBuilder(1025); - - if (Native.enet_address_get_ip(ref nativeAddress, ip, (IntPtr)ip.Capacity) != 0) - return String.Empty; - - return ip.ToString(); - } - - public bool SetIP(string ip) - { - if (ip == null) - throw new ArgumentNullException("ip"); - - return Native.enet_address_set_ip(ref nativeAddress, ip) == 0; - } - - public string GetHost() - { - StringBuilder hostName = new StringBuilder(1025); - - if (Native.enet_address_get_hostname(ref nativeAddress, hostName, (IntPtr)hostName.Capacity) != 0) - return String.Empty; - - return hostName.ToString(); - } - - public bool SetHost(string hostName) - { - if (hostName == null) - throw new ArgumentNullException("hostName"); - - return Native.enet_address_set_hostname(ref nativeAddress, hostName) == 0; - } - } - - public struct Event - { - private ENetEvent nativeEvent; - - internal ENetEvent NativeData - { - get - { - return nativeEvent; - } - - set - { - nativeEvent = value; - } - } - - internal Event(ENetEvent @event) - { - nativeEvent = @event; - } - - public EventType Type - { - get - { - return nativeEvent.type; - } - } - - public Peer Peer - { - get - { - return new Peer(nativeEvent.peer); - } - } - - public byte ChannelID - { - get - { - return nativeEvent.channelID; - } - } - - public uint Data - { - get - { - return nativeEvent.data; - } - } - - public Packet Packet - { - get - { - return new Packet(nativeEvent.packet); - } - } - } - - public class Callbacks - { - private ENetCallbacks nativeCallbacks; - - internal ENetCallbacks NativeData - { - get - { - return nativeCallbacks; - } - - set - { - nativeCallbacks = value; - } - } - - public Callbacks(AllocCallback allocCallback, FreeCallback freeCallback, NoMemoryCallback noMemoryCallback) - { - nativeCallbacks.malloc = allocCallback; - nativeCallbacks.free = freeCallback; - nativeCallbacks.noMemory = noMemoryCallback; - } - } - - public struct Packet : IDisposable - { - private IntPtr nativePacket; - - internal IntPtr NativeData - { - get - { - return nativePacket; - } - - set - { - nativePacket = value; - } - } - - internal Packet(IntPtr packet) - { - nativePacket = packet; - } - - public void Dispose() - { - if (nativePacket != IntPtr.Zero) - { - Native.enet_packet_dispose(nativePacket); - nativePacket = IntPtr.Zero; - } - } - - public bool IsSet - { - get - { - return nativePacket != IntPtr.Zero; - } - } - - public IntPtr Data - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_data(nativePacket); - } - } - - public IntPtr UserData - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_user_data(nativePacket); - } - - set - { - ThrowIfNotCreated(); - - Native.enet_packet_set_user_data(nativePacket, value); - } - } - - public int Length - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_get_length(nativePacket); - } - } - - public bool HasReferences - { - get - { - ThrowIfNotCreated(); - - return Native.enet_packet_check_references(nativePacket) != 0; - } - } - - internal void ThrowIfNotCreated() - { - if (nativePacket == IntPtr.Zero) - throw new InvalidOperationException("Packet not created"); - } - - public void SetFreeCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_packet_set_free_callback(nativePacket, callback); - } - - public void SetFreeCallback(PacketFreeCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_packet_set_free_callback(nativePacket, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void Create(byte[] data) - { - if (data == null) - throw new ArgumentNullException("data"); - - Create(data, data.Length); - } - - public void Create(byte[] data, int length) - { - Create(data, length, PacketFlags.None); - } - - public void Create(byte[] data, PacketFlags flags) - { - Create(data, data.Length, flags); - } - - public void Create(byte[] data, int length, PacketFlags flags) - { - if (data == null) - throw new ArgumentNullException("data"); - - if (length < 0 || length > data.Length) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); - } - - public void Create(IntPtr data, int length, PacketFlags flags) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - - if (length < 0) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create(data, (IntPtr)length, flags); - } - - public void Create(byte[] data, int offset, int length, PacketFlags flags) - { - if (data == null) - throw new ArgumentNullException("data"); - - if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); - - if (length < 0 || length > data.Length) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); - } - - public void Create(IntPtr data, int offset, int length, PacketFlags flags) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - - if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); - - if (length < 0) - throw new ArgumentOutOfRangeException("length"); - - nativePacket = Native.enet_packet_create_offset(data, (IntPtr)length, (IntPtr)offset, flags); - } - - public void CopyTo(byte[] destination, int startPos = 0) - { - if (destination == null) - throw new ArgumentNullException("destination"); - - // Fix by katori, prevents trying to copy a NULL - // from native world (ie. disconnect a client) - if (Data == null) - { - return; - } - - Marshal.Copy(Data, destination, startPos, Length); - } - } - - public class Host : IDisposable - { - private IntPtr nativeHost; - - internal IntPtr NativeData - { - get - { - return nativeHost; - } - - set - { - nativeHost = value; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (nativeHost != IntPtr.Zero) - { - Native.enet_host_destroy(nativeHost); - nativeHost = IntPtr.Zero; - } - } - - ~Host() - { - Dispose(false); - } - - public bool IsSet - { - get - { - return nativeHost != IntPtr.Zero; - } - } - - public uint PeersCount - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_peers_count(nativeHost); - } - } - - public uint PacketsSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_packets_sent(nativeHost); - } - } - - public uint PacketsReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_packets_received(nativeHost); - } - } - - public uint BytesSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_bytes_sent(nativeHost); - } - } - - public uint BytesReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_host_get_bytes_received(nativeHost); - } - } - - internal void ThrowIfNotCreated() - { - if (nativeHost == IntPtr.Zero) - throw new InvalidOperationException("Host not created"); - } - - private static void ThrowIfChannelsExceeded(int channelLimit) - { - if (channelLimit < 0 || channelLimit > Library.maxChannelCount) - throw new ArgumentOutOfRangeException("channelLimit"); - } - - public void Create() - { - Create(null, 1, 0); - } - - public void Create(int bufferSize) - { - Create(null, 1, 0, 0, 0, bufferSize); - } - - public void Create(Address? address, int peerLimit) - { - Create(address, peerLimit, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit) - { - Create(address, peerLimit, channelLimit, 0, 0, 0); - } - - public void Create(int peerLimit, int channelLimit) - { - Create(null, peerLimit, channelLimit, 0, 0, 0); - } - - public void Create(int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) - { - Create(null, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth) - { - Create(address, peerLimit, channelLimit, incomingBandwidth, outgoingBandwidth, 0); - } - - public void Create(Address? address, int peerLimit, int channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize) - { - if (nativeHost != IntPtr.Zero) - throw new InvalidOperationException("Host already created"); - - if (peerLimit < 0 || peerLimit > Library.maxPeers) - throw new ArgumentOutOfRangeException("peerLimit"); - - ThrowIfChannelsExceeded(channelLimit); - - if (address != null) - { - var nativeAddress = address.Value.NativeData; - - nativeHost = Native.enet_host_create(ref nativeAddress, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); - } - else - { - nativeHost = Native.enet_host_create(IntPtr.Zero, (IntPtr)peerLimit, (IntPtr)channelLimit, incomingBandwidth, outgoingBandwidth, bufferSize); - } - - if (nativeHost == IntPtr.Zero) - throw new InvalidOperationException("Host creation call failed"); - } - - public void PreventConnections(bool state) - { - ThrowIfNotCreated(); - - Native.enet_host_prevent_connections(nativeHost, (byte)(state ? 1 : 0)); - } - - public void Broadcast(byte channelID, ref Packet packet) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - Native.enet_host_broadcast(nativeHost, channelID, packet.NativeData); - packet.NativeData = IntPtr.Zero; - } - - public void Broadcast(byte channelID, ref Packet packet, Peer excludedPeer) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - Native.enet_host_broadcast_exclude(nativeHost, channelID, packet.NativeData, excludedPeer.NativeData); - packet.NativeData = IntPtr.Zero; - } - - public void Broadcast(byte channelID, ref Packet packet, Peer[] peers) - { - if (peers == null) - throw new ArgumentNullException("peers"); - - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - - if (peers.Length > 0) - { - IntPtr[] nativePeers = ArrayPool.GetPointerBuffer(); - int nativeCount = 0; - - for (int i = 0; i < peers.Length; i++) - { - if (peers[i].NativeData != IntPtr.Zero) - { - nativePeers[nativeCount] = peers[i].NativeData; - nativeCount++; - } - } - - Native.enet_host_broadcast_selective(nativeHost, channelID, packet.NativeData, nativePeers, (IntPtr)nativeCount); - } - - packet.NativeData = IntPtr.Zero; - } - - public int CheckEvents(out Event @event) - { - ThrowIfNotCreated(); - - ENetEvent nativeEvent; - - var result = Native.enet_host_check_events(nativeHost, out nativeEvent); - - if (result <= 0) - { - @event = default(Event); - - return result; - } - - @event = new Event(nativeEvent); - - return result; - } - - public Peer Connect(Address address) - { - return Connect(address, 0, 0); - } - - public Peer Connect(Address address, int channelLimit) - { - return Connect(address, channelLimit, 0); - } - - public Peer Connect(Address address, int channelLimit, uint data) - { - ThrowIfNotCreated(); - ThrowIfChannelsExceeded(channelLimit); - - var nativeAddress = address.NativeData; - var peer = new Peer(Native.enet_host_connect(nativeHost, ref nativeAddress, (IntPtr)channelLimit, data)); - - if (peer.NativeData == IntPtr.Zero) - throw new InvalidOperationException("Host connect call failed"); - - return peer; - } - - public int Service(int timeout, out Event @event) - { - if (timeout < 0) - throw new ArgumentOutOfRangeException("timeout"); - - ThrowIfNotCreated(); - - ENetEvent nativeEvent; - - var result = Native.enet_host_service(nativeHost, out nativeEvent, (uint)timeout); - - if (result <= 0) - { - @event = default(Event); - - return result; - } - - @event = new Event(nativeEvent); - - return result; - } - - public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth) - { - ThrowIfNotCreated(); - - Native.enet_host_bandwidth_limit(nativeHost, incomingBandwidth, outgoingBandwidth); - } - - public void SetChannelLimit(int channelLimit) - { - ThrowIfNotCreated(); - ThrowIfChannelsExceeded(channelLimit); - - Native.enet_host_channel_limit(nativeHost, (IntPtr)channelLimit); - } - - public void SetMaxDuplicatePeers(ushort number) - { - ThrowIfNotCreated(); - - Native.enet_host_set_max_duplicate_peers(nativeHost, number); - } - - public void SetInterceptCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_intercept_callback(nativeHost, callback); - } - - public void SetInterceptCallback(InterceptCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_intercept_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void SetChecksumCallback(IntPtr callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_checksum_callback(nativeHost, callback); - } - - public void SetChecksumCallback(ChecksumCallback callback) - { - ThrowIfNotCreated(); - - Native.enet_host_set_checksum_callback(nativeHost, Marshal.GetFunctionPointerForDelegate(callback)); - } - - public void Flush() - { - ThrowIfNotCreated(); - - Native.enet_host_flush(nativeHost); - } - } - - public struct Peer - { - private IntPtr nativePeer; - private uint nativeID; - - internal IntPtr NativeData - { - get - { - return nativePeer; - } - - set - { - nativePeer = value; - } - } - - internal Peer(IntPtr peer) - { - nativePeer = peer; - nativeID = nativePeer != IntPtr.Zero ? Native.enet_peer_get_id(nativePeer) : 0; - } - - public bool IsSet - { - get - { - return nativePeer != IntPtr.Zero; - } - } - - public uint ID - { - get - { - return nativeID; - } - } - - public string IP - { - get - { - ThrowIfNotCreated(); - - byte[] ip = ArrayPool.GetByteBuffer(); - - if (Native.enet_peer_get_ip(nativePeer, ip, (IntPtr)ip.Length) == 0) - return Encoding.ASCII.GetString(ip, 0, ip.StringLength()); - else - return String.Empty; - } - } - - public ushort Port - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_port(nativePeer); - } - } - - public uint MTU - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_mtu(nativePeer); - } - } - - public PeerState State - { - get - { - return nativePeer == IntPtr.Zero ? PeerState.Uninitialized : Native.enet_peer_get_state(nativePeer); - } - } - - public uint RoundTripTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_rtt(nativePeer); - } - } - - public uint LastRoundTripTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_last_rtt(nativePeer); - } - } - - public uint LastSendTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_lastsendtime(nativePeer); - } - } - - public uint LastReceiveTime - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_lastreceivetime(nativePeer); - } - } - - public ulong PacketsSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_sent(nativePeer); - } - } - - public ulong PacketsLost - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_lost(nativePeer); - } - } - - public float PacketsThrottle - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_packets_throttle(nativePeer); - } - } - - public ulong BytesSent - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_bytes_sent(nativePeer); - } - } - - public ulong BytesReceived - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_bytes_received(nativePeer); - } - } - - public IntPtr Data - { - get - { - ThrowIfNotCreated(); - - return Native.enet_peer_get_data(nativePeer); - } - - set - { - ThrowIfNotCreated(); - - Native.enet_peer_set_data(nativePeer, value); - } - } - - internal void ThrowIfNotCreated() - { - if (nativePeer == IntPtr.Zero) - throw new InvalidOperationException("Peer not created"); - } - - public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration, uint threshold) - { - ThrowIfNotCreated(); - - Native.enet_peer_throttle_configure(nativePeer, interval, acceleration, deceleration, threshold); - } - - public int Send(byte channelID, ref Packet packet) - { - ThrowIfNotCreated(); - - packet.ThrowIfNotCreated(); - - return Native.enet_peer_send(nativePeer, channelID, packet.NativeData); - } - - public bool Receive(out byte channelID, out Packet packet) - { - ThrowIfNotCreated(); - - IntPtr nativePacket = Native.enet_peer_receive(nativePeer, out channelID); - - if (nativePacket != IntPtr.Zero) - { - packet = new Packet(nativePacket); - - return true; - } - - packet = default(Packet); - - return false; - } - - public void Ping() - { - ThrowIfNotCreated(); - - Native.enet_peer_ping(nativePeer); - } - - public void PingInterval(uint interval) - { - ThrowIfNotCreated(); - - Native.enet_peer_ping_interval(nativePeer, interval); - } - - public void Timeout(uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum) - { - ThrowIfNotCreated(); - - Native.enet_peer_timeout(nativePeer, timeoutLimit, timeoutMinimum, timeoutMaximum); - } - - public void Disconnect(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect(nativePeer, data); - } - - public void DisconnectNow(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect_now(nativePeer, data); - } - - public void DisconnectLater(uint data) - { - ThrowIfNotCreated(); - - Native.enet_peer_disconnect_later(nativePeer, data); - } - - public void Reset() - { - ThrowIfNotCreated(); - - Native.enet_peer_reset(nativePeer); - } - } - - public static class Extensions - { - public static int StringLength(this byte[] data) - { - if (data == null) - throw new ArgumentNullException("data"); - - int i; - - for (i = 0; i < data.Length && data[i] != 0; i++) ; - - return i; - } - } - - public static class Library - { - public const uint maxChannelCount = 0xFF; - public const uint maxPeers = 0xFFF; - public const uint maxPacketSize = 32 * 1024 * 1024; - public const uint throttleThreshold = 40; - public const uint throttleScale = 32; - public const uint throttleAcceleration = 2; - public const uint throttleDeceleration = 2; - public const uint throttleInterval = 5000; - public const uint timeoutLimit = 32; - public const uint timeoutMinimum = 5000; - public const uint timeoutMaximum = 30000; - public const uint version = (2 << 16) | (4 << 8) | (7); - - public static uint Time - { - get - { - return Native.enet_time_get(); - } - } - - public static bool Initialize() - { - if (Native.enet_linked_version() != version) - throw new InvalidOperationException("ENet native is out of date. Download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); - - return Native.enet_initialize() == 0; - } - - public static bool Initialize(Callbacks callbacks) - { - if (callbacks == null) - throw new ArgumentNullException("callbacks"); - - if (Native.enet_linked_version() != version) - throw new InvalidOperationException("ENet native is out of date. Download the latest release from https://github.com/SoftwareGuy/ENet-CSharp/releases"); - - ENetCallbacks nativeCallbacks = callbacks.NativeData; - - return Native.enet_initialize_with_callbacks(version, ref nativeCallbacks) == 0; - } - - public static void Deinitialize() - { - Native.enet_deinitialize(); - } - - public static ulong CRC64(IntPtr buffers, int bufferCount) - { - return Native.enet_crc64(buffers, bufferCount); - } - } - - [SuppressUnmanagedCodeSecurity] - internal static class Native - { - // This should address Unity usage and bug #66: Platform specific Enet / libenet - // https://github.com/SoftwareGuy/Ignorance/issues/66 -#if UNITY_EDITOR - // We are inside the Unity Editor. -#if UNITY_EDITOR_OSX - // Unity Editor on macOS needs to use libenet. - private const string nativeLibrary = "libenet"; -#else - private const string nativeLibrary = "enet"; -#endif -#endif - -#if !UNITY_EDITOR - // We're not inside the Unity Editor. -#if __APPLE__ && !(__IOS__ || UNITY_IOS) - // Use libenet on macOS. - private const string nativeLibrary = "libenet"; -#elif __IOS__ || UNITY_IOS - // We're building for a certain mobile fruity OS. - private const string nativeLibrary = "__Internal"; -#else - // Assume everything else, Windows et al. - private const string nativeLibrary = "enet"; -#endif -#endif - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_initialize(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_initialize_with_callbacks(uint version, ref ENetCallbacks inits); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_deinitialize(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_linked_version(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_time_get(); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_crc64(IntPtr buffers, int bufferCount); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_set_ip(ref ENetAddress address, string ip); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_set_hostname(ref ENetAddress address, string hostName); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_get_ip(ref ENetAddress address, StringBuilder ip, IntPtr ipLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_address_get_hostname(ref ENetAddress address, StringBuilder hostName, IntPtr nameLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create(byte[] data, IntPtr dataLength, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create(IntPtr data, IntPtr dataLength, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create_offset(byte[] data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_create_offset(IntPtr data, IntPtr dataLength, IntPtr dataOffset, PacketFlags flags); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_packet_check_references(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_get_data(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_get_user_data(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_packet_set_user_data(IntPtr packet, IntPtr userData); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_packet_get_length(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_packet_set_free_callback(IntPtr packet, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_packet_dispose(IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_create(ref ENetAddress address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_create(IntPtr address, IntPtr peerLimit, IntPtr channelLimit, uint incomingBandwidth, uint outgoingBandwidth, int bufferSize); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_host_connect(IntPtr host, ref ENetAddress address, IntPtr channelCount, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast(IntPtr host, byte channelID, IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast_exclude(IntPtr host, byte channelID, IntPtr packet, IntPtr excludedPeer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_broadcast_selective(IntPtr host, byte channelID, IntPtr packet, IntPtr[] peers, IntPtr peersLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_host_service(IntPtr host, out ENetEvent @event, uint timeout); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_host_check_events(IntPtr host, out ENetEvent @event); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_channel_limit(IntPtr host, IntPtr channelLimit); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_bandwidth_limit(IntPtr host, uint incomingBandwidth, uint outgoingBandwidth); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_peers_count(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_packets_sent(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_packets_received(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_bytes_sent(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_host_get_bytes_received(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_max_duplicate_peers(IntPtr host, ushort number); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_intercept_callback(IntPtr host, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_set_checksum_callback(IntPtr host, IntPtr callback); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_flush(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_destroy(IntPtr host); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_host_prevent_connections(IntPtr host, byte state); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_throttle_configure(IntPtr peer, uint interval, uint acceleration, uint deceleration, uint threshold); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_id(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_peer_get_ip(IntPtr peer, byte[] ip, IntPtr ipLength); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ushort enet_peer_get_port(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_mtu(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern PeerState enet_peer_get_state(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_rtt(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_last_rtt(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_lastsendtime(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint enet_peer_get_lastreceivetime(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_packets_sent(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_packets_lost(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern float enet_peer_get_packets_throttle(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_bytes_sent(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong enet_peer_get_bytes_received(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_peer_get_data(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_set_data(IntPtr peer, IntPtr data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int enet_peer_send(IntPtr peer, byte channelID, IntPtr packet); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr enet_peer_receive(IntPtr peer, out byte channelID); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_ping(IntPtr peer); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_ping_interval(IntPtr peer, uint pingInterval); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_timeout(IntPtr peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect_now(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_disconnect_later(IntPtr peer, uint data); - - [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void enet_peer_reset(IntPtr peer); - -#if UNITY_EDITOR - public static string nativeLibraryName { get { return nativeLibrary; } } -#endif - - } -} diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs deleted file mode 100644 index 0ff3186..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs +++ /dev/null @@ -1,83 +0,0 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using System.Linq; -using UnityEditor; - -namespace IgnoranceTransport -{ - /// - /// Adds the given define symbols to PlayerSettings define symbols. - /// Just add your own define symbols to the Symbols property at the below. - /// - [InitializeOnLoad] - public class AddIgnoranceDefine : Editor - { - private static string existingDefines = string.Empty; - - /// - /// Symbols that will be added to the editor - /// - public static readonly string[] Symbols = new string[] { - "IGNORANCE", // Ignorance exists - "IGNORANCE_1", // Major version - "IGNORANCE_1_4" // Major and minor version - }; - - /// - /// Do not remove these symbols - /// - public static readonly string[] DoNotRemoveTheseSymbols = new string[] - { - "IGNORANCE_NO_UPNP", - "IGNORANCE_MIRROR_POLLING" - }; - - /// - /// Add define symbols as soon as Unity gets done compiling. - /// - static AddIgnoranceDefine() - { - // Get the current scripting defines - string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); - if (existingDefines == definesString) - { - // 1.2.6: There is no need to apply the changes, return. - return; - } - - // Convert the string to a list - List allDefines = definesString.Split(';').ToList(); - // Remove any old version defines from previous installs - allDefines.RemoveAll(IsSafeToRemove); - // x => x.StartsWith("IGNORANCE") && !DoesSymbolExistInBlacklist(x)); - // Add any symbols that weren't already in the list - allDefines.AddRange(Symbols.Except(allDefines)); - - string newDefines = string.Join(";", allDefines.ToArray()); - PlayerSettings.SetScriptingDefineSymbolsForGroup( - EditorUserBuildSettings.selectedBuildTargetGroup, - newDefines - ); - - existingDefines = newDefines; - } - - // 1.2.4: Workaround to stop things from eating custom IGNORANCE_ symbols - static bool DoesSymbolExistInBlacklist(string symbol) - { - foreach(string s in DoNotRemoveTheseSymbols) - { - if (s == symbol.Trim()) return true; - } - - return false; - } - - static bool IsSafeToRemove (string input) - { - if (input.StartsWith("IGNORANCE") && !DoesSymbolExistInBlacklist(input)) return true; - return false; - } - } -} -#endif diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs.meta deleted file mode 100644 index dbff870..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/AddScriptingDefine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ed8acbde141f2d8469baf2142712de9e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs deleted file mode 100644 index dee6b62..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs +++ /dev/null @@ -1,44 +0,0 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor; - -namespace IgnoranceTransport -{ - public class IgnoranceToolbox - { -#pragma warning disable IDE0051 - [MenuItem("Ignorance/Mirror/Switch Update Method")] - public static void SwitchIgnoranceUpdateMethod () - { - - } - - [MenuItem("Ignorance/Debug/Reveal ENet Native Library Name")] - public static void RevealEnetLibraryName() - { - EditorUtility.DisplayDialog("Enet Library Name", $"Use this for debugging.\nYour platform expects the native Enet library to be called: {ENet.Native.nativeLibraryName}", "Got it"); - } - - [MenuItem("Ignorance/RTFM/Github Repository")] - private static void LaunchGithubRepo() - { - UnityEngine.Application.OpenURL("https://github.com/SoftwareGuy/Ignorance"); - } - - [MenuItem("Ignorance/RTFM/Github Issue Tracker")] - private static void LaunchGithubIssueTracker() - { - UnityEngine.Application.OpenURL("https://github.com/SoftwareGuy/Ignorance/issues"); - } - - [MenuItem("Ignorance/RTFM/ENet-CSharp Fork")] - private static void LaunchENetCSharpForkRepo() - { - UnityEngine.Application.OpenURL("https://github.com/SoftwareGuy/ENet-CSharp"); - } - - -#pragma warning restore - } -} -#endif diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs.meta deleted file mode 100644 index cf61ba3..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Editor/IgnoranceToolbox.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1fdecc996313d614ca16214d4e2b9162 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs deleted file mode 100644 index 28dbf7a..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs +++ /dev/null @@ -1,746 +0,0 @@ -// Ignorance 1.4.x -// Ignorance. It really kicks the Unity LLAPIs ass. -// https://github.com/SoftwareGuy/Ignorance -// ----------------- -// Copyright (c) 2019 - 2020 Matt Coburn (SoftwareGuy/Coburn64) -// Ignorance Transport is licensed under the MIT license. Refer -// to the LICENSE file for more information. -// ----------------- -// Ignorance Experimental (New) Version -// ----------------- -using ENet; -using Mirror; -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace IgnoranceTransport -{ - [DisallowMultipleComponent] - public class Ignorance : Transport - { - #region Inspector options - public int port = 7777; - - [Header("Debug & Logging Configuration")] - [Tooltip("How verbose do you want Ignorance to be?")] - public IgnoranceLogType LogType = IgnoranceLogType.Standard; - [Tooltip("Uses OnGUI to present you with statistics for Server and Client backend instances.")] - public bool DebugDisplay = false; - - [Header("Server Configuration")] - [Tooltip("Should the server bind to all interfaces?")] - public bool serverBindsAll = true; - [Tooltip("This is only used if Server Binds All is unticked.")] - public string serverBindAddress = string.Empty; - [Tooltip("This tells ENet how many Peer slots to create. Helps performance, avoids looping over huge native arrays. Recommended: Max Mirror players, rounded to nearest 10. (Example: 16 -> 20).")] - public int serverMaxPeerCapacity = 50; - [Tooltip("How long ENet waits in native world. The higher this value, the more CPU usage. Lower values may/may not impact performance at high packet load.")] - public int serverMaxNativeWaitTime = 1; - - [Header("Client Configuration")] - [Tooltip("How long ENet waits in native world. The higher this value, the more CPU usage used. This is for the client, unlike the one above. Higher value probably trades CPU for more responsive networking.")] - public int clientMaxNativeWaitTime = 3; - [Tooltip("Interval between asking ENet for client status updates. Set to -1 to disable.")] - public int clientStatusUpdateInterval = -1; - - [Header("Channel Configuration")] - [Tooltip("You must define your channels in the array shown here, otherwise ENet will not know what channel delivery type to use.")] - public IgnoranceChannelTypes[] Channels; - - [Header("Low-level Tweaking")] - [Tooltip("Used internally to keep allocations to a minimum. This is how much memory will be consumed by the packet buffer on startup, and then reused.")] - public int PacketBufferCapacity = 4096; - - [Tooltip("For UDP based protocols, it's best to keep your data under the safe MTU of 1200 bytes. You can increase this, however beware this may open you up to allocation attacks.")] - public int MaxAllowedPacketSize = 33554432; - #endregion - - #region Public Statistics - public IgnoranceClientStats ClientStatistics; - #endregion - -#if MIRROR_26_0_OR_NEWER - public override bool Available() - { - // Ignorance is not available for Unity WebGL, the PS4 (no dev kit to confirm) or Switch (port exists but I have no access to said code). - // Ignorance is available for most other operating systems. -#if (UNITY_WEBGL || UNITY_PS4 || UNITY_SWITCH) - return false; -#else - return true; -#endif - } - - public void Awake() - { - if (LogType != IgnoranceLogType.Nothing) - Debug.Log($"Thanks for using Ignorance {IgnoranceInternals.Version}. Keep up to date, report bugs and support the developer at https://github.com/SoftwareGuy/Ignorance!"); - } - - public override string ToString() - { - return $"Ignorance v{IgnoranceInternals.Version}"; - } - - public override void ClientConnect(string address) - { - ClientState = ConnectionState.Connecting; - cachedConnectionAddress = address; - - // Initialize. - InitializeClientBackend(); - - // Get going. - ignoreDataPackets = false; - - // Start! - Client.Start(); - } - - public override void ClientConnect(Uri uri) - { - if (uri.Scheme != IgnoranceInternals.Scheme) - throw new ArgumentException($"You used an invalid URI: {uri}. Please use {IgnoranceInternals.Scheme}://host:port instead", nameof(uri)); - - if (!uri.IsDefaultPort) - // Set the communication port to the one specified. - port = uri.Port; - - // Pass onwards to the proper handler. - ClientConnect(uri.Host); - } - - public override bool ClientConnected() => ClientState == ConnectionState.Connected; - - public override void ClientDisconnect() - { - if (Client != null) - Client.Stop(); - - // TODO: Figure this one out to see if it's related to a race condition. - // Maybe experiment with a while loop to pause main thread when disconnecting, - // since client might not stop on a dime. - // while(Client.IsAlive) ; - // v1.4.0b1: Probably fixed in IgnoranceClient.cs; need further testing. - - // ignoreDataPackets = true; - ClientState = ConnectionState.Disconnected; - } - -#if !MIRROR_37_0_OR_NEWER - public override void ClientSend(int channelId, ArraySegment segment) -#else - // v1.4.0b6: Mirror rearranged the ClientSend params, so we need to apply a fix for that or - // we end up using the obsoleted version. The obsolete version isn't a fatal error, but - // it's best to stick with the new structures. - public override void ClientSend(ArraySegment segment, int channelId) -#endif - { - if (Client == null) - { - Debug.LogError("Client object is null, this shouldn't really happen but it did..."); - return; - } - - if (channelId < 0 || channelId > Channels.Length) - { - Debug.LogError("Channel ID is out of bounds."); - return; - } - - // Create our struct... - Packet clientOutgoingPacket = default; - int byteCount = segment.Count; - int byteOffset = segment.Offset; - // Set our desired flags... - PacketFlags desiredFlags = (PacketFlags)Channels[channelId]; - - // Warn if over recommended MTU... - bool flagsSet = (desiredFlags & ReliableOrUnreliableFragmented) > 0; - - if (LogType != IgnoranceLogType.Nothing && byteCount > 1200 && !flagsSet) - Debug.LogWarning($"Warning: Client trying to send a Unreliable packet bigger than the recommended ENet 1200 byte MTU ({byteCount} > 1200). ENet will force Reliable Fragmented delivery."); - - // Create the packet. - clientOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, desiredFlags); - // byteCount - - // Enqueue the packet. - IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket - { - Channel = (byte)channelId, - Payload = clientOutgoingPacket - }; - - // Pass the packet onto the thread for dispatch. - Client.Outgoing.Enqueue(dispatchPacket); - } - - public override bool ServerActive() - { - // Very simple check. - return Server != null && Server.IsAlive; - } - -#if !MIRROR_37_0_OR_NEWER - // Workaround for legacy Mirror versions. - public override bool ServerDisconnect(int connectionId) => ServerDisconnectLegacy(connectionId); -#else - public override void ServerDisconnect(int connectionId) - { - if (Server == null) - { - Debug.LogError("Cannot enqueue kick packet; our Server object is null. Something has gone wrong."); - // Return here because otherwise we will get a NRE when trying to enqueue the kick packet. - return; - } - - IgnoranceCommandPacket kickPacket = new IgnoranceCommandPacket - { - Type = IgnoranceCommandType.ServerKickPeer, - PeerId = (uint)connectionId - 1 // ENet's native peer ID will be ConnID - 1 - }; - - // Pass the packet onto the thread for dispatch. - Server.Commands.Enqueue(kickPacket); - } -#endif - - public override string ServerGetClientAddress(int connectionId) - { - if (ConnectionLookupDict.TryGetValue(connectionId, out PeerConnectionData details)) - return $"{details.IP}:{details.Port}"; - - return "(unavailable)"; - } - -#if !MIRROR_37_0_OR_NEWER - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) -#else - // v1.4.0b6: Mirror rearranged the ServerSend params, so we need to apply a fix for that or - // we end up using the obsoleted version. The obsolete version isn't a fatal error, but - // it's best to stick with the new structures. - public override void ServerSend(int connectionId, ArraySegment segment, int channelId) -#endif - { - // Debug.Log($"ServerSend({connectionId}, {channelId}, <{segment.Count} byte segment>)"); - - if (Server == null) - { - Debug.LogError("Cannot enqueue data packet; our Server object is null. Something has gone wrong."); - return; - } - - if (channelId < 0 || channelId > Channels.Length) - { - Debug.LogError("Channel ID is out of bounds."); - return; - } - - // Packet Struct - Packet serverOutgoingPacket = default; - int byteCount = segment.Count; - int byteOffset = segment.Offset; - PacketFlags desiredFlags = (PacketFlags)Channels[channelId]; - - // Warn if over recommended MTU - bool flagsSet = (desiredFlags & ReliableOrUnreliableFragmented) > 0; - - if (LogType != IgnoranceLogType.Nothing && byteCount > 1200 && !flagsSet) - Debug.LogWarning($"Warning: Server trying to send a Unreliable packet bigger than the recommended ENet 1200 byte MTU ({byteCount} > 1200). ENet will force Reliable Fragmented delivery."); - - // Create the packet. - serverOutgoingPacket.Create(segment.Array, byteOffset, byteCount + byteOffset, (PacketFlags)Channels[channelId]); - - // Enqueue the packet. - IgnoranceOutgoingPacket dispatchPacket = new IgnoranceOutgoingPacket - { - Channel = (byte)channelId, - NativePeerId = (uint)connectionId - 1, // ENet's native peer ID will be ConnID - 1 - Payload = serverOutgoingPacket - }; - - Server.Outgoing.Enqueue(dispatchPacket); - - } - - public override void ServerStart() - { - if (LogType != IgnoranceLogType.Nothing) - Debug.Log("Ignorance Server Instance starting up..."); - - InitializeServerBackend(); - - Server.Start(); - } - - public override void ServerStop() - { - if (Server != null) - { - if (LogType != IgnoranceLogType.Nothing) - Debug.Log("Ignorance Server Instance shutting down..."); - - Server.Stop(); - } - - ConnectionLookupDict.Clear(); - } - - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder - { - Scheme = IgnoranceInternals.Scheme, - Host = serverBindAddress, - Port = port - }; - - return builder.Uri; - } - - public override void Shutdown() - { - // TODO: Nothing needed here? - } - - // Check to ensure channels 0 and 1 mimic LLAPI. Override this at your own risk. - private void OnValidate() - { - if (Channels != null && Channels.Length >= 2) - { - // Check to make sure that Channel 0 and 1 are correct. - if (Channels[0] != IgnoranceChannelTypes.Reliable) - { - Debug.LogWarning("Please do not modify Ignorance Channel 0. The channel will be reset to Reliable delivery. If you need a channel with a different delivery, define and use it instead."); - Channels[0] = IgnoranceChannelTypes.Reliable; - } - if (Channels[1] != IgnoranceChannelTypes.Unreliable) - { - Debug.LogWarning("Please do not modify Ignorance Channel 1. The channel will be reset to Unreliable delivery. If you need a channel with a different delivery, define and use it instead."); - Channels[1] = IgnoranceChannelTypes.Unreliable; - } - } - else - { - Debug.LogWarning("Invalid Channels setting, fixing. If you've just added Ignorance to your NetworkManager GameObject, seeing this message is normal."); - Channels = new IgnoranceChannelTypes[2] - { - - IgnoranceChannelTypes.Reliable, - IgnoranceChannelTypes.Unreliable - }; - } - - // ENet only supports a maximum of 32MB packet size. - if (MaxAllowedPacketSize > 33554432) - MaxAllowedPacketSize = 33554432; - } - - private void InitializeServerBackend() - { - if (Server == null) - { - Debug.LogWarning("IgnoranceServer reference for Server mode was null. This shouldn't happen, but to be safe we'll reinitialize it."); - Server = new IgnoranceServer(); - } - - // Set up the new IgnoranceServer reference. - if (serverBindsAll) - // MacOS is special. It's also a massive thorn in my backside. - Server.BindAddress = IgnoranceInternals.BindAllMacs; - else - // Use the supplied bind address. - Server.BindAddress = serverBindAddress; - - // Sets port, maximum peers, max channels, the server poll time, maximum packet size and verbosity. - Server.BindPort = port; - Server.MaximumPeers = serverMaxPeerCapacity; - Server.MaximumChannels = Channels.Length; - Server.PollTime = serverMaxNativeWaitTime; - Server.MaximumPacketSize = MaxAllowedPacketSize; - Server.Verbosity = (int)LogType; - - // Initializes the packet buffer. - // Allocates once, that's it. - if (InternalPacketBuffer == null) - InternalPacketBuffer = new byte[PacketBufferCapacity]; - } - - private void InitializeClientBackend() - { - if (Client == null) - { - Debug.LogWarning("Ignorance: IgnoranceClient reference for Client mode was null. This shouldn't happen, but to be safe we'll reinitialize it."); - Client = new IgnoranceClient(); - } - - // Sets address, port, channels to expect, verbosity, the server poll time and maximum packet size. - Client.ConnectAddress = cachedConnectionAddress; - Client.ConnectPort = port; - Client.ExpectedChannels = Channels.Length; - Client.PollTime = clientMaxNativeWaitTime; - Client.MaximumPacketSize = MaxAllowedPacketSize; - Client.Verbosity = (int)LogType; - - // Initializes the packet buffer. - // Allocates once, that's it. - if (InternalPacketBuffer == null) - InternalPacketBuffer = new byte[PacketBufferCapacity]; - } - - private void ProcessServerPackets() - { - IgnoranceIncomingPacket incomingPacket; - IgnoranceConnectionEvent connectionEvent; - int adjustedConnectionId; - Packet payload; - - // Incoming connection events. - while (Server.ConnectionEvents.TryDequeue(out connectionEvent)) - { - adjustedConnectionId = (int)connectionEvent.NativePeerId + 1; - - if (LogType == IgnoranceLogType.Verbose) - Debug.Log($"Processing a server connection event from ENet native peer {connectionEvent.NativePeerId}. This peer would be Mirror ConnID {adjustedConnectionId}."); - - // TODO: Investigate ArgumentException: An item with the same key has already been added. Key: - ConnectionLookupDict.Add(adjustedConnectionId, new PeerConnectionData - { - NativePeerId = connectionEvent.NativePeerId, - IP = connectionEvent.IP, - Port = connectionEvent.Port - }); - - OnServerConnected?.Invoke(adjustedConnectionId); - } - - // Handle incoming data packets. - // Console.WriteLine($"Server Incoming Queue is {Server.Incoming.Count}"); - while (Server.Incoming.TryDequeue(out incomingPacket)) - { - adjustedConnectionId = (int)incomingPacket.NativePeerId + 1; - payload = incomingPacket.Payload; - - int length = payload.Length; - ArraySegment dataSegment; - - // Copy to working buffer and dispose of it. - if (length > InternalPacketBuffer.Length) - { - byte[] oneFreshNTastyGcAlloc = new byte[length]; - - payload.CopyTo(oneFreshNTastyGcAlloc); - dataSegment = new ArraySegment(oneFreshNTastyGcAlloc, 0, length); - } - else - { - payload.CopyTo(InternalPacketBuffer); - dataSegment = new ArraySegment(InternalPacketBuffer, 0, length); - } - - payload.Dispose(); - - OnServerDataReceived?.Invoke(adjustedConnectionId, dataSegment, incomingPacket.Channel); - - // Some messages can disable the transport - // If the transport was disabled by any of the messages, we have to break out of the loop and wait until we've been re-enabled. - if (!enabled) - break; - } - - // Disconnection events. - while (Server.DisconnectionEvents.TryDequeue(out IgnoranceConnectionEvent disconnectionEvent)) - { - adjustedConnectionId = (int)disconnectionEvent.NativePeerId + 1; - - if (LogType == IgnoranceLogType.Verbose) - Debug.Log($"ProcessServerPackets fired; handling disconnection event from native peer {disconnectionEvent.NativePeerId}."); - - ConnectionLookupDict.Remove(adjustedConnectionId); - - // Invoke Mirror handler. - OnServerDisconnected?.Invoke(adjustedConnectionId); - } - } - - private void ProcessClientPackets() - { - IgnoranceIncomingPacket incomingPacket; - IgnoranceCommandPacket commandPacket; - IgnoranceClientStats clientStats; - Packet payload; - IgnoranceConnectionEvent connectionEvent; - - // Handle connection events. - while (Client.ConnectionEvents.TryDequeue(out connectionEvent)) - { - if (LogType == IgnoranceLogType.Verbose) - Debug.Log($"ProcessClientConnectionEvents fired: processing a client ConnectionEvents queue item."); - - if (connectionEvent.WasDisconnect) - { - // Disconnected from server. - ClientState = ConnectionState.Disconnected; - - if (LogType != IgnoranceLogType.Nothing) - Debug.Log($"Ignorance Client has been disconnected from server."); - - ignoreDataPackets = true; - OnClientDisconnected?.Invoke(); - } - else - { - // Connected to server. - ClientState = ConnectionState.Connected; - - if (LogType != IgnoranceLogType.Nothing) - Debug.Log($"Ignorance Client successfully connected to server at address {connectionEvent.IP}:{connectionEvent.Port}"); - - ignoreDataPackets = false; - OnClientConnected?.Invoke(); - } - } - - // Now handle the incoming messages. - while (Client.Incoming.TryDequeue(out incomingPacket)) - { - // Temporary fix: if ENet thread is too fast for Mirror, then ignore the packet. - // This is seen sometimes if you stop the client and there's still stuff in the queue. - if (ignoreDataPackets) - { - if (LogType == IgnoranceLogType.Verbose) - Debug.Log("ProcessClientPackets cycle skipped; ignoring data packet"); - break; - } - - - // Otherwise client recieved data, advise Mirror. - // print($"Byte array: {incomingPacket.RentedByteArray.Length}. Packet Length: {incomingPacket.Length}"); - payload = incomingPacket.Payload; - int length = payload.Length; - ArraySegment dataSegment; - - // Copy to working buffer and dispose of it. - if (length > InternalPacketBuffer.Length) - { - // Unity's favourite: A fresh 'n' tasty GC Allocation! - byte[] oneFreshNTastyGcAlloc = new byte[length]; - - payload.CopyTo(oneFreshNTastyGcAlloc); - dataSegment = new ArraySegment(oneFreshNTastyGcAlloc, 0, length); - } - else - { - payload.CopyTo(InternalPacketBuffer); - dataSegment = new ArraySegment(InternalPacketBuffer, 0, length); - } - - payload.Dispose(); - - OnClientDataReceived?.Invoke(dataSegment, incomingPacket.Channel); - - // Some messages can disable the transport - // If the transport was disabled by any of the messages, we have to break out of the loop and wait until we've been re-enabled. - if (!enabled) - break; - } - - // Step 3: Handle other commands. - while (Client.Commands.TryDequeue(out commandPacket)) - { - switch (commandPacket.Type) - { - // ... - default: - break; - } - } - - // Step 4: Handle status updates. - if (Client.StatusUpdates.TryDequeue(out clientStats)) - { - ClientStatistics = clientStats; - } - } - - #region Main Thread Processing and Polling - // Ignorance 1.4.0b5: To use Mirror's polling or not use Mirror's polling, that is up to the developer to decide -#if !IGNORANCE_MIRROR_POLLING - // IMPORTANT: Set Ignorance' execution order before everything else. Yes, that's -32000 !! - // This ensures it has priority over other things. - - // FixedUpdate can be called many times per frame. - // Once we've handled stuff, we set a flag so that we don't poll again for this frame. - - private bool fixedUpdateCompletedWork; - public void FixedUpdate() - { - if (!enabled) return; - if (fixedUpdateCompletedWork) return; - - ProcessAndExecuteAllPackets(); - - // Flip the bool to signal we've done our work. - fixedUpdateCompletedWork = true; - } - - // Normally, Mirror blocks Update() due to poor design decisions... - // But thanks to Vincenzo, we've found a way to bypass that block. - // Update is called once per frame. We don't have to worry about this shit now. - public new void Update() - { - if (!enabled) return; - - // Process what FixedUpdate missed, only if the boolean is not set. - if (!fixedUpdateCompletedWork) - ProcessAndExecuteAllPackets(); - - // Flip back the bool, so it can be reset. - fixedUpdateCompletedWork = false; - } - - // Processes and Executes All Packets. - private void ProcessAndExecuteAllPackets() - { - // Process Server Events... - if (Server.IsAlive) - ProcessServerPackets(); - - // Process Client Events... - if (Client.IsAlive) - { - ProcessClientPackets(); - - if (ClientState == ConnectionState.Connected && clientStatusUpdateInterval > -1) - { - statusUpdateTimer += Time.deltaTime; - - if (statusUpdateTimer >= clientStatusUpdateInterval) - { - Client.Commands.Enqueue(new IgnoranceCommandPacket { Type = IgnoranceCommandType.ClientRequestsStatusUpdate }); - statusUpdateTimer = 0f; - } - } - } - } -#else - // This section will be compiled in instead if you enable IGNORANCE_MIRROR_POLLING. - - public override void ServerEarlyUpdate() { - // This is used by Mirror to consume the incoming server packets. - if (!enabled) return; - - // Process Server Events... - if (Server.IsAlive) - ProcessServerPackets(); - } - - public override void ClientEarlyUpdate() { - // This is used by Mirror to consume the incoming client packets. - if(!enabled) return; - - if(Client.IsAlive) - { - ProcessClientPackets(); - - if (ClientState == ConnectionState.Connected && clientStatusUpdateInterval > -1) - { - statusUpdateTimer += Time.deltaTime; - - if (statusUpdateTimer >= clientStatusUpdateInterval) - { - Client.Commands.Enqueue(new IgnoranceCommandPacket { Type = IgnoranceCommandType.ClientRequestsStatusUpdate }); - statusUpdateTimer = 0f; - } - } - } - - } - - /* - public override void ClientLateUpdate() { - // This is used by Mirror to send out the outgoing client packets. - if (!enabled) return; - } - - public override void ServerLateUpdate() { - // This is used by Mirror to send out the outgoing server packets. - if (!enabled) return; - } - */ -#endif - #endregion - - #region Debug - private void OnGUI() - { - if (DebugDisplay) - GUI.Box(new Rect( - new Vector2(32, Screen.height - 240), new Vector2(200, 160)), - - "-- CLIENT --\n" + - $"State: {ClientState}\n" + - $"Incoming Queue: {Client.Incoming.Count}\n" + - $"Outgoing Queue: {Client.Outgoing.Count}\n\n" + - - "-- SERVER --\n" + - $"Incoming Queue: {Server.Incoming.Count}\n" + - $"Outgoing Queue: {Server.Outgoing.Count}\n" + - $"ConnEvent Queue: {Server.ConnectionEvents.Count}" - ); - } - #endregion - - public override int GetMaxPacketSize(int channelId = 0) => MaxAllowedPacketSize; - - // UDP Recommended Max MTU = 1200. - public override int GetMaxBatchSize(int channelId) { - bool isFragmentedAlready = ((PacketFlags)Channels[channelId] & ReliableOrUnreliableFragmented) > 0; - return isFragmentedAlready ? MaxAllowedPacketSize : 1200; - } - - #region Internals - private bool ignoreDataPackets; - private string cachedConnectionAddress = string.Empty; - private IgnoranceServer Server = new IgnoranceServer(); - private IgnoranceClient Client = new IgnoranceClient(); - private Dictionary ConnectionLookupDict = new Dictionary(); - - private enum ConnectionState { Connecting, Connected, Disconnecting, Disconnected } - private ConnectionState ClientState = ConnectionState.Disconnected; - private byte[] InternalPacketBuffer; - - private const PacketFlags ReliableOrUnreliableFragmented = PacketFlags.Reliable | PacketFlags.UnreliableFragmented; - - private float statusUpdateTimer = 0f; - #endregion - - #region Legacy Overrides -#if !MIRROR_37_0_OR_NEWER - public bool ServerDisconnectLegacy(int connectionId) - { - if (Server == null) - { - Debug.LogError("Cannot enqueue kick packet; our Server object is null. Something has gone wrong."); - // Return here because otherwise we will get a NRE when trying to enqueue the kick packet. - return false; - } - - IgnoranceCommandPacket kickPacket = new IgnoranceCommandPacket - { - Type = IgnoranceCommandType.ServerKickPeer, - PeerId = (uint)connectionId - 1 // ENet's native peer ID will be ConnID - 1 - }; - - // Pass the packet onto the thread for dispatch. - Server.Commands.Enqueue(kickPacket); - return true; - } -#endif - #endregion -#endif - - } -} diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs.meta deleted file mode 100644 index 9703c34..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Ignorance.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 872fa23ef6e77334ca452ce16f6cd091 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -32000 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs deleted file mode 100644 index ca677ac..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using ENet; - -namespace IgnoranceTransport -{ - // Snipped from the transport files, as this will help - // me keep things up to date. - [Serializable] - public enum IgnoranceChannelTypes - { - Reliable = PacketFlags.Reliable, // TCP Emulation. - ReliableUnsequenced = PacketFlags.Reliable | PacketFlags.Unsequenced, // TCP Emulation, but no sequencing. - Unreliable = PacketFlags.Unsequenced, // Pure UDP. - UnreliableFragmented = PacketFlags.UnreliableFragmented, // Pure UDP, but fragmented. - UnreliableSequenced = PacketFlags.None, // Pure UDP, but sequenced. - Unthrottled = PacketFlags.Unthrottled, // Apparently ENet's version of Taco Bell. - } - - public class IgnoranceInternals - { - public const string Version = "1.4.0b6"; - public const string Scheme = "enet"; - public const string BindAllIPv4 = "0.0.0.0"; - public const string BindAllMacs = "::0"; - } - - public enum IgnoranceLogType - { - Nothing, - Standard, - Verbose - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceIncomingPacket - { - public byte Channel; - public uint NativePeerId; - public Packet Payload; - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceOutgoingPacket - { - public byte Channel; - public uint NativePeerId; - public Packet Payload; - } - - // Struct optimized for cache efficiency. (Thanks Vincenzo!) - public struct IgnoranceConnectionEvent - { - public bool WasDisconnect; - public ushort Port; - public uint NativePeerId; - public string IP; - } - - public struct IgnoranceCommandPacket - { - public IgnoranceCommandType Type; - public uint PeerId; - } - - public struct IgnoranceClientStats - { - // Stats only - may not always be used! - public uint RTT; - public ulong BytesReceived; - public ulong BytesSent; - public ulong PacketsReceived; - public ulong PacketsSent; - public ulong PacketsLost; - } - - public enum IgnoranceCommandType - { - // Client - ClientWantsToStop, - ClientRequestsStatusUpdate, - // ENet internal - ResponseToClientStatusRequest, - // Server - ServerKickPeer - } - - // TODO: Optimize struct for Cache performance. - public struct PeerConnectionData - { - public ushort Port; - public uint NativePeerId; - public string IP; - } -} diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs.meta deleted file mode 100644 index 444855c..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/IgnoranceDefinitions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3b2d1f7f7d9d3d64297755419f6ab925 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android.meta deleted file mode 100644 index f51f451..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c90c88052305a054d87177362f63dea8 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a.meta deleted file mode 100644 index 738b943..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e4a42b5855436864693138f74335c094 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so deleted file mode 100644 index 5a48a3bcb96e549104f848d26611ac59ed6f21bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47024 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ʶ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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so.meta deleted file mode 100644 index 63cd799..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/arm64-v8a/libenet.so.meta +++ /dev/null @@ -1,111 +0,0 @@ -fileFormatVersion: 2 -guid: 4b3abd2268dea254da11190b00d16051 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 0 - Exclude Editor: 1 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude WebGL: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 1 - - first: - Android: Android - second: - enabled: 1 - settings: - CPU: ARM64 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Linux - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: LinuxUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - WebGL: WebGL - second: - enabled: 0 - settings: {} - - first: - iPhone: iOS - second: - enabled: 0 - settings: - AddToEmbeddedBinaries: false - CompileFlags: - FrameworkDependencies: - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a.meta deleted file mode 100644 index bbb65c6..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bfbaf4fbcf8987e4585ca666e28f4871 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so deleted file mode 100644 index e8be7347c21fe3c59ee1076e224aad64d1011720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42636 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so.meta deleted file mode 100644 index 07ea880..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/armeabi-v7a/libenet.so.meta +++ /dev/null @@ -1,106 +0,0 @@ -fileFormatVersion: 2 -guid: e3ce4b8600e09d74ead46137ba184d01 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 0 - Exclude Editor: 1 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude WebGL: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 1 - - first: - Android: Android - second: - enabled: 1 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Linux - second: - enabled: 0 - settings: - CPU: x86 - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: LinuxUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - iPhone: iOS - second: - enabled: 0 - settings: - AddToEmbeddedBinaries: false - CompileFlags: - FrameworkDependencies: - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86.meta deleted file mode 100644 index 4491214..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b3486c84aaebff4489e2e11f5bd3030f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Android/x86/libenet.so deleted file mode 100644 index 391f83e8361d805df9b7936823579a58cbac0573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50764 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux.meta deleted file mode 100644 index f1aae5d..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8e3ca9b41c9f4064581a6b56ae549a9c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux/libenet.so b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/Linux/libenet.so deleted file mode 100644 index c64bfb75bee9db3d5c8c0c23fd880b209259ea50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60144 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

E 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%0Ab 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a.meta deleted file mode 100644 index 7106afb..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a.meta +++ /dev/null @@ -1,80 +0,0 @@ -fileFormatVersion: 2 -guid: 385bb48fb124b5f40a79bdecf421671f -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: X64 - CompileFlags: - FrameworkDependencies: - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS.meta deleted file mode 100644 index b4c703f..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 957ba76da095cd64aaa658f034ab78e5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS/libenet.dylib b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/macOS/libenet.dylib deleted file mode 100644 index da377b7dcbbc8cc9f26472a61cd9f0a62eb1c12b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53596 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%0D2W(z&E%pe2PJT03X;? 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt deleted file mode 100644 index 66f084a..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/readme.txt +++ /dev/null @@ -1,35 +0,0 @@ -ENET Pre-compiled Binary Library Blobs -========================== -This folder contains pre-compiled binaries for a variety of different platforms. - -A brief summary of these folders are as follows: - -- Windows, Mac, Linux --- 64bit (x64) - -- Android (Kitkat 4.4 minimum target OS) --- ARMv7 (armeabi-v7a), ARMv8/AArch64 (arm64-v8a) - -- iOS --- FAT Library (armv7 + arm64). Targeted for iOS 8 minimum. Unsigned library. - -DEBUG VERSIONS -=============== -Debug versions of the libraries can be obtained at https://github.com/SoftwareGuy/ENet-CSharp/releases. -Otherwise you can also compile the library yourself with Debug enabled. - -DOT POINTS -=========== -1. 32bit Support for Ignorance has been removed. Originally, I did not want to support 32bit operating systems, -however due to some countries in the world still stuck in the 32bit era (Brasil, some Russian areas, etc) I added them as a -goodwill gesture. However, since those who needed the libraries have now vanished, I have stopped building 32bit versions of ENet. - -COMPILE THE CODE YOURSELF -========================= -If you don't trust the above binaries then git clone the ENET-CSharp repository (http://github.com/SoftwareGuy/ENet-CSharp) and read the readme. - -EXCLUSION INSTRUCTIONS -====================== -No need, the meta data will cover that for you. - -Still don't know what to do with these? Drop by the Mirror discord and post in the Ignorance channel. \ No newline at end of file diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt deleted file mode 100644 index e14bdc8..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.4.0b6 \ No newline at end of file diff --git a/UnityProject/Assets/StreamingAssets.meta b/UnityProject/Assets/StreamingAssets.meta new file mode 100644 index 0000000..9ac2d02 --- /dev/null +++ b/UnityProject/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abbacaf6bf94070499ef235e8c8eacc3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Tanks.meta b/UnityProject/Assets/Tanks.meta new file mode 100644 index 0000000..7f8ff0b --- /dev/null +++ b/UnityProject/Assets/Tanks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 19432d11756827e4893b4bfa175109ca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models.meta b/UnityProject/Assets/Tanks/Models.meta new file mode 100644 index 0000000..159578d --- /dev/null +++ b/UnityProject/Assets/Tanks/Models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d307fd629611ead439088684e6f29967 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank.meta new file mode 100644 index 0000000..cc474cc --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8128b15da07d4ef45b888982f679e992 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd4bee1a09ee33116fd4766157857e238ac497b GIT binary patch literal 939498 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≺_cNzcoF8cN5|<^ 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 z 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�dX*h1ys34c5_CSWit^`OG~v;7su-1TQ#Js1D(J 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 c4 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

CFD#LxA3 zw=`z^UgjtmcnwIs7v&TdJfSssKrBS`tL1T-5&wOmgy?1uW{^}5uyJyUsdr&BW5|VN zgdN5Pg<6HFHC+@65+7FLKGgU*kJP#>hcJ;VERNu;8y423v^Y>vOlgy(s0r(bW#^dI zT$Lm;Y|uVa9McF+r1&N7{dB4;?Hyv&di2BZtq{k6;V#$ZO4*Woz;;WS=(EV?=hM^- znvl((hqPI{E|P)HD?}tf*i++4n>l<>TLiAVvU*si{wQ3?*PNU$m93_}6J& zv&@5qJSD^VpzDAu{6==-p@}e@dcprf`= zz%1I8Gi@;lA>#RKB>I+No@Q+BvbgWNEGqq~TYr%_1L+3Mb*|CaR@FiLWb8x6kx zv9raZcxGYnmu9Dn?z)9>6aII-YW`D>>!5v+N(t3yR%mlZq(yscs%PU6{(S$YvaX(g zTT&B7^v|Z4OK$-* zOgc*LP(WxT`pyqXc(29 z+}ysEF&cmZi=VU*JE$`XuEL!kz$ce+l%r_Sy+^lr{{abXO?02m(KkK24 zYnAckgGBZ!3HyjE!M!LCcYgM9!UC%iOi{**p3Vwqig7Bn$}3x_sTizL5APe$d8BWC z7ZB8kluM=6s6FE4-PJ894fpE2RDc&w>8TBz-)t|X>Ge=|)Bu{&@F_diVqG`|BvFGD z9AzykVy_4oz88W)=|M@-EQejhuujR_<5g`Jydv_gA@4^nmuUz}GQY8@*UqHBJ3AG_ z?`7LpY&w}K%1>kOJ>l1+|9j)>W>Yqy(RzvyWTh=+(0%pIBTQ)_Yt{#2#QuBv!AHx_ zno0sWak~5>aS#))cvJL3aHoCqY*iAclY?AR99PO10f5zuOiWIiuf6{jxI>d%~i@smVc}YtxdYoz_?N zAU~tBScJ&+rE{q%)<&bRi{ZzIsXHhWbiN(a$xh|1Qe8v-6b=$* zdu+d5iExV^0`n+AtiLtm+!+=|6oGSm~h21GLf%kH};Opk9XaMG;+iM z;BWo~9&B%7x*2P2_>|MWp2h#ralk@bp*=S*7k&YM;zoea zY|BsSc|3C$+ieVW!d(Y9MlxB}ldze)hG`w+J>MSm0g#~FpqC0BxB>7AFi%G zXm5a$1_3np2{_@#em^q>6sOp}GM`cZt0w_}zfa%khqe!6X|W^f@(|hyZ6DQ*(5V;RJAsm&Xl116!ASrmWL4Aamc~`6FEP> zxq>+;&lNg4{I{09z{-|UYTIzX&**)+6t0fJKq$}XXxKx7J5bWaiW}xLDAZjiZbPlH z>2Ai#Hr(iv<0v8JaCse`Z8`FAPztlCfYcoR7g*V7H^4i?QfyV$QBe_!gm19Wd$r7+ zu2A?jby<@G^K%c(B?9~w&YA2}fBWdHg^0Rzv)BrY{b$^`?&C$P!C+!^7{xG|*qfBz zaMYMe_4UK$wHgIZP zK(0*Md_}4~caia{zn^Olb#Fd}@Ppo%JUn!&;_*;0n@;@oG{h3tmu*M_BSo+d+Sy}^la5o#Xcv^ zV=(OF=XWFLjTw(D?S9= zY}eEqS+)o0tKFPeg&z2a;hUGP)|YN1!fc)D>Y45V1V8Dyi?Kt)_QSt20;`h2<3eEx zCZ-fOeOqYA!QtM@*>omdXjq6pQ|QjirPsmwqo-`iF88HoGarj=Z|~1DKk0KCw9|47 z#t#bw6=3r##L8=zgR$cOiAo%I(m2VHIoFu4OLE(|HVzHi)D=O+85Iwq5oNZDKU~^G z3q%X}ZE7M5RL6jZ6U7bU{*EgPR1xb+SCSKTFHtpyI4rslZ)R`S7 zUV>ai2ciQy3?XwZ@CX`ZWmv2ykM@zsB(G-%GfV z`C_@w+>(n~T(dpC7^0g?Otq};O(759h5PUimcEhr=T01syImICUZy{ruxD?{&6kyM zWU(>T9>0IlF%q<&M45yZr=a~nP3?6oApwGb`)fx91F`f_Cf#fmMkvfsw-lIi(sz_2 z>1(Uwh0WJFmlYv~gp^^})KA&Ysz&cQf6d(fcnb;+vX71&k$#08(Z+s*W>DqF+{-KS zh^8Pwl{_*<*gpu-uGS9g3Hk32oa>b{m-L_fL&(+6fX9P!8#H6XV@gxzsXGE1yvT9H zC}D%K86cZ3QKWz&1YA0KK)}r9Gug0^bEXz;*O!U*1$+5P@17E@>5@I*AERN%N3x7Nh zTn4p^Q4!)PE|qAX-s^hExs??~%`2rtdtrImuZDH4%>IXw4)%(#(9qw3PZDgYR^f7H zto!ecb>8_n`#m!iXSRLmMcnNuJdGuKx3>Cy8)8bPVjlrSIrVC2Mru%28(Q}vHcp$3 z)Rq|Di$bjTK^mG#NTd>VQ7pVp81`AL+ldvN1ufplvgPK+<*fw=4mD%y3DpmpU4kE) z2Ov`UU|S1!dJ%TEXKbHSWIiZSCuLjWq-dWTI+wG5kPKwoW5b4Q*_^*s#;aewl=v&U zcX$O4395+2lJ2JwHuaZ3@91-O`-Cz*Rp~q4=efhKct1n1*Qbzx=z`p!A`CnaA9+aRaX=x`x~pYzXJOj>?~W zu;9ki$ARCI=H{l2G1DKS;1Dm1Cr!c=U6ZnV$KQenNhd(_Wt9PkS&0<%V#z@}(q6>C z-KRF*(L-ZquCTk^4vJYrGVg!}nrU)g1YTic54UZrJ7>f9>FuCKs1e4Ejuns`|t zCAzPT&G20!5jilnnsQVCP@^!EGGpf3V60ds%ev#4<-= z71SIgPrd8$#;N=Jkk`lqAz7%%!U2L}01Ux3_toB?@!@lJbR~0XOY*Wv<>F>-$gJFt zr+daJIvu(JSeehHOkyrihgR}QsK$;lt6gu)c4;r&KYN62^=QkxzhG^sGX4=Fdx;Mm zK9T*cUOP>{Lkwcaz4yG~V*K*Uj#pVp_;1_3rM>1Ekz96@nbvDHjlsZ3G2EM?bg9TZ zt3RTCO7d|^8W3d6SNfIe+!1;pQo+a2$5i{FS~~LJcRiWMH<~owxmi1I_g5+%*3H%8 zSP4=E2^^{t+Xl@Kc#@fJG{@rm=LX7pl9ErnQ+2X8Os$kjT98?)YNf(i|AV1o8_X`O z9LxI&)EOelVpgcVBC)?${~~(oc=@M!v6Eta=@;JLkAc4)4-?sV+lY+);66Zf$A`6j zM11^EqFzbQdlYdQ6lj^c4rZo65ZCuA2OS(ggD?3U&AOM!zmbtg4G9?H|HR|nyX$bM zJNGUVln&(fT8^s3+LBqo9noSPqxh}S8M|{hSKYo5^>^{4M-m_f6~M-i*hYcG{iiPG zD-8*UEtKQY#Su!(tL*n?Z{8FtP=A(+m#Xo%^BybX5d?WL^+`aBWC#}! zFzh*6uSa>v01gNVy17-_uB9}$?XLvHG#01a%}DvLSCs{+`VrAw+L)ff0bwVN9QvG+ zKUjg>KIbe-W}temZm6h}RrC${E+w%MMiVV@;%})=XUQ?@Na7;k8F}* zk-MC1TR3UvgQDq9$x4bC{)eWkervMv`uE6z#6}3ph>db8N|z`I1CdU7Kxsij=@Ci{ zK^P$=-6EYzNK8sn7$G4!DH%P$sWiO%{_y?*yB61dot^W^*AgiKsTQSM@-)%k=bfcS zr5`Ue&$0DK=}ekVk(1@_BBZYLVrU#?b3_?oKVEk=ZQe9J-!QwtVna^H^UB#QXOsEt z@MVK%9s0E5ueCYlSS6aNBRfLhe8kg=8`$)Al+mlEXhH3TJo`@wEyG|w>XK{*ORas# zfQ3|vBztQG?OW>iz-80t0)U5^l_1OL&(ps#ZycQ5$Nyjg584*7(w^N_+Q;j`^VE{9I?>GhQJ;>}cqPx;wDx zEF-HTnRBOm)4P5!DkE)ic=0x6k+gjF;*e-nF3#w4#uakmr+hv$0^IHWnEqG7>d|*; zLuIF`P|Dy0{|dSa1hZb*irnYae&8s6-%j9|P3sy;gU#56wd8&lW z7H7@WmTr{pvZ1MK)ejqW?4llO+X}=0%D~wQEDza^;Nc$BZv}V+>t}eHGT&$1DNP>B zyuzXf|HXYZDYQ3e5$GPNzoE($8ui}*OjQ+NxxeXh>(S*B0lJUXwm2y%b4NU~yZTCK z3>ezSt)QXe^p)%HKBc8Q=5xvQ^geE53YhQ6i0o+y=g!*=rH1Y9n(nBgnc>~s(pc=f z=EkR-8Psr(r$X1jk1j<(I8-~Xqs{Zb?HOyKP%sqp_s5KKzDG++f>ik#F#D(8RGKte zp6havo{jc#*E#LWT?UW->ptG;B@`mlbf4XL)56C-Xu{LzXkM)SGryhOOu@qns za^&v%H%o?_qSQ1}Ft`DX**@TkKy0i?@czSwpTkEQgrDxHH_izx6L1HSa&jjXH-M19 zkf~o9vz$yF%K_S#hS=M%KyK`Ken z548O2!h{#|n>qyf`{6>W*74uhuPia)<-cBCF5m3#tzidmY;>3uT@<$ zQbBDVJf?wk)0T;vm{R)`aziJc&!4vIP-!>~hy-tNNsG5$jkcEWbkV~zpe%<=$%*-rtgcl^y!HOHxYXzi7K?$=a(C_$p2s1-dL;AdFcSq4>PET(Y zQCTOfnw$^~alX<3V1Pl@V#z+$4wsSSK&`Vy7Z=B$xaffkjS>^nuN5fWbcTu3s0gU!kJdBKGfhy?lUQBjh?{PV`AB$uo%`050a$ki%NW`ObA0 z(^5%r>*EOi#})GFR?Gw=BvTlMAXclXnpHG-U>(GYOuUT^O+j+>-hRNZ{ti5Bf-r$i z$GRZ11+NLbjQylY)8-`B)ObPHboEEi!^}T|&e1a&%cTn~K`zRnFf_ z|30YX-%k5Em2}SfIt0t`SO4PA+FIn?!o9YWH49evd)nFeX)`*i6f&bT%HIUkCi9da zNOBhHuJ3O}pg(zjC^7ymG_LR`r?~=`xnc2=g=rmZTO||GQW>zV+wG!W5F_*!XG(1X zxIzB2zukv)KR%&E@>gHB|Iak6>)|BD#vG7K{r%4P6BI~i(q6M%;de`A_2>U|b%=^1 z!oFpC+S^hi6*WcTp;t9>31Qf>G1oZdwSb_%(LFy^uWr>QXvHzXK%Tk8;KmdSHE>lA z^KE{enw?MNot?Vf8UkT#@svjkJ`uf*|0lG zO0b{j*bRk!f0q+#%$?z_uw+UIUSqN`4>fFo@WP#C^t_bJ#`;RAn0V*UZ zx5ov$ZZ@Q!6JTFCvxY|=?YLIn-u_<;X> z`4WAEEzE=x@pWF3ce>9Xbk@>vC~$HRlQ+hybi;o~r~PrD>%R*nJ?D3sKc4P1@&H(* zRkGLK@8O|fzd$92y$|KoK0sXCOt6B?%Z)aeeKznkH*%;KFrp-#MY~)zehSvB#0nZJ zojlSV>70lk#^h|Y8*Ay6--8ir;utD=TXvCpOr=4%DQ=DZJYFI zaFNfu)`50!*$H?upqR6C02|rb^V+Zn3`J2A^eWzLt-sC=lZwy&ENfRO(V%Up>UQ%g zFD?uZ`2oH0+AD2$<<89J&)xUWA_0=}#gTsd-@}ClZhzmn)8Aog6Fr?V&@vObFi(^e zy*T2jsv1;A25@c3i^ZTMo>7g2Qvsx{jqHf`4@2_9ve*nYk;JFqD(vMlk{+s{;JQ(j z^DM+JO={Un-9*gq`_NE*s?iozc(zeHp;YlrH?-VD>ONwb+m1$1NK*p%cx6!}(`DU@ zbkgx>&ib6fD9PcH-(3#9w5(J^*1|u}h|mF+TFe?Cf{>!K&u^bWTQddi7Hw>dI8$ZZ zJ69JC*a6|WN;9-$=bAof_pA#h^G`%1d? z#ciK&OBpiVa1j+qnWx40bc%zzMqxtZUmrg9~x2Ekw8Z3&#ZnNc95fh7MvX|MwOT~M|^UhUi zJevlts~t$uudUI5f3%^g?j)fwRhk7xNni+o$>Fh8-#OVzdT*;oD;%hR(dNuBuw8$b z;|+9BQ_!xPf`+d?YOr?pENES>aX0wnyYRmk4=)Bscdx;ZT?z@IKUlCozZ`wHSUuap z+4=!8ETL<4+y6)q+yuwd%AtNd0GQr)5WY5!^obI~l%+SjW@v32Yck-TB4oL^B@sk; zNkA3yqr%V)mWLIkjNTrMPf6Du9m{!ND@gvwQH4k6!k;CwO*SMaOeC<^H9ZuP{=ngp z;vHu}Yv&3UmeESo zfR7nHF#Yq1a@(u+SKeXR$gM05P$r45cPlK5mtv9+{x@T0WbgNC;CJF)pYqY^;a<}f zzw!aR{xqojj1=`Sc90NsQaK31SC~j`9kT!#NAc&s;;mcVMmz&U8e5xR^IIgWsf+Db zYWzEizPThEK6c$`cCV5)Myels z{-;+m?O?VFA=KZjz#@#N(4*KVL#!6zs_A@ukp#zJc?}e*`~8Ex@fGK~g}Xn0?$ogM z;rigU%H;!YnbN*X4j|7P;|4oFQCc}Xg{z-5t7 z@Jc$nOXBrO-d0ZrLW0HZ3rI`bZgx_LE zY-U|X*h39f#<$}7DBZbfe3E%tO2+rQn5+qiy%>UW<#-Px9a!F1YisQXcs5${<>At? zE0gDkB;UG)vW$mfjs=+}lgSwg{l(vg#@$34B%8`4Y-6Di-M8GI-50dP@Y_Il;B{{~ zCRB1u=a7~;b;#$NQwp?IFUd1`8BrNE+TSddXXfKqT5h3k4l;%6#j|QwBC_q2pBKM- zbP$kRbqkN3*VMJB2)~|bG{+u;RZxizPblAn1fRuR>>cS}B=x?{gxcJ_8?p0f@S&+a z)?abSk=<_lxNS?(Kl2$vWng0`K13;}#Nx7tsk8kfuY(R91ujlI4~R1Z^I}d@F}ZD7tto) zDj1pURVCwlHx%j3ekxFmsV0ipEn<@?0Tg=MUBPPr!IyfmK!gnQzIsgZ4~Y+V{MiTb z%UV|{H{N1MS(bQ>qv%pQd#2p{ra?(s4U}K{14!VL{7vmExY1qZ<)po?o~gD#Fm~}Z zqetkkCs!G{+!qINd(Nfni$EN9NTX!v^(^{WZQ#6JlEz=`Bj*XqF14Xdd(irx9fxaW1JN$Kl%+XJG8snM{pSTP$&Kp0^s zqPksOGylY7h~QdPRLo&Ce0+$_V)i#SDP81KwIjA|>6freH1cNmc_)Le9Db? zo)+)~8zW`a`w$Tsw?jHN&&7o?+w3mV#gG*)Tn1-)g8zbi+_ zP4Qhr>f6pfD5KdI!!qfTN_Mkay)Alxe|#VE;}wMDCpu^X&4r0)4+jR@SE6>o1RGMt&-XH)XD7&;L1d z558l?oB5$cFoMwQ%1K{W6s=zNmWGK)vxp}}EUNTl?1sT~HsMaWldk!*=(u6MN(0vn zVgrvNhqgq{uvFY#mm<5+(PAoC>Bccy0nQ<1sP>mzP_eSWRqSD7H;4E4 zBx*IJUVXHYfb5h7!8CT!g?ycE?5`mB73#5>$^iT(i-@AWHa0X8bokJh?)J5CG2{D(|LR5_4;B+@Ev`p);BQ~- zaba$t!cPwTBC~2tth-|Dwoe!$+L$;E>$q3OF$M6pdpZ{-2b4FDe<>5#?!I`MwyQKe}d-^ljj>!S%rikeX% zt_TqLBO_#k5^MD%A%TK|9L>Lw{iUJ+S{{EloLM1a@(pm7LfCQB2Psh@;#a(sqPslM zv~C_sk1!T4A?Q6>P+TIUJ{m}hrV35LZ&+|G*sL!KOL_`!vc%p z0%*`O@5(LXyJ5yuC>dyqk(spXwvA6D@Dd~#8s^Cpz@GRCDvRV}5D-x82xs9j$w54QW0T=%Qw+|4p7J&!O6Klt`l2@QF4bo z!6Y{~OV{j$g>l;jppz7*-(g@pS)Q+j$8s3OO30o|OG&*cFPe-&Tk>RgbUN1=`iVbI zy)s{znl33>)~}>{@rM%Htbaaa4WXh6SMo70+l_kog5Ai5m_D{2bK7a2hD9=mDI07Y zd$t5|0STBtQdu|dGoy@;&Fj_1QAlb@LrxhD4+9xfH4n)9wkdQE3`k5>KWY2GZD%m> zh{m{F`y266pKT*E9HUl+wlpi_S~GNP`-6lcKURTl(*D#xY?UT+FzyUUS2L;b7$)9f zYvGjWeRK=T7P+{nAPRcyI+Vo>EoyYfUh6GvV5_6@P*%F>hZtk!l~?>Uk%WT+=SNc) zdsP)1S?_{F(AQ3R)#?X?;B>@OLE0-jZc1sx6B*QK0N=P0rg%ndkuP z`Sk`j^Rk*jObgCCeXR(~V((tWgnJvc*?Czd<`2VfDcNsN*`qEQTZ2;JlJjru+x9y)$q$Cf16#9wD(rkA}jjZ`LD6g2# zFL`*ckT4N?BStDL;%%)NBtF@x$iBJAuB@%|O^l|PUtoq{&d&w6HjC+BTWKL_X=uYb zv{m0uG5<052e4*qHWc2Q9JfoF+Csw`yAJ0=&@8c-F2@y;Wm=wcN;>7ls_CVlxmd;O zC(pRYQBK?;*Y#6$ycSK>>Lq z{5KS+19eSALX0(jB=Y6VmzCt6ZJ&_5UJ&*lE~i<4JXy^^e3^zcC~XY3c*NRihbrDA z8OdvK<)k&wJ@=Y|+hwd#aQoV1hnelhh6$B)uj(y}AClX?aeBBHUCWfE|6^s*LL7OA zm!%b#<-$$(fTmbccYf7^Q3~g>F4?p)O^+%yO_O;pJNaqB-Svf%42_(}!Oo)+DQ4c( zNn9@TH-gKMrJm&vi}xHd#(fe!uv-b?3$99>z;Oz5sc8~+gz-4->Z0~>SIq8zWKCbd zFL?pyeFae3y?#-4d-d%Ge+nf4v$ox2ub^`n6& z!j{{Pso}>w8a6#KT=D=VB*HRL6s}Vq%~D`T!c4yvOfT~VSV$bpT{vs+MeDQQT<-Ty zU?4WH+2`F%2`px2th;Ubo&t#BoXO?F2$nr8GiT z%G2*Na#>)tOjFy^$4M;loLxei&czt;wzb$E}P;-t-4-B zQaY436xK6AcxXu__~~D`qX450%lcx_q&IfbQBy*(Qq0@dWD<=`C|EPNfz{MZ^sX#l z$IujNFtQuvT{8>(&&+G#Z;)*?jPoXY6>(GXqrN&7ty%#F{8uwA+&QMmd;TeizwmRL&CDf;zc!Z|6GI}K2pd}J-avyIb6uQI9fP8Z9h*I3~97mbe>fSJ@%wF;!k~epXk7lA!x*{ zVPa_L=hQ7=Z^v>b0`jDG;g2`gLW*ZBeW~08!+(i>v`;S{TOGW~lR#ajW&Q(#5cpwK z>})Yb3!SHdL6d4Un6QtE1n5y6qSjjN6Z&p$Ho1-VVw|P`JUkp5s=yS4O-#tT)Nspn zx>$6Hl_EGaMs{osETwyS4oj-Ppj+kTnbd$IO%RZ99lcegmdgY2a05;v)q zER!pr)!tcd%4NO0$1q0xIB37%6>anbZCQAEf-xw9LsjSgr(OX2n^!o zBZ(7BK1!Q5;ZI598^0Xq2(rCS)y%E=rXM>+K+un=Z$?de2x$)22bn~=xAWC$I-u}y zClo3TcONbw6NaYu-t!)(S;3GDBNbpuZ7wN(AS%!4CUQ&qz`*{Cl|F5D&N~+u`Xmw_0mTb++1b?z{ zvvK#guavGgQ|R&ep~w7_oh4_Q2LMTB2dwYULnFWNGfvKI?$V2c6KW=GdfO**(ET;) z`fYvyZ;~<_09#nNcPU90_o<@MowU%pu<&HZ%`G>*a?d9z?ev^sS8Z($x0A(FaOtj} zB@wbxVRLMBsfj&OgO)|2y#L%oMt_aF@9)2R+j7`^JFpW`hr=$AO}>SLzrjRYjp$&( zYG$_gBF-{z-TkO)=7N>8@Agl3YeARxSoi*O<*WJ}EKQhP$h>{5gJst95NzihOC09y zJncFuW8+twF4Q|v;rLiZq;U7u*0^NeSNRBTXG_QMqd>a7{_I8^+Wcv*nqFwe$xpmI zjqw#bm0~Fs{1vF)nw0MhfqAa0PdCNhM-F{SB5hp3y-`8bnMD~X#U@>Jud()~oyZm& z6+43cx8o%dV#4PviwZ=+olI3GKu^ERW0o`zlH)PEk8qzmlFrfMWj%SBTTYQQin{~h z_tZapx#g=`i%&MMm6fk&HJ}bNyA3ffE~S!N0?0GE$Wx1)MAs zW7Bi82~o{KB!^T+E_EwEwHI~rG=3E+SHm(8GVHGqPr;um{0^iR{}D6O=UZ(bLlZ1` z>YYoPyz?!7$j1f4?`Bc|Zi0@BSRLUzU0?ngO=inb!@>|$Sf^Pg#3n#A_#vr3-cpT~ zC;WU_chC5~9SU#B0()XQsVarc*}AkXxUPdcyx}0l4fv%uI#j=C-zKtCL?D3K7%8GE*!@#r{(Nu>?F` zTbQYMn3bcS)-f#-*R7IAv+ZM@+#Km7sFO^2t69QP5|VXhWkul>o~gKHnEY`Dvj5vd z-;CbFz?3uKOY2tSV??Y(dU>g0L0KwVqN=;F+_XMg04NZIPPmXdnL!EPhVY%=0hOWw z3;QWfC=G{9nM`ae7ojL+^X{6%fUNct=Jbnd(eeR=wDr*l*gjay{))PsJlG z{+Maz+ZP8RCw>=O3#UUNFBt%thSD92~I0ttXWGW-i+z# zx2zV?DRgto^b&2TXYtD&MsstNrXP-m2AH8YlkQMau`Ad-xxCRLITV1W>&DW7$Ehss zx+iz`{)s-C@Opi{^FBm?HjA-0KfjU)d&>aP!qQYDH@^S|v7jN>vQHz+EWn(KWxn6| ze56hF&PIsE0Hmd&i^p%T|G6)8`qhiN)AataQ~&V4FzRnDwHXy+YtGpBwsr~Y52^qB zKK~Jz68Y*Usdwv!R7pJk^1ZuPQ;3uNDRVfVAkMf4sxLE4)63zC9sWTn=|WQ_$t6(+v< zAD3KHV;2kK283yS50|IfTb1v@s#&_G1rf&nxvkR1uhR>{Kx3nQL~8QT{>JFeOF#Y^ zt8ZTh&+HWg?{J?TpNGh z5em&ue_J*FhvWF`hXhsFXC9<*k&>9Pn6QDssL_^)I_uJ(JqV&N`8D>y^1CAc$cm!} zbW<|siRI2D@B1su@0$gU^FPA);Tj&SFp9c)(o+AyJ(w!Eyquy12vcAyJEEQ9Ls)6d zW7es#;LpjcN^eiZfbfR&8hJMu2Qqy|DMv1=DrWPD!xyK`LO{=Xa@5t&)NfIZ3qe%D z@oQxdVoAU-QYW7E%h$gt-t})WJQ)`Hm(rmCDrxs7LifaK^6yiByqf-hxSPlbi=tH1EjD`& z_J^LC!{L<;Kd##;=I|w!^3zePsl79rGIe!cdF!nB*iv1FsPh&eRvW1c7s1rT{bNU-G`Qy*zB|m0GFV+svopGvo z_nfC53T#{m1Vbv0(_g()EsioyapCR&r8Us8aP(DlO=e}SlJP`yFd$xsCe4CXVw&7OITLBTGs(B-yHpsKVfBw;FHFxCG-Q ziEMyPQGuJ(P1LxmtDTXWjC$CPxpZbJ)-d{r zN4M8a7S}%zm`(*H1@GPsyDW!^lzYTt>ae}3SfL_-0m~!i+r5Y7=40Khs4=7i|9fqx zshI`Ar-fTPx^2Oe&%R|%)c`7PxoC-R-|*?c1dxp0o-=cA!j2O zNAC{T!}4~j3@A2yh=99X$;yf&4lRY&M3y;wTdp}A4_e36r?WwqUadI!kXMzw1*m>O zKpxG?al7ocA%;Ph&!{`hMlZBM2VQ>4!Ao*VT)e@`w>g0bR_d^Z&k4C-`S-iJ7IwYk z75+Bzya9lv&Fdp|saGi^W^wv{58uPQt3O4U3zrzXC}FNsD<)}weOi=KJALGzqy)&)Jitqo&D1aaqx~Y-n?3); zRhXrk=-5`>-)*^}1wI>|Wy6JVou=t%ojcD|bB#;m z1o@gtdDs8&6IqP2A&u&PRz9LVi^_;RXNO%J9AEKOu`bJ-Wm4K|%pG^3G+N~7)k&uy zx*q}@?3o~WPjPQX?rR=c7*%?i^DF;9w%iOt5w=%fl^RBd`xY*>FwI1L+M+lac{`D{$3TU^Zke76aJ1)6s;DPVZ-j)gy^bUL;w~E zt>gbUR$lf<#mghcQDCd3xy6pr-;l?@tfKKpv!G)!skmFB1RirWpLzUV@jB^gaXDd! zDT8Sq6#kn|0F2hHU=0lD-f1Ei*f0@n3MM$ZYnz z_wJ=8EwrUP8YwY0Cqh1GJ*Fy2z9u3?X}XBK)6(KX0F{Z+jGCmOH=>&B3veGAX0O5# zo|;bwH0$Sf6Z<=nADbI32CmP}?vrxLXbXlaqQE8&3={794R{XX)1rw8q}CM=U8_a zW+j-Q`BHx+ z3d=8rwT?~#<)oUgS5hh@SeZbOy_#5bZkKq|`(6P=ja9oObz-rL9&DgxfuE1m?gaXS z9=)g)KR04m+l3EEH9fAHRNWJCuneOFUuw+R))yyq1z*rXb%yRI9`2v}y!1c#H`Pv3 zl4FfsWc*2r_iR)TfAZLK>vEmYrfV5e5=e85N(}oO^fse-+JfCsLc0sVun>IMm?hXE z`qlWPOIs?gB7R$RC1hTUgfK8+VD`~;!HRj_U^z_}F6J905^q3>q0ZCKQ5Hz4FY{_D>3z_U%Z-A2nVsT)ayDNouAT)qxAN3fA76{Z?k#oRq4@&-3qa>~EWfm! z8&XinL!r&BKO{%;@g%$L%Gty7CBo3s-74C?W;`Z1)AJ4pgD$vxctlL?9V&l~p^Tc` zgcVxlxSHyd%lrPXaJV+Qy;Y)HU=Sfs#M0XD^5{Nc$OoMw`wkZgX>r+Ft$F#mYnS5= zLMcaYZs#8*xO9GE$S1qk`mD!Kvmf5kW4_+icuig)N=s5LJTLmZoul|)#)F^p@L-$i zSyKFdm*Zkl&^Tr65Ds>$+mE6)hOMjHCXW_x9V8$+R)hXZIC{Gy=5vH0ykDw?S0{#_ z(NJ2ZEbPE`eC@H&(f8SWUE+wO3B?!x29=cW@ntxfry_;lMWYHbRlT5PRYRiFFQOEf zXLP=Qf4u4`wp>|2K$ND1R1xGgg|B+f@3z~!v#zsVJ;=0j zt;BoY?YlHfSmwqGLrG$KV&{kNnqV1yt&kCkKEu`C;`ne|6BYq) z#$ge!upYLh)n6mK@p?j>;nXRQ5~TuDNm0vpwkH;EItrDBm(r{Qzuf%yH`@31TdqE&nCk+X?g@k< z<(DXuZ?L95%_EF8-&e}(Rea! zQK7x6^csXMFxP_)^$eL3I4S9l_Pbk8h6L6?i5X?CN~z>#mG2_s^)do>bSf{Xs`ee( zoM$b(5B}b)`nK}6ek|1}?VUFkyBer3ai@O5s0=|)@|}ZmW}I}WxQ65_ zn|>ijawX$u5BM)LD!(1KUXwbPzf)6_oY8n>=qiTD;(p}qtt)Zr@v4qM;>cm{e=+Y? zBUr2@ENbP zZG1JRzll(oY(HESD6s8nxpUTxI1cnykF02-xyxwC@A>+s_N?2uBQ^HO0|+PY5Qu-# z^Sk&jVY4v;wDY{ne;YD`uG>(qr@iJTOngC`V)hw_#21wd3>JN-v&{DoKhbpDL!wKa z$?QaTK`*mSpBl(>ClzZ`16dVe8L7AvA9RrmZ}LIvG=X2A{BfcARb!kdy;M*X(&`U2 zmx^+nar|GjpODhsd%fH)WjfpU33vkRXo*PL@mpv;RqORMNrAA1Af%c?{9gSf`f-=H zp)R)0y7pGjm&|{^YH6KoYoWs&dPk|WKlsB6#LS4M6CbYcJqI7L4Z?f5Z(o4?05Byq zzQ-h0__gcekE_}7pM&#le9sqO2#@`m_}#=T!9C{Y$KAX0vW?$JDOWEFtjg`>LRO_I zmtj#;r79qQNihGZ!$Fn7AON3mU{;;@LPte)t&|h~5)%iVo!+HHy<2vYeXi zg96|^e?R3HviYj;1Td7IX3N(n#9!C>kmJ~|KbJ}=BzxkPC=1z5+VlJB6a1?@zG)7{ zKlJUVY=K0syH~<|y$C&`^=q#VPa>DNmU}6KMR{gFq-Nw6=zQnmw|lO8$OUW2$)&vI zK51%3BAwGvk(Z4KThCay0sCrP#hr0!-7Z=Q1p^zGw|+dvt40A*UN-7x4jPgN5-m~M zu1)}k4ugdka-XciT*U?z8(ShE_`=C6iu`gO9tL}E%*6#FLqpjN0OSfdF*^a)k*Q)M zMJ>f?D8U)(DSq(Cm30uhaT%+EUy(4mo(k zAeDl)Oe?w-gL~7jxjw7)j>tFC+n~vW(A5HQxyE3*o7i#A#>SP~js>K5w@j%YR-mt{ zMT^(KMd?}Lc)vbv6qns%_wPkx*~v#)cG0$r=P!*aStLY>`7ZcQRA5;^d%W|t!P#ha zmM#eIhZHsi8b&xR)$;}@6;*TQ_#4+yjLP)DY}bydDGJpf6D6T@(pv9Wymk^?_@Jb(zx(MZhg_*Nr=dO0)luEEY}^N(iA`HROdehbS;a=!3(oRo5+ls zghCRM=cS)F2DqRkA|R^K8y^Pe=(!H{(}3T!?}X{OKmg4(mio&B=C^|U({3IS|K8wK zR}H@W=-$qcJEI%DIDbQmL_3P>&&7M}-=#=D%aRjkX0i)c>nOc@nBPK3NK?z^EtNE7 zhpVrzH;u2r&Nq2X(FZH6aw<)&Z7(CX%YS>k+A5ecGYewvz*XHdR?DqrhAbUtnURm` z3A`q6GDaE?0@{OI9$4SxxTSm$D5n$8IKQt%abUqkY% z4`(GWqs}R>$yyLDI;&jRDrq`#@{2=QD z*bq?$nc>{uKSnqet+yZyr`_shU=J=+e@&t{TY|v%Hb}Ow&N8V2Tr0eFz8O=|8&{!q z6=*$TB+_LI4F);vBpAkf&-bb`^A!G;a2?!z%hUDB)KBFHGyd%L zE_CtePsH?&8Z@sik2jYvlKU{qf8$0lk)JH8!GHX&>^2hAb`;Zow4Q4{#-=1k-F{qi zzWQL{_<|ClQ}-|m1cKAK6l|^7Yerp3w8s(`C4}P`UX9&CNUb=k(n#f)ekQ#)72NdE zK>0|gv{ciE^>V8Ya3hPMFl-ccje}L1H^1j(Z8DnDe;fv7gDCon+QXbd&|Whke*(69tm>A=cPm8Nlu(SRc^=X2Jt zsNA0*tdg5AEWM^WYMN4m&KIu-VLAC>VV)%~pw1$}evn3kMWDq*leax9tHFo!B+2I`r4|hyIc*Pi+VM1v$mf08;6}R0C4_{r9x8jvYp*WlyWXmRpbcVRG zwhDQz$zKSiVD_I2Kiz7o?S^j+bSu!%6sFs0bue@gkFp~e0If5^qg?*b^R!j##j=Y- zNvZs%D|Ph|`2O(X1aCfiXcenpHhpTj$Yn4-Zs9_bfD7`mbfX-T5+I&Jb%WPbHSsW%iXJqChh92ICdiyz}=9L5KVQ z-28$FCdFr$=hZVa?&_xGJtu;GEq&_oP~=-U-!xm1=5=?IGrI$ny4-(rWPY(niCz0J z9CDJi5J)D}Kybz1>mOW|D9px-b&nFRTLY(}vQYUZN(f^61trh0qGlIoRd9jJn%mM> zdN|lZ%)7LF(Z9}r@6&m*(br4p+plq9H-(w5KyqOj`IA?TU!I3pe$2h@TS1F*9!h-F z0dblpwfktQ-y^m+JOTu|3mXiuc!h2No=l#BTD;IS;F6PgszHxrwg^jbxZ4Bodd~47 z9evd{XKKS^wBaSwq6mxaqOFv3MO8zI2Kz5*ZA-3CO2pt+Un!e6z z7RP(kkH_ye-g5%JM&7vp(j^=^6w3<(ftBc_)u_c^{Q&vd8(>OUZ`?h4cyK$ncH-dtlm$v$N$caWL+T z36Q$6o{q_5_4{s3)pb$f=_WkTU+@a^Qqv4^LoH;n6DH^Nic6&kyx@vL1(KSrfcM5Pi+9HlPsR5p@2H z&ntR)EEzn+1j?YM$5Xp~&N^D6aJOQN6DUqorj`q4j4Y?^bGUz5OqPlzw%Psp6Nh^_ zm8r#SMj9yNsBp~*mnFz=dGm(iA_;ee|D)+V{Hgx`_y0PGW1oX^$U29V-pF1V2PetQ ztdt$u>tt0{i9@oIot1g4>~VxL%Q+ex`G0ydC;Ps>y)X$k~fxYKW%p z?hSvl(MFg*h>1GfBYk<1_)TDBNe9KHHMn5D$O+uczZsc+V@iU-LB;~QAPNsC$Sfoj zOS_wC-S{`U({aDQKcimipZxn9NPWU_q#@e3!$9`C^As!gWo)D-S=S?}Wjmp*{O0m(| zVTa~Uf)2GIHy5R=*PL+|@7dhbkI{->a+>fem1j@V@R_Q#8 z8H2tK6ZkE0IdXaOMI6i{tz^)fBnJvb5iZKQZOwBJ4~Uy_s|sj+R! z0h}LDGXXEG7Y7E0bdb}1-%0){5We`sgvpJIPbnlLTi?KF?{@OV(CchLCW6PyVX^1b zav-!oR3DB^5`+?-v!|UpWqJe4%aq`lKO~gor&3d67g4(CO-XC-t>60=f)t#xP~J^w zhMR>y5TMOgd5Q9KSu`Q5Hk+(b%>DZCk1*4hFHN`)S<%@B%!jkg~ST% zFnyA>C4+{BI=v!qvE_dy__*u>J!WOl%h-&pYWFdZ9R5{I*@s0XmR?n>rZ#l=z<)Pi z?6EeR2zX5RRKC|8%ES6TSn<)tS(kh-cMIf3iRvf~+HEkVfeU(rzs1_$ zLyDP}aGwXAckZ`?f@02BdM=YblS8d6UaI#W4y@bWc$mRG-gz{901pp|+nsx@x+ME| zJGAcK(u4C{OZWukNaKth5DW;lRTDegJ?ngN3h#yj6Gq&ju>=Ds-kdK5qQz2y zHIUQ+#qdBiD{mgq(ilA;rdJN_UhD=yH5dMw;yaU6?0NBIhTE*go zeREsW(p^4S>?^~jEgnVgLI`*+49%^Fqvl!bO)mfN3e{`8W^(VHV_)_c8d?zX&!V{D z2+a^xHzsO>FMn^6wqDJ1&|BC34=+3ls7oeE&pdqFSl;4)JF5_ufvoY+F>aOEuPoP1_0%+|N!_-c(9chSJ*Nl7XYeAfR+b*?h8D4K22puVs51it8^ocs zsABDR$zA;V;-^cx4?bJS1`QL+X=x%M^xLLcx_>*lU<6nV0quX6YF^{3XHMND1SfyY zP_`#?|3T}F>HRet`u#rK)Bfp{n)p?zac`XS9afK7dUs7R98&Dsr5g7!f*kDSm~7ff z8u4puxl-Ir`W)+f;hw92l2EX#d{nYo=2Bw@xb(?TYeZ{?FhX2^u9ImKsA+f)MgJT6 z8l2q!M~CY}f9J?=CBM-D)T{8}dWG;}J$T|}nnl<>n>fP%?E?5slw{8|b56c3D zFIp1QRA@V|Wc;}>Rqb@=1|;lZM`NmQAS-;we1xh`rC7(!i}lAWX9U%!r`Byg(}YJ; z&uaO-lF3Qy=t2y*eQG*k^xln9^^VK@i20IwKL#l?S@I(hWb{C@^~jJC&>8T+D9cmG z^dj0naK!RqMD)i)1z=h@Ky0mkW~8+-y6@9u=a7GwIVuISE7i&y4a~~*SdIEl(KNTb zdX*7C`&~eFo-N+SOYm!GN%5wRE_c(y=Cn_~eAnEGn&u2iz{|@*#DEc$hFjPsarf+K z^xp26PAa!1Pcajq?Bx13>1Z`edAe)I-h?=UvU;$P zZf0j$XJyG$Q^6eF-H`V&HQ7%@@oGIpvgE>{++(wMmTRrWzCWE+4c!(|Qa{umKbv5# zk9G{&(;OZ0S}QVT50yj_Br~@@p5k;$RmIjYBpV#I`b6P z0zZxdlZMk{%q2F?uPFnzFVD9I$kQdvVKupm|6+3fJs4>}P7}A=cG95Cy?ZqL3i!G6 zUBgDLGq;cOgO~SthN|0;vBHUCav`tb(OBro_9}5>UA;to#iT@wjc0I2fW%FX;fOS z@@TjHq`=C;npcOOq1S7zAZx-%OgX$PH8|BR_$EgZEkydJs)}0~TnUj5wOabriV@<> zq_xwlm_X&NJ&Q?{{MOyykp7=icXr~>BsUfpHW%Q}=DE+GjceE~${iZJX>-H(8L$Fj z1bWJ|G6km1P8BUz0&O4^M9fu@fe}sTrl77Q?vv}Jexsy*4o;Ark0{?@_$<`c{c9T z9!?oU&bTTKDOoe~A%7b!fgejlb3U)}*I7X&UG1vs2!zzA=@g3tD*TyB$wp)LAa>%; zMSNs7L9Te24OQrNra{0@c7alROs}yY7V!4|Vo8)jiMF(yPe8b1BE zZRe+K$iLOz%yd-$bGmEj|5p%AQZ_p%I~ruy&*XEBw0(R;&zBKdE8e|u145j`^}xWD z6Fv7XnC`^NB0mSMu!Kr(T1s@{{Gwa5*TUxAVR8D>3y=|*b@vp_?;2N*H%S?H=46JQ zo`MXt8@WOxUUo|VHnr-M@|2QlO)w&IL5GKF*ijy#R~ut0y!uRK-w9=|I^%_JskhO{ zGJP>*`80em?JKyVEV?^%1yDT%y6wKNxMSn|)SD(UD>esFPGT#c&?ZB@%CyvWy;)=) z6JE{J?NBu_U^F^<=cQ%Xg!vKL0Z?o(UKgDEw;9kjeYjchF$_?8D=aL7ex^D&wCp8c zL!C%2S9ZRkpFQ>Y4v1dlLuR?qGK8wGc@5!$9JtDYc~83t=Maix`0d{VDuis->N<@u>V6uxm=$t|J-tc#b*v2!2|jD3TfxRQd!_t}75C#l=|*34=tA(Rac+M#Atl`$r8mA|duwoG&ROk49ER{kF5wkTar&x^ zJEyEiQQRbdcy&UFYX|x;Kn3nM?N#_+KcjLl>JL^o4q&U=GZ?~nVLp6tU#k_7)hX=s z?YJOoc_SeqW86aO39Zn-XEqA~U9(U9)4i!-tmhxnq~g{7dPzu_$OZ-`!U~>K>lMUA z%>4_~j}pSex@1o%Tqoq`1PFj+vWg_TBthvq*S}c-0AG&Q8mI%<0nNsQo*wTq+t3}A zT`i$}b(2*1YrC4TbJZ;OHbszl!-XE0CC{Ap-B2^tXP(7_9G{j)3Au%vWRG9_gN&4x zqEUL6y&BZ86}2;<`syYv5{#!~+ix2|^3fn(HCm3qM0?Xqd~u|f{7l74L+a!d;lq;W zj8*%7T`KRtd`G_tT~iNKYS z8>t^GnT`EuM6_reoY^jIocc_m!%1IAjP@{wMIT=abhUe#A&~c;!xXt=WoSOt(=)jA z4)aghL09^3PW-%eJRV-l0OD7i^+YOuO78Q-UkOQ@5{l zl8Mod{pMJ)Cc}T=N6Gs=;=~xyG-=)5E^|l)b{drsi1M-}*#rZ}y}6cN7s zYb#IuVq)M!c?;KRbi_E1h0*@6;3x=1PKc)_xa;{>6AUE%M$A$>x5l z2ev7P=ihf<^2KFTvF*=MpUhgypy_kGU=%X?mE?bc7M;dl>Y|&xb3D&;2OeqcUmtG| zCYpiCX-}!aP+ERvNN!YNWt&pXixUPm;4alc?|8j2Y|_3i3NTPxm1O~0GlssB_kZi0 z4`WnkH}i^tX?V;{+r;hxP| zWo4S(NEWtuT?2kbJx;c`O*{&t%39gzRhn>=(cz`imMQ3!+aX@5st82bW_wOK#!44K zKDK!Nvt#?sRN8!vqanDG3Wd6(;3#8MX~8g?V*dV`uR~rQ7OoT6G@+zZ;I*%BUH(6Q zdnX8n2cd=n1~6hezJYanJN9iVg@n=~VneZOxTtTYOVfp+0QD^L0nxwAzj7a_>T;Qd zM@g~#vVQ2wF zCDbg_HnrAVyMQ`@W)HQnU$|7krtnSBubOI$HMb74)Y%LaN zNd&mip;G>0#6Tn?5aEasYvytJ3*jfXyiVc)K|Yq;DT^{qq2-`LTa6u+C46NU``_NR zdMmjKiiss}Uz)+sSw0Vn}rN#5Ob( zOTx|E%atDn&TGR^ZiC$w*jWLGer4MnMlruQF{t0SNyuQOcva?*1#fX;GFEbcLn*u` zg)_ok$-HRush}xSxc>)&^ce3CbcRA?x*1 zzjs5uQ=3PI78bmk{-!&!VCZzgiGEZ3RaTV^<_vQ3CRb2G^EOlt%dn|gEIg_gKzP&W)WD-HT>B8&=;Fg$wk>IH+*nm#@;HT1any|H8kg85d9gzB{B&Rtmnio^CRP zv<$AD+&Cw8w1*r{h8-PJ(q4HB7d-`wUGEGHySV4m8U_oz$&eP^*F|iHQ_IB~`4VPM z|IT#V(`_%1NK$O2vG9!NNE$iq-&{OmL{n3puh(g2NfUx7$SlWp^q3xPneyVyDQU*b z=JOqRN^p@cvH>?axp&OvI8g|X`lLrI5-3ljV_LZ3%-;1!*;C=N{KGU(pp&!WSSaAI zhXWv;avnQMy!oEMVR2*aQJMvxA4|W7baF;13y$<6P{YQysGJt)Z$(5WB9;zOZgjKu zz~S+M*E9c+B)U_u%YT(2k>{lR=cOTM3>zWWnPnKN*NSeROtDAx)vYT4ki&;Sda8fu z1YA5}uQ_YEZOmE3LFDVz;PbyR25DJYJ4CWa#K0-p;pQ^d!AtFHg={!bLu?%P@Wd}9 z#<(<3?58oLF+BWe47;~$7}*}IosKUH0*Rr+FyFmz_|UfVjPv}R6Dx1;W8zYq zA&D?$ef;V6P|k~mO>n>0V!ySNv(dlx`B%W8!S%23dM9Y%eRrlWjApt=f1?)uTcD(E zWv3v3xL}t8teXVwb=|#`Krv-gYv-L=w#wmj$8uIE_}3Rg(iBQHs=ZnWY3HmVu_J{v zZkzTpL0O~?F$R(oIYg*c_hY1^#go-LhfKb(?`?lvO^MIcO9-Ot0rayNc#%1lr7L2t zX^BJouEjch8(wSiU^HdEf&&=mD-0d^KskIk$DEz}BdpNT0l+XO&Mvmsot{2eJ)?t$ zw!i(6YkC&U_;YRMteUcUe1N_Rgne?J#dVylg)VGS&M1@KbVd%>imQ6@aY~A`flmSy z0n=#HNu_@=Xkd9g;A*je&=w|w6%+IA@G={`7lZk5fexs`R`#TmyZZ@z`A;-5co=$( zHtsFJRQxX{&CbL6;WUVA(wQ_`{l5&PrJD~FvRaMBf<&%46tmVB+9zHYiq!>QqHXZ9 z7*$(?O|DdE>j2JAEokcK9p=Ni5cFLozgQtKNak+nWS?tWZXxl!N$A(WgIRZ1nMNp=9{jd`^b$oqD`;7L7RtZ9a|9V3^U*@ zeJJK$ev8i!Gr)80E||qGrvyfWz-DGe+b7nl=%i600GWESOhW;bm7`pB_-yEBtFv^% z?z`(f=A+|;z)^4M?#2qfmz=C!QeI8iRK+a+j0~}jKpLC0Rj?lXu=!#ksXo6`ie)Lf zZ}@WE^}9^PV759~U;8`m5S6S%+>Q55+JRkvva#USutP-(9*GwAR$3)$yc`FAR><@=B#TaRAPpQJEOM21I7_39tR!YDz0v@slP$qbYTx#Iq3;!Tr0%ctf_knDiC;Qe6SWN2rqQ zt&0gzK&jA*84$`8A84LLWM2LmI{EPhH7!#IN;iFa6NT4y#Jr=Qs;94_kJgtv(;`XbwJP1H3|yDqDW{ zBmgufLXxv^QPfit7V*jkpBRS=fR>y#69@_x>ILg|FE2(?TPU=Vbh3&jP+y;mcY>Kf zF|eH9e~6z`zw)|ZL^)_2?F5AVSEK+Sz#bt4f!g_*c_I)fm*1%FTVh2J*tXxdkJA@@ zDzHC!`{)3An09o#-6Dpo>0MbtmV!R0qU*NMZ7z`Mj(X`;AzC5ipHR${H74;+l8+1;DZaqD&2YYJYFx^aFp) zS(0J_koY0zRy$rZS5x*lLc%`j8Yo2YQ?Q0u6=y2C(W)Lx$G7B#d;WOCCh0h zOKbsutgsK!upiD1CwIMx*H;NQ0=Yi-AB;B7s4<@Cug6~i zj!$@7-`@=sZpqfO&3UNNrTOewK1Uz~_xxl{T^r;UcvwFJ%HubdYWKbj5sTbrQA-o8 zah(j62*@;g<9QnhCo!;hJ^5$+&wl155Y+yB?2#ZK$psJB&ovv_rFtqO{3!W2=>FLdOa2Z8t|KdM(ji$2ZbTyh% zCWLs?;mRl4@PVFkK|bj1#YobXf5(ZH1IfJ+z~EA_CRn=pI$YuIx!VX){~u-Uzn0+v zW6mC_9*CCI(89(Bac;GKu=0{n{0`;GmSLvIgJfB068^>8D|NNgYoji5QnV0lJ`62; zn`tDXFi~|odasjKOv^7ymWxG4>T??w9~aj{A{bZ%f5J?;g}v>)TbwJPhp0mctEx^B z%r(y1jXy?S`+R@U5I~B1VR@%ATqd?S2by_*mYa{)+~?;og(Ec!?LRqPLPBYfvNy12 zW6#BkF`L~oHntY`%x+s5nc0}4Fl!bV6AMjZnq1LvrA`(%)0fl>&`jU%6?2v`ePIKz zZaM+i`S;<-pWI6~n8SaFZp{_RxZa@$TMwH(bMQUOKBMp@?2Lw;l~=!56fA=Uq0wlS z4~4D)fee1yqIBWKaH&gh2aZdOx{tA$bv>O^HJ@-ew{XjZ+i&wz#Nhx$mczk=rY2ir z8-o#Q(f7c>(#iJsFX3IkJ@~KP%WA4nFgp2C>BCFR(0faaND-mDHw$tcjHBX@>R$4^ z?nLOWZ?+tb3tU#>W``reRTnaVPJX!?4J9TIg7K*EVkFD^z{hFQlKY*DmbjJ6d#d@lEdvBs5JRBAiZ@qEU!QB1;mCPC2~(__%& z?QQ-hqu41U5O+?<`i{tR-SqZa&1N=pT9o|^13IPa_lJtE$S)MnQ$Ds^=w zmlkEm_d$B_FzH6Z&Ri!Vd^N8-f|fCuq&ehtKKNul_%}uM`{{(4Dy(;gpBedFjFpLi_aR;ixxYDdE7~>PH6f`P{Q`=|F zloghh7$~s9^n>^#fD9gzo{_$!#0BWDiu-Z>4W-H~mCgGYqP9Q zSKiwXb1zVl^)2TXGG=@)J9xOaE40QmY$h8#Axj{Si9L=F|?=t0GH}kEY zatawjW&l!4+^q?qJXWS~^m)eSuF84J10*%~I74Zo?C&Us9okY9ZTF(Xbfvf9k&QEg ziz^trhL6#9o4=+US+1EjVB=v9NN3sHK=RIFEOt=d4q+e$hvr5PzI?SmB*V@UF0Qr7 z$cHYos)>cZ!L)EBy+>%4IuD@ugqwv;39v-WvT92&XlnRPtDEHFre($EUqnO<h|JyBAIi{N*EfrJ>csYnGdg1pOXN)4TF)c|tc)dH82Kg!3==J%Y?TM)x71ic2 zgWN-pT%1Q}zqr5cqs8$lElf*cvgvhwBmG}2V1I*%j7()tm7|YOul1(Bq8d7`w_ax6 z0e_vU_vG*I)skpx2*Jan#-hfA5ScxVH**ze#r`T8=euSc*K0g=H0HqhqQ^A2pic&Y za67kwS{E?`^Tjf$k65~1-zyyVX?hpk?sIZ-X1VFP@(F`mFu1L-!{=UFIMUc$|Jr^V zZVMYm?djl<9kGABS@gKzq(PRsuS_JVAoi;&_F(EQeLh~wQMKW9>i&))*H^-PtxxU0B?w=V*yK$&YYb1sd{r{<(qoWPOPF4}ZxtC$j+VQz z;by`7quZ%>^-)of_&hLsS1-xuK(wmqVC5h*2>sgsM003(K~w94s7L0pm*R^H z>eh7>zrd?MYPA`{)`4Y`nucuiFo~^I)WcHj2Jq9XcQNQ|=#|}Wl}+QJvM}eTN8^?N zpsLc_?_5NVIU#nDacf&0T~~$uG-UlH<-d#*mMR`&hmxP^yl9fh^b$ln+`W3Qteht7E2+csNxcNQ@q3If<>-Ing4 z{jH84%o*O5AD`XF7VFoInOjSM$x27AyTxA`q4TvbE=O!D&xrRPnFFdrjGv^!_d~q- z3!OBNiiA_1G8z7d8j_Pvq)x80F3Pe+K=j1+c3}5wv6(b^(pi@tn#vwL>*(6oOZ!7F za}a6no4exUlJUDuO7y{7=aGNbnNLK&dm$Wd8AlH_3shb*xg~!kUb7cE$12NQE%SBG##4pj2GRh0i~>`TP8IPffeJXy$G z1|h9yov$mJv? zYBn4jiTa8uwK}c63{8?9)i!!9;`o2N08Y?>JE%|BkFm7{{C%RAB=n}LV<4DYT2c&~ z6ZL;on(mvRzsE&}8-U@xzId?=8X*%Cx7YVY^6TfwemJDygR%~jZo9^}{Zxz{pSCor-c)O-yAjH`UoWi1zi`oklghkbvpq#f zFq>+LT=d^weQ%GTs*KV90MpP&h^y#?G%#|c((&0AMUovSX?%v^8sr$2j15%be)(~U_npw&1jv<~W@KF8;l ziIf!mUt^e-zhXVUchP03+iY0gD~LKyExlS^5I_!4%I0_(DACAzBY5-W)k?2QWK_Sw zi;0r(en5Z6HSaVqhyy-W3k?<7OU!Sld}#bNcJP|$i&H}mCg3gO1bU#hXtF-2X2A68lXv zQwNmT11db8s`$@!V!@Z4`-t*>;*a(b<(Lza1bvB-hsKny#g}}3$&MnsUb?3_TfC61 z|J^l5n={{h;if-wxK><$w5euGPi(3I)otA-_tRQ;>htB>5=D&g8~Q|+QY-;|zjAj@ zcapGUZ;Ws&#@d*tYmd@|w@muZ*F>LbPSUfAis&(dxPULQn&hJ7BX;&*^Sdy72Qq3-0L}Ve1ZgTdg<}8?alO$0MtZP}H0kiY$!+u3Yg-zcpozj;_Nn$5`>**qY-2Qme9QV5B?!YN3t zvU$auZ?DTGVzQp|E1Sl)q}Gay=QB0(;aP{eYFZ|gf((T!QdZY3w${GGt5|mk`^A3V zYEIlErlv+#98#8Bd3%a;PXyJRzh98+4gO}L#hv-{Ks^7zVCu`6s>*2_!{kDM2b+)q z6??qMg=k(%x!+AC$9hDq-n?3>oJE_SmTlO;#`E)0d|(qjQW^u1i6UBQ>0ZeagSdTT zcJO&$RV0cHwo2}bj9gGcB=-r0IFcQD<_WyWl1Z{NZX_GRh#JE~_Rax)x6JtTtbK)E z0PHM@vzED65Zb^YimV8>_zYXU&!|Xy$$?E;$iah`;AZE1$#0~ ziFeJM$an0P`BAgAm<+_2M+7T>DE+==z%SIRv{WF5yG&E8{8|CwHUT-u#$g<;g1{g^WIBARBp*4KzYwZS-BB2B(-r-^x!$^z2!3 zxKcNuoR)ogxs^Z<{Pw!{Haw>_z)iaMnOvx|*DH${jqE*nBrK|gN)0;F7f9L6-8nti zO~K(3&O^ufGYR+WD9&Q~!U^LY>U=HgRoc=3nb11&!~ZK6RIPAW@*Rm3IC>8=Mw(K+ z($0POO!g*egIGUV)z*4FmoXuYw-Zj)HpF{Zqrac~ZtF8{pKRXuR>*xaJi5bNp0x*7 z0FJb4Dc($hH?GLa+NR6uir6lRJ!O+E6^{IYCV-|AF{?3}g)n#7OGi^g&HOzMLposP z%(Hon)0YLD$W`N|J@8Um*CW2~h5_GIp;rmZba!);)+Dzz2G$1T37m*@u}>+5o*Kn} zmz^c0Zzerd|1kWa^Gixry1oJfqVZ9;nu3H-#D7sr8;9i^sWDJ!%*NBNjS}P!9tzQ9 z(x(TUXcfLLDY-1dPH0o>#LKRr1`7*1yGslV@^o|v`a}zF-H|}c6jMZg3m3pOsx20x zy&0C+wL98<@AH=@bCf4E08;B`E_3*koswRf6K@Kxq>TFZvs1Q4Prp&Me)EJ!0M6Q` z7$%%~6ItuB&X1ewSgeTKQg3X8nt`v{AE#f}-(Eq?{k%)On$3tK zS`Ak`)}|2=MW9`7{z`_{c=lBK&eq-0zPKX;?aFX?4CpQztUG6-U%L9$)r%Xlz#D4? z2LI%$?Cd1}rPAh9>(3yQ2aiCVIdoNJ`OwsK?_ewL*OFUo!g?-k97(b+6YnV1HE zz;fc^KcD`+IKvc3WRU>7P^xK^uak3)r*X7!ev{$PY%@J7wG*Qj?ew6~HKXh`3+Zm` zUndTzFq`4FM`~KOtm)5!z6I@36madt>B6exZ_0Ho^3YYw)(3a)B(`xeNbSKEYDEn7 zJ0AS#6NdIwX-tzUo3e(wv~gDN>+QbVe^#h-?eOk{H}b=C*ch0y0kocIaZyT2VN&uX zs#DSaSZvYr9lnSE{-cYmORC0!TO;0KAk2sUU+)tUCt^dNtXLOXp>XH_Zdivqgaq?hSggzwyhBs<19-9 z2*j(i>F=d@&z@(WO?GK!mFjOctqJYm%MW4`?&7Qodr5uqB#_X|v^;m;?-O754XL*A zX-bfOH#oqHv8@91^;wbSprj&qz$Cil7jMZzP4%C*H+ptR&+P=N8q3qJ&*21TtUu>q z5B7cM?uKfmc{pRQEIsb^shV$pQTq45C}%Rp^3ClEWIOTQV=D>5;4LULLRqM|tE`MR zizx7+Vt)Uks%pA$WgpX0y}^~VGA_+Hyw_j%!Tg`@M}isw9nCyHmHFQv{gM1Ti|I5N z_4bbM`{;w4j&z;4F`z2QzKM)$6(@ELv&dZ$pl9PanVw=4?@o;GBNF|=UzT_#8e4Dl ztA3FZn*T&XI-STvp^rTM8~o)(Ri|f~?%mt;Y3sPG;4Wkp-zOE1Sq8{BvKQaeoYJk` zWF|Co>ZJ?+R{uNciyytvS@J3DNc@x{F);dLr-UQyU@h$U=!mKTnkm4;XG(nigcuT0 zPo0LvBpu`T03tz8hZaKB7s*-6=_u-S^7SueWW?~0c?PPP=F7*PIhK#>W05v{se2a5tpwT07%z;8ci*~Ec79Z9c)t)bLX0}Fs_WY zIg92~chr3htN#Azfz=lQ>%M`vC0rGoCJn9d5g3@Z6p`Bd znCVJ#n(_=*8ksM1eTeFger0RxYJ$9RWy$SmL7lXP+xRZX)+}%`Bkb&1is`vQHN3UlGF01|kW~&0||JA2FI$#&LeD$g9CCOFY z`adFubz#j9y+^?teoA1INuBxGa7HA7q^9eVS?VUBeX))}9y(bpj?E^-EqvX}?j)Vo zYp`Vb_xM3vL-usgMr7^#3CPHB`#MC@HG3JwJqYimxpLOh_vV(~Re*GNX)*CZN~w)C z8zxR}L!fbnG#t4eMETU-Vx*6iT_seM)`F!MB94oSpEzZA>oFdCSG zt`m5LnYjOZo{E;eD-oWgFZ#V~BUa!7-u8s=sS%9ZHoyfGuyhieqK|TSL6nOsI+&S)O7r!8#8dv+k11G z)EJpd*-MDBef$t*ygxyeeLK50&Y643XqmJ+d)hDD?m%$u>z=)Qn|Oj`{6Da*~P-2YZdck|Hv5_m+ z-H=8MJd^t{0n^4%dw%p0n>u*dONlp`Jm`k`Z@Q)5HzC4sg)X~I?CUHHYM@J<<&`m~ z>_^O!0VI#4MO=)N98 z;lXUfolTA47cI2gOy?Q`x!ExSb77R&lU-wlb5thqqlUu1K)n;jY>vvdLRHb3uQ1SX zGtlfrd!Sjg)+2j={c*l@-AFN=mnu}OOZxlY3UB40iO@2ci1B=>RuCu$O{41WY?f1( z#l9uQU3@~A#r8*JIgk{hpT@+ zJtON_?A126R1{SAt@2=73fojO^8&My4&GJK2P*9wpBgbbbR*e%ovk8nAFhgknkV?C zX9CtNNTWktM%p4MXFs%jPu;G;Msn=m>|*jw7epZ=5ZS{Iu5oS6YJvi4 zhxrCVnyIqA(DbXh8l5gP;!iMJmcM6mH}P)#Z6OhV^mef(ifVyH9bscwqwo5SWTU#{ zKuLFmbnfmCL0j3xIkmsJer~z*SN>5*!x?>**6a<)8x2lpbzD^Yt4FJ!Z=>KCDi&h$ zCVV8j$kXrJ-dDrKm4lE+)#&eV1#uQICei3BQg?5vzOrSl-o?m)$?z#{WzKzc0j$ma zrw7bRV%&^|G39sjXTQUj5UBi;^516O$wp?p=MZ(J9kAYI5&0a%9r}N&K>Z5+SlsAL zY);0jA`#th;t*aXkPk#vxRN?Qb8TrPSuy+jHVuoitEE004G)L<= zD^^#zV0?ncsuik#%a@!nHhK$&h31@fY`fmfez6X+J6yQQG-d5g{Qh5g%~IGenvzb{|pCNcsD& zjY=W5dk+~H>d^TLJu>|0xWFZQU*Jc}!jNF5!dP}-aQYr2xp z=s6O8s8?hZ*Z)c8kBdp?N$S8fP^r`R8M=sq7Fl~)JWvG;l^dP&dJCr?dzIjEM16kLTbK(4CvZ6ZhgFOp$HxDui)V3L)_?ok%jinywr;3#r^ zPh8Ut8vI<3RD4C#VgXhbWAa9YtHCLgF^N|9@~>`l`6Au)iwG@IrA4{(o#TJT-_D+V z3Ty79{HUY!1)cjZ-|n~4=nFgFnV}d{Xdj7Ahe@B0^>h*@xBMi5ZF1P@?I*qUa_}7U zH)I)!$FtmaM82PwuEcsW&muHYdM2gX7NCi$TVI`wt~dcwTAIFC7OtmLCoVt zv7)NWAeW9X@5fIywZ7L^Ktn05H4irh^VBXcy*FJ9rVo?> zQ2z5mH8C$#of!dL@yvHw%$%{G-YH7R3fH9KjruPbelsNMM!rr|iVCMvxQkuYAAGZ_ z&EW9;Yf}fd)k#jzSTy~OK)kn1L7V<(ET9Qik-H*+>F3yv<1zs!-8nr_Pk41n9*us2 zVvv&ssA1$H5*sca_4v_>>L`Lhl6&H;Fq9%1-C86Bl`r={%Nv**j=wBlXNuB_`|PGU zws__5P)=5r!5dvAfdi@^sx{gqCQsSfq7ZT^#F^HQv@a)9wz5#pZ*b4Mrtb*Lkx1Tu!wJSQ<#SF z>OPJ{HlgEJ(+vy>sR`9E<4SjGn@)YiYXKmO=N1ifimy<=NlCh!L-ki({CXjn@h^l< z>iWqgko>jG2E4e}h~CXAMbF9J@8KO%VW--V{of4#(+LJITo@kDcO((UMV3W{*t4qWQvPZjpVEjR3 z#$Y_k6V{&2`AO%_>>-{^wS68}o04G`3g>=>X1yy9Bt$E#@!|IGP8PjTJysG(=qrxt zIN8tbgGCb?5B?h-Hu#U5T7{S@C3j_Mabt43=D*|QvYa0bNtNDJ?p3LQ>}WkmI&AGI zT()Bo9}v8w;;e%rM@L&$MiyW0h@g40Ihi%u(w;#&KRQ3zxC|(@cks8HvrtzJYI){3 zrvzm6gQbb9gB92x&oAW0-ZO@IPe1Av%gb0Oit(|;G{4gAaga2J=QUmc{)@E^Q-5N? z5C>Cm2jnc4tqiaH(C5C84+*{4Ph#&{35sN|3xft_oN4r;k2-<}O~k)}qf!y8*EG$U&P4htLYqj5OV|rH0=Ei4wG5Va zWKSvR;ZkZjQ}>hDb4q;=5^Oq5;PPWbTbh!R4EQvCvZ>SE*c-jY|AmwX0JBdsmBENIWtvYY zC{z?0Z@7e9r`OCB9dVj6;v|B)P*U;E69H;MDW-`FZqJ7T7CI{e0)(t|yVE9kasZWWS4tUWo|U%8uH3>v`Fvor2or<73as){_TG!Yrq$?H1~gz0 zh4)(Q=F>LWtL3tAV9Rp9B!fnNFNsO-B^(5WF_hl<;wSp6@eP1Ha_U@>ruu@oke@Fo zCqK^w$eT~YZ24M+U>QJa@JiJ5)awUkt!Fz;Ta~Bdw&#WmugW-v=Y}_dyiUZ>*)K!Q z%xk{_ZmvHRbwhFCYuzKJ=xp*J&B}n#$4D1vHlzMcH!a97?lqRb^XdZ>VIXD#KONXEx=)5wcqtD#x)Tc=alWzqQhW!(^>ApS~Oc3NO z&k5d1pu7%GYisHVrcIj>{@QE>LdN|f<<<{`qaH6R|Lsc9i1(iP%3u<)ch6i9;d}{M zAzCd@b`>nq10m*v8Z^6WbLRtI-}9Untg4zWBs1JTISV@_u+Pl-e3n-n(let|{qLoo zAxYhl+TAhtV*L5`C*B^zhAGPCZ3+Fl2NtOcd9S)&;4XJOFIX4c+64LRFERn`_oW4= zXX1ZwoKQ`{=t=V0lV{;KoGAdTTA}E%tndj&Wt{3vdxb*3tc~{H=^_%*)lcYPjcaZT z0I;Nof#jHM2=05Zy-$do4W+JmdsoehLxp)3#$X`Pd+eNSd7 z$NxmAyDM$k-6U;~i3XL_Y-4A4gnVGP{pa7=cgOU;VP2vPQifzclx~RhLLA@x^Lei5 zp%|Hdz(D^4#YNLIvKpsf7yiD^$zGoKD6~niPrx7p5^Y0t7jAxR;g7yq%5c|(SB}DK zFvqTDy?uqcQo&5&4rx6KjiP8=r0~>*3)E5W?fiJea!QyvzgK;}CU`z4_}y<7GMt}o z$t%LRl+tOfRWbBuP5rT(>z%JJ8kcUP=9#vLChD7j|11klrZ6WbM_mR8A4*?NI3P^Xm?cMu4pXXmV=iJx1uWy1Q;mod?QQ6U`hh|S>@(7|YSGZnHrRZO@^VpN;nA~E#qN2_)VsYAu6&QSrMr%5s z)<|^$e@n%Vr9U3MAOPvU+I2Ob4Md)}dcFsaY|l*VP&ZafV|FJ@ll%6-Xxdvh>z;ai z;VDA@GU13L<;3lyao*uo-v#tn?d;dzqF}%`?ckB;^})ZJ_g7GEdmAAfZvieW9A*)5 zLq7e^SyGIYevS37O%UCjRz>`yVDA1eYz97f8oc(IAaSnlqQctKANF~muLqA^v0AVw ztglMexk~COsXqdV8szjGlZ>qpsZjXjF!R_tsIyB^X(7;zbxd@gQn7W8Prd&tOl_F8L|rF!+sQ>Isn#ej z@^?@eEL<{ex|KL$NB7yL{w!4*C@Rxi!{1xk517mc=wE%5>n0oC*DL4sUU8pG`L^sy z4<7>2X1g|p?9{iW#0|G_wYgnhR5_{kZ}YH;It2j$SEWKsZWonRxVT|q7^4HT?6ywD zeqhr=LF)Z46MJ>%@k1Ag+nc#7V@*gvvs*&=HV>7c;!Aq~6JwdPv$fstx=%RXwt#BN%6ApiXKq#-_5@ zPJY}(={=`mwS0UspS|Bx|9t#kSxF!%`~)={(&88VZP8=dDjJ#B!6G1hhjC|o2NDgO zw`Gc0F_=`1fKPtM4Pp8=HXdI0bWT(<#K-Vz38(prLPpTO@#ACZ4i83zv#m(2d}o5= z2$Ddh3*ALA;HUUHdK^5IZ(kO=_>syIJzG~WjLh{j4!CN4{b;fC{!hONLy8{@ zvy}+bwc6F%2l>F@iznV!=_Z!2bvdehon|f~Y(G`;_KEOJ7}fa1)QO+n=Mo(9)dxxc|&MRzpZBm zhuL?B?eyXC4xzKZ&Dyy7-`M>GNi~X_EG7dO9o{l&O)dEpB1;I@e@VlXk2uO+m+dWa zOV`mQzEtDwuV7cvJAHl>bvCef*;jMmoK{< z-gOpqRFnw=C>5l(HAfhb{H^+NX?-{OLiN2d3@c5i_H?UKCoGD^oP+nmM+i?g8oO;g z8n*jHY29=Nf9O3n7-_UfCWDvz&%g8@)}_!Vx@zL}EX@a&s=!<(dt^I>!{Xoq<6{Tb zvv6e_=7xG&NN18%&(si5bOCq65>pl{n7O3XaYrcLs5RX7%pxGhwB=cxD0qIQ1;X%l z&63b=QKjf&F(4x8-p65>3@4{)OFDzOdA{rKdG$9eDM84CATK;wv(damG=sKAqVpDl zTg+yKxV^6;kpw|4>xU)r$d%65gVYn&#Q9#Fck6BZsmfaY3$AMN6%>8&Qa{6e>kPPsHE-VsQn_=Q&)K)fbIyr z9EhP}zNPlHOnys9Z$dAMkS~X>AQcg2iSAH3RhQh988_t4{3HKKd0G8@zY1f+U(LHG z%&jlIdHQes*CPdHq>l_xZh)Dbk3pXho36e9e?$0`OouSob`yP0`aYcRA8z291&a&+ zw>?jEU4+ZVo!q3#N6j)E4~ddsu`Ae>s2g(}1wepF^?neM%=)mp-r?MN#PbETFcU-= z$`$OYY<|9iYI#MqwF?c?HH{9>;%Wh{ZbN1p|GP5HT>@O*S<_D&J8GS5St_a zgm6ZKEPi3aL$0xLnHGyOr2{A+2*t7e(#+TGQxcT>Od+7PTQ|ZmVzqO^u`TgL=}m4d zW&TW!3Mg36Y<5H@3{osb$k52a{Tv^U1|nMn zO%W#l_wCIzj> zi|~?|6Fnh90QMK8kRoGF9$>KYHH;y)pP9WN9wGpeSB?Dj?tlUOo;L2Uf7FWC+zXTq zEwa9*p1qy^nC*73V&UyKA?;v%UO+h``O@$D{HvoqiSfHs#g-^(;XuGKC$8;i zZw9T7j+**TG211+O+G*J3H9EEq=D8iD)h-3Z5~->8yA)C78iA(0!riu26J$^%P%d~ zQ>3ITXqoz?58;O7Lqf>bKF&TYq{amt7SN-@>9$vD8Po|$a zELrsAcs=$IF|_gKJZGI}{o2PjY9u#DKj0R96#Q!M9jjRNfq&1QXdi+WK;GxppH1C7 zzRz)+|9Ykr0vo@-gb|LCq~XSgXZzcHtU$&FA{iOM%1dbd8S)3dZ8Ha$E-OZ3_1R_7r{G_)XP^EpS#O^qQa7A*ApHo!K?ca4e0_wO9$Ra zs0?qyqR3AR)Huf*IA?17QtwY+R%K?9tD9gqf?;!uUr{7jF$!1Zd`cPp9-W!PuZC0+ zi{rW}9;tCaqO^Zs&+tk=y_g6uc|xPv`De!$v+wnThAiGMZ@)wGM>7{cQSz1@c5}v4 zR8P19^OJMcW`xf&0%`1-zq)E2cq=7{N57S<+THnskY_mR83pgq#2Xa$7p>unHl$93 z@QrG;g>%LD6}@)_hm49iy9}FM*ECoK0rlssYrT1i3uX?Iv+lsu0-V`29CT z60vUiC5mx%uoW{h1pn zS79@56syKtq0>4rvu+J{v(jO6@D7rttTYMv3Q*xWF+1>N>$03P9cp#!H1YdK0nB6J zGW=v@Y#t^x%o5w3!kL&4_2A)wk7x>N*~t^GQ`kq%ndGbRFn93P)Ne5=Lq zPgmD1wtEMkv68hJEa$xvA49udP7!T9nhuk4WQ5f}4}|2HNSau{Y`omMqO}gYL;W^9 z$1o`kt)8>IeOt(vyF=o&0JYgA)Se1rYuV#*`JZ~u55vHYi{JYB_EUU88V?p*ZKw|9 zrcSEbrS}@u3Jy8VyjB3cI~cTgSDm8sGUt~g9Z_x)nCIf-a(dZ4{0IHAfn4Hoqbt}Z z#||q8-(h27uon4B+d>Ztaj$tP2y5M^*|=!o5m)7%5Num~M4xhBJtA zU@TOh``hm(;p<=@|0f9mF42&Qyk?S^^|*@09pLI3S|##?qgETYM|oWd(>hdUryks= zHhU;mEd&O95sGJ{sjPT?b>y`;`|GRzNV$-yP}}$M++lt4>7NrzLA^euen^yM#0zf!_#vM?{6->g*A?FohM~CxN}DmY{I6aIkIY|xA%~O6_L-d- zm_9%9TuICt2}cjFuWDA#@WR98reJ3RHpEr*fl7FOxuK1Es%}s!E6n2UXkX!cjc&`$ z`dN1&G@P7KjmUeq8#mzkyXSVfs3|IDNNj!f(N9G9!jqU;GI(685`I9(1(bu|ppEL= z&ic5)kLS%ZpGhxw0=>7qJHo!*Y|=;$^x2bA`$)~d9?^K-1#VCMiLz;=Kes4e9fN%L1&=pHF_Y()M)=$u>^N)a)(p-5-fWc^(b<3 zpciRl*Zem`uGk`;Hah){n+~FcDyH{US>B0gZaE2zMEJE%rjD{upqcvx(-T#}xm=Gd6)sl+ z5xzfErua~LUW8j`x`Z1p-q!N^t% z_Bf03(2Nc38D*xm$l4CnK473g`##-(DnR_+$0H?zpVo?(m01>=w?jjv2d4MIupa2qiLCB2=?_9+{@EPfffuux<7uG0 z`jFd8sJCYxKY;oDckaT;?2h`o4f2Y{h!cX4MlNEb%Zc%vn_zjxqX?toZQUr6FLoc8 zM-&|sw0ngIG8{VCQv2kVyTWq;@n{TsQY~4<&htah-`E$EMPSl%hck}u{mP*&EY{y2 z?cJg0HxfQVRRs2iiPRV~#;OrX$+P95Nly8)k0Jm>THut0x(=#V!d`kFI!Bv#%dcK^ zf^L48H4ivnz9naaiRxf6-g4%9&Sf98aTlHs^8oDCr?X$>IG%3?Y6QIm?;ZwbR}wad zSx>{|x97wTB{v1zDwwqOWS*q{R3hEYi7UK{okfef;I_?aB4-nLNABIve3wHr|FjK( za8iEs5xGyZi5S?^`K6-VMT}YL2^~*b4r<0nn{tP{C{1F4s~QU`PV}_tmU`)@1!w4e z9OLms_-fZl-u}t$zL-7_T#w}}=M3x8M#8;yVjcMe;B@gzFOLAgD+wa{gZP<2M)iS$ zz)K-9qv#o@?;-wdd3)egCb53!UOwai)%!IRc#lh!{>O2;FK7B21$51lG2wE&$rIz%Y&%W)en0595uIW#Tiq`K2dq@R}aa%nYd})zG42>Q0a`K9Xg!dT% z5-nzMH>A|02XhmQF3+G%Vwc}$YvTU|WTs*snHpDR=zQC8t}Msd=~w<6m^)oS`QfE4 z1d@R+HdRgkldLUrrS|K1E?duypm_Oa)-9~Npu$yL3Ow-umA}H(K;>2c3c_C+@XlC40Hedl zkl^6p-`$<&r8oYk9)tiyma)_JC|Y5LIh-t4LN7*{X!{AEj2VrxCI8Z85Aakx)GsC~ zL3`NJ9n+%D{~gTi4m<&Hfw(tEpRE_9QJH2!!j;%OSZh$bCvCPz-N6=h=7I^I!m3`f zPIw{-XI*uycdCTPT(edUW}LM0#kv)GHb}%%i%b&;d(T}p?~q1w_h8ISZ%B_P;t8|} z;D+XZ3(g}}IHN8%CpBm9;P4W%jT0g=O^g15L@sb~mBNq^1sT7YtOpyZ6V0}AhCSq*MB+d$?{M#u(d3^s!?i`6Yf0O=1B~q#7J}Qj$&FEVcwi9DgS%^AjzX z;|TpjGfS>Zl9%0*)I8bKRFlfUOqF^kxyQr9rP^r0vwr+-5^E9e;cs<06xxheX9ZmE za$Xv8ooCN*^;>=2+}n=|iOLx)S#XCKA5wp-*A`r+fLHf;Z+@@$l?YjTOiTzKnh2Pm zfAf9Qb!E9rWZ}HNa8jh(>oO`l*ec=&)!OOti2hN83mkzDr=jU}{njKst>6=P#)%&PT~j2Y4&PUhLrvGxfHQa_Uj_|ek?~VnyNaP`sOqzEYh28^m^tYAcvpinI z_P?nV?$zt}X%2*2qcEDl+!s(}g$PyD)eY|1Lx4&P4i}M(+bQ}t$r+`dC1N1h=tp@+ z3Iz0EW*a;wN1RntdUyr^;0!1spds??QSuMFW)>2!87{D!MOzEA3H&(#5<*RcEAk6ww4W4X8_p8P({1fN1vm0LltP%R&k&LkhPqUY z(c6g=8tiI~Co-V$ds5u!4_i@3OsQt`LE@cjl>1ST-CWUahwHEQr0Jq9mXT3B*H%dZ zh+|IpFq!?*lkO$pzIT8n3Ls7dQR)hPbreVjk7#g?XW4bzDmb!P1`4+phJ4#s3bWO( zjD*zA*NjE3)XfV*eeiatiD6;!k_stZqa;n3(0%`tf`gbFS^)B3QLJZD~029Wo-e;sI6pCdd z>OcJIm2{#Y*B@Z8sfgD|6Lq2DdwU;zUpwy}`90?8xaWP&U1&Hf9Y66ivW@fW^F^_q z+mAtr^Q(TU(etOzgy#WX_khP1^ZSQ~V+Qs#QM{)2run3Zq{U&`yz)oDB(m?qsA(}B zITn++da}@2;)yt_ODa4w{d4)BZG!>61skWu_22FQW@bkAhI*i_sK{Pg{^ILeczyk0 zyKaStTg4_UQx~{!h270CwzYqZ@3Qn~a74{3gZ+c@yH!+Qwn1&Qw-#+ROV@T(gOG;w zLV^`ll^lyY5QwoTV7+ljK}%~b;A|r z)Z?j4kBO{u>I3PjZbtI<%(pRl5Mz360Jg3|&d2Pljnnr+90I-k!IBJs!rYrbr`jxf za7*;6Q`lIuw_Gkpdh)P^YyZa+q>LP#mMXZ}<}{2D@S!Xz!$CT>kFC-*rZi>y$dEbA z>qC^m`t7F!yw64>epFl!Msl{_MU(Wgs;0&vW$N*8#>-HxzXfB+hoqB#I$boBI8yd5 z+;%4^4E<4SJFB#8%}zzS;6NJ)p!n5G*1;3WVz;WXA2Y$-rXGZO(iNlfnq2)@;SK4Q zE0qV1;YXDi(8iOYlR0dZ?49gtQ87-17n_Ycc$<6GB39~FAymPi-ej!SswgpQ@T$4X zW}?D}N;5c?BW8!x3M$rpyBl)PJF!P`pjWOSv6O&iSe_WpY@f%i&B9g<7Gt)D`KDY` zv{$Sa_$`x~XSAMQXdC;AI=wwfx|@ub%~sxCC?WGHBv0#f89nT!t{-z)IqIT(CsuG4 zF#BdlLN-~p} zekgQ(Z_^eirSWqUxY5VC@P%ITjuu z{O=P&E_0d0tN=lYPeqpwQ}yPH7Ya;+d1b#nw}#%n4048oKwP)rD$Bxjmy@Xn+=@}N zE@9%L&n9CQtUpRCsVGSY1)(w2RC=a+B(A{Ur2!%q0(zw&;S+a z%4DBnz7^%3MLV4Y-B9u)Ya!#>m0k<2>(h*gt{`LVO!Ye_27|sdhZw{7yR9ZlgiVqn zqC9_-{3q-voG-)|q{KlxB0>0TMs~%lM4)r1_q$yVEVZ{@oOssY$6uF+Vn;onfgukF zzUtqdxJ0_->`12+lkC$<==0DeXO~zt49f$^pqYN-V~q{wbu3HaQBu|9^#scHT@&V8 z-uPRpr|XUlZanBGpyI?E0+E7dVtsICkpGvOo6X6pJf+QdWubwc&>kd zy+84Of%e!ADKx-HeV|%a_8R%ETkdklPmD z@a9Fi?a4cn1!&vGiBG_E+j?Eh-P8LygAy^tux*S_KwB4j8l{-A=NctYPg}g$rmUhQ z6J(JWpA(%%{GVLvez?(8K9XG0ncOjm?ll3Ne#5)n-@LJ+udTuC3OUmk*`g;^I7yq8 z%PV%>(FqZajq7UL^Yd-tnSpTUAb{hQbmlFT$|@V@$A(^QLfX7f`%ivKne23>w{N|D z>dTpW?OwK}e&X{NCrkq1RI^<|9~55F2npuOJEUfriqjXQ0=QX4xz^591FB26vEEmw zno73272W4ul-zG;DF$ElLO0oKSb;fYHaqn9O^~~TGk8=f4_dj9^|C+n`__##D&dcs zEq=Maz)UJ1t%iq&ALqehk0WoIWY;S%aSsQJa04p0i&!$1=iyZ(-v*A_nTvz;;!}it^*+jPCG>_n2Ortu zfPg5|PlWKBHN%j(mCOn7B#*_lHxG%w)FNZ#ORgrYMVVkO@9_!heM+fl}OCFD~ z&0qk9Jj=!^rSM4MsiR*-PyE{PJ#VxOLCCQg<(hOV1B2PXu|g9a`!*6n2V*0!!jnUM z@6iBdM@tNdsp%+xr&sdu**De-5xa%0!^0M*XWep4#ZunK3&iUe$Q+<*M4P@u!e0jt zDsh|l^gN1L8A)HF6x?l=C5+z7<1G_@wex%Qjz(>A&*8Kmb1b`ThAOX7vYfoYC@Tn? zN*IqgKx*{8cZ_zO;eh*`PB@F`-H^GMEp~se59{KwxU|BPPWy>EcC~LU_!}}xzEG@N z*r{+N%x?Ql8?Pq1-?hLX8+ms}|CzV?@oVj7?zw<297?vjdYw%};Flj4(rQqW-WtSD zIDIWVds8;Nqh)6KZBy_g@@er;`fyNySuZt9wP>j1-d8tgIa$`6r^ojs726= z(ptwzlaZa{WdXds2Fgd*wsx^i3_jk=%*CqU_KPqhE4Z1xPfoF3oYn^weeKoefdj9( z?aaiR5jw6mX7$2XJm5S}+}z&Eg>`06OW{MeETNPI`E7)?-}UW-G}EKU-cZJl^8HwI zni?c~V2;4MOrl#3Y5LyEB**SRC^9P0~J_w!;?l!=shnOl|_jqhGd* zxOvGzc?Xg&^dHY6Q+8zHwpo1&F?GludWJyaCe^3r%c>6Y4aAVk@4gxXwJ#bxH*<3X zf)tHVV)m0;OU&E7^mo{1Bhd*aPJ5Y^{-|_{aMAqGwrXV|G)^LABs>LIJKn+j#l=W%91 z=%pfSkd=|%w%tCe+P(SI_bgA;MTnEc>d*p?)|H@ChLiH zP;GeNh8C@B=~m%Z&8tj6C%x*k(*}KiWAaRO7{WpRMEAKe*>^)3DM*Vzg0SM-dF6#u zIUcXa`AG;;Lhba$F3wwbKekxPcZOWXWF_wyz!PUxh&agbcyXQ{it$qm+azn((IVVq z`uM3-X2zE5<+A(`gou$m{?*P6cleM%)c2yCY9Xh#wTu|+=P#QHT;G3y9rV-|5#lWs zkIuMhU8+k4WE0~yls@*+DoKSMb%~w2j0!%zJeaP@K$DH=nCwXtt@OpMBOp z9=FQoQ$;?02fnQIZ1$O8FS@K&F|T?4@%&E12p{ij1w~`n*$h^#9up}g9RHsdKqKz% z^NOb^O={c=&v~uj@ZehHT|( zr2#08T+$?-2BwT7e&}OD!mieL*g3>cAEH~0luc#^d*j&Y26)Nr-WkBYpVW@VXj(+x z%yJGg_gtUS@ZyUe+AOto#*_5KY&*rL44E)%uk17}NH{rqZYmBGU?fua^xR^^C!3@5 zO8AWWE+%cLvi%CS(M)1a&$CzaXo=hlHadiTS^_4@gZv45q_#qc;IyM5dCQraLh2$a z2}gqKo8hPYy{37r?G{imjYb=uW`4B_t6tj~2XQHo{n4?)y6ch7MaW^(5Ipdpgs z_h2mG%e5n6@20m~&;v^Y`;=_|ZA z_9K)7;M?~Am<}rBn^eBujz=GSh+Gkuf=w2r_wx#t=Mc|ioss_5>EE=+Ft>|J9KQV8c0FoGp@}yKDPUh$AY;Y5q!U( z=qL<8GG@UZC(2cHRK53kab)vj+kkpaDSTXGH8^;bblpUqfopb4F>fl2MTyufNQ5g1v%t+I1wiQJIa-@nsp~ju_$aJ9uOFt*MQ>zg5L5Y^F0|rI3~a6v{;#E=AMg`sM7uWX=mJy0RRyD=U0am z5`=!;z!KT_cD~q`h?Scwm@36$@ zL=aKBAOZZMkIQ)b$p{tg_Sx{CZ;@x-B8v)6rlkv#Y7fCg6O6>KK9rv{onpgOmKl5k z-{J^Z)70`Fn(zhI3uH}`!YBNa{0dx%{g++B1;d_c*@Y~RkEg_+aeRD43LBbGDN-W@ zD9RdqL`=*`TTM7y0PS?nHWybWQa;eepE@YAr&?uJ2q0L-b=n_3e{uaIwp3Ubwtm1L zkN1$sl!!-x zONkXj4@rcB9;gbm?P1rdyH?6E+(8!;E1kRBg26?k^dW}IY(iONM%w=Jd2!s zN4jk&LX?`4)|DG74&;G{B;YP>v58{c*CAD-tSA0Tj8Ld)i%Ulm4=9wg;7n*o40oe~ z+fc#GctxE(xJp#{7lk{;Pmyp7vlg$KvR-)XOnjWWbt6RT1Me4p$X}Wv`0;$IZIRf< z81k-On2^csk_B5UU$J9Me}VK>y$TZRUU{)bXpa!RUQ?1hb1kgl-R)|~%6ceK?WSa_ zYW&NckrK8)(ge4mdsT@fFZ{9RFD z;lEJK`qNr>BE*StJq@qM`bH;911?)q6R=Ht%-3A7 zOI^{Vmb^ZdXpi>p-iDss0=Az``t2oA-gfSD)-xMzhwB*q$2=4M2yps5*8JJ#;`Kvw z9#4rWzNK!LimSrAzV2+G0qD1dik)st7Km}y-CItU))(Xl9&;BAjmRIZ*VdDNcTv8WvQ0qTH!b~bP5v#^&;;7yb{lJTWr$7q@5e7AU6pm$d`i&v z9K-4?#w&?u79U?`Y<$=as3aigt>MT^%S8>Dyr}!C(wZ*m8!!8czpga2 z=GTTgxgEd=W6o}tmeIucwQKsP*_P}`huWC7Y_ro=7Z1_7oc>3RB%jL?M8`cqLCPJC z?X<3ysF!;e4NcFXS&>d!I7bPY_AG!`(@}lsOg!VeOQshaiRf6VTQ_EF4=EO9BW^W8 z$dw1obcWKiynvILBtaJsI5|s)@#N^(iGMJ7=`hfG9($XOgUttMP2459YpB}=F4yo@ zzddtqya|h1GH~3X5KR~ivx}rOIq6cDN!D-(b##6pTGSU5E{pIip8>$jSaSwQP1U#z zpRgOCLNy^Jug^LUFA;%lGR>ZC5^%#zO67Zu=8}NFS9cc=?Ja#ZdI86$*K+%*vw^ej zW?soci3f9fE91BZd{A|IY1OyimC}=UHX!2!-wyi4i{o#$=!2y5uPSwiL6{Abu%4QH ziZoMVfN4OAqs3fXkGV$&vkUlA`FL)UhUT{noY_F*?{2Vy-%IPR}h5)E6dsCJAZVr2@cW;Rk`;DhJJG zzgkFwH7nx&`oka_R}f9Q^SrPCEI@sfB!I^AX?OTzU+6#T6j*xyAlDisSm#| zLgfk&0hJV4|GCYgW~^G0S>SF06slHbu6)iL*&%t3k<$||E&6tXXLS;hJQu{oy@Uu4dJ(a=GZox zQ|Z*q4GC>yM=4%^O`x9>G2)4QV81dyIR{9$5!h`0@cu`IApLYQQwb@;IPQ-Cfioa& znkfU|)0taoM{$sifmV^Gj`qii8Rmo^%@4sx>K1cvE#J5El=^Y>Iuro)G>>!p)uy5U z*?tQf%;;Db22D-D0r2L(lIr|I&N7q2bXSkrMS3)`lj`40#;5^-9w{XRAF9bK$oi>7 z`$*!3W8qq&*ALc&zcNTk$yX$)y~!vIN||z5oY16Y&35F~&V$|^FE$`iLN0x0Y*N2f zkm;LPE7*gYXp*9>zd6xUdMx^=W8VZVOZ*WuP8|ApqyTu^F>;MMYi#J4W3u@OMsUI1 zkTyj$vBImX;m6B0g52>=oKni1)b+Jw-{phwzZNkY$Xj=eU+7X05_SG{(vHKq@akF5 zAtE3MPnx$_H2YD&!I+tDCWQwkRT6 z$=YidzJ&jywd|gz$v;tUMScR(=O-&E6M*W>-_ueM!4Jl=&y-x^@_0yzDs)m7<4ibyim<|}BI^8mz zr(O+KV(Hy%zzY4t^w_p6m`2Bqa1Uls^#W%1Q?Y;XAuqT++>(3H{*#;IO58DL=yo^u zHlIl>>M7M-&ka7G`1u_s+ZGevZIv_3@NTr6%9+4)7AgSI*PH!g`2bgpx2^X61@wl= zR&qX@>7$Ba=dWf%ImD20b2S447g6_mG#aM4ZlGC5>%t77gx)J%uDVbLkS`epFzZFWm>A4cJY>ZK^DLn`;DJpMz zLnNNK;H+APsJA+P{LFsd>`>B*zE{knVa21fdrIX$Z0hNg>mwZZkP1cxJAKp*yHlh; zssnnSgb9$0y6yZ|{)mnXRScneQy3cpJ0hdf`&csbD5Uz_j?qysMGqL;d{wy1`iYbn zFP`@m^`Z&s8Me%_sE&UE^t+rJ^$xTFoOs2G<~s$M^dKxq|>Y*_Sjly8^^?w|&RVdtvI;MG+9-5s80 zoRNd4k?X4mci1){#S%OB-r8+bW<=9UJQY=v01?PCe72uwT+UCp=c8ln`FKG!kd;J$ z5`yR;0XZdz21^6@)BKffexr0`K==PEZF{#YvEkg)U{=%N5sT^mhSVqxY-8czK%yT% zG{slKlQ=&oH4W*y&#-OPg8n1LhnToK^b86Ow>)S?b>KTo!K!l>DiL=Ss2}JDp^Nf& zDoO{kLC6O!w=H=^(Rsd$aaxS&jzehAkP4l3wCEU?3#=%6KvVA;XI=30vapM1eGF?T zjryWuT0;$D_WRiKLmx7Ti5I>xb4LkTWH7 z?!V3-nh2!Mfs;=jqoV#5VIT7Q9*X%TK`kUfim`ExDkdiQt@#&|UAF-447c8sq>axb z!0maq=t$t%mCV`lBMbu5tb%D?!Cv%4$RuNSzAd|_Yw3)KV0(?mP#MzZ|4H6KvYxsS~}Wodon0- z+wAT_V89;5A5Ln6JGZa^+OUVGGzK)On;mr82;aVVr3j2iiyLy50yMEbbH*e_9-6SQ zz=N9#XvuvKol)7}^I$UJZpHkgDgF&}y1Ht1X4QOA>Kn&-Ta4pzq1r56P2dy&WO^g1C)hDN3b3{) zms^zP2Jr-VY$WbJ8_E7p@&oQ)8rq3Re5i~>XuSTIzOx#9=UO0iv>TAkJL0_Bkxt*` zHzS={BdX_TDnfg*Tb8V6Kg(STOv-Mw4A|a~;6kvtZ1_S5Kia!@JcazaS@S25;_Uo1 zX+{qhfIA=GI&zVyaCo^~9(mw;9^m1>l>`-BV$^w&{S+ngJpD|jrO5B{kPUkly*YzM=vmgd0Y$OKA@6DA(;W+;K|Ag6@@a;IGC zp1z+gE{ek7b!qFI_G(MW7+`Fbl1?h$-Ds_i77@aFs@UiU;}{<)L{vMhZZ3D=9Ezw^5|8*KDbcKSQHHGnxkH+65DS$p9x(m3`MrW|uQfRUy- z3wfR={CcUTiWO{c(vDXq2xbfLDn0cpd;dz{jB4Vo-{0^o^4+4s-C3RV>kp6kYkof- zl;;CB--IJNL`rzJ&qzY#*$`0DI4#palxvR|Es{y>7b)1OG?;y#jkAbVy?U?dwWH2` zlZBsx-@UX=^nJ*|^o+NJOU7dD|$e&;m| zRUzAvn6V!0f_cyNY(o@g9ZO6=)URFV@p?zBS*L4Pm`@+{$?<)*ZDfc7hbi%(n#M?g zh1tb?4;IC@qm-15wK5Bsl`eG|dgoB9c5h8`LXez+gFI~^0xo~X!o4$8&F9;nacgq) zD{WL@gisEC;_r*^a4;)~Eq%cVhJv{Jsq`(l61^(?XVwg@%DL}ihXUI~WM4Ck{KG9N z;%kP{9Ru5Vn;oEP=gg!Bv#$BLMK1hqRCe=09}zSyWBs2^>N~fYyoISNsP%=xooCy~ z0TusNMFxHHucTgh98Ckqmg`hVOozzhN8$pH4~};kVqVkz7FO&s$!z)J_h`$EdFsEL zhy383XP%Fk2Zgvd4=0lPrWbam@?!JWhkWPNl zIC33~ViX_)X$U|A3WrX7$-7tQ6`cMSyv}0)l+lZ6to*cAx}5d&3%>Xo`Rw)#m4v(C z{3i5Mr1?Ysm>Ab-s56N@vUR?p%TpTi-{T2S2bcJT5*l^-yJa@gqwTXzsqWJ=L&Dqd zpH4%VQAxrfwoM}7%EC|4x2u_-3dFe5%w7jh0GO+HEmetn180D6o9F^WLQEy5(Yk?+ zj_Ye;G2LaX2GV9Tqr|d>l@3&x`V27TnliIQj}32Uw)_5vx17_9{MJyISk)8PBYTId z#^6q_&w8$hR47{ZR;I6S@WlQ_4;FXo82;=DUa_bsL_%hlSK+Gk0G#_x&zp#Ml99MZ zvW-tqUlk?%Ms70$U5yyM_qImoTYF*d_Z=>%hF%<(LrevHVR$}=R!t2>bZi|;^*pxw zMVo9v5~7T`(v_@a++T3Jv!jf^R9j6ANS4E1XcG8+{rVr+hgKiy{DN z8AhsIEaVsE=?{^}%f08Q2YSzfx#gcFw$f#y zDF9*ysoi_h@uZL16i4-7>o>s}nhIz$WF3OK2cr-|LxP|XLZj=Wmb`4b0dVYE<8p00 z(~0T$m!g2z3)0_v0ZpRG)zC@Wwi^`)S?k|~jGDvK-NyEwu=nNfcwO-T<_k%setO6H zA%M@>Y2;cy>vgH2wsMTptBLK`au?8fL={bUR50(%32lVMob| vbE?3&z_x5uv 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

(nl!7GX#u6#1 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Ξ+E|!%#RGRp@lp!T8O?08E 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

xp43y1 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�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%0AiZ+@2XI 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⋘dfLaw^+NzU|&B$gAq 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 fITU2#HaeRdl zt7jqY)SYGr@5p!kCiGW%>&SQAt1hs>Hu=M592hBeHL05=eG?``+002ec0|JIQy8eE z=^#~F_Vl7e#@|=?aLlGC-H`dp(M~ z)1^U;vc>GxhgL+SRw2+Rdf+fouedd$_mbE;HM%&t=Cba7LQ!h_KzI*ZJe^n;-MZB3 zZ%2d_Nxz#hfHxmMuR5;!vg*3Z3EhyE99`XSHr=#tM{@vYdOcErBt=`~g~F#D2JvyW zSn5h}0Y_wHh{{~i4YC*$s9NN7-s}SOv4(e%S3i$7%xEq`v!>CVmPJIrgzDzgoW1Xj zhSJ4Kdo?-#ST=fwqFdpziKpEn$CY#{7coc3+G1Mouoi{*fn7{WYV<}|PcJA)aawQ- z9qLBzbd|rx9xUZiqM;}1?)9|_`vQfcNB6{k%9!V)CNv7#ETx_kX@!irnrh{gog#-6 zczW6}Ags=^3l~^AYvZg`yHJrVw8pOF;sAg-*f5`8A{?UCsrQ!5>$&Hhi#1#+?7Q}h zCIbol^JaC7E8FG$`-vizArK!QujEE;Zbkk2`1L%1hFg+ev@XYOFG+LJp4f%nM0U{~ zwnU|5(M9(z`bMwbPr8U(NY+D#5g<`eYNNmDzN^5Zw2KjS!gLDMjwUT?$0ys=Vpl>ruDVC4-nMUR&OKqIFCJ)hQ~WRb`#>&y1{3p+&yMo zPkEfj_;3TwC%n~>2InRjm{EU&ZvWhD68~uUOC{-n<6_Rth+25?T_+D z(Y8~nESa>R8M11jclzoWOR)yj%?bEhWxWP--`;gRo`q2xA5nV08_g0SC2u*@y0=)y z%v|HU?6A=WbAv^5W5*c`2BBHCWdXD|X%*eb30bJZ3c0a05L)x*!S*bUmJU<(bF1

=Sf3gto-z_S@26L#>}w32#;*+$y8uv4q&O;kLL? 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ð?zpX>n?FffkdK0b8C#a8S4Xl} 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 z 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 Qp#T5?07*qoM6N<$f{{wu-2eap literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Normal.png.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Normal.png.meta new file mode 100644 index 0000000..0dc3333 --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Normal.png.meta @@ -0,0 +1,88 @@ +fileFormatVersion: 2 +guid: f000bac298646b642be72cb1ec3bfbbf +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 1 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: '' + vertices: [] + indices: '' + edges: [] + weights: [] + spritePackingTag: '' + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt new file mode 100644 index 0000000..ed10006 --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt @@ -0,0 +1,7 @@ +Recon Tank (update), by Mophs +https://opengameart.org/users/mophs + +Based on original work, Recon Tank, By MNDV.ecb, 2018 Eric Buisson +https://opengameart.org/content/recon-tank + +CC-BY 4.0 \ No newline at end of file diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta new file mode 100644 index 0000000..e6301fa --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 17e6c2c3325f51e429a71bd91a872788 +TextScriptImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat new file mode 100644 index 0000000..207b1f7 --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat @@ -0,0 +1,82 @@ +%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: TankMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION _METALLICGLOSSMAP _NORMALMAP _SPECGLOSSMAP + m_LightmapFlags: 0 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 2800000, guid: 2617bfecca4d44805a3a51a7aa215d7c, type: 3} + 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: 2800000, guid: 9b3e91ab0048a4aa3a17706a349c6bf5, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: ce00d67f9368944fa8ef4de6ccc77bfa, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 2800000, guid: a7467e18a834e4d1390091c8b1ea562c, type: 3} + 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} + - _SpecGlossMap: + m_Texture: {fileID: 2800000, guid: a7467e18a834e4d1390091c8b1ea562c, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1.75 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 0.09 + - _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: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 1, g: 1, b: 1, a: 1} + - _SpecColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat.meta new file mode 100644 index 0000000..67f306a --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/TankMaterial.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cdd2a40c3c724354c936d49e544910f9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx new file mode 100644 index 0000000000000000000000000000000000000000..5877b09457d82ce53fd745c56c2cbf0f9e216114 GIT binary patch literal 224204 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 R_NmcVeu}v8@>}Kd{tsDmN#Oth literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx.meta new file mode 100644 index 0000000..f801ec0 --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/reconTank.fbx.meta @@ -0,0 +1,239 @@ +fileFormatVersion: 2 +guid: 3dfcc78d7c6beed488fabf8a79f7c4b6 +ModelImporter: + serializedVersion: 23 + fileIDToRecycleName: + 100000: Barrel + 100002: Barrel_end + 100004: Chasis + 100006: Recon_Tank + 100008: Recon_Tank_Rig + 100010: //RootNode + 100012: Root + 100014: Turret + 100016: Wheel_Front_L + 100018: Wheel_Front_L_end + 100020: Wheel_Middle_L + 100022: Wheel_Middle_L_end + 100024: Wheel_Rear_L + 100026: Wheel_Rear_L_end + 400000: Barrel + 400002: Barrel_end + 400004: Chasis + 400006: Recon_Tank + 400008: Recon_Tank_Rig + 400010: //RootNode + 400012: Root + 400014: Turret + 400016: Wheel_Front_L + 400018: Wheel_Front_L_end + 400020: Wheel_Middle_L + 400022: Wheel_Middle_L_end + 400024: Wheel_Rear_L + 400026: Wheel_Rear_L_end + 2100000: Recon_Tank + 4300000: Recon_Tank + 7400000: Recon_Tank_Rig|Drive + 7400002: Recon_Tank_Rig|Forward + 7400004: Recon_Tank_Rig|Idle + 7400006: Recon_Tank_Rig|Shoot + 9500000: //RootNode + 13700000: Recon_Tank + externalObjects: {} + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + motionNodeName: '' + rigImportErrors: '' + rigImportWarnings: '' + animationImportErrors: '' + animationImportWarnings: '' + animationRetargetingWarnings: '' + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: + - serializedVersion: 16 + name: Recon_Tank_Rig|Drive + takeName: Recon_Tank_Rig|Drive + firstFrame: 0 + lastFrame: 1 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + hasAdditiveReferencePose: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 3 + maskSource: {instanceID: 0} + additiveReferencePoseFrame: 0 + - serializedVersion: 16 + name: Recon_Tank_Rig|Forward + takeName: Recon_Tank_Rig|Forward + firstFrame: 0 + lastFrame: 25 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + hasAdditiveReferencePose: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 3 + maskSource: {instanceID: 0} + additiveReferencePoseFrame: 0 + - serializedVersion: 16 + name: Recon_Tank_Rig|Idle + takeName: Recon_Tank_Rig|Idle + firstFrame: 0 + lastFrame: 11 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + hasAdditiveReferencePose: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 3 + maskSource: {instanceID: 0} + additiveReferencePoseFrame: 0 + - serializedVersion: 16 + name: Recon_Tank_Rig|Shoot + takeName: Recon_Tank_Rig|Shoot + firstFrame: 0 + lastFrame: 15 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + hasAdditiveReferencePose: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 3 + maskSource: {instanceID: 0} + additiveReferencePoseFrame: 0 + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 0.15 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + keepQuads: 0 + weldVertices: 1 + preserveHierarchy: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + useFileScale: 1 + previousCalculatedGlobalScale: 0.0015 + hasPreviousCalculatedGlobalScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + serializedVersion: 2 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + rootMotionBoneName: '' + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 2 + humanoidOversampling: 1 + additionalBone: 0 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Prefabs.meta b/UnityProject/Assets/Tanks/Prefabs.meta new file mode 100644 index 0000000..782b2c3 --- /dev/null +++ b/UnityProject/Assets/Tanks/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61745bed6d4e50a4e8238970f9ad1068 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab b/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab new file mode 100644 index 0000000..40a0fbd --- /dev/null +++ b/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab @@ -0,0 +1,291 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &63476987332307980 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8035186136109819211} + - component: {fileID: 9118274893554935717} + - component: {fileID: 69063397099238371} + m_Layer: 0 + m_Name: 3D Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8035186136109819211 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63476987332307980} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.1, z: 0.05} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 24373266488650541} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &9118274893554935717 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63476987332307980} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &69063397099238371 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63476987332307980} + 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: cba1b63a0bccc4b12ac25f05d0ae2dd1, 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: 0 + 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 &5890560936853567077 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 24373266488650541} + - component: {fileID: 2355290524794870353} + - component: {fileID: 4629190479245867726} + - component: {fileID: 4686139084300654196} + - component: {fileID: 744839112580503729} + m_Layer: 0 + m_Name: Projectile + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &24373266488650541 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5890560936853567077} + 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: 8035186136109819211} + - {fileID: 7830988697844474908} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &2355290524794870353 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5890560936853567077} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.05 + m_Height: 0.2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &4629190479245867726 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5890560936853567077} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 0 + m_CollisionDetection: 1 +--- !u!114 &4686139084300654196 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5890560936853567077} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bd3a7936935f94845b3efc633e716dcc, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 744839112580503729} + _networkObjectCache: {fileID: 744839112580503729} + destroyAfter: 5 + rigidBody: {fileID: 4629190479245867726} + force: 1000 +--- !u!114 &744839112580503729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5890560936853567077} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + k__BackingField: 0 + k__BackingField: 0 + _networkBehaviours: + - {fileID: 4686139084300654196} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 16150412557470202507 + _sceneNetworkObjects: [] +--- !u!1 &9126921595194253319 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7830988697844474908} + - component: {fileID: 4878977110396366525} + m_Layer: 0 + m_Name: Point Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7830988697844474908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9126921595194253319} + 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: 24373266488650541} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!108 &4878977110396366525 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9126921595194253319} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 2 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 5 + m_Range: 2 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + 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: 3 + 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 diff --git a/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab.meta b/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab.meta new file mode 100644 index 0000000..b95bfa7 --- /dev/null +++ b/UnityProject/Assets/Tanks/Prefabs/Projectile.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f86c53b4b7ca9ca47ada8b4674970afb +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Prefabs/Tank.prefab b/UnityProject/Assets/Tanks/Prefabs/Tank.prefab new file mode 100644 index 0000000..4d592af --- /dev/null +++ b/UnityProject/Assets/Tanks/Prefabs/Tank.prefab @@ -0,0 +1,382 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1916082411674582 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4492442352427800} + - component: {fileID: 2240606817507776182} + - component: {fileID: 1970997826722237872} + - component: {fileID: 6900008319038825817} + - component: {fileID: 5194388907919410155} + - component: {fileID: 1022466107096954536} + - component: {fileID: -1263032358799398780} + m_Layer: 0 + m_Name: Tank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4492442352427800 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + 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: 7831918942946891954} + - {fileID: 6564220120147636086} + - {fileID: 5718089106632469514} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &2240606817507776182 +Animator: + serializedVersion: 4 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Enabled: 1 + m_Avatar: {fileID: 9000000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Controller: {fileID: 9100000, guid: a7211483bbd794b6d85ed88576e7d85c, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorControllerStateOnDisable: 0 +--- !u!114 &1970997826722237872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0d572d88e906595448b407b53633743d, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: 1022466107096954536} + _networkObjectCache: {fileID: 1022466107096954536} + agent: {fileID: 6900008319038825817} + animator: {fileID: 2240606817507776182} + rotationSpeed: 100 + shootKey: 32 + projectilePrefab: {fileID: 5890560936853567077, guid: f86c53b4b7ca9ca47ada8b4674970afb, + type: 3} + projectileMount: {fileID: 5718089106632469514} +--- !u!195 &6900008319038825817 +NavMeshAgent: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Enabled: 1 + m_AgentTypeID: 0 + m_Radius: 0.5 + m_Speed: 1 + m_Acceleration: 1 + avoidancePriority: 50 + m_AngularSpeed: 120 + m_StoppingDistance: 0 + m_AutoTraverseOffMeshLink: 1 + m_AutoBraking: 1 + m_AutoRepath: 1 + m_Height: 0.5 + m_BaseOffset: 0 + m_WalkableMask: 4294967295 + m_ObstacleAvoidanceType: 0 +--- !u!135 &5194388907919410155 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0.25, z: 0} +--- !u!114 &1022466107096954536 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} + m_Name: + m_EditorClassIdentifier: + k__BackingField: 0 + k__BackingField: 0 + _networkBehaviours: + - {fileID: 1970997826722237872} + - {fileID: -1263032358799398780} + k__BackingField: {fileID: 0} + k__BackingField: [] + _isNetworked: 1 + _isGlobal: 0 + _disableOnDespawn: 0 + NetworkObserver: {fileID: 0} + k__BackingField: -1 + _scenePathHash: 0 + k__BackingField: 0 + k__BackingField: 7519518230224857689 + _sceneNetworkObjects: [] +--- !u!114 &-1263032358799398780 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1916082411674582} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a2836e36774ca1c4bbbee976e17b649c, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: 1022466107096954536} + _networkObjectCache: {fileID: 1022466107096954536} + _synchronizeParent: 0 + _packing: + Position: 1 + Rotation: 1 + Scale: 0 + _interpolation: 2 + _extrapolation: 2 + _enableTeleport: 0 + _teleportThreshold: 1 + _clientAuthoritative: 1 + _sendToOwner: 1 + _interval: 1 + _synchronizePosition: 1 + _positionSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeRotation: 1 + _rotationSnapping: + X: 0 + Y: 0 + Z: 0 + _synchronizeScale: 1 + _scaleSnapping: + X: 0 + Y: 0 + Z: 0 +--- !u!1 &4426914200102054949 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6564220120147636086} + - component: {fileID: 7604806193092689376} + m_Layer: 0 + m_Name: Spot Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6564220120147636086 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4426914200102054949} + m_LocalRotation: {x: 0.02281505, y: -0, z: -0, w: 0.9997397} + m_LocalPosition: {x: 0.07, y: 0.46, z: 0.126} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4492442352427800} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 2.615, y: 0, z: 0} +--- !u!108 &7604806193092689376 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4426914200102054949} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 0 + m_Shape: 0 + m_Color: {r: 1, g: 0.9205329, b: 0.7877358, a: 1} + m_Intensity: 3 + m_Range: 15 + m_SpotAngle: 80 + m_InnerSpotAngle: 62.1886 + 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!1 &4730779867780281009 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5718089106632469514} + m_Layer: 0 + m_Name: ProjectileMount + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5718089106632469514 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4730779867780281009} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.412, z: 0.936} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4492442352427800} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &7831918942947279416 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 4492442352427800} + m_Modifications: + - target: {fileID: 100010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_Name + value: 3D Model + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 13700000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 2e67e42170aa64aa9a33424f8045ac89, type: 2} + m_RemovedComponents: + - {fileID: 9500000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} +--- !u!4 &7831918942946891954 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, + type: 3} + m_PrefabInstance: {fileID: 7831918942947279416} + m_PrefabAsset: {fileID: 0} diff --git a/UnityProject/Assets/Tanks/Prefabs/Tank.prefab.meta b/UnityProject/Assets/Tanks/Prefabs/Tank.prefab.meta new file mode 100644 index 0000000..0de4edd --- /dev/null +++ b/UnityProject/Assets/Tanks/Prefabs/Tank.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b6afe29d22f1fc458cbbcaa766322ac +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Scenes.meta b/UnityProject/Assets/Tanks/Scenes.meta new file mode 100644 index 0000000..7343a5f --- /dev/null +++ b/UnityProject/Assets/Tanks/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d8cb67f0c9558b04699c715b7aa1926f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Scenes/Scene.meta b/UnityProject/Assets/Tanks/Scenes/Scene.meta new file mode 100644 index 0000000..4212bb4 --- /dev/null +++ b/UnityProject/Assets/Tanks/Scenes/Scene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b7538c43bba94da4e9164c8a2b7698b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity b/UnityProject/Assets/Tanks/Scenes/Scene.unity similarity index 62% rename from UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity rename to UnityProject/Assets/Tanks/Scenes/Scene.unity index b470ed4..804c241 100644 --- a/UnityProject/Assets/Ignorance/Demo/Super Basic/SuperBasic.unity +++ b/UnityProject/Assets/Tanks/Scenes/Scene.unity @@ -24,9 +24,9 @@ RenderSettings: 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_AmbientMode: 3 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_SkyboxMaterial: {fileID: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 @@ -38,13 +38,13 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 11 - m_GIWorkflowMode: 0 + m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 @@ -54,7 +54,7 @@ LightmapSettings: m_EnableBakedLightmaps: 0 m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: - serializedVersion: 12 + serializedVersion: 10 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 @@ -62,7 +62,6 @@ LightmapSettings: m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 - m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 @@ -72,21 +71,15 @@ LightmapSettings: m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 - m_BakeBackend: 1 + m_BakeBackend: 0 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 - m_PVREnvironmentSampleCount: 500 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 2 - m_PVRDenoiserTypeDirect: 0 - m_PVRDenoiserTypeIndirect: 0 - m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 0 + m_PVRFilteringMode: 1 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 @@ -94,9 +87,7 @@ LightmapSettings: m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 + m_ShowResolutionOverlay: 1 m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -120,8 +111,8 @@ NavMeshSettings: accuratePlacement: 0 debug: m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &249891953 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -129,113 +120,8 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 249891957} - - component: {fileID: 249891954} - - component: {fileID: 249891956} - - component: {fileID: 249891958} - m_Layer: 0 - m_Name: NetworkManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &249891954 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 249891953} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} - m_Name: - m_EditorClassIdentifier: - showGUI: 1 - offsetX: 0 - offsetY: 0 ---- !u!114 &249891956 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 249891953} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} - m_Name: - m_EditorClassIdentifier: - dontDestroyOnLoad: 0 - runInBackground: 1 - autoStartServerBuild: 1 - showDebugMessages: 0 - serverTickRate: 60 - serverBatching: 0 - serverBatchInterval: 0 - offlineScene: - onlineScene: - transport: {fileID: 249891958} - networkAddress: localhost - maxConnections: 16 - disconnectInactiveConnections: 1 - disconnectInactiveTimeout: 60 - authenticator: {fileID: 0} - playerPrefab: {fileID: 897184729387425976, guid: dc2c4328591bef748abb8df795c17202, - type: 3} - autoCreatePlayer: 1 - playerSpawnMethod: 1 - spawnPrefabs: [] ---- !u!4 &249891957 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 249891953} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -10, y: 4, z: 5} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &249891958 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 249891953} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 872fa23ef6e77334ca452ce16f6cd091, type: 3} - m_Name: - m_EditorClassIdentifier: - port: 7777 - LogType: 1 - DebugDisplay: 0 - serverBindsAll: 1 - serverBindAddress: - serverMaxPeerCapacity: 50 - serverMaxNativeWaitTime: 1 - clientMaxNativeWaitTime: 3 - clientStatusUpdateInterval: -1 - Channels: 0100000002000000 - PacketBufferCapacity: 4096 - MaxAllowedPacketSize: 33554432 ---- !u!1 &288173824 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 288173827} - - component: {fileID: 288173826} - - component: {fileID: 288173825} + - component: {fileID: 88936777} + - component: {fileID: 88936776} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -243,30 +129,21 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!81 &288173825 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 288173824} - m_Enabled: 1 ---- !u!20 &288173826 +--- !u!20 &88936776 Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 288173824} + m_GameObject: {fileID: 88936773} m_Enabled: 1 serializedVersion: 2 - m_ClearFlags: 2 + m_ClearFlags: 1 m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 @@ -277,7 +154,7 @@ Camera: near clip plane: 0.3 far clip plane: 1000 field of view: 60 - orthographic: 1 + orthographic: 0 orthographic size: 5 m_Depth: -1 m_CullingMask: @@ -294,21 +171,21 @@ Camera: m_OcclusionCulling: 1 m_StereoConvergence: 10 m_StereoSeparation: 0.022 ---- !u!4 &288173827 +--- !u!4 &88936777 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 288173824} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -1} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0, y: 0.92387956, z: -0.38268343, w: 0} + m_LocalPosition: {x: 0, y: 6.5, z: 8} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &379082678 + m_LocalEulerAnglesHint: {x: 45, y: 180, z: 0} +--- !u!1 &251893064 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -316,139 +193,85 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 379082679} - - component: {fileID: 379082681} - - component: {fileID: 379082680} - m_Layer: 5 - m_Name: PlayersPanel - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &379082679 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 379082678} - 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: [] - m_Father: {fileID: 533055204} - 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!114 &379082680 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 379082678} - 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, g: 0, b: 0, a: 0} - m_RaycastTarget: 0 - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 0} - m_Type: 1 - 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 &379082681 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 379082678} - m_CullTransparentMesh: 0 ---- !u!1 &522137823 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 522137826} - - component: {fileID: 522137825} - - component: {fileID: 522137824} + - component: {fileID: 251893065} + - component: {fileID: 251893066} m_Layer: 0 - m_Name: EventSystem + m_Name: Spawn m_TagString: Untagged - m_Icon: {fileID: 0} + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &522137824 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 522137823} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalAxis: Horizontal - m_VerticalAxis: Vertical - m_SubmitButton: Submit - m_CancelButton: Cancel - m_InputActionsPerSecond: 10 - m_RepeatDelay: 0.5 - m_ForceModuleActive: 0 ---- !u!114 &522137825 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 522137823} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} - m_Name: - m_EditorClassIdentifier: - m_FirstSelected: {fileID: 0} - m_sendNavigationEvents: 1 - m_DragThreshold: 10 ---- !u!4 &522137826 +--- !u!4 &251893065 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 522137823} + m_GameObject: {fileID: 251893064} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalPosition: {x: 3, y: 0, z: 3} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &251893066 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 251893064} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: -3} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &533055200 +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1107091652 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -456,98 +279,194 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 533055204} - - component: {fileID: 533055203} - - component: {fileID: 533055202} - - component: {fileID: 533055201} - m_Layer: 5 - m_Name: Canvas + - component: {fileID: 1107091656} + - component: {fileID: 1107091655} + - component: {fileID: 1107091654} + - component: {fileID: 1107091653} + m_Layer: 0 + m_Name: Ground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1107091653 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 29b49c27a74f145918356859bd7af511, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + 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 +--- !u!64 &1107091654 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Convex: 0 + m_CookingOptions: 14 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &1107091655 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1107091656 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + 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: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + m_Layer: 0 + m_Name: NetworkManager m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &533055201 -MonoBehaviour: +--- !u!4 &1282001518 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 533055200} - 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 &533055202 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 533055200} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 ---- !u!223 &533055203 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 533055200} - 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 &533055204 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 533055200} + m_GameObject: {fileID: 1282001517} 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_Children: - - {fileID: 379082679} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] m_Father: {fileID: 0} m_RootOrder: 3 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!1 &707756284 +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + autoStartServerBuild: 1 + showDebugMessages: 0 + serverTickRate: 30 + serverBatching: 0 + serverBatchInterval: 0 + offlineScene: + onlineScene: + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 1916082411674582, guid: 6f43bf5488a7443d19ab2a83c6b91f35, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 5890560936853567077, guid: b7dd46dbf38c643f09e206f9fa4be008, type: 3} +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + Port: 7777 + NoDelay: 1 + Interval: 10 + FastResend: 2 + CongestionWindow: 0 + SendWindowSize: 4096 + ReceiveWindowSize: 4096 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!1 &1458789072 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -555,31 +474,115 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 707756286} - - component: {fileID: 707756285} + - component: {fileID: 1458789073} + - component: {fileID: 1458789074} m_Layer: 0 - m_Name: Directional Light + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1458789073 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1458789072} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: 3} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1458789074 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1458789072} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1501912662 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1501912663} + - component: {fileID: 1501912664} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1501912663 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1501912662} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: -3} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1501912664 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1501912662} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + 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 &707756285 +--- !u!108 &2054208275 Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 707756284} + m_GameObject: {fileID: 2054208274} m_Enabled: 1 - serializedVersion: 10 + serializedVersion: 8 m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 m_CookieSize: 10 m_Shadows: m_Type: 2 @@ -589,24 +592,6 @@ Light: 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} @@ -614,28 +599,25 @@ Light: 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_ShadowRadius: 0 m_ShadowAngle: 0 ---- !u!4 &707756286 +--- !u!4 &2054208276 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 707756284} - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.10938167, y: 0.8754261, z: -0.40821788, w: 0.23456976} + m_LocalPosition: {x: 0, y: 10, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 50, y: 150, z: 0} diff --git a/UnityProject/Assets/Tanks/Scenes/Scene.unity.meta b/UnityProject/Assets/Tanks/Scenes/Scene.unity.meta new file mode 100644 index 0000000..d7d5826 --- /dev/null +++ b/UnityProject/Assets/Tanks/Scenes/Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 64e64f42ad0a55d478c06ee0677702b9 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Scenes/Scene/NavMesh.asset b/UnityProject/Assets/Tanks/Scenes/Scene/NavMesh.asset new file mode 100644 index 0000000000000000000000000000000000000000..3acffc80e7884117f6ba1c24763179df0d46214e GIT binary patch literal 5444 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�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%0Ai~*MUVw4AGhb2nu1yyAT(LQSwUKz9h*DaXxJ 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 literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Racket.png.meta b/UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta similarity index 79% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Racket.png.meta rename to UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta index d3760fb..11d3546 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Racket.png.meta +++ b/UnityProject/Assets/Tanks/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta @@ -1,12 +1,12 @@ fileFormatVersion: 2 -guid: e11aad367beb44f4b8a3def9b8fc57ec +guid: 50a5faa357e652149b6c5fe194c1661f TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 9 mipmaps: mipMapMode: 0 - enableMipMap: 0 + enableMipMap: 1 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -27,31 +27,31 @@ TextureImporter: generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: 0 - aniso: 16 + filterMode: -1 + aniso: -1 mipBias: -100 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 lightmap: 0 compressionQuality: 50 - spriteMode: 1 + spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 1 + spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 1 + alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 @@ -63,7 +63,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 @@ -75,14 +75,14 @@ TextureImporter: outline: [] physicsShape: [] bones: [] - spriteID: 09819c66a21defd49b2cfc87fea685d2 + spriteID: '' vertices: [] - indices: + indices: '' edges: [] weights: [] - spritePackingTag: + spritePackingTag: '' pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat b/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat new file mode 100644 index 0000000..d231b59 --- /dev/null +++ b/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat @@ -0,0 +1,77 @@ +%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: ProjectileMaterial + 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 + - _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: 1, b: 0.8901961, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat.meta b/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat.meta new file mode 100644 index 0000000..54c48f6 --- /dev/null +++ b/UnityProject/Assets/Tanks/Textures/ProjectileMaterial.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f3d71e19a6dd5674e8f739bf1a38d397 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Packages/manifest.json b/UnityProject/Packages/manifest.json index 368fe46..a635e0f 100644 --- a/UnityProject/Packages/manifest.json +++ b/UnityProject/Packages/manifest.json @@ -1,11 +1,12 @@ { "dependencies": { - "com.unity.collab-proxy": "1.2.16", - "com.unity.ide.rider": "1.1.4", - "com.unity.ide.vscode": "1.2.3", - "com.unity.test-framework": "1.1.19", - "com.unity.textmeshpro": "2.1.1", - "com.unity.timeline": "1.2.17", + "com.unity.collab-proxy": "1.15.18", + "com.unity.ide.rider": "3.0.14", + "com.unity.ide.visualstudio": "2.0.15", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", "com.unity.ugui": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", diff --git a/UnityProject/Packages/packages-lock.json b/UnityProject/Packages/packages-lock.json index b1777c4..e33e7e8 100644 --- a/UnityProject/Packages/packages-lock.json +++ b/UnityProject/Packages/packages-lock.json @@ -1,48 +1,77 @@ { "dependencies": { "com.unity.collab-proxy": { - "version": "1.2.16", + "version": "1.15.18", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.services.core": "1.0.1" + }, "url": "https://packages.unity.com" }, "com.unity.ext.nunit": { - "version": "1.0.5", + "version": "1.0.6", "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "1.1.4", + "version": "3.0.14", "depth": 0, "source": "registry", "dependencies": { - "com.unity.test-framework": "1.1.1" + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.15", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" }, "url": "https://packages.unity.com" }, "com.unity.ide.vscode": { - "version": "1.2.3", + "version": "1.2.5", "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.0.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.services.core": { + "version": "1.4.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.modules.androidjni": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.test-framework": { - "version": "1.1.19", + "version": "1.1.31", "depth": 0, "source": "registry", "dependencies": { - "com.unity.ext.nunit": "1.0.5", + "com.unity.ext.nunit": "1.0.6", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.com" }, "com.unity.textmeshpro": { - "version": "2.1.1", + "version": "3.0.6", "depth": 0, "source": "registry", "dependencies": { @@ -51,10 +80,15 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.2.17", + "version": "1.6.4", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, "url": "https://packages.unity.com" }, "com.unity.ugui": { @@ -199,6 +233,18 @@ "depth": 0, "source": "builtin", "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" } diff --git a/UnityProject/ProjectSettings/MemorySettings.asset b/UnityProject/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/UnityProject/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/UnityProject/ProjectSettings/PackageManagerSettings.asset b/UnityProject/ProjectSettings/PackageManagerSettings.asset index ca9e773..bd915d7 100644 --- a/UnityProject/ProjectSettings/PackageManagerSettings.asset +++ b/UnityProject/ProjectSettings/PackageManagerSettings.asset @@ -9,10 +9,14 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 13960, guid: 0000000000000000e000000000000000, type: 0} + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 oneTimeWarningShown: 0 m_Registries: - m_Id: main @@ -20,19 +24,12 @@ MonoBehaviour: m_Url: https://packages.unity.com m_Scopes: [] m_IsDefault: 1 + m_Capabilities: 7 m_UserSelectedRegistryName: m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: - m_ErrorMessage: - m_Original: - m_Id: - m_Name: - m_Url: - m_Scopes: [] - m_IsDefault: 0 m_Modified: 0 - m_Name: - m_Url: - m_Scopes: - - - m_SelectedScopeIndex: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -850 + m_OriginalInstanceId: -852 + m_LoadAssets: 0 diff --git a/UnityProject/ProjectSettings/ProjectSettings.asset b/UnityProject/ProjectSettings/ProjectSettings.asset index 86fa990..9bdcd70 100644 --- a/UnityProject/ProjectSettings/ProjectSettings.asset +++ b/UnityProject/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 20 + serializedVersion: 23 productGUID: 6a73dd68b09754c4f94f10516ae1a93a AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -49,6 +49,8 @@ PlayerSettings: m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 @@ -66,6 +68,12 @@ PlayerSettings: androidRenderOutsideSafeArea: 1 androidUseSwappy: 0 androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 @@ -117,7 +125,9 @@ PlayerSettings: stadiaTargetFramerate: 0 vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 m_SupportedAspectRatios: 4:3: 1 5:4: 1 @@ -132,45 +142,27 @@ PlayerSettings: xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 vrSettings: - cardboard: - depthFormat: 0 - enableTransitionView: 0 - daydream: - depthFormat: 0 - useSustainedPerformanceMode: 0 - enableVideoLayer: 0 - useProtectedVideoMemory: 0 - minimumSupportedHeadTracking: 0 - maximumSupportedHeadTracking: 1 - hololens: - depthFormat: 1 - depthBufferSharingEnabled: 1 - lumin: - depthFormat: 0 - frameTiming: 2 - enableGLCache: 0 - glCacheMaxBlobSize: 524288 - glCacheMaxFileSize: 8388608 - oculus: - sharedDepthBuffer: 1 - dashSupport: 1 - lowOverheadMode: 0 - protectedContext: 0 - v2Signing: 1 enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 useHDRDisplay: 0 D3DHDRBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 - applicationIdentifier: {} - buildNumber: {} + applicationIdentifier: + Standalone: com.DefaultCompany.UnityProject + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 19 + AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -185,10 +177,10 @@ PlayerSettings: StripUnusedMeshComponents: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 10.0 + iOSTargetOSVersionString: 11.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 10.0 + tvOSTargetOSVersionString: 11.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -222,10 +214,11 @@ PlayerSettings: iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 iOSLaunchScreeniPadCustomXibPath: - iOSUseLaunchScreenStoryboard: 0 iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] + macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 1 @@ -241,10 +234,19 @@ PlayerSettings: iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 + shaderPrecisionModel: 0 clonedFromGUID: 00000000000000000000000000000000 templatePackageId: templateDefaultScene: + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: @@ -261,6 +263,10 @@ PlayerSettings: height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 + chromeosInputEmulation: 1 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 m_BuildTargetIcons: [] @@ -268,7 +274,13 @@ PlayerSettings: m_BuildTargetBatching: [] m_BuildTargetGraphicsJobs: [] m_BuildTargetGraphicsJobMode: [] - m_BuildTargetGraphicsAPIs: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AndroidPlayer + m_APIs: 0b00000008000000 + m_Automatic: 0 m_BuildTargetVRSettings: [] openGLRequireES31: 0 openGLRequireES31AEP: 0 @@ -280,6 +292,8 @@ PlayerSettings: tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: [] m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 @@ -289,12 +303,16 @@ PlayerSettings: cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: + bluetoothUsageDescription: + switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: switchTitleNames_0: @@ -312,6 +330,7 @@ PlayerSettings: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: + switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: @@ -327,6 +346,7 @@ PlayerSettings: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -342,6 +362,7 @@ PlayerSettings: switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} @@ -357,6 +378,7 @@ PlayerSettings: switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: @@ -419,6 +441,11 @@ PlayerSettings: switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -489,6 +516,7 @@ PlayerSettings: ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] @@ -509,22 +537,28 @@ PlayerSettings: webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 0 + webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 - webGLWasmStreaming: 0 + webGLDecompressionFallback: 0 scriptingDefineSymbols: - 1: MIRROR;MIRROR_17_0_OR_NEWER;MIRROR_18_0_OR_NEWER;MIRROR_24_0_OR_NEWER;MIRROR_26_0_OR_NEWER;MIRROR_27_0_OR_NEWER;MIRROR_28_0_OR_NEWER;MIRROR_29_0_OR_NEWER;MIRROR_30_0_OR_NEWER;MIRROR_30_5_2_OR_NEWER;MIRROR_32_1_2_OR_NEWER;MIRROR_32_1_4_OR_NEWER;MIRROR_35_0_OR_NEWER;MIRROR_35_1_OR_NEWER;MIRROR_37_0_OR_NEWER;MIRROR_38_0_OR_NEWER;MIRROR_39_0_OR_NEWER;MIRROR_40_0_OR_NEWER;IGNORANCE;IGNORANCE_1;IGNORANCE_1_4 - 13: MIRROR;MIRROR_17_0_OR_NEWER;MIRROR_18_0_OR_NEWER;MIRROR_24_0_OR_NEWER;MIRROR_26_0_OR_NEWER;MIRROR_27_0_OR_NEWER;MIRROR_28_0_OR_NEWER;MIRROR_29_0_OR_NEWER;MIRROR_30_0_OR_NEWER;MIRROR_30_5_2_OR_NEWER;MIRROR_32_1_2_OR_NEWER;MIRROR_32_1_4_OR_NEWER;MIRROR_35_0_OR_NEWER;MIRROR_35_1_OR_NEWER + Standalone: MIRROR;MIRROR_17_0_OR_NEWER;MIRROR_18_0_OR_NEWER;MIRROR_24_0_OR_NEWER;MIRROR_26_0_OR_NEWER;MIRROR_27_0_OR_NEWER;MIRROR_28_0_OR_NEWER;MIRROR_29_0_OR_NEWER;MIRROR_30_0_OR_NEWER;MIRROR_30_5_2_OR_NEWER;MIRROR_32_1_2_OR_NEWER;MIRROR_32_1_4_OR_NEWER;MIRROR_35_0_OR_NEWER;MIRROR_35_1_OR_NEWER;MIRROR_37_0_OR_NEWER;MIRROR_38_0_OR_NEWER;MIRROR_39_0_OR_NEWER;MIRROR_40_0_OR_NEWER;FISHNET + WebGL: MIRROR;MIRROR_17_0_OR_NEWER;MIRROR_18_0_OR_NEWER;MIRROR_24_0_OR_NEWER;MIRROR_26_0_OR_NEWER;MIRROR_27_0_OR_NEWER;MIRROR_28_0_OR_NEWER;MIRROR_29_0_OR_NEWER;MIRROR_30_0_OR_NEWER;MIRROR_30_5_2_OR_NEWER;MIRROR_32_1_2_OR_NEWER;MIRROR_32_1_4_OR_NEWER;MIRROR_35_0_OR_NEWER;MIRROR_35_1_OR_NEWER + additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: Standalone: 0 il2cppCompilerConfiguration: {} managedStrippingLevel: {} incrementalIl2cppBuild: {} - allowUnsafeCode: 0 + suppressCommonWarnings: 1 + allowUnsafeCode: 1 + useDeterministicCompilation: 1 + enableRoslynAnalyzers: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 0 + assemblyVersionValidation: 1 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: Standalone: 3 @@ -558,6 +592,7 @@ PlayerSettings: metroFTAName: metroFTAFileTypes: [] metroProtocolName: + vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -585,10 +620,7 @@ PlayerSettings: XboxOneXTitleMemory: 8 XboxOneOverrideIdentityName: XboxOneOverrideIdentityPublisher: - vrEditorSettings: - daydream: - daydreamIconForeground: {fileID: 0} - daydreamIconBackground: {fileID: 0} + vrEditorSettings: {} cloudServicesEnabled: {} luminIcon: m_Name: @@ -602,11 +634,14 @@ PlayerSettings: m_VersionCode: 1 m_VersionName: apiCompatibilityLevel: 6 + activeInputHandler: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 - enableNativePlatformBackendsForNewInputSystem: 0 - disableOldInputManagerSupport: 0 legacyClampBlendShapeWeights: 0 + playerDataPath: + forceSRGBBlit: 1 + virtualTexturingSupportEnabled: 0 diff --git a/UnityProject/ProjectSettings/ProjectVersion.txt b/UnityProject/ProjectSettings/ProjectVersion.txt index 5767309..bdb3ba5 100644 --- a/UnityProject/ProjectSettings/ProjectVersion.txt +++ b/UnityProject/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2019.4.16f1 -m_EditorVersionWithRevision: 2019.4.16f1 (e05b6e02d63e) +m_EditorVersion: 2021.3.5f1 +m_EditorVersionWithRevision: 2021.3.5f1 (40eb3a945986) diff --git a/UnityProject/ProjectSettings/SceneTemplateSettings.json b/UnityProject/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..6f3e60f --- /dev/null +++ b/UnityProject/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,167 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "ignore": false, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/UnityProject/ProjectSettings/VersionControlSettings.asset b/UnityProject/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/UnityProject/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/UnityProject/ProjectSettings/boot.config b/UnityProject/ProjectSettings/boot.config new file mode 100644 index 0000000..e69de29

vH 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 literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallHorizontal.png.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png.meta similarity index 79% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallHorizontal.png.meta rename to UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png.meta index 67ceb63..2c02d75 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/WallHorizontal.png.meta +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/BaseColor.png.meta @@ -1,12 +1,12 @@ fileFormatVersion: 2 -guid: 51f6a08479c829a49b6a15df6849e727 +guid: f70f14d686c89c046b2ed6a106769305 TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 9 mipmaps: mipMapMode: 0 - enableMipMap: 0 + enableMipMap: 1 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -27,31 +27,31 @@ TextureImporter: generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: 0 - aniso: 16 + filterMode: -1 + aniso: -1 mipBias: -100 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 lightmap: 0 compressionQuality: 50 - spriteMode: 1 + spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 1 + spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 1 + alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 @@ -63,7 +63,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 @@ -75,14 +75,14 @@ TextureImporter: outline: [] physicsShape: [] bones: [] - spriteID: 74c5541eed52f67428025c83260d8bec + spriteID: '' vertices: [] - indices: + indices: '' edges: [] weights: [] - spritePackingTag: + spritePackingTag: '' pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller new file mode 100644 index 0000000..e05d28c --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller @@ -0,0 +1,272 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Controller + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: Moving + m_Type: 4 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + - m_Name: Shoot + m_Type: 9 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 0} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 1107772262116321704} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1101 &1101104249963802978 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Moving + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102824315819425342} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.6 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &1101366829127142966 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Shoot + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102254808008813326} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0 + m_TransitionOffset: 0 + m_ExitTime: 1 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &1101806660142692138 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 2 + m_ConditionEvent: Moving + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102207974245764242} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.6 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &1101862483397811748 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 2 + m_ConditionEvent: Moving + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102207974245764242} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1101 &1101947542735704306 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Moving + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1102824315819425342} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 +--- !u!1102 &1102207974245764242 +AnimatorState: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Idle + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1101947542735704306} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &1102254808008813326 +AnimatorState: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Shoot + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1101104249963802978} + - {fileID: 1101806660142692138} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400006, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1102 &1102824315819425342 +AnimatorState: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Moving + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1101862483397811748} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400004, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &1107772262116321704 +AnimatorStateMachine: + serializedVersion: 5 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 1102207974245764242} + m_Position: {x: 252, y: 48, z: 0} + - serializedVersion: 1 + m_State: {fileID: 1102824315819425342} + m_Position: {x: 252, y: 204, z: 0} + - serializedVersion: 1 + m_State: {fileID: 1102254808008813326} + m_Position: {x: 420, y: 120, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: + - {fileID: 1101366829127142966} + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 60, y: 132, z: 0} + m_EntryPosition: {x: 60, y: 168, z: 0} + m_ExitPosition: {x: 60, y: 96, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 1102207974245764242} diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller.meta new file mode 100644 index 0000000..94edacc --- /dev/null +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Controller.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c441a2f9b47848243b2e48ca1e6e413a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png new file mode 100644 index 0000000000000000000000000000000000000000..61ca0cbaf3c3a65d4f9e6903252d5505af499806 GIT binary patch literal 80294 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 O1W=Gs{a7Vs68wM81?4ON literal 0 HcmV?d00001 diff --git a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png.meta b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png.meta similarity index 79% rename from UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png.meta rename to UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png.meta index 72a3307..c87980f 100644 --- a/UnityProject/Assets/Ignorance/Demo/PongChamp/Textures/Sprites/Ball.png.meta +++ b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Emissive.png.meta @@ -1,12 +1,12 @@ fileFormatVersion: 2 -guid: 03167da12fa50334e8c8641a23df41b0 +guid: 0e5ac450496e9644b841ee624e02a8f7 TextureImporter: fileIDToRecycleName: {} externalObjects: {} serializedVersion: 9 mipmaps: mipMapMode: 0 - enableMipMap: 0 + enableMipMap: 1 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 @@ -27,31 +27,31 @@ TextureImporter: generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 - filterMode: 0 - aniso: 16 + filterMode: -1 + aniso: -1 mipBias: -100 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 lightmap: 0 compressionQuality: 50 - spriteMode: 1 + spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 1 + spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 1 + alphaIsTransparency: 0 spriteTessellationDetail: -1 - textureType: 8 + textureType: 0 textureShape: 1 singleChannelComponent: 0 maxTextureSizeSet: 0 @@ -63,7 +63,7 @@ TextureImporter: maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 - textureCompression: 0 + textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 @@ -75,14 +75,14 @@ TextureImporter: outline: [] physicsShape: [] bones: [] - spriteID: c5a291323e0d5f34883a55625f66ca70 + spriteID: '' vertices: [] - indices: + indices: '' edges: [] weights: [] - spritePackingTag: + spritePackingTag: '' pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Metallic.png b/UnityProject/Assets/Tanks/Models/(Public Domain) Recon_Tank/Metallic.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d5559fe82d85d11be1b75d41003ed1c74b05c7 GIT binary patch literal 62860 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Μyqb~6>QDL)D5~7m!QF` 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-arm64.a.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-arm64.a.meta deleted file mode 100644 index 1504880..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-arm64.a.meta +++ /dev/null @@ -1,80 +0,0 @@ -fileFormatVersion: 2 -guid: 1485de7d76884a64bac00df01454081e -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: ARM64 - CompileFlags: - FrameworkDependencies: - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a deleted file mode 100644 index d8b77ba428e0ec356f1b6427f21cf758ae40cc83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145208 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 z 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 diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a.meta b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a.meta deleted file mode 100644 index aa56177..0000000 --- a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-armv7.a.meta +++ /dev/null @@ -1,80 +0,0 @@ -fileFormatVersion: 2 -guid: fa239cb4c47fc9447816815f80667fea -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: ARMv7 - CompileFlags: - FrameworkDependencies: - userData: - assetBundleName: - assetBundleVariant: diff --git a/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a b/UnityProject/Assets/Mirror/Runtime/Transport/Ignorance/Plugins/iOS/libenet-release-simulator64.a deleted file mode 100644 index e6051c3a94211cce891da52a0cb1d35fc03b4a60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167208 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