From eea56cc68897b1b500da846b0c41098fda61d32a Mon Sep 17 00:00:00 2001 From: Anthony Berg Date: Sun, 6 Dec 2020 14:36:06 +0000 Subject: [PATCH] Finished Card Functionality --- Assets/Mirror.meta | 8 - Assets/Mirror/Authenticators.meta | 8 - .../Authenticators/BasicAuthenticator.cs | 161 -- .../Authenticators/BasicAuthenticator.cs.meta | 11 - .../Mirror.Authenticators.asmdef | 14 - .../Mirror.Authenticators.asmdef.meta | 7 - .../Authenticators/TimeoutAuthenticator.cs | 64 - .../TimeoutAuthenticator.cs.meta | 11 - Assets/Mirror/Cloud.meta | 8 - Assets/Mirror/Cloud/ApiConnector.cs | 61 - Assets/Mirror/Cloud/ApiConnector.cs.meta | 11 - Assets/Mirror/Cloud/Core.meta | 8 - Assets/Mirror/Cloud/Core/BaseApi.cs | 25 - Assets/Mirror/Cloud/Core/BaseApi.cs.meta | 11 - Assets/Mirror/Cloud/Core/Events.cs | 12 - Assets/Mirror/Cloud/Core/Events.cs.meta | 11 - Assets/Mirror/Cloud/Core/Extensions.cs | 12 - Assets/Mirror/Cloud/Core/Extensions.cs.meta | 11 - Assets/Mirror/Cloud/Core/ICoroutineRunner.cs | 12 - .../Cloud/Core/ICoroutineRunner.cs.meta | 11 - Assets/Mirror/Cloud/Core/IRequestCreator.cs | 42 - .../Mirror/Cloud/Core/IRequestCreator.cs.meta | 11 - Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs | 26 - .../Cloud/Core/IUnityEqualCheck.cs.meta | 11 - Assets/Mirror/Cloud/Core/JsonStructs.cs | 24 - Assets/Mirror/Cloud/Core/JsonStructs.cs.meta | 11 - Assets/Mirror/Cloud/Core/Logger.cs | 72 - Assets/Mirror/Cloud/Core/Logger.cs.meta | 11 - Assets/Mirror/Cloud/Core/RequestCreator.cs | 144 -- .../Mirror/Cloud/Core/RequestCreator.cs.meta | 11 - Assets/Mirror/Cloud/ListServer.meta | 8 - Assets/Mirror/Cloud/ListServer/ListServer.cs | 66 - .../Cloud/ListServer/ListServer.cs.meta | 11 - .../Cloud/ListServer/ListServerBaseApi.cs | 9 - .../ListServer/ListServerBaseApi.cs.meta | 11 - .../Cloud/ListServer/ListServerClientApi.cs | 70 - .../ListServer/ListServerClientApi.cs.meta | 11 - .../Mirror/Cloud/ListServer/ListServerJson.cs | 207 --- .../Cloud/ListServer/ListServerJson.cs.meta | 11 - .../Cloud/ListServer/ListServerServerApi.cs | 219 --- .../ListServer/ListServerServerApi.cs.meta | 11 - Assets/Mirror/Cloud/Mirror.Cloud.asmdef | 14 - Assets/Mirror/Cloud/Mirror.Cloud.asmdef.meta | 7 - Assets/Mirror/Cloud/README.md | 152 -- Assets/Mirror/Cloud/README.md.meta | 7 - Assets/Mirror/Cloud/version.txt | 1 - Assets/Mirror/Cloud/version.txt.meta | 7 - Assets/Mirror/CompilerSymbols.meta | 8 - .../Mirror.CompilerSymbols.asmdef | 14 - .../Mirror.CompilerSymbols.asmdef.meta | 7 - .../CompilerSymbols/PreprocessorDefine.cs | 49 - .../PreprocessorDefine.cs.meta | 11 - Assets/Mirror/Components.meta | 8 - Assets/Mirror/Components/Discovery.meta | 8 - .../Components/Discovery/NetworkDiscovery.cs | 114 -- .../Discovery/NetworkDiscovery.cs.meta | 11 - .../Discovery/NetworkDiscoveryBase.cs | 360 ---- .../Discovery/NetworkDiscoveryBase.cs.meta | 11 - .../Discovery/NetworkDiscoveryHUD.cs | 95 -- .../Discovery/NetworkDiscoveryHUD.cs.meta | 11 - .../Components/Discovery/ServerRequest.cs | 4 - .../Discovery/ServerRequest.cs.meta | 11 - .../Components/Discovery/ServerResponse.cs | 18 - .../Discovery/ServerResponse.cs.meta | 11 - Assets/Mirror/Components/Experimental.meta | 8 - .../Experimental/NetworkLerpRigidbody.cs | 93 - .../Experimental/NetworkLerpRigidbody.cs.meta | 11 - .../Experimental/NetworkRigidbody.cs | 363 ---- .../Experimental/NetworkRigidbody.cs.meta | 11 - .../Experimental/NetworkRigidbody2D.cs | 362 ---- .../Experimental/NetworkRigidbody2D.cs.meta | 11 - .../Experimental/NetworkTransform.cs | 12 - .../Experimental/NetworkTransform.cs.meta | 11 - .../Experimental/NetworkTransformBase.cs | 529 ------ .../Experimental/NetworkTransformBase.cs.meta | 11 - .../Experimental/NetworkTransformChild.cs | 18 - .../NetworkTransformChild.cs.meta | 11 - .../Components/Mirror.Components.asmdef | 14 - .../Components/Mirror.Components.asmdef.meta | 7 - Assets/Mirror/Components/NetworkAnimator.cs | 636 ------- .../Mirror/Components/NetworkAnimator.cs.meta | 11 - .../Mirror/Components/NetworkLobbyManager.cs | 18 - .../Components/NetworkLobbyManager.cs.meta | 11 - .../Mirror/Components/NetworkLobbyPlayer.cs | 15 - .../Components/NetworkLobbyPlayer.cs.meta | 11 - .../Mirror/Components/NetworkMatchChecker.cs | 132 -- .../Components/NetworkMatchChecker.cs.meta | 11 - .../Mirror/Components/NetworkPingDisplay.cs | 41 - .../Components/NetworkPingDisplay.cs.meta | 11 - .../Components/NetworkProximityChecker.cs | 98 -- .../NetworkProximityChecker.cs.meta | 11 - .../Mirror/Components/NetworkRoomManager.cs | 697 -------- .../Components/NetworkRoomManager.cs.meta | 11 - Assets/Mirror/Components/NetworkRoomPlayer.cs | 198 --- .../Components/NetworkRoomPlayer.cs.meta | 11 - .../Mirror/Components/NetworkSceneChecker.cs | 115 -- .../Components/NetworkSceneChecker.cs.meta | 11 - Assets/Mirror/Components/NetworkTransform.cs | 12 - .../Components/NetworkTransform.cs.meta | 11 - .../Mirror/Components/NetworkTransformBase.cs | 508 ------ .../Components/NetworkTransformBase.cs.meta | 11 - .../Components/NetworkTransformChild.cs | 18 - .../Components/NetworkTransformChild.cs.meta | 11 - Assets/Mirror/Editor.meta | 8 - .../Editor/EnterPlayModeSettingsCheck.cs | 74 - .../Editor/EnterPlayModeSettingsCheck.cs.meta | 11 - Assets/Mirror/Editor/InspectorHelper.cs | 76 - Assets/Mirror/Editor/InspectorHelper.cs.meta | 11 - Assets/Mirror/Editor/LogLevelWindow.cs | 1 - Assets/Mirror/Editor/LogLevelWindow.cs.meta | 11 - Assets/Mirror/Editor/Logging.meta | 8 - .../Mirror/Editor/Logging/LogLevelWindow.cs | 70 - .../Editor/Logging/LogLevelWindow.cs.meta | 11 - Assets/Mirror/Editor/Logging/LogLevelsGUI.cs | 61 - .../Editor/Logging/LogLevelsGUI.cs.meta | 11 - .../Editor/Logging/LogSettingsEditor.cs | 24 - .../Editor/Logging/LogSettingsEditor.cs.meta | 11 - .../Logging/NetworkLogSettingsEditor.cs | 31 - .../Logging/NetworkLogSettingsEditor.cs.meta | 11 - Assets/Mirror/Editor/Mirror.Editor.asmdef | 17 - .../Mirror/Editor/Mirror.Editor.asmdef.meta | 7 - .../Editor/NetworkBehaviourInspector.cs | 186 -- .../Editor/NetworkBehaviourInspector.cs.meta | 11 - .../Editor/NetworkInformationPreview.cs | 305 ---- .../Editor/NetworkInformationPreview.cs.meta | 11 - Assets/Mirror/Editor/NetworkManagerEditor.cs | 113 -- .../Editor/NetworkManagerEditor.cs.meta | 11 - .../Mirror/Editor/NetworkScenePostProcess.cs | 92 - .../Editor/NetworkScenePostProcess.cs.meta | 11 - Assets/Mirror/Editor/SceneDrawer.cs | 47 - Assets/Mirror/Editor/SceneDrawer.cs.meta | 11 - .../Mirror/Editor/ScriptableObjectUtility.cs | 54 - .../Editor/ScriptableObjectUtility.cs.meta | 11 - .../Mirror/Editor/SyncVarAttributeDrawer.cs | 28 - .../Editor/SyncVarAttributeDrawer.cs.meta | 11 - Assets/Mirror/Editor/Weaver.meta | 8 - Assets/Mirror/Editor/Weaver/AssemblyInfo.cs | 3 - .../Mirror/Editor/Weaver/AssemblyInfo.cs.meta | 11 - .../Editor/Weaver/CompilationFinishedHook.cs | 175 -- .../Weaver/CompilationFinishedHook.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Extensions.cs | 266 --- .../Mirror/Editor/Weaver/Extensions.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Helpers.cs | 25 - Assets/Mirror/Editor/Weaver/Helpers.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Log.cs | 20 - Assets/Mirror/Editor/Weaver/Log.cs.meta | 11 - .../Mirror/Editor/Weaver/Mirror.Weaver.asmdef | 16 - .../Editor/Weaver/Mirror.Weaver.asmdef.meta | 7 - Assets/Mirror/Editor/Weaver/Processors.meta | 8 - .../Weaver/Processors/CommandProcessor.cs | 127 -- .../Processors/CommandProcessor.cs.meta | 11 - .../Processors/GenericArgumentResolver.cs | 1 - .../GenericArgumentResolver.cs.meta | 11 - .../Processors/MessageClassProcessor.cs | 1 - .../Processors/MessageClassProcessor.cs.meta | 11 - .../Weaver/Processors/MethodProcessor.cs | 125 -- .../Weaver/Processors/MethodProcessor.cs.meta | 11 - .../Processors/MonoBehaviourProcessor.cs | 45 - .../Processors/MonoBehaviourProcessor.cs.meta | 11 - .../Processors/NetworkBehaviourProcessor.cs | 1099 ------------ .../NetworkBehaviourProcessor.cs.meta | 11 - .../Processors/PropertySiteProcessor.cs | 160 -- .../Processors/PropertySiteProcessor.cs.meta | 11 - .../Processors/ReaderWriterProcessor.cs | 175 -- .../Processors/ReaderWriterProcessor.cs.meta | 11 - .../Editor/Weaver/Processors/RpcProcessor.cs | 105 -- .../Weaver/Processors/RpcProcessor.cs.meta | 11 - .../ServerClientAttributeProcessor.cs | 153 -- .../ServerClientAttributeProcessor.cs.meta | 11 - .../Processors/SyncDictionaryProcessor.cs | 1 - .../SyncDictionaryProcessor.cs.meta | 11 - .../Weaver/Processors/SyncEventProcessor.cs | 1 - .../Processors/SyncEventProcessor.cs.meta | 11 - .../Weaver/Processors/SyncListProcessor.cs | 1 - .../Processors/SyncListProcessor.cs.meta | 11 - .../Processors/SyncObjectInitializer.cs | 47 - .../Processors/SyncObjectInitializer.cs.meta | 11 - .../Weaver/Processors/SyncObjectProcessor.cs | 63 - .../Processors/SyncObjectProcessor.cs.meta | 11 - .../Weaver/Processors/SyncVarProcessor.cs | 434 ----- .../Processors/SyncVarProcessor.cs.meta | 11 - .../Weaver/Processors/TargetRpcProcessor.cs | 134 -- .../Processors/TargetRpcProcessor.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Program.cs | 1 - Assets/Mirror/Editor/Weaver/Program.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Readers.cs | 325 ---- Assets/Mirror/Editor/Weaver/Readers.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Resolvers.cs | 86 - Assets/Mirror/Editor/Weaver/Resolvers.cs.meta | 11 - Assets/Mirror/Editor/Weaver/Weaver.cs | 232 --- Assets/Mirror/Editor/Weaver/Weaver.cs.meta | 11 - .../Mirror/Editor/Weaver/WeaverExceptions.cs | 25 - .../Editor/Weaver/WeaverExceptions.cs.meta | 11 - Assets/Mirror/Editor/Weaver/WeaverTypes.cs | 132 -- .../Mirror/Editor/Weaver/WeaverTypes.cs.meta | 3 - Assets/Mirror/Editor/Weaver/Writers.cs | 309 ---- Assets/Mirror/Editor/Weaver/Writers.cs.meta | 11 - Assets/Mirror/Icon.meta | 8 - Assets/Mirror/Icon/MirrorIcon.png | 3 - Assets/Mirror/Icon/MirrorIcon.png.meta | 110 -- Assets/Mirror/Notice.txt | 123 -- Assets/Mirror/Notice.txt.meta | 7 - Assets/Mirror/Plugins.meta | 8 - Assets/Mirror/Plugins/Mono.Cecil.meta | 8 - Assets/Mirror/Plugins/Mono.Cecil/License.txt | 23 - .../Plugins/Mono.Cecil/License.txt.meta | 7 - .../Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll | 3 - .../Mono.Cecil/Mono.CecilX.Mdb.dll.meta | 92 - .../Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll | 3 - .../Mono.Cecil/Mono.CecilX.Pdb.dll.meta | 92 - .../Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll | 3 - .../Mono.Cecil/Mono.CecilX.Rocks.dll.meta | 92 - .../Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll | 3 - .../Plugins/Mono.Cecil/Mono.CecilX.dll.meta | 94 - Assets/Mirror/Readme.txt | 15 - Assets/Mirror/Readme.txt.meta | 7 - Assets/Mirror/Runtime.meta | 8 - Assets/Mirror/Runtime/AssemblyInfo.cs | 9 - Assets/Mirror/Runtime/AssemblyInfo.cs.meta | 11 - Assets/Mirror/Runtime/ClientScene.cs | 1047 ------------ Assets/Mirror/Runtime/ClientScene.cs.meta | 11 - Assets/Mirror/Runtime/Compression.cs | 225 --- Assets/Mirror/Runtime/Compression.cs.meta | 11 - Assets/Mirror/Runtime/CustomAttributes.cs | 88 - .../Mirror/Runtime/CustomAttributes.cs.meta | 11 - Assets/Mirror/Runtime/DotNetCompatibility.cs | 16 - .../Runtime/DotNetCompatibility.cs.meta | 11 - .../Runtime/ExponentialMovingAverage.cs | 38 - .../Runtime/ExponentialMovingAverage.cs.meta | 11 - Assets/Mirror/Runtime/FloatBytePacker.cs | 2 - Assets/Mirror/Runtime/FloatBytePacker.cs.meta | 11 - Assets/Mirror/Runtime/LocalConnections.cs | 141 -- .../Mirror/Runtime/LocalConnections.cs.meta | 11 - Assets/Mirror/Runtime/LogFactory.cs | 1 - Assets/Mirror/Runtime/LogFactory.cs.meta | 11 - Assets/Mirror/Runtime/LogFilter.cs | 7 - Assets/Mirror/Runtime/LogFilter.cs.meta | 11 - Assets/Mirror/Runtime/Logging.meta | 8 - .../Runtime/Logging/ConsoleColorLogHandler.cs | 44 - .../Logging/ConsoleColorLogHandler.cs.meta | 11 - .../Logging/EditorLogSettingsLoader.cs | 50 - .../Logging/EditorLogSettingsLoader.cs.meta | 11 - Assets/Mirror/Runtime/Logging/LogFactory.cs | 100 -- .../Mirror/Runtime/Logging/LogFactory.cs.meta | 11 - Assets/Mirror/Runtime/Logging/LogSettings.cs | 67 - .../Runtime/Logging/LogSettings.cs.meta | 11 - .../Runtime/Logging/NetworkHeadlessLogger.cs | 24 - .../Logging/NetworkHeadlessLogger.cs.meta | 11 - .../Runtime/Logging/NetworkLogSettings.cs | 46 - .../Logging/NetworkLogSettings.cs.meta | 11 - Assets/Mirror/Runtime/MessagePacker.cs | 131 -- Assets/Mirror/Runtime/MessagePacker.cs.meta | 11 - Assets/Mirror/Runtime/Messages.cs | 161 -- Assets/Mirror/Runtime/Messages.cs.meta | 11 - Assets/Mirror/Runtime/Mirror.asmdef | 16 - Assets/Mirror/Runtime/Mirror.asmdef.meta | 7 - Assets/Mirror/Runtime/NetworkAuthenticator.cs | 101 -- .../Runtime/NetworkAuthenticator.cs.meta | 11 - Assets/Mirror/Runtime/NetworkBehaviour.cs | 682 -------- .../Mirror/Runtime/NetworkBehaviour.cs.meta | 11 - Assets/Mirror/Runtime/NetworkClient.cs | 384 ----- Assets/Mirror/Runtime/NetworkClient.cs.meta | 11 - Assets/Mirror/Runtime/NetworkConnection.cs | 301 ---- .../Mirror/Runtime/NetworkConnection.cs.meta | 11 - .../Runtime/NetworkConnectionToClient.cs | 37 - .../Runtime/NetworkConnectionToClient.cs.meta | 11 - .../Runtime/NetworkConnectionToServer.cs | 35 - .../Runtime/NetworkConnectionToServer.cs.meta | 11 - Assets/Mirror/Runtime/NetworkDiagnostics.cs | 80 - .../Mirror/Runtime/NetworkDiagnostics.cs.meta | 11 - Assets/Mirror/Runtime/NetworkIdentity.cs | 1518 ----------------- Assets/Mirror/Runtime/NetworkIdentity.cs.meta | 11 - Assets/Mirror/Runtime/NetworkManager.cs | 1463 ---------------- Assets/Mirror/Runtime/NetworkManager.cs.meta | 11 - Assets/Mirror/Runtime/NetworkManagerHUD.cs | 158 -- .../Mirror/Runtime/NetworkManagerHUD.cs.meta | 11 - Assets/Mirror/Runtime/NetworkMessage.cs | 1 - Assets/Mirror/Runtime/NetworkMessage.cs.meta | 11 - Assets/Mirror/Runtime/NetworkReader.cs | 426 ----- Assets/Mirror/Runtime/NetworkReader.cs.meta | 11 - Assets/Mirror/Runtime/NetworkReaderPool.cs | 135 -- .../Mirror/Runtime/NetworkReaderPool.cs.meta | 11 - Assets/Mirror/Runtime/NetworkServer.cs | 1306 -------------- Assets/Mirror/Runtime/NetworkServer.cs.meta | 11 - Assets/Mirror/Runtime/NetworkStartPosition.cs | 24 - .../Runtime/NetworkStartPosition.cs.meta | 11 - Assets/Mirror/Runtime/NetworkTime.cs | 168 -- Assets/Mirror/Runtime/NetworkTime.cs.meta | 11 - Assets/Mirror/Runtime/NetworkVisibility.cs | 42 - .../Mirror/Runtime/NetworkVisibility.cs.meta | 11 - Assets/Mirror/Runtime/NetworkWriter.cs | 596 ------- Assets/Mirror/Runtime/NetworkWriter.cs.meta | 11 - Assets/Mirror/Runtime/NetworkWriterPool.cs | 98 -- .../Mirror/Runtime/NetworkWriterPool.cs.meta | 11 - Assets/Mirror/Runtime/RemoteCallHelper.cs | 188 -- .../Mirror/Runtime/RemoteCallHelper.cs.meta | 11 - Assets/Mirror/Runtime/StringHash.cs | 18 - Assets/Mirror/Runtime/StringHash.cs.meta | 11 - Assets/Mirror/Runtime/SyncDictionary.cs | 311 ---- Assets/Mirror/Runtime/SyncDictionary.cs.meta | 11 - Assets/Mirror/Runtime/SyncList.cs | 431 ----- Assets/Mirror/Runtime/SyncList.cs.meta | 11 - Assets/Mirror/Runtime/SyncObject.cs | 49 - Assets/Mirror/Runtime/SyncObject.cs.meta | 11 - Assets/Mirror/Runtime/SyncSet.cs | 340 ---- Assets/Mirror/Runtime/SyncSet.cs.meta | 11 - Assets/Mirror/Runtime/Transport.meta | 8 - .../Runtime/Transport/FallbackTransport.cs | 189 -- .../Transport/FallbackTransport.cs.meta | 11 - Assets/Mirror/Runtime/Transport/KCP.meta | 8 - .../Transport/KCP/MirrorTransport.meta | 8 - .../KCP/MirrorTransport/KcpTransport.cs | 172 -- .../KCP/MirrorTransport/KcpTransport.cs.meta | 11 - .../Mirror/Runtime/Transport/KCP/kcp2k.meta | 8 - .../Runtime/Transport/KCP/kcp2k/LICENSE | 24 - .../Runtime/Transport/KCP/kcp2k/LICENSE.meta | 7 - .../Runtime/Transport/KCP/kcp2k/VERSION | 9 - .../Runtime/Transport/KCP/kcp2k/VERSION.meta | 7 - .../Transport/KCP/kcp2k/highlevel.meta | 8 - .../KCP/kcp2k/highlevel/KcpClient.cs | 95 -- .../KCP/kcp2k/highlevel/KcpClient.cs.meta | 3 - .../kcp2k/highlevel/KcpClientConnection.cs | 59 - .../highlevel/KcpClientConnection.cs.meta | 3 - .../KCP/kcp2k/highlevel/KcpConnection.cs | 366 ---- .../KCP/kcp2k/highlevel/KcpConnection.cs.meta | 3 - .../KCP/kcp2k/highlevel/KcpServer.cs | 229 --- .../KCP/kcp2k/highlevel/KcpServer.cs.meta | 3 - .../kcp2k/highlevel/KcpServerConnection.cs | 20 - .../highlevel/KcpServerConnection.cs.meta | 3 - .../Transport/KCP/kcp2k/highlevel/Utils.cs | 23 - .../KCP/kcp2k/highlevel/Utils.cs.meta | 3 - .../Runtime/Transport/KCP/kcp2k/kcp.meta | 8 - .../Transport/KCP/kcp2k/kcp/AssemblyInfo.cs | 3 - .../KCP/kcp2k/kcp/AssemblyInfo.cs.meta | 3 - .../Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs | 1025 ----------- .../Transport/KCP/kcp2k/kcp/Kcp.cs.meta | 11 - .../Transport/KCP/kcp2k/kcp/Segment.cs | 81 - .../Transport/KCP/kcp2k/kcp/Segment.cs.meta | 11 - .../Runtime/Transport/KCP/kcp2k/kcp/Utils.cs | 68 - .../Transport/KCP/kcp2k/kcp/Utils.cs.meta | 11 - .../Runtime/Transport/KCP/kcp2k/kcp2k.asmdef | 12 - .../Transport/KCP/kcp2k/kcp2k.asmdef.meta | 7 - .../Runtime/Transport/LLAPITransport.cs | 384 ----- .../Runtime/Transport/LLAPITransport.cs.meta | 11 - .../Runtime/Transport/MiddlewareTransport.cs | 36 - .../Transport/MiddlewareTransport.cs.meta | 11 - .../Runtime/Transport/MultiplexTransport.cs | 278 --- .../Transport/MultiplexTransport.cs.meta | 11 - .../Runtime/Transport/SimpleWebTransport.meta | 8 - .../SimpleWebTransport/AssemblyInfo.cs | 4 - .../SimpleWebTransport/AssemblyInfo.cs.meta | 11 - .../Transport/SimpleWebTransport/Client.meta | 8 - .../Client/SimpleWebClient.cs | 86 - .../Client/SimpleWebClient.cs.meta | 11 - .../SimpleWebTransport/Client/StandAlone.meta | 8 - .../Client/StandAlone/ClientHandshake.cs | 77 - .../Client/StandAlone/ClientHandshake.cs.meta | 11 - .../Client/StandAlone/ClientSslHelper.cs | 47 - .../Client/StandAlone/ClientSslHelper.cs.meta | 11 - .../StandAlone/WebSocketClientStandAlone.cs | 139 -- .../WebSocketClientStandAlone.cs.meta | 11 - .../SimpleWebTransport/Client/Webgl.meta | 8 - .../Client/Webgl/SimpleWebJSLib.cs | 34 - .../Client/Webgl/SimpleWebJSLib.cs.meta | 11 - .../Client/Webgl/WebSocketClientWebGl.cs | 99 -- .../Client/Webgl/WebSocketClientWebGl.cs.meta | 11 - .../Client/Webgl/plugin.meta | 8 - .../Client/Webgl/plugin/SimpleWeb.jslib | 105 -- .../Client/Webgl/plugin/SimpleWeb.jslib.meta | 37 - .../Transport/SimpleWebTransport/Common.meta | 8 - .../SimpleWebTransport/Common/BufferPool.cs | 265 --- .../Common/BufferPool.cs.meta | 11 - .../SimpleWebTransport/Common/Connection.cs | 90 - .../Common/Connection.cs.meta | 11 - .../SimpleWebTransport/Common/Constants.cs | 72 - .../Common/Constants.cs.meta | 11 - .../SimpleWebTransport/Common/EventType.cs | 10 - .../Common/EventType.cs.meta | 11 - .../SimpleWebTransport/Common/Log.cs | 116 -- .../SimpleWebTransport/Common/Log.cs.meta | 11 - .../SimpleWebTransport/Common/Message.cs | 49 - .../SimpleWebTransport/Common/Message.cs.meta | 11 - .../Common/MessageProcessor.cs | 140 -- .../Common/MessageProcessor.cs.meta | 11 - .../SimpleWebTransport/Common/ReadHelper.cs | 132 -- .../Common/ReadHelper.cs.meta | 11 - .../SimpleWebTransport/Common/ReceiveLoop.cs | 195 --- .../Common/ReceiveLoop.cs.meta | 11 - .../SimpleWebTransport/Common/SendLoop.cs | 163 -- .../Common/SendLoop.cs.meta | 11 - .../SimpleWebTransport/Common/TcpConfig.cs | 25 - .../Common/TcpConfig.cs.meta | 11 - .../SimpleWebTransport/Common/Utils.cs | 13 - .../SimpleWebTransport/Common/Utils.cs.meta | 11 - .../Transport/SimpleWebTransport/README.txt | 22 - .../SimpleWebTransport/README.txt.meta | 7 - .../Transport/SimpleWebTransport/Server.meta | 8 - .../Server/ServerHandshake.cs | 149 -- .../Server/ServerHandshake.cs.meta | 11 - .../Server/ServerSslHelper.cs | 74 - .../Server/ServerSslHelper.cs.meta | 11 - .../Server/SimpleWebServer.cs | 105 -- .../Server/SimpleWebServer.cs.meta | 11 - .../Server/WebSocketServer.cs | 230 --- .../Server/WebSocketServer.cs.meta | 11 - .../SimpleWebTransport.asmdef | 14 - .../SimpleWebTransport.asmdef.meta | 7 - .../SimpleWebTransport/SimpleWebTransport.cs | 280 --- .../SimpleWebTransport.cs.meta | 11 - .../SimpleWebTransport/SslConfigLoader.cs | 49 - .../SslConfigLoader.cs.meta | 11 - .../Mirror/Runtime/Transport/Telepathy.meta | 8 - .../Runtime/Transport/Telepathy/Client.cs | 213 --- .../Transport/Telepathy/Client.cs.meta | 11 - .../Runtime/Transport/Telepathy/Common.cs | 296 ---- .../Transport/Telepathy/Common.cs.meta | 11 - .../Runtime/Transport/Telepathy/EventType.cs | 9 - .../Transport/Telepathy/EventType.cs.meta | 11 - .../Runtime/Transport/Telepathy/LICENSE | 21 - .../Runtime/Transport/Telepathy/LICENSE.meta | 7 - .../Runtime/Transport/Telepathy/Logger.cs | 15 - .../Transport/Telepathy/Logger.cs.meta | 11 - .../Runtime/Transport/Telepathy/Message.cs | 18 - .../Transport/Telepathy/Message.cs.meta | 11 - .../Telepathy/NetworkStreamExtensions.cs | 59 - .../Telepathy/NetworkStreamExtensions.cs.meta | 11 - .../Runtime/Transport/Telepathy/SafeQueue.cs | 75 - .../Transport/Telepathy/SafeQueue.cs.meta | 11 - .../Runtime/Transport/Telepathy/Server.cs | 298 ---- .../Transport/Telepathy/Server.cs.meta | 11 - .../Transport/Telepathy/Telepathy.asmdef | 12 - .../Transport/Telepathy/Telepathy.asmdef.meta | 7 - .../Transport/Telepathy/ThreadExtensions.cs | 26 - .../Telepathy/ThreadExtensions.cs.meta | 11 - .../Runtime/Transport/Telepathy/Utils.cs | 44 - .../Runtime/Transport/Telepathy/Utils.cs.meta | 11 - .../Runtime/Transport/TelepathyTransport.cs | 261 --- .../Transport/TelepathyTransport.cs.meta | 11 - Assets/Mirror/Runtime/Transport/Transport.cs | 219 --- .../Runtime/Transport/Transport.cs.meta | 11 - Assets/Mirror/Runtime/UNetwork.cs | 69 - Assets/Mirror/Runtime/UNetwork.cs.meta | 11 - Assets/Mirror/Version.txt | 1 - Assets/Mirror/Version.txt.meta | 7 - Assets/Scenes/menu.unity | 105 -- Assets/Scripts/monopoly/AI.cs | 29 + Assets/Scripts/monopoly/Main.cs | 122 +- Assets/Scripts/monopoly/Movement.cs | 1 - Assets/Scripts/monopoly/RollDice.cs | 2 +- 449 files changed, 135 insertions(+), 33133 deletions(-) delete mode 100644 Assets/Mirror.meta delete mode 100644 Assets/Mirror/Authenticators.meta delete mode 100644 Assets/Mirror/Authenticators/BasicAuthenticator.cs delete mode 100644 Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta delete mode 100644 Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef delete mode 100644 Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta delete mode 100644 Assets/Mirror/Authenticators/TimeoutAuthenticator.cs delete mode 100644 Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta delete mode 100644 Assets/Mirror/Cloud.meta delete mode 100644 Assets/Mirror/Cloud/ApiConnector.cs delete mode 100644 Assets/Mirror/Cloud/ApiConnector.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core.meta delete mode 100644 Assets/Mirror/Cloud/Core/BaseApi.cs delete mode 100644 Assets/Mirror/Cloud/Core/BaseApi.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/Events.cs delete mode 100644 Assets/Mirror/Cloud/Core/Events.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/Extensions.cs delete mode 100644 Assets/Mirror/Cloud/Core/Extensions.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/ICoroutineRunner.cs delete mode 100644 Assets/Mirror/Cloud/Core/ICoroutineRunner.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/IRequestCreator.cs delete mode 100644 Assets/Mirror/Cloud/Core/IRequestCreator.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs delete mode 100644 Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/JsonStructs.cs delete mode 100644 Assets/Mirror/Cloud/Core/JsonStructs.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/Logger.cs delete mode 100644 Assets/Mirror/Cloud/Core/Logger.cs.meta delete mode 100644 Assets/Mirror/Cloud/Core/RequestCreator.cs delete mode 100644 Assets/Mirror/Cloud/Core/RequestCreator.cs.meta delete mode 100644 Assets/Mirror/Cloud/ListServer.meta delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServer.cs delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServer.cs.meta delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs.meta delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs.meta delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerJson.cs delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerJson.cs.meta delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs delete mode 100644 Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs.meta delete mode 100644 Assets/Mirror/Cloud/Mirror.Cloud.asmdef delete mode 100644 Assets/Mirror/Cloud/Mirror.Cloud.asmdef.meta delete mode 100644 Assets/Mirror/Cloud/README.md delete mode 100644 Assets/Mirror/Cloud/README.md.meta delete mode 100644 Assets/Mirror/Cloud/version.txt delete mode 100644 Assets/Mirror/Cloud/version.txt.meta delete mode 100644 Assets/Mirror/CompilerSymbols.meta delete mode 100644 Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef delete mode 100644 Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta delete mode 100644 Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs delete mode 100644 Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta delete mode 100644 Assets/Mirror/Components.meta delete mode 100644 Assets/Mirror/Components/Discovery.meta delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscovery.cs delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs delete mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta delete mode 100644 Assets/Mirror/Components/Discovery/ServerRequest.cs delete mode 100644 Assets/Mirror/Components/Discovery/ServerRequest.cs.meta delete mode 100644 Assets/Mirror/Components/Discovery/ServerResponse.cs delete mode 100644 Assets/Mirror/Components/Discovery/ServerResponse.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkRigidbody.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransform.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransformBase.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransformChild.cs delete mode 100644 Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta delete mode 100644 Assets/Mirror/Components/Mirror.Components.asmdef delete mode 100644 Assets/Mirror/Components/Mirror.Components.asmdef.meta delete mode 100644 Assets/Mirror/Components/NetworkAnimator.cs delete mode 100644 Assets/Mirror/Components/NetworkAnimator.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkLobbyManager.cs delete mode 100644 Assets/Mirror/Components/NetworkLobbyManager.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkLobbyPlayer.cs delete mode 100644 Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkMatchChecker.cs delete mode 100644 Assets/Mirror/Components/NetworkMatchChecker.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkPingDisplay.cs delete mode 100644 Assets/Mirror/Components/NetworkPingDisplay.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkProximityChecker.cs delete mode 100644 Assets/Mirror/Components/NetworkProximityChecker.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkRoomManager.cs delete mode 100644 Assets/Mirror/Components/NetworkRoomManager.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkRoomPlayer.cs delete mode 100644 Assets/Mirror/Components/NetworkRoomPlayer.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkSceneChecker.cs delete mode 100644 Assets/Mirror/Components/NetworkSceneChecker.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkTransform.cs delete mode 100644 Assets/Mirror/Components/NetworkTransform.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkTransformBase.cs delete mode 100644 Assets/Mirror/Components/NetworkTransformBase.cs.meta delete mode 100644 Assets/Mirror/Components/NetworkTransformChild.cs delete mode 100644 Assets/Mirror/Components/NetworkTransformChild.cs.meta delete mode 100644 Assets/Mirror/Editor.meta delete mode 100644 Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs delete mode 100644 Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta delete mode 100644 Assets/Mirror/Editor/InspectorHelper.cs delete mode 100644 Assets/Mirror/Editor/InspectorHelper.cs.meta delete mode 100644 Assets/Mirror/Editor/LogLevelWindow.cs delete mode 100644 Assets/Mirror/Editor/LogLevelWindow.cs.meta delete mode 100644 Assets/Mirror/Editor/Logging.meta delete mode 100644 Assets/Mirror/Editor/Logging/LogLevelWindow.cs delete mode 100644 Assets/Mirror/Editor/Logging/LogLevelWindow.cs.meta delete mode 100644 Assets/Mirror/Editor/Logging/LogLevelsGUI.cs delete mode 100644 Assets/Mirror/Editor/Logging/LogLevelsGUI.cs.meta delete mode 100644 Assets/Mirror/Editor/Logging/LogSettingsEditor.cs delete mode 100644 Assets/Mirror/Editor/Logging/LogSettingsEditor.cs.meta delete mode 100644 Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs delete mode 100644 Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs.meta delete mode 100644 Assets/Mirror/Editor/Mirror.Editor.asmdef delete mode 100644 Assets/Mirror/Editor/Mirror.Editor.asmdef.meta delete mode 100644 Assets/Mirror/Editor/NetworkBehaviourInspector.cs delete mode 100644 Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta delete mode 100644 Assets/Mirror/Editor/NetworkInformationPreview.cs delete mode 100644 Assets/Mirror/Editor/NetworkInformationPreview.cs.meta delete mode 100644 Assets/Mirror/Editor/NetworkManagerEditor.cs delete mode 100644 Assets/Mirror/Editor/NetworkManagerEditor.cs.meta delete mode 100644 Assets/Mirror/Editor/NetworkScenePostProcess.cs delete mode 100644 Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta delete mode 100644 Assets/Mirror/Editor/SceneDrawer.cs delete mode 100644 Assets/Mirror/Editor/SceneDrawer.cs.meta delete mode 100644 Assets/Mirror/Editor/ScriptableObjectUtility.cs delete mode 100644 Assets/Mirror/Editor/ScriptableObjectUtility.cs.meta delete mode 100644 Assets/Mirror/Editor/SyncVarAttributeDrawer.cs delete mode 100644 Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver.meta delete mode 100644 Assets/Mirror/Editor/Weaver/AssemblyInfo.cs delete mode 100644 Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs delete mode 100644 Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Extensions.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Extensions.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Helpers.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Helpers.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Log.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Log.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef delete mode 100644 Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Program.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Program.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Readers.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Readers.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Resolvers.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Resolvers.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Weaver.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Weaver.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/WeaverExceptions.cs delete mode 100644 Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/WeaverTypes.cs delete mode 100644 Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta delete mode 100644 Assets/Mirror/Editor/Weaver/Writers.cs delete mode 100644 Assets/Mirror/Editor/Weaver/Writers.cs.meta delete mode 100644 Assets/Mirror/Icon.meta delete mode 100644 Assets/Mirror/Icon/MirrorIcon.png delete mode 100644 Assets/Mirror/Icon/MirrorIcon.png.meta delete mode 100644 Assets/Mirror/Notice.txt delete mode 100644 Assets/Mirror/Notice.txt.meta delete mode 100644 Assets/Mirror/Plugins.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/License.txt delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/License.txt.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll.meta delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll delete mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll.meta delete mode 100644 Assets/Mirror/Readme.txt delete mode 100644 Assets/Mirror/Readme.txt.meta delete mode 100644 Assets/Mirror/Runtime.meta delete mode 100644 Assets/Mirror/Runtime/AssemblyInfo.cs delete mode 100644 Assets/Mirror/Runtime/AssemblyInfo.cs.meta delete mode 100644 Assets/Mirror/Runtime/ClientScene.cs delete mode 100644 Assets/Mirror/Runtime/ClientScene.cs.meta delete mode 100644 Assets/Mirror/Runtime/Compression.cs delete mode 100644 Assets/Mirror/Runtime/Compression.cs.meta delete mode 100644 Assets/Mirror/Runtime/CustomAttributes.cs delete mode 100644 Assets/Mirror/Runtime/CustomAttributes.cs.meta delete mode 100644 Assets/Mirror/Runtime/DotNetCompatibility.cs delete mode 100644 Assets/Mirror/Runtime/DotNetCompatibility.cs.meta delete mode 100644 Assets/Mirror/Runtime/ExponentialMovingAverage.cs delete mode 100644 Assets/Mirror/Runtime/ExponentialMovingAverage.cs.meta delete mode 100644 Assets/Mirror/Runtime/FloatBytePacker.cs delete mode 100644 Assets/Mirror/Runtime/FloatBytePacker.cs.meta delete mode 100644 Assets/Mirror/Runtime/LocalConnections.cs delete mode 100644 Assets/Mirror/Runtime/LocalConnections.cs.meta delete mode 100644 Assets/Mirror/Runtime/LogFactory.cs delete mode 100644 Assets/Mirror/Runtime/LogFactory.cs.meta delete mode 100644 Assets/Mirror/Runtime/LogFilter.cs delete mode 100644 Assets/Mirror/Runtime/LogFilter.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging.meta delete mode 100644 Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs delete mode 100644 Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs delete mode 100644 Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging/LogFactory.cs delete mode 100644 Assets/Mirror/Runtime/Logging/LogFactory.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging/LogSettings.cs delete mode 100644 Assets/Mirror/Runtime/Logging/LogSettings.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs delete mode 100644 Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs.meta delete mode 100644 Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs delete mode 100644 Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs.meta delete mode 100644 Assets/Mirror/Runtime/MessagePacker.cs delete mode 100644 Assets/Mirror/Runtime/MessagePacker.cs.meta delete mode 100644 Assets/Mirror/Runtime/Messages.cs delete mode 100644 Assets/Mirror/Runtime/Messages.cs.meta delete mode 100644 Assets/Mirror/Runtime/Mirror.asmdef delete mode 100644 Assets/Mirror/Runtime/Mirror.asmdef.meta delete mode 100644 Assets/Mirror/Runtime/NetworkAuthenticator.cs delete mode 100644 Assets/Mirror/Runtime/NetworkAuthenticator.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkBehaviour.cs delete mode 100644 Assets/Mirror/Runtime/NetworkBehaviour.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkClient.cs delete mode 100644 Assets/Mirror/Runtime/NetworkClient.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkConnection.cs delete mode 100644 Assets/Mirror/Runtime/NetworkConnection.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkConnectionToClient.cs delete mode 100644 Assets/Mirror/Runtime/NetworkConnectionToClient.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkConnectionToServer.cs delete mode 100644 Assets/Mirror/Runtime/NetworkConnectionToServer.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkDiagnostics.cs delete mode 100644 Assets/Mirror/Runtime/NetworkDiagnostics.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkIdentity.cs delete mode 100644 Assets/Mirror/Runtime/NetworkIdentity.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkManager.cs delete mode 100644 Assets/Mirror/Runtime/NetworkManager.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkManagerHUD.cs delete mode 100644 Assets/Mirror/Runtime/NetworkManagerHUD.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkMessage.cs delete mode 100644 Assets/Mirror/Runtime/NetworkMessage.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkReader.cs delete mode 100644 Assets/Mirror/Runtime/NetworkReader.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkReaderPool.cs delete mode 100644 Assets/Mirror/Runtime/NetworkReaderPool.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkServer.cs delete mode 100644 Assets/Mirror/Runtime/NetworkServer.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkStartPosition.cs delete mode 100644 Assets/Mirror/Runtime/NetworkStartPosition.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkTime.cs delete mode 100644 Assets/Mirror/Runtime/NetworkTime.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkVisibility.cs delete mode 100644 Assets/Mirror/Runtime/NetworkVisibility.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkWriter.cs delete mode 100644 Assets/Mirror/Runtime/NetworkWriter.cs.meta delete mode 100644 Assets/Mirror/Runtime/NetworkWriterPool.cs delete mode 100644 Assets/Mirror/Runtime/NetworkWriterPool.cs.meta delete mode 100644 Assets/Mirror/Runtime/RemoteCallHelper.cs delete mode 100644 Assets/Mirror/Runtime/RemoteCallHelper.cs.meta delete mode 100644 Assets/Mirror/Runtime/StringHash.cs delete mode 100644 Assets/Mirror/Runtime/StringHash.cs.meta delete mode 100644 Assets/Mirror/Runtime/SyncDictionary.cs delete mode 100644 Assets/Mirror/Runtime/SyncDictionary.cs.meta delete mode 100644 Assets/Mirror/Runtime/SyncList.cs delete mode 100644 Assets/Mirror/Runtime/SyncList.cs.meta delete mode 100644 Assets/Mirror/Runtime/SyncObject.cs delete mode 100644 Assets/Mirror/Runtime/SyncObject.cs.meta delete mode 100644 Assets/Mirror/Runtime/SyncSet.cs delete mode 100644 Assets/Mirror/Runtime/SyncSet.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport.meta delete mode 100644 Assets/Mirror/Runtime/Transport/FallbackTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/FallbackTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/MirrorTransport.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef delete mode 100644 Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef.meta delete mode 100644 Assets/Mirror/Runtime/Transport/LLAPITransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/LLAPITransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/MultiplexTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/MultiplexTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs delete mode 100644 Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Client.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Client.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Common.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Common.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/LICENSE delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/LICENSE.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Message.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Message.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Server.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Server.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/TelepathyTransport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/TelepathyTransport.cs.meta delete mode 100644 Assets/Mirror/Runtime/Transport/Transport.cs delete mode 100644 Assets/Mirror/Runtime/Transport/Transport.cs.meta delete mode 100644 Assets/Mirror/Runtime/UNetwork.cs delete mode 100644 Assets/Mirror/Runtime/UNetwork.cs.meta delete mode 100644 Assets/Mirror/Version.txt delete mode 100644 Assets/Mirror/Version.txt.meta diff --git a/Assets/Mirror.meta b/Assets/Mirror.meta deleted file mode 100644 index a7a3dd0..0000000 --- a/Assets/Mirror.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5cf8eb36be0834b3da408c694a41cb88 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Authenticators.meta b/Assets/Mirror/Authenticators.meta deleted file mode 100644 index 644f4ec..0000000 --- a/Assets/Mirror/Authenticators.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1b2f9d254154cd942ba40b06b869b8f3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs b/Assets/Mirror/Authenticators/BasicAuthenticator.cs deleted file mode 100644 index 4a6b03b..0000000 --- a/Assets/Mirror/Authenticators/BasicAuthenticator.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System.Collections; -using UnityEngine; - -namespace Mirror.Authenticators -{ - [AddComponentMenu("Network/Authenticators/BasicAuthenticator")] - public class BasicAuthenticator : NetworkAuthenticator - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(BasicAuthenticator)); - - [Header("Custom Properties")] - - // set these in the inspector - public string username; - public string password; - - #region Messages - - public struct AuthRequestMessage : NetworkMessage - { - // use whatever credentials make sense for your game - // for example, you might want to pass the accessToken if using oauth - public string authUsername; - public string authPassword; - } - - public struct AuthResponseMessage : NetworkMessage - { - public byte code; - public string message; - } - - #endregion - - #region Server - - /// - /// Called on server from StartServer to initialize the Authenticator - /// Server message handlers should be registered in this method. - /// - public override void OnStartServer() - { - // register a handler for the authentication request we expect from client - NetworkServer.RegisterHandler(OnAuthRequestMessage, false); - } - - /// - /// Called on server from OnServerAuthenticateInternal when a client needs to authenticate - /// - /// Connection to client. - public override void OnServerAuthenticate(NetworkConnection conn) - { - // do nothing...wait for AuthRequestMessage from client - } - - /// - /// Called on server when the client's AuthRequestMessage arrives - /// - /// Connection to client. - /// The message payload - public void OnAuthRequestMessage(NetworkConnection conn, AuthRequestMessage msg) - { - if (logger.LogEnabled()) logger.LogFormat(LogType.Log, "Authentication Request: {0} {1}", msg.authUsername, msg.authPassword); - - // check the credentials by calling your web server, database table, playfab api, or any method appropriate. - if (msg.authUsername == username && msg.authPassword == password) - { - // create and send msg to client so it knows to proceed - AuthResponseMessage authResponseMessage = new AuthResponseMessage - { - code = 100, - message = "Success" - }; - - conn.Send(authResponseMessage); - - // Accept the successful authentication - ServerAccept(conn); - } - else - { - // create and send msg to client so it knows to disconnect - AuthResponseMessage authResponseMessage = new AuthResponseMessage - { - code = 200, - message = "Invalid Credentials" - }; - - conn.Send(authResponseMessage); - - // must set NetworkConnection isAuthenticated = false - conn.isAuthenticated = false; - - // disconnect the client after 1 second so that response message gets delivered - StartCoroutine(DelayedDisconnect(conn, 1)); - } - } - - IEnumerator DelayedDisconnect(NetworkConnection conn, float waitTime) - { - yield return new WaitForSeconds(waitTime); - - // Reject the unsuccessful authentication - ServerReject(conn); - } - - #endregion - - #region Client - - /// - /// Called on client from StartClient to initialize the Authenticator - /// Client message handlers should be registered in this method. - /// - public override void OnStartClient() - { - // register a handler for the authentication response we expect from server - NetworkClient.RegisterHandler(OnAuthResponseMessage, false); - } - - /// - /// Called on client from OnClientAuthenticateInternal when a client needs to authenticate - /// - /// Connection of the client. - public override void OnClientAuthenticate(NetworkConnection conn) - { - AuthRequestMessage authRequestMessage = new AuthRequestMessage - { - authUsername = username, - authPassword = password - }; - - conn.Send(authRequestMessage); - } - - /// - /// Called on client when the server's AuthResponseMessage arrives - /// - /// Connection to client. - /// The message payload - public void OnAuthResponseMessage(NetworkConnection conn, AuthResponseMessage msg) - { - if (msg.code == 100) - { - if (logger.LogEnabled()) logger.LogFormat(LogType.Log, "Authentication Response: {0}", msg.message); - - // Authentication has been accepted - ClientAccept(conn); - } - else - { - logger.LogFormat(LogType.Error, "Authentication Response: {0}", msg.message); - - // Authentication has been rejected - ClientReject(conn); - } - } - - #endregion - } -} diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta b/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta deleted file mode 100644 index 4765013..0000000 --- a/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 28496b776660156428f00cf78289c1ec -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef deleted file mode 100644 index 16cdfbc..0000000 --- a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Mirror.Authenticators", - "references": [ - "Mirror" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta deleted file mode 100644 index 2731701..0000000 --- a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e720aa64e3f58fb4880566a322584340 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs deleted file mode 100644 index 4fa580b..0000000 --- a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections; -using UnityEngine; - -namespace Mirror.Authenticators -{ - /// - /// An authenticator that disconnects connections if they don't - /// authenticate within a specified time limit. - /// - [AddComponentMenu("Network/Authenticators/TimeoutAuthenticator")] - public class TimeoutAuthenticator : NetworkAuthenticator - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(TimeoutAuthenticator)); - - public NetworkAuthenticator authenticator; - - [Range(0, 600), Tooltip("Timeout to auto-disconnect in seconds. Set to 0 for no timeout.")] - public float timeout = 60; - - public void Awake() - { - authenticator.OnClientAuthenticated.AddListener(connection => OnClientAuthenticated.Invoke(connection)); - authenticator.OnServerAuthenticated.AddListener(connection => OnServerAuthenticated.Invoke(connection)); - } - - public override void OnStartClient() - { - authenticator.OnStartClient(); - } - - public override void OnStartServer() - { - authenticator.OnStartServer(); - } - - public override void OnClientAuthenticate(NetworkConnection conn) - { - authenticator.OnClientAuthenticate(conn); - if (timeout > 0) - StartCoroutine(BeginAuthentication(conn)); - } - - public override void OnServerAuthenticate(NetworkConnection conn) - { - authenticator.OnServerAuthenticate(conn); - if (timeout > 0) - StartCoroutine(BeginAuthentication(conn)); - } - - IEnumerator BeginAuthentication(NetworkConnection conn) - { - if (logger.LogEnabled()) logger.Log($"Authentication countdown started {conn} {timeout}"); - - yield return new WaitForSecondsRealtime(timeout); - - if (!conn.isAuthenticated) - { - if (logger.LogEnabled()) logger.Log($"Authentication Timeout {conn}"); - - conn.Disconnect(); - } - } - } -} diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta deleted file mode 100644 index b19ddec..0000000 --- a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 24d8269a07b8e4edfa374753a91c946e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud.meta b/Assets/Mirror/Cloud.meta deleted file mode 100644 index e2c44de..0000000 --- a/Assets/Mirror/Cloud.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 73a9bb2dacafa8141bce8feef34e33a7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ApiConnector.cs b/Assets/Mirror/Cloud/ApiConnector.cs deleted file mode 100644 index ae9f858..0000000 --- a/Assets/Mirror/Cloud/ApiConnector.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Mirror.Cloud.ListServerService; -using UnityEngine; - -namespace Mirror.Cloud -{ - /// - /// Used to requests and responses from the mirror api - /// - public interface IApiConnector - { - ListServer ListServer { get; } - } - - /// - /// Used to requests and responses from the mirror api - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/CloudServices/ApiConnector")] - [HelpURL("https://mirror-networking.com/docs/CloudServices/ApiConnector.html")] - public class ApiConnector : MonoBehaviour, IApiConnector, ICoroutineRunner - { - #region Inspector - [Header("Settings")] - - [Tooltip("Base URL of api, including https")] - [SerializeField] string ApiAddress = ""; - - [Tooltip("Api key required to access api")] - [SerializeField] string ApiKey = ""; - - [Header("Events")] - - [Tooltip("Triggered when server list updates")] - [SerializeField] ServerListEvent _onServerListUpdated = new ServerListEvent(); - #endregion - - IRequestCreator requestCreator; - - public ListServer ListServer { get; private set; } - - void Awake() - { - requestCreator = new RequestCreator(ApiAddress, ApiKey, this); - - InitListServer(); - } - - void InitListServer() - { - IListServerServerApi serverApi = new ListServerServerApi(this, requestCreator); - IListServerClientApi clientApi = new ListServerClientApi(this, requestCreator, _onServerListUpdated); - ListServer = new ListServer(serverApi, clientApi); - } - - public void OnDestroy() - { - ListServer?.ServerApi.Shutdown(); - ListServer?.ClientApi.Shutdown(); - } - } -} diff --git a/Assets/Mirror/Cloud/ApiConnector.cs.meta b/Assets/Mirror/Cloud/ApiConnector.cs.meta deleted file mode 100644 index 9279c0c..0000000 --- a/Assets/Mirror/Cloud/ApiConnector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8bdb99a29e179d14cb0acc43f175d9ad -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core.meta b/Assets/Mirror/Cloud/Core.meta deleted file mode 100644 index 8c00059..0000000 --- a/Assets/Mirror/Cloud/Core.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 3f34c32971e65984c93a15376ec11c65 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/BaseApi.cs b/Assets/Mirror/Cloud/Core/BaseApi.cs deleted file mode 100644 index 720f598..0000000 --- a/Assets/Mirror/Cloud/Core/BaseApi.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Mirror.Cloud -{ - public interface IBaseApi - { - /// - /// Cleans up any data created by the instance - /// For Example: removing server from list - /// - void Shutdown(); - } - - public abstract class BaseApi - { - protected readonly ICoroutineRunner runner; - protected readonly IRequestCreator requestCreator; - - protected BaseApi(ICoroutineRunner runner, IRequestCreator requestCreator) - { - this.runner = runner ?? throw new ArgumentNullException(nameof(runner)); - this.requestCreator = requestCreator ?? throw new ArgumentNullException(nameof(requestCreator)); - } - } -} diff --git a/Assets/Mirror/Cloud/Core/BaseApi.cs.meta b/Assets/Mirror/Cloud/Core/BaseApi.cs.meta deleted file mode 100644 index f66b84e..0000000 --- a/Assets/Mirror/Cloud/Core/BaseApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 70f563b7a7210ae43bbcde5cb7721a94 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/Events.cs b/Assets/Mirror/Cloud/Core/Events.cs deleted file mode 100644 index ffee4d3..0000000 --- a/Assets/Mirror/Cloud/Core/Events.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Mirror.Cloud.ListServerService; -using UnityEngine.Events; - -namespace Mirror.Cloud -{ - [Serializable] - public class ServerListEvent : UnityEvent { } - - [Serializable] - public class MatchFoundEvent : UnityEvent { } -} diff --git a/Assets/Mirror/Cloud/Core/Events.cs.meta b/Assets/Mirror/Cloud/Core/Events.cs.meta deleted file mode 100644 index 150d85b..0000000 --- a/Assets/Mirror/Cloud/Core/Events.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7c472a3ea1bc4348bd5a0b05bf7cc3b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/Extensions.cs b/Assets/Mirror/Cloud/Core/Extensions.cs deleted file mode 100644 index fa7dfa7..0000000 --- a/Assets/Mirror/Cloud/Core/Extensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine.Networking; - -namespace Mirror.Cloud -{ - public static class Extensions - { - public static bool IsOk(this UnityWebRequest webRequest) - { - return 200 <= webRequest.responseCode && webRequest.responseCode <= 299; - } - } -} diff --git a/Assets/Mirror/Cloud/Core/Extensions.cs.meta b/Assets/Mirror/Cloud/Core/Extensions.cs.meta deleted file mode 100644 index 6bf6291..0000000 --- a/Assets/Mirror/Cloud/Core/Extensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 97501e783fc67a4459b15d10e6c63563 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs b/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs deleted file mode 100644 index 7fe3bbf..0000000 --- a/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections; -using UnityEngine; - -namespace Mirror.Cloud -{ - public interface ICoroutineRunner : IUnityEqualCheck - { - Coroutine StartCoroutine(IEnumerator routine); - void StopCoroutine(IEnumerator routine); - void StopCoroutine(Coroutine routine); - } -} diff --git a/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs.meta b/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs.meta deleted file mode 100644 index f1149a9..0000000 --- a/Assets/Mirror/Cloud/Core/ICoroutineRunner.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 43472c60a7c72e54eafe559290dd0fc6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/IRequestCreator.cs b/Assets/Mirror/Cloud/Core/IRequestCreator.cs deleted file mode 100644 index 2709707..0000000 --- a/Assets/Mirror/Cloud/Core/IRequestCreator.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections; -using UnityEngine.Networking; - -namespace Mirror.Cloud -{ - public delegate void RequestSuccess(string responseBody); - - public delegate void RequestFail(string responseBody); - - /// - /// Objects that can be sent to the Api must have this interface - /// - public interface ICanBeJson { } - - /// - /// Methods to create and send UnityWebRequest - /// - public interface IRequestCreator - { - UnityWebRequest Delete(string page); - UnityWebRequest Get(string page); - UnityWebRequest Patch(string page, T json) where T : struct, ICanBeJson; - UnityWebRequest Post(string page, T json) where T : struct, ICanBeJson; - - /// - /// Sends Request to api and invokes callback when finished - /// Starts Coroutine of SendRequestEnumerator - /// - /// - /// - /// - void SendRequest(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null); - /// - /// Sends Request to api and invokes callback when finished - /// - /// - /// - /// - /// - IEnumerator SendRequestEnumerator(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null); - } -} diff --git a/Assets/Mirror/Cloud/Core/IRequestCreator.cs.meta b/Assets/Mirror/Cloud/Core/IRequestCreator.cs.meta deleted file mode 100644 index 966c503..0000000 --- a/Assets/Mirror/Cloud/Core/IRequestCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b80b95532a9d6e8418aa676a261e4f69 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs b/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs deleted file mode 100644 index be5e057..0000000 --- a/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs +++ /dev/null @@ -1,26 +0,0 @@ -using UnityEngine; - -namespace Mirror.Cloud -{ - /// - /// Adds Extension to check if unity object is null. - /// Use these methods to stop MissingReferenceException - /// - public interface IUnityEqualCheck - { - - } - - public static class UnityEqualCheckExtension - { - public static bool IsNull(this IUnityEqualCheck obj) - { - return (obj as Object) == null; - } - - public static bool IsNotNull(this IUnityEqualCheck obj) - { - return (obj as Object) != null; - } - } -} diff --git a/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs.meta b/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs.meta deleted file mode 100644 index 7cb2a59..0000000 --- a/Assets/Mirror/Cloud/Core/IUnityEqualCheck.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05185b973ba389a4588fc8a99c75a4f6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/JsonStructs.cs b/Assets/Mirror/Cloud/Core/JsonStructs.cs deleted file mode 100644 index 7827abc..0000000 --- a/Assets/Mirror/Cloud/Core/JsonStructs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Mirror.Cloud -{ - [Serializable] - public struct CreatedIdJson : ICanBeJson - { - public string id; - } - - [Serializable] - public struct ErrorJson : ICanBeJson - { - public string code; - public string message; - - public int HtmlCode => int.Parse(code); - } - - [Serializable] - public struct EmptyJson : ICanBeJson - { - } -} diff --git a/Assets/Mirror/Cloud/Core/JsonStructs.cs.meta b/Assets/Mirror/Cloud/Core/JsonStructs.cs.meta deleted file mode 100644 index 2c04009..0000000 --- a/Assets/Mirror/Cloud/Core/JsonStructs.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0688c0fdae5376e4ea74d5c3904eed17 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/Logger.cs b/Assets/Mirror/Cloud/Core/Logger.cs deleted file mode 100644 index 89daca9..0000000 --- a/Assets/Mirror/Cloud/Core/Logger.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Networking; - -namespace Mirror.Cloud -{ - public static class Logger - { - public static bool VerboseLogging = false; - static readonly ILogger logger = LogFactory.GetLogger("MirrorCloudServices"); - - public static void LogRequest(string page, string method, bool hasJson, string json) - { - if (hasJson) - { - logger.LogFormat(LogType.Log, "Request: {0} {1} {2}", method, page, json); - } - else - { - logger.LogFormat(LogType.Log, "Request: {0} {1}", method, page); - } - } - - public static void LogResponse(UnityWebRequest statusRequest) - { - long code = statusRequest.responseCode; - LogType logType = statusRequest.IsOk() - ? LogType.Log - : LogType.Error; - - string format = "Response: {0} {1} {2} {3}"; - if (logger.IsLogTypeAllowed(logType)) - { - // we split path like this to make sure api key doesn't leak - Uri uri = new Uri(statusRequest.url); - string path = string.Join("", uri.Segments); - string msg = string.Format(format, statusRequest.method, code, path, statusRequest.downloadHandler.text); - logger.Log(logType, msg); - } - - if (!string.IsNullOrEmpty(statusRequest.error)) - { - string msg = string.Format("WEB REQUEST ERROR: {0}", statusRequest.error); - logger.Log(LogType.Error, msg); - } - } - - internal static void Log(string msg) - { - if (logger.LogEnabled()) - logger.Log(msg); - } - - internal static void LogWarning(string msg) - { - if (logger.WarnEnabled()) - logger.LogWarning(msg); - } - - internal static void LogError(string msg) - { - if (logger.ErrorEnabled()) - logger.LogError(msg); - } - - internal static void Verbose(string msg) - { - if (VerboseLogging && logger.LogEnabled()) - logger.Log(msg); - } - } -} diff --git a/Assets/Mirror/Cloud/Core/Logger.cs.meta b/Assets/Mirror/Cloud/Core/Logger.cs.meta deleted file mode 100644 index 5984ce3..0000000 --- a/Assets/Mirror/Cloud/Core/Logger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 457ba2df6cb6e1542996c17c715ee81b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Core/RequestCreator.cs b/Assets/Mirror/Cloud/Core/RequestCreator.cs deleted file mode 100644 index 7195c0e..0000000 --- a/Assets/Mirror/Cloud/Core/RequestCreator.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections; -using System.Text; -using UnityEngine; -using UnityEngine.Networking; - -namespace Mirror.Cloud -{ - /// - /// Methods to create and send UnityWebRequest - /// - public class RequestCreator : IRequestCreator - { - const string GET = "GET"; - const string POST = "POST"; - const string PATCH = "PATCH"; - const string DELETE = "DELETE"; - - public readonly string baseAddress; - public readonly string apiKey; - readonly ICoroutineRunner runner; - - public RequestCreator(string baseAddress, string apiKey, ICoroutineRunner coroutineRunner) - { - if (string.IsNullOrEmpty(baseAddress)) - { - throw new ArgumentNullException(nameof(baseAddress)); - } - - if (string.IsNullOrEmpty(apiKey)) - { - throw new ArgumentNullException(nameof(apiKey)); - } - - this.baseAddress = baseAddress; - this.apiKey = apiKey; - - runner = coroutineRunner ?? throw new ArgumentNullException(nameof(coroutineRunner)); - } - - - Uri CreateUri(string page) - { - return new Uri(string.Format("{0}/{1}?key={2}", baseAddress, page, apiKey)); - } - - UnityWebRequest CreateWebRequest(string page, string method, string json = null) - { - bool hasJson = !string.IsNullOrEmpty(json); - Logger.LogRequest(page, method, hasJson, json); - - UnityWebRequest request = new UnityWebRequest(CreateUri(page)); - request.method = method; - if (hasJson) - { - request.SetRequestHeader("Content-Type", "application/json"); - } - - request.downloadHandler = new DownloadHandlerBuffer(); - - byte[] bodyRaw = hasJson - ? Encoding.UTF8.GetBytes(json) - : null; - - request.uploadHandler = new UploadHandlerRaw(bodyRaw); - - return request; - } - - - - /// - /// Create Get Request to page - /// - /// - /// - public UnityWebRequest Get(string page) - { - return CreateWebRequest(page, GET); - } - - /// - /// Creates Post Request to page with Json body - /// - /// - /// - /// - /// - public UnityWebRequest Post(string page, T json) where T : struct, ICanBeJson - { - string jsonString = JsonUtility.ToJson(json); - return CreateWebRequest(page, POST, jsonString); - } - - /// - /// Creates Patch Request to page with Json body - /// - /// - /// - /// - /// - public UnityWebRequest Patch(string page, T json) where T : struct, ICanBeJson - { - string jsonString = JsonUtility.ToJson(json); - return CreateWebRequest(page, PATCH, jsonString); - } - - /// - /// Create Delete Request to page - /// - /// - /// - public UnityWebRequest Delete(string page) - { - return CreateWebRequest(page, DELETE); - } - - - public void SendRequest(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null) - { - runner.StartCoroutine(SendRequestEnumerator(request, onSuccess, onFail)); - } - - public IEnumerator SendRequestEnumerator(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null) - { - using (UnityWebRequest webRequest = request) - { - yield return webRequest.SendWebRequest(); - Logger.LogResponse(webRequest); - - string text = webRequest.downloadHandler.text; - Logger.Verbose(text); - if (webRequest.IsOk()) - { - onSuccess?.Invoke(text); - } - else - { - onFail?.Invoke(text); - } - } - } - } -} diff --git a/Assets/Mirror/Cloud/Core/RequestCreator.cs.meta b/Assets/Mirror/Cloud/Core/RequestCreator.cs.meta deleted file mode 100644 index eb139af..0000000 --- a/Assets/Mirror/Cloud/Core/RequestCreator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cfaa626443cc7c94eae138a2e3a04d7c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer.meta b/Assets/Mirror/Cloud/ListServer.meta deleted file mode 100644 index bc85c3d..0000000 --- a/Assets/Mirror/Cloud/ListServer.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c4c4be148a492b143a881cd08bf7e320 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer/ListServer.cs b/Assets/Mirror/Cloud/ListServer/ListServer.cs deleted file mode 100644 index 8b4af80..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServer.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using UnityEngine.Events; - -namespace Mirror.Cloud.ListServerService -{ - public sealed class ListServer - { - public readonly IListServerServerApi ServerApi; - public readonly IListServerClientApi ClientApi; - - public ListServer(IListServerServerApi serverApi, IListServerClientApi clientApi) - { - ServerApi = serverApi ?? throw new ArgumentNullException(nameof(serverApi)); - ClientApi = clientApi ?? throw new ArgumentNullException(nameof(clientApi)); - } - } - - public interface IListServerServerApi : IBaseApi - { - /// - /// Has a server been added to the list with this connection - /// - bool ServerInList { get; } - /// - /// Add a server to the list - /// - /// - void AddServer(ServerJson server); - /// - /// Update the current server - /// - /// - void UpdateServer(int newPlayerCount); - /// - /// Update the current server - /// - /// - void UpdateServer(ServerJson server); - /// - /// Removes the current server - /// - void RemoveServer(); - } - - public interface IListServerClientApi : IBaseApi - { - /// - /// Called when the server list is updated - /// - event UnityAction onServerListUpdated; - - /// - /// Get the server list once - /// - void GetServerList(); - /// - /// Start getting the server list every interval - /// - /// - void StartGetServerListRepeat(int interval); - /// - /// Stop getting the server list - /// - void StopGetServerListRepeat(); - } -} diff --git a/Assets/Mirror/Cloud/ListServer/ListServer.cs.meta b/Assets/Mirror/Cloud/ListServer/ListServer.cs.meta deleted file mode 100644 index 519876d..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6f0311899162c5b49a3c11fa9bd9c133 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs b/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs deleted file mode 100644 index 05d2e2e..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Mirror.Cloud.ListServerService -{ - public abstract class ListServerBaseApi : BaseApi - { - protected ListServerBaseApi(ICoroutineRunner runner, IRequestCreator requestCreator) : base(runner, requestCreator) - { - } - } -} diff --git a/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs.meta b/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs.meta deleted file mode 100644 index a9d32ea..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerBaseApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b6838f9df45594d48873518cbb75b329 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs b/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs deleted file mode 100644 index 22867c1..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.Networking; - -namespace Mirror.Cloud.ListServerService -{ - public sealed class ListServerClientApi : ListServerBaseApi, IListServerClientApi - { - readonly ServerListEvent _onServerListUpdated; - - Coroutine getServerListRepeatCoroutine; - - public event UnityAction onServerListUpdated - { - add => _onServerListUpdated.AddListener(value); - remove => _onServerListUpdated.RemoveListener(value); - } - - public ListServerClientApi(ICoroutineRunner runner, IRequestCreator requestCreator, ServerListEvent onServerListUpdated) : base(runner, requestCreator) - { - _onServerListUpdated = onServerListUpdated; - } - - public void Shutdown() - { - StopGetServerListRepeat(); - } - - public void GetServerList() - { - runner.StartCoroutine(getServerList()); - } - - public void StartGetServerListRepeat(int interval) - { - getServerListRepeatCoroutine = runner.StartCoroutine(GetServerListRepeat(interval)); - } - - public void StopGetServerListRepeat() - { - // if runner is null it has been destroyed and will alraedy be null - if (runner.IsNotNull() && getServerListRepeatCoroutine != null) - { - runner.StopCoroutine(getServerListRepeatCoroutine); - } - } - - IEnumerator GetServerListRepeat(int interval) - { - while (true) - { - yield return getServerList(); - - yield return new WaitForSeconds(interval); - } - } - IEnumerator getServerList() - { - UnityWebRequest request = requestCreator.Get("servers"); - yield return requestCreator.SendRequestEnumerator(request, onSuccess); - - void onSuccess(string responseBody) - { - ServerCollectionJson serverlist = JsonUtility.FromJson(responseBody); - _onServerListUpdated?.Invoke(serverlist); - } - } - } -} diff --git a/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs.meta b/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs.meta deleted file mode 100644 index 306bf7c..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerClientApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d49649fb32cb96b46b10f013b38a4b50 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer/ListServerJson.cs b/Assets/Mirror/Cloud/ListServer/ListServerJson.cs deleted file mode 100644 index 2591331..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerJson.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Mirror.Cloud.ListServerService -{ - [Serializable] - public struct ServerCollectionJson : ICanBeJson - { - public ServerJson[] servers; - } - - [Serializable] - public struct ServerJson : ICanBeJson - { - public string protocol; - public int port; - public int playerCount; - public int maxPlayerCount; - - /// - /// optional - /// - public string displayName; - - /// - /// Uri string of the ip and port of the server. - /// The ip is calculated by the request to the API - /// This is returns from the api, any incoming address fields will be ignored - /// - public string address; - - /// - /// Can be used to set custom uri - /// optional - /// - public string customAddress; - - /// - /// Array of custom data, use SetCustomData to set values - /// optional - /// - public KeyValue[] customData; - - /// - /// Uri from address field - /// - /// - public Uri GetServerUri() => new Uri(address); - - /// - /// Uri from customAddress field - /// - /// - public Uri GetCustomUri() => new Uri(customAddress); - - /// - /// Updates the customData array - /// - /// - public void SetCustomData(Dictionary data) - { - if (data == null) - { - customData = null; - } - else - { - customData = data.ToKeyValueArray(); - CustomDataHelper.ValidateCustomData(customData); - } - } - - public bool Validate() - { - CustomDataHelper.ValidateCustomData(customData); - - if (string.IsNullOrEmpty(protocol)) - { - Logger.LogError("ServerJson should not have empty protocol"); - return false; - } - - if (port == 0) - { - Logger.LogError("ServerJson should not have port equal 0"); - return false; - } - - if (maxPlayerCount == 0) - { - Logger.LogError("ServerJson should not have maxPlayerCount equal 0"); - return false; - } - - return true; - } - } - - [Serializable] - public struct PartialServerJson : ICanBeJson - { - /// - /// optional - /// - public int playerCount; - - /// - /// optional - /// - public int maxPlayerCount; - - /// - /// optional - /// - public string displayName; - - /// - /// Array of custom data, use SetCustomData to set values - /// optional - /// - public KeyValue[] customData; - - - public void SetCustomData(Dictionary data) - { - if (data == null) - { - customData = null; - } - else - { - customData = data.ToKeyValueArray(); - CustomDataHelper.ValidateCustomData(customData); - } - } - - public void Validate() - { - CustomDataHelper.ValidateCustomData(customData); - } - } - - public static class CustomDataHelper - { - const int MaxCustomData = 16; - - public static Dictionary ToDictionary(this KeyValue[] keyValues) - { - return keyValues.ToDictionary(x => x.key, x => x.value); - } - public static KeyValue[] ToKeyValueArray(this Dictionary dictionary) - { - return dictionary.Select(kvp => new KeyValue(kvp.Key, kvp.Value)).ToArray(); - } - - public static void ValidateCustomData(KeyValue[] customData) - { - if (customData == null) - { - return; - } - - if (customData.Length > MaxCustomData) - { - Logger.LogError($"There can only be {MaxCustomData} custom data but there was {customData.Length} values given"); - Array.Resize(ref customData, MaxCustomData); - } - - foreach (KeyValue item in customData) - { - item.Validate(); - } - } - } - - [Serializable] - public struct KeyValue - { - const int MaxKeySize = 32; - const int MaxValueSize = 256; - - public string key; - public string value; - - public KeyValue(string key, string value) - { - this.key = key; - this.value = value; - } - - public void Validate() - { - if (key.Length > MaxKeySize) - { - Logger.LogError($"Custom Data must have key with length less than {MaxKeySize}"); - key = key.Substring(0, MaxKeySize); - } - - if (value.Length > MaxValueSize) - { - Logger.LogError($"Custom Data must have value with length less than {MaxValueSize}"); - value = value.Substring(0, MaxValueSize); - } - } - } -} diff --git a/Assets/Mirror/Cloud/ListServer/ListServerJson.cs.meta b/Assets/Mirror/Cloud/ListServer/ListServerJson.cs.meta deleted file mode 100644 index 7e206f1..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerJson.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a963606335eae0f47abe7ecb5fd028ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs b/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs deleted file mode 100644 index 3ca4b0d..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.Networking; - -namespace Mirror.Cloud.ListServerService -{ - public sealed class ListServerServerApi : ListServerBaseApi, IListServerServerApi - { - const int PingInterval = 20; - const int MaxPingFails = 15; - - ServerJson currentServer; - string serverId; - - Coroutine _pingCoroutine; - /// - /// If the server has already been added - /// - bool added; - /// - /// if a request is currently sending - /// - bool sending; - /// - /// If an update request was recently sent - /// - bool skipNextPing; - /// - /// How many failed pings in a row - /// - int pingFails = 0; - - public bool ServerInList => added; - - public ListServerServerApi(ICoroutineRunner runner, IRequestCreator requestCreator) : base(runner, requestCreator) - { - } - - public void Shutdown() - { - stopPingCoroutine(); - if (added) - { - removeServerWithoutCoroutine(); - } - added = false; - } - - public void AddServer(ServerJson server) - { - if (added) { Logger.LogWarning("AddServer called when server was already adding or added"); return; } - bool valid = server.Validate(); - if (!valid) { return; } - - runner.StartCoroutine(addServer(server)); - } - - public void UpdateServer(int newPlayerCount) - { - if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); return; } - - currentServer.playerCount = newPlayerCount; - UpdateServer(currentServer); - } - - public void UpdateServer(ServerJson server) - { - // TODO, use PartialServerJson as Arg Instead - if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); return; } - - PartialServerJson partialServer = new PartialServerJson - { - displayName = server.displayName, - playerCount = server.playerCount, - maxPlayerCount = server.maxPlayerCount, - customData = server.customData, - }; - partialServer.Validate(); - - runner.StartCoroutine(updateServer(partialServer)); - } - - public void RemoveServer() - { - if (!added) { return; } - - if (string.IsNullOrEmpty(serverId)) - { - Logger.LogWarning("Can not remove server because serverId was empty"); - return; - } - - stopPingCoroutine(); - runner.StartCoroutine(removeServer()); - } - - void stopPingCoroutine() - { - if (_pingCoroutine != null) - { - runner.StopCoroutine(_pingCoroutine); - _pingCoroutine = null; - } - } - - IEnumerator addServer(ServerJson server) - { - added = true; - sending = true; - currentServer = server; - - UnityWebRequest request = requestCreator.Post("servers", currentServer); - yield return requestCreator.SendRequestEnumerator(request, onSuccess, onFail); - sending = false; - - void onSuccess(string responseBody) - { - CreatedIdJson created = JsonUtility.FromJson(responseBody); - serverId = created.id; - - // Start ping to keep server alive - _pingCoroutine = runner.StartCoroutine(ping()); - } - void onFail(string responseBody) - { - added = false; - } - } - - IEnumerator updateServer(PartialServerJson server) - { - // wait to not be sending - while (sending) - { - yield return new WaitForSeconds(1); - } - - // We need to check added incase Update is called soon after Add, and add failed - if (!added) { Logger.LogWarning("UpdateServer called when before server was added"); yield break; } - - sending = true; - UnityWebRequest request = requestCreator.Patch("servers/" + serverId, server); - yield return requestCreator.SendRequestEnumerator(request, onSuccess); - sending = false; - - void onSuccess(string responseBody) - { - skipNextPing = true; - - if (_pingCoroutine == null) - { - _pingCoroutine = runner.StartCoroutine(ping()); - } - } - } - - /// - /// Keeps server alive in database - /// - /// - IEnumerator ping() - { - while (pingFails <= MaxPingFails) - { - yield return new WaitForSeconds(PingInterval); - if (skipNextPing) - { - skipNextPing = false; - continue; - } - - sending = true; - UnityWebRequest request = requestCreator.Patch("servers/" + serverId, new EmptyJson()); - yield return requestCreator.SendRequestEnumerator(request, onSuccess, onFail); - sending = false; - } - - Logger.LogWarning("Max ping fails reached, stoping to ping server"); - _pingCoroutine = null; - - - void onSuccess(string responseBody) - { - pingFails = 0; - } - void onFail(string responseBody) - { - pingFails++; - } - } - - IEnumerator removeServer() - { - sending = true; - UnityWebRequest request = requestCreator.Delete("servers/" + serverId); - yield return requestCreator.SendRequestEnumerator(request); - sending = false; - - added = false; - } - - void removeServerWithoutCoroutine() - { - if (string.IsNullOrEmpty(serverId)) - { - Logger.LogWarning("Can not remove server becuase serverId was empty"); - return; - } - - UnityWebRequest request = requestCreator.Delete("servers/" + serverId); - UnityWebRequestAsyncOperation operation = request.SendWebRequest(); - - operation.completed += (op) => - { - Logger.LogResponse(request); - }; - } - } -} diff --git a/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs.meta b/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs.meta deleted file mode 100644 index 82e23fd..0000000 --- a/Assets/Mirror/Cloud/ListServer/ListServerServerApi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 675f0d0fd4e82b04290c4d30c8d78ede -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/Mirror.Cloud.asmdef b/Assets/Mirror/Cloud/Mirror.Cloud.asmdef deleted file mode 100644 index dbea971..0000000 --- a/Assets/Mirror/Cloud/Mirror.Cloud.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Mirror.Cloud", - "references": [ - "Mirror" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Cloud/Mirror.Cloud.asmdef.meta b/Assets/Mirror/Cloud/Mirror.Cloud.asmdef.meta deleted file mode 100644 index bd17c2b..0000000 --- a/Assets/Mirror/Cloud/Mirror.Cloud.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c21ba7b8c3183cb47b7fe3b3799d49c4 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/README.md b/Assets/Mirror/Cloud/README.md deleted file mode 100644 index 9b32497..0000000 --- a/Assets/Mirror/Cloud/README.md +++ /dev/null @@ -1,152 +0,0 @@ -# Mirror Cloud Services - -## Mirror List Server - -Example has an API key which can be used as a demo. - -To get an API key to use within your game you can subscribe on the [Mirror Networking Website](https://mirror-networking.com/list-server/) - -### Key features - -- The Cloud Service works via https so it is secure and can be used from any platform. -- It runs on Google Cloud so there is no worry about server downtime. -- It scales really well. Default quota is 1000 API requests per minute. If you have high demands, contact us and we can increase that limit. - -## List Server Examples - -An example for this can be found in [Mirror/Examples/Cloud/](https://github.com/vis2k/Mirror/tree/master/Assets/Mirror/Examples/Cloud) - -*Note: you cannot connect to your own public IP address, you will need at least one other person to test this* - -## How to use - -Add `ApiConnector` component to an object in your game. It is probably best to put this on the same object as your NetworkManager. Once it has been added set the `ApiAddress` and `ApiKey` fields. - -To use `ApiConnector` either directly reference it in an inspector field or get it when your script awakes -```cs -ApiConnector connector; - -void Awake() -{ - connector = FindObjectOfType(); -} -``` - - -The Api calls are grouped into objects. `connector.ListServer.ServerApi` has the Server Api calls like `AddServer`. `connector.ListServer.ClientApi` has the Client Api calls like `GetServerList`. - -### Server Api Example - -Example of how to add server -```cs -void AddServer(int playerCount) -{ - Transport transport = Transport.activeTransport; - - Uri uri = transport.ServerUri(); - int port = uri.Port; - string protocol = uri.Scheme; - - connector.ListServer.ServerApi.AddServer(new ServerJson - { - displayName = "Fun game!!!", - protocol = protocol, - port = port, - maxPlayerCount = NetworkManager.singleton.maxConnections, - playerCount = playerCount - }); -} -``` - -### Client Api Example -Example of how to list servers - -```cs -ApiConnector connector; - -void Awake() -{ - connector = FindObjectOfType(); - // add listener to event that will update UI when Server list is refreshed - connector.ListServer.ClientApi.onServerListUpdated += onServerListUpdated; - - // add listen to button so that player can refresh server list - refreshButton.onClick.AddListener(RefreshButtonHandler); -} - -public void RefreshButtonHandler() -{ - connector.ListServer.ClientApi.GetServerList(); -} - -void onServerListUpdated() -{ - // Update UI here -} -``` - - -## Debug - -If something doesn't seem to be working then here are some tips to help solve the problem - -### Check logs - -Enable `showDebugMessages` on your NetworkManager or use the log level window to enable logging for the cloud scripts - -Below are some example logs to look for to check things are working. - -#### Add Server - -The add request is sent to add a server to the list server - -``` -Request: POST servers {"protocol":"tcp4","port":7777,"playerCount":0,"maxPlayerCount":4,"displayName":"Tanks Game 521","address":"","customAddress":"","customData":[]} -``` -``` -Response: POST 200 /servers {"id":"BI6bQQ2TbNiqhdp1D7UB"} -``` - -#### Update Server - -The object sent in update request maybe be empty, this is sent to keep the server record alive so it shows up. - -The update request can also be used to change info. For example the player count when someone joins or leaves - -``` -Request: PATCH servers/BI6bQQ2TbNiqhdp1D7UB {} -``` -``` -Response: PATCH 204 /servers/BI6bQQ2TbNiqhdp1D7UB -``` - -#### Remove Server - -The remove request is sent to remove a server from the list server. This is automatically called when the ApiConnection is destroyed. - -``` -Request: DELETE servers/BI6bQQ2TbNiqhdp1D7UB -``` -``` -Response: DELETE 204 /servers/BI6bQQ2TbNiqhdp1D7UB -``` - - -#### Get Servers - -The get request is sent in order to get the list of servers. - -The example below shows an array of 2 servers, one with name `Tanks Game 521` and the other with name `Tanks Game 212` - -``` -Request: GET servers -``` -``` -Response: GET 200 /servers {"servers":[{"address":"tcp4://xx.xx.xx.xx:7777","displayName":"Tanks Game 521","port":7777,"protocol":"tcp4","playerCount":0,"maxPlayerCount":4,"customAddress":"","customData":[]},{"address":"tcp4://xx.xx.xx.xx:7777","displayName":"Tanks Game 212","port":7777,"protocol":"tcp4","playerCount":0,"maxPlayerCount":4,"customData":[]}]} -``` -*xx.xx.xx.xx will be the IP address for the server* - - -### Use the QuickListServerDebug - -The QuickListServerDebug script uses `OnGUI` to show the list of servers. This script can be used to check the server list without using Canvas UI. diff --git a/Assets/Mirror/Cloud/README.md.meta b/Assets/Mirror/Cloud/README.md.meta deleted file mode 100644 index d669f54..0000000 --- a/Assets/Mirror/Cloud/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 04945d14ccbed964597a1ee00805c059 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Cloud/version.txt b/Assets/Mirror/Cloud/version.txt deleted file mode 100644 index 7b0bc8d..0000000 --- a/Assets/Mirror/Cloud/version.txt +++ /dev/null @@ -1 +0,0 @@ -MirrorCloudServices v0.1.0 \ No newline at end of file diff --git a/Assets/Mirror/Cloud/version.txt.meta b/Assets/Mirror/Cloud/version.txt.meta deleted file mode 100644 index 1e13fd5..0000000 --- a/Assets/Mirror/Cloud/version.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bf81e376b88e68e48a47531b8bfeb0f4 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/CompilerSymbols.meta b/Assets/Mirror/CompilerSymbols.meta deleted file mode 100644 index 4652ae1..0000000 --- a/Assets/Mirror/CompilerSymbols.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1f8b918bcd89f5c488b06f5574f34760 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef deleted file mode 100644 index af25622..0000000 --- a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Mirror.CompilerSymbols", - "references": [], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta deleted file mode 100644 index 8b23823..0000000 --- a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 325984b52e4128546bc7558552f8b1d2 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs deleted file mode 100644 index f6c4d17..0000000 --- a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using UnityEditor; - -namespace Mirror -{ - static class PreprocessorDefine - { - /// - /// Add define symbols as soon as Unity gets done compiling. - /// - [InitializeOnLoadMethod] - public static void AddDefineSymbols() - { - string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); - HashSet defines = new HashSet(currentDefines.Split(';')) - { - "MIRROR", - "MIRROR_1726_OR_NEWER", - "MIRROR_3_0_OR_NEWER", - "MIRROR_3_12_OR_NEWER", - "MIRROR_4_0_OR_NEWER", - "MIRROR_5_0_OR_NEWER", - "MIRROR_6_0_OR_NEWER", - "MIRROR_7_0_OR_NEWER", - "MIRROR_8_0_OR_NEWER", - "MIRROR_9_0_OR_NEWER", - "MIRROR_10_0_OR_NEWER", - "MIRROR_11_0_OR_NEWER", - "MIRROR_12_0_OR_NEWER", - "MIRROR_13_0_OR_NEWER", - "MIRROR_14_0_OR_NEWER", - "MIRROR_15_0_OR_NEWER", - "MIRROR_16_0_OR_NEWER", - "MIRROR_17_0_OR_NEWER", - "MIRROR_18_0_OR_NEWER", - "MIRROR_24_0_OR_NEWER", - "MIRROR_26_0_OR_NEWER" - }; - - // only touch PlayerSettings if we actually modified it. - // otherwise it shows up as changed in git each time. - string newDefines = string.Join(";", defines); - if (newDefines != currentDefines) - { - PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); - } - } - } -} diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta deleted file mode 100644 index 30806d0..0000000 --- a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f1d66fe74ec6f42dd974cba37d25d453 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components.meta b/Assets/Mirror/Components.meta deleted file mode 100644 index c2771d9..0000000 --- a/Assets/Mirror/Components.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9bee879fbc8ef4b1a9a9f7088bfbf726 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery.meta b/Assets/Mirror/Components/Discovery.meta deleted file mode 100644 index d5bb0cb..0000000 --- a/Assets/Mirror/Components/Discovery.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b5dcf9618f5e14a4eb60bff5480284a6 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs deleted file mode 100644 index dd64a34..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Net; -using UnityEngine; -using UnityEngine.Events; - -namespace Mirror.Discovery -{ - [Serializable] - public class ServerFoundUnityEvent : UnityEvent { }; - - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkDiscovery")] - public class NetworkDiscovery : NetworkDiscoveryBase - { - #region Server - - public long ServerId { get; private set; } - - [Tooltip("Transport to be advertised during discovery")] - public Transport transport; - - [Tooltip("Invoked when a server is found")] - public ServerFoundUnityEvent OnServerFound; - - public override void Start() - { - ServerId = RandomLong(); - - // active transport gets initialized in awake - // so make sure we set it here in Start() (after awakes) - // Or just let the user assign it in the inspector - if (transport == null) - transport = Transport.activeTransport; - - base.Start(); - } - - /// - /// Process the request from a client - /// - /// - /// Override if you wish to provide more information to the clients - /// such as the name of the host player - /// - /// Request comming from client - /// Address of the client that sent the request - /// The message to be sent back to the client or null - protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoint endpoint) - { - // In this case we don't do anything with the request - // but other discovery implementations might want to use the data - // in there, This way the client can ask for - // specific game mode or something - - try - { - // this is an example reply message, return your own - // to include whatever is relevant for your game - return new ServerResponse - { - serverId = ServerId, - uri = transport.ServerUri() - }; - } - catch (NotImplementedException) - { - Debug.LogError($"Transport {transport} does not support network discovery"); - throw; - } - } - - #endregion - - #region Client - - /// - /// Create a message that will be broadcasted on the network to discover servers - /// - /// - /// Override if you wish to include additional data in the discovery message - /// such as desired game mode, language, difficulty, etc... - /// An instance of ServerRequest with data to be broadcasted - protected override ServerRequest GetRequest() => new ServerRequest(); - - /// - /// Process the answer from a server - /// - /// - /// A client receives a reply from a server, this method processes the - /// reply and raises an event - /// - /// Response that came from the server - /// Address of the server that replied - protected override void ProcessResponse(ServerResponse response, IPEndPoint endpoint) - { - // we received a message from the remote endpoint - response.EndPoint = endpoint; - - // although we got a supposedly valid url, we may not be able to resolve - // the provided host - // However we know the real ip address of the server because we just - // received a packet from it, so use that as host. - UriBuilder realUri = new UriBuilder(response.uri) - { - Host = response.EndPoint.Address.ToString() - }; - response.uri = realUri.Uri; - - OnServerFound.Invoke(response); - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta deleted file mode 100644 index c691a61..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c761308e733c51245b2e8bb4201f46dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs deleted file mode 100644 index 394a228..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs +++ /dev/null @@ -1,360 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; -using UnityEngine; - -// Based on https://github.com/EnlightenedOne/MirrorNetworkDiscovery -// forked from https://github.com/in0finite/MirrorNetworkDiscovery -// Both are MIT Licensed - -namespace Mirror.Discovery -{ - /// - /// Base implementation for Network Discovery. Extend this component - /// to provide custom discovery with game specific data - /// NetworkDiscovery for a sample implementation - /// - [DisallowMultipleComponent] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkDiscovery.html")] - public abstract class NetworkDiscoveryBase : MonoBehaviour - where Request : NetworkMessage - where Response : NetworkMessage - { - public static bool SupportedOnThisPlatform { get { return Application.platform != RuntimePlatform.WebGLPlayer; } } - - // each game should have a random unique handshake, this way you can tell if this is the same game or not - [HideInInspector] - public long secretHandshake; - - [SerializeField] - [Tooltip("The UDP port the server will listen for multi-cast messages")] - protected int serverBroadcastListenPort = 47777; - - [SerializeField] - [Tooltip("Time in seconds between multi-cast messages")] - [Range(1, 60)] - float ActiveDiscoveryInterval = 3; - - protected UdpClient serverUdpClient; - protected UdpClient clientUdpClient; - -#if UNITY_EDITOR - void OnValidate() - { - if (secretHandshake == 0) - { - secretHandshake = RandomLong(); - UnityEditor.Undo.RecordObject(this, "Set secret handshake"); - } - } -#endif - - public static long RandomLong() - { - int value1 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); - int value2 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); - return value1 + ((long)value2 << 32); - } - - /// - /// virtual so that inheriting classes' Start() can call base.Start() too - /// - public virtual void Start() - { - // Server mode? then start advertising -#if UNITY_SERVER - AdvertiseServer(); -#endif - } - - // Ensure the ports are cleared no matter when Game/Unity UI exits - void OnApplicationQuit() - { - Shutdown(); - } - - void Shutdown() - { - if (serverUdpClient != null) - { - try - { - serverUdpClient.Close(); - } - catch (Exception) - { - // it is just close, swallow the error - } - - serverUdpClient = null; - } - - if (clientUdpClient != null) - { - try - { - clientUdpClient.Close(); - } - catch (Exception) - { - // it is just close, swallow the error - } - - clientUdpClient = null; - } - - CancelInvoke(); - } - - #region Server - - /// - /// Advertise this server in the local network - /// - public void AdvertiseServer() - { - if (!SupportedOnThisPlatform) - throw new PlatformNotSupportedException("Network discovery not supported in this platform"); - - StopDiscovery(); - - // Setup port -- may throw exception - serverUdpClient = new UdpClient(serverBroadcastListenPort) - { - EnableBroadcast = true, - MulticastLoopback = false - }; - - // listen for client pings - _ = ServerListenAsync(); - } - - public async Task ServerListenAsync() - { - while (true) - { - try - { - await ReceiveRequestAsync(serverUdpClient); - } - catch (ObjectDisposedException) - { - // socket has been closed - break; - } - catch (Exception) - { - } - } - } - - async Task ReceiveRequestAsync(UdpClient udpClient) - { - // only proceed if there is available data in network buffer, or otherwise Receive() will block - // average time for UdpClient.Available : 10 us - - UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); - - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer)) - { - long handshake = networkReader.ReadInt64(); - if (handshake != secretHandshake) - { - // message is not for us - throw new ProtocolViolationException("Invalid handshake"); - } - - Request request = networkReader.Read(); - - ProcessClientRequest(request, udpReceiveResult.RemoteEndPoint); - } - } - - /// - /// Reply to the client to inform it of this server - /// - /// - /// Override if you wish to ignore server requests based on - /// custom criteria such as language, full server game mode or difficulty - /// - /// Request comming from client - /// Address of the client that sent the request - protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint) - { - Response info = ProcessRequest(request, endpoint); - - if (info == null) - return; - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - try - { - writer.WriteInt64(secretHandshake); - - writer.Write(info); - - ArraySegment data = writer.ToArraySegment(); - // signature matches - // send response - serverUdpClient.Send(data.Array, data.Count, endpoint); - } - catch (Exception ex) - { - Debug.LogException(ex, this); - } - } - } - - /// - /// Process the request from a client - /// - /// - /// Override if you wish to provide more information to the clients - /// such as the name of the host player - /// - /// Request comming from client - /// Address of the client that sent the request - /// The message to be sent back to the client or null - protected abstract Response ProcessRequest(Request request, IPEndPoint endpoint); - - #endregion - - #region Client - - /// - /// Start Active Discovery - /// - public void StartDiscovery() - { - if (!SupportedOnThisPlatform) - throw new PlatformNotSupportedException("Network discovery not supported in this platform"); - - StopDiscovery(); - - try - { - // Setup port - clientUdpClient = new UdpClient(0) - { - EnableBroadcast = true, - MulticastLoopback = false - }; - } - catch (Exception) - { - // Free the port if we took it - Shutdown(); - throw; - } - - _ = ClientListenAsync(); - - InvokeRepeating(nameof(BroadcastDiscoveryRequest), 0, ActiveDiscoveryInterval); - } - - /// - /// Stop Active Discovery - /// - public void StopDiscovery() - { - Shutdown(); - } - - /// - /// Awaits for server response - /// - /// ClientListenAsync Task - public async Task ClientListenAsync() - { - while (true) - { - try - { - await ReceiveGameBroadcastAsync(clientUdpClient); - } - catch (ObjectDisposedException) - { - // socket was closed, no problem - return; - } - catch (Exception ex) - { - Debug.LogException(ex); - } - } - } - - /// - /// Sends discovery request from client - /// - public void BroadcastDiscoveryRequest() - { - if (clientUdpClient == null) - return; - - IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, serverBroadcastListenPort); - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - writer.WriteInt64(secretHandshake); - - try - { - Request request = GetRequest(); - - writer.Write(request); - - ArraySegment data = writer.ToArraySegment(); - - clientUdpClient.SendAsync(data.Array, data.Count, endPoint); - } - catch (Exception) - { - // It is ok if we can't broadcast to one of the addresses - } - } - } - - /// - /// Create a message that will be broadcasted on the network to discover servers - /// - /// - /// Override if you wish to include additional data in the discovery message - /// such as desired game mode, language, difficulty, etc... - /// An instance of ServerRequest with data to be broadcasted - protected virtual Request GetRequest() => default; - - async Task ReceiveGameBroadcastAsync(UdpClient udpClient) - { - // only proceed if there is available data in network buffer, or otherwise Receive() will block - // average time for UdpClient.Available : 10 us - - UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); - - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(udpReceiveResult.Buffer)) - { - if (networkReader.ReadInt64() != secretHandshake) - return; - - Response response = networkReader.Read(); - - ProcessResponse(response, udpReceiveResult.RemoteEndPoint); - } - } - - /// - /// Process the answer from a server - /// - /// - /// A client receives a reply from a server, this method processes the - /// reply and raises an event - /// - /// Response that came from the server - /// Address of the server that replied - protected abstract void ProcessResponse(Response response, IPEndPoint endpoint); - - #endregion - } -} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta deleted file mode 100644 index 7dfbaf6..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b9971d60ce61f4e39b07cd9e7e0c68fa -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs deleted file mode 100644 index cfb53d6..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.Discovery -{ - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkDiscoveryHUD")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkDiscovery.html")] - [RequireComponent(typeof(NetworkDiscovery))] - public class NetworkDiscoveryHUD : MonoBehaviour - { - readonly Dictionary discoveredServers = new Dictionary(); - Vector2 scrollViewPos = Vector2.zero; - - public NetworkDiscovery networkDiscovery; - -#if UNITY_EDITOR - void OnValidate() - { - if (networkDiscovery == null) - { - networkDiscovery = GetComponent(); - UnityEditor.Events.UnityEventTools.AddPersistentListener(networkDiscovery.OnServerFound, OnDiscoveredServer); - UnityEditor.Undo.RecordObjects(new Object[] { this, networkDiscovery }, "Set NetworkDiscovery"); - } - } -#endif - - void OnGUI() - { - if (NetworkManager.singleton == null) - return; - - if (NetworkServer.active || NetworkClient.active) - return; - - if (!NetworkClient.isConnected && !NetworkServer.active && !NetworkClient.active) - DrawGUI(); - } - - void DrawGUI() - { - GUILayout.BeginHorizontal(); - - if (GUILayout.Button("Find Servers")) - { - discoveredServers.Clear(); - networkDiscovery.StartDiscovery(); - } - - // LAN Host - if (GUILayout.Button("Start Host")) - { - discoveredServers.Clear(); - NetworkManager.singleton.StartHost(); - networkDiscovery.AdvertiseServer(); - } - - // Dedicated server - if (GUILayout.Button("Start Server")) - { - discoveredServers.Clear(); - NetworkManager.singleton.StartServer(); - - networkDiscovery.AdvertiseServer(); - } - - GUILayout.EndHorizontal(); - - // show list of found server - - GUILayout.Label($"Discovered Servers [{discoveredServers.Count}]:"); - - // servers - scrollViewPos = GUILayout.BeginScrollView(scrollViewPos); - - foreach (ServerResponse info in discoveredServers.Values) - if (GUILayout.Button(info.EndPoint.Address.ToString())) - Connect(info); - - GUILayout.EndScrollView(); - } - - void Connect(ServerResponse info) - { - NetworkManager.singleton.StartClient(info.uri); - } - - public void OnDiscoveredServer(ServerResponse info) - { - // Note that you can check the versioning to decide if you can connect to the server or not using this method - discoveredServers[info.serverId] = info; - } - } -} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta deleted file mode 100644 index f93b275..0000000 --- a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 88c37d3deca7a834d80cfd8d3cfcc510 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs b/Assets/Mirror/Components/Discovery/ServerRequest.cs deleted file mode 100644 index 6c08768..0000000 --- a/Assets/Mirror/Components/Discovery/ServerRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Mirror.Discovery -{ - public struct ServerRequest : NetworkMessage { } -} diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta deleted file mode 100644 index 84f3232..0000000 --- a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ea7254bf7b9454da4adad881d94cd141 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs b/Assets/Mirror/Components/Discovery/ServerResponse.cs deleted file mode 100644 index 7465783..0000000 --- a/Assets/Mirror/Components/Discovery/ServerResponse.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Net; - -namespace Mirror.Discovery -{ - public struct ServerResponse : NetworkMessage - { - // The server that sent this - // this is a property so that it is not serialized, but the - // client fills this up after we receive it - public IPEndPoint EndPoint { get; set; } - - public Uri uri; - - // Prevent duplicate server appearance when a connection can be made via LAN on multiple NICs - public long serverId; - } -} \ No newline at end of file diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta deleted file mode 100644 index 44f23ba..0000000 --- a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 36f97227fdf2d7a4e902db5bfc43039c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental.meta b/Assets/Mirror/Components/Experimental.meta deleted file mode 100644 index 57cce38..0000000 --- a/Assets/Mirror/Components/Experimental.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bfbf2a1f2b300c5489dcab219ef2846e -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs deleted file mode 100644 index 6cfb453..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs +++ /dev/null @@ -1,93 +0,0 @@ -using UnityEngine; - -namespace Mirror.Experimental -{ - [AddComponentMenu("Network/Experimental/NetworkLerpRigidbody")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkLerpRigidbody.html")] - public class NetworkLerpRigidbody : NetworkBehaviour - { - [Header("Settings")] - [SerializeField] internal Rigidbody target = null; - [Tooltip("How quickly current velocity approaches target velocity")] - [SerializeField] float lerpVelocityAmount = 0.5f; - [Tooltip("How quickly current position approaches target position")] - [SerializeField] float lerpPositionAmount = 0.5f; - - [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] - [SerializeField] bool clientAuthority = false; - - float nextSyncTime; - - - [SyncVar()] - Vector3 targetVelocity; - - [SyncVar()] - Vector3 targetPosition; - - /// - /// Ignore value if is host or client with Authority - /// - /// - bool IgnoreSync => isServer || ClientWithAuthority; - - bool ClientWithAuthority => clientAuthority && hasAuthority; - - void OnValidate() - { - if (target == null) - { - target = GetComponent(); - } - } - - void Update() - { - if (isServer) - { - SyncToClients(); - } - else if (ClientWithAuthority) - { - SendToServer(); - } - } - - private void SyncToClients() - { - targetVelocity = target.velocity; - targetPosition = target.position; - } - - private void SendToServer() - { - float now = Time.time; - if (now > nextSyncTime) - { - nextSyncTime = now + syncInterval; - CmdSendState(target.velocity, target.position); - } - } - - [Command] - private void CmdSendState(Vector3 velocity, Vector3 position) - { - target.velocity = velocity; - target.position = position; - targetVelocity = velocity; - targetPosition = position; - } - - void FixedUpdate() - { - if (IgnoreSync) { return; } - - target.velocity = Vector3.Lerp(target.velocity, targetVelocity, lerpVelocityAmount); - target.position = Vector3.Lerp(target.position, targetPosition, lerpPositionAmount); - // add velocity to position as position would have moved on server at that velocity - targetPosition += target.velocity * Time.fixedDeltaTime; - - // TODO does this also need to sync acceleration so and update velocity? - } - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta b/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta deleted file mode 100644 index 35ef1fe..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkLerpRigidbody.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7f032128052c95a46afb0ddd97d994cc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs deleted file mode 100644 index fe85158..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs +++ /dev/null @@ -1,363 +0,0 @@ -using UnityEngine; - -namespace Mirror.Experimental -{ - [AddComponentMenu("Network/Experimental/NetworkRigidbody")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkRigidbody.html")] - public class NetworkRigidbody : NetworkBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkRigidbody)); - - [Header("Settings")] - [SerializeField] internal Rigidbody target = null; - - [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] - [SerializeField] bool clientAuthority = false; - - [Header("Velocity")] - - [Tooltip("Syncs Velocity every SyncInterval")] - [SerializeField] bool syncVelocity = true; - - [Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")] - [SerializeField] bool clearVelocity = false; - - [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] - [SerializeField] float velocitySensitivity = 0.1f; - - - [Header("Angular Velocity")] - - [Tooltip("Syncs AngularVelocity every SyncInterval")] - [SerializeField] bool syncAngularVelocity = true; - - [Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")] - [SerializeField] bool clearAngularVelocity = false; - - [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] - [SerializeField] float angularVelocitySensitivity = 0.1f; - - /// - /// Values sent on client with authoirty after they are sent to the server - /// - readonly ClientSyncState previousValue = new ClientSyncState(); - - void OnValidate() - { - if (target == null) - { - target = GetComponent(); - } - } - - - #region Sync vars - [SyncVar(hook = nameof(OnVelocityChanged))] - Vector3 velocity; - - [SyncVar(hook = nameof(OnAngularVelocityChanged))] - Vector3 angularVelocity; - - [SyncVar(hook = nameof(OnIsKinematicChanged))] - bool isKinematic; - - [SyncVar(hook = nameof(OnUseGravityChanged))] - bool useGravity; - - [SyncVar(hook = nameof(OnuDragChanged))] - float drag; - - [SyncVar(hook = nameof(OnAngularDragChanged))] - float angularDrag; - - /// - /// Ignore value if is host or client with Authority - /// - /// - bool IgnoreSync => isServer || ClientWithAuthority; - - bool ClientWithAuthority => clientAuthority && hasAuthority; - - void OnVelocityChanged(Vector3 _, Vector3 newValue) - { - if (IgnoreSync) - return; - - target.velocity = newValue; - } - - - void OnAngularVelocityChanged(Vector3 _, Vector3 newValue) - { - if (IgnoreSync) - return; - - target.angularVelocity = newValue; - } - - void OnIsKinematicChanged(bool _, bool newValue) - { - if (IgnoreSync) - return; - - target.isKinematic = newValue; - } - - void OnUseGravityChanged(bool _, bool newValue) - { - if (IgnoreSync) - return; - - target.useGravity = newValue; - } - - void OnuDragChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.drag = newValue; - } - - void OnAngularDragChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.angularDrag = newValue; - } - #endregion - - - internal void Update() - { - if (isServer) - { - SyncToClients(); - } - else if (ClientWithAuthority) - { - SendToServer(); - } - } - - internal void FixedUpdate() - { - if (clearAngularVelocity && !syncAngularVelocity) - { - target.angularVelocity = Vector3.zero; - } - - if (clearVelocity && !syncVelocity) - { - target.velocity = Vector3.zero; - } - } - - /// - /// Updates sync var values on server so that they sync to the client - /// - [Server] - void SyncToClients() - { - // only update if they have changed more than Sensitivity - - Vector3 currentVelocity = syncVelocity ? target.velocity : default; - Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; - - bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); - bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); - - if (velocityChanged) - { - velocity = currentVelocity; - previousValue.velocity = currentVelocity; - } - - if (angularVelocityChanged) - { - angularVelocity = currentAngularVelocity; - previousValue.angularVelocity = currentAngularVelocity; - } - - // other rigidbody settings - isKinematic = target.isKinematic; - useGravity = target.useGravity; - drag = target.drag; - angularDrag = target.angularDrag; - } - - /// - /// Uses Command to send values to server - /// - [Client] - void SendToServer() - { - if (!hasAuthority) - { - logger.LogWarning("SendToServer called without authority"); - return; - } - - SendVelocity(); - SendRigidBodySettings(); - } - - [Client] - void SendVelocity() - { - float now = Time.time; - if (now < previousValue.nextSyncTime) - return; - - Vector3 currentVelocity = syncVelocity ? target.velocity : default; - Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; - - bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); - bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); - - // if angularVelocity has changed it is likely that velocity has also changed so just sync both values - // however if only velocity has changed just send velocity - if (angularVelocityChanged) - { - CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity); - previousValue.velocity = currentVelocity; - previousValue.angularVelocity = currentAngularVelocity; - } - else if (velocityChanged) - { - CmdSendVelocity(currentVelocity); - previousValue.velocity = currentVelocity; - } - - - // only update syncTime if either has changed - if (angularVelocityChanged || velocityChanged) - { - previousValue.nextSyncTime = now + syncInterval; - } - } - - [Client] - void SendRigidBodySettings() - { - // These shouldn't change often so it is ok to send in their own Command - if (previousValue.isKinematic != target.isKinematic) - { - CmdSendIsKinematic(target.isKinematic); - previousValue.isKinematic = target.isKinematic; - } - if (previousValue.useGravity != target.useGravity) - { - CmdSendUseGravity(target.useGravity); - previousValue.useGravity = target.useGravity; - } - if (previousValue.drag != target.drag) - { - CmdSendDrag(target.drag); - previousValue.drag = target.drag; - } - if (previousValue.angularDrag != target.angularDrag) - { - CmdSendAngularDrag(target.angularDrag); - previousValue.angularDrag = target.angularDrag; - } - } - - /// - /// Called when only Velocity has changed on the client - /// - [Command] - void CmdSendVelocity(Vector3 velocity) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.velocity = velocity; - target.velocity = velocity; - } - - /// - /// Called when angularVelocity has changed on the client - /// - [Command] - void CmdSendVelocityAndAngular(Vector3 velocity, Vector3 angularVelocity) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - if (syncVelocity) - { - this.velocity = velocity; - - target.velocity = velocity; - - } - this.angularVelocity = angularVelocity; - target.angularVelocity = angularVelocity; - } - - [Command] - void CmdSendIsKinematic(bool isKinematic) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.isKinematic = isKinematic; - target.isKinematic = isKinematic; - } - - [Command] - void CmdSendUseGravity(bool useGravity) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.useGravity = useGravity; - target.useGravity = useGravity; - } - - [Command] - void CmdSendDrag(float drag) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.drag = drag; - target.drag = drag; - } - - [Command] - void CmdSendAngularDrag(float angularDrag) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.angularDrag = angularDrag; - target.angularDrag = angularDrag; - } - - /// - /// holds previously synced values - /// - public class ClientSyncState - { - /// - /// Next sync time that velocity will be synced, based on syncInterval. - /// - public float nextSyncTime; - public Vector3 velocity; - public Vector3 angularVelocity; - public bool isKinematic; - public bool useGravity; - public float drag; - public float angularDrag; - } - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta b/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta deleted file mode 100644 index 1610f0a..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 83392ae5c1b731446909f252fd494ae4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs deleted file mode 100644 index 616f99d..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs +++ /dev/null @@ -1,362 +0,0 @@ -using UnityEngine; - -namespace Mirror.Experimental -{ - [AddComponentMenu("Network/Experimental/NetworkRigidbody2D")] - public class NetworkRigidbody2D : NetworkBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkRigidbody2D)); - - [Header("Settings")] - [SerializeField] internal Rigidbody2D target = null; - - [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] - [SerializeField] bool clientAuthority = false; - - [Header("Velocity")] - - [Tooltip("Syncs Velocity every SyncInterval")] - [SerializeField] bool syncVelocity = true; - - [Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")] - [SerializeField] bool clearVelocity = false; - - [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] - [SerializeField] float velocitySensitivity = 0.1f; - - - [Header("Angular Velocity")] - - [Tooltip("Syncs AngularVelocity every SyncInterval")] - [SerializeField] bool syncAngularVelocity = true; - - [Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")] - [SerializeField] bool clearAngularVelocity = false; - - [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")] - [SerializeField] float angularVelocitySensitivity = 0.1f; - - /// - /// Values sent on client with authoirty after they are sent to the server - /// - readonly ClientSyncState previousValue = new ClientSyncState(); - - void OnValidate() - { - if (target == null) - { - target = GetComponent(); - } - } - - - #region Sync vars - [SyncVar(hook = nameof(OnVelocityChanged))] - Vector2 velocity; - - [SyncVar(hook = nameof(OnAngularVelocityChanged))] - float angularVelocity; - - [SyncVar(hook = nameof(OnIsKinematicChanged))] - bool isKinematic; - - [SyncVar(hook = nameof(OnGravityScaleChanged))] - float gravityScale; - - [SyncVar(hook = nameof(OnuDragChanged))] - float drag; - - [SyncVar(hook = nameof(OnAngularDragChanged))] - float angularDrag; - - /// - /// Ignore value if is host or client with Authority - /// - /// - bool IgnoreSync => isServer || ClientWithAuthority; - - bool ClientWithAuthority => clientAuthority && hasAuthority; - - void OnVelocityChanged(Vector2 _, Vector2 newValue) - { - if (IgnoreSync) - return; - - target.velocity = newValue; - } - - - void OnAngularVelocityChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.angularVelocity = newValue; - } - - void OnIsKinematicChanged(bool _, bool newValue) - { - if (IgnoreSync) - return; - - target.isKinematic = newValue; - } - - void OnGravityScaleChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.gravityScale = newValue; - } - - void OnuDragChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.drag = newValue; - } - - void OnAngularDragChanged(float _, float newValue) - { - if (IgnoreSync) - return; - - target.angularDrag = newValue; - } - #endregion - - - internal void Update() - { - if (isServer) - { - SyncToClients(); - } - else if (ClientWithAuthority) - { - SendToServer(); - } - } - - internal void FixedUpdate() - { - if (clearAngularVelocity && !syncAngularVelocity) - { - target.angularVelocity = 0f; - } - - if (clearVelocity && !syncVelocity) - { - target.velocity = Vector2.zero; - } - } - - /// - /// Updates sync var values on server so that they sync to the client - /// - [Server] - void SyncToClients() - { - // only update if they have changed more than Sensitivity - - Vector2 currentVelocity = syncVelocity ? target.velocity : default; - float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; - - bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); - bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity) > angularVelocitySensitivity); - - if (velocityChanged) - { - velocity = currentVelocity; - previousValue.velocity = currentVelocity; - } - - if (angularVelocityChanged) - { - angularVelocity = currentAngularVelocity; - previousValue.angularVelocity = currentAngularVelocity; - } - - // other rigidbody settings - isKinematic = target.isKinematic; - gravityScale = target.gravityScale; - drag = target.drag; - angularDrag = target.angularDrag; - } - - /// - /// Uses Command to send values to server - /// - [Client] - void SendToServer() - { - if (!hasAuthority) - { - logger.LogWarning("SendToServer called without authority"); - return; - } - - SendVelocity(); - SendRigidBodySettings(); - } - - [Client] - void SendVelocity() - { - float now = Time.time; - if (now < previousValue.nextSyncTime) - return; - - Vector2 currentVelocity = syncVelocity ? target.velocity : default; - float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default; - - bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity); - bool angularVelocityChanged = syncAngularVelocity && previousValue.angularVelocity != currentAngularVelocity;//((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity); - - // if angularVelocity has changed it is likely that velocity has also changed so just sync both values - // however if only velocity has changed just send velocity - if (angularVelocityChanged) - { - CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity); - previousValue.velocity = currentVelocity; - previousValue.angularVelocity = currentAngularVelocity; - } - else if (velocityChanged) - { - CmdSendVelocity(currentVelocity); - previousValue.velocity = currentVelocity; - } - - - // only update syncTime if either has changed - if (angularVelocityChanged || velocityChanged) - { - previousValue.nextSyncTime = now + syncInterval; - } - } - - [Client] - void SendRigidBodySettings() - { - // These shouldn't change often so it is ok to send in their own Command - if (previousValue.isKinematic != target.isKinematic) - { - CmdSendIsKinematic(target.isKinematic); - previousValue.isKinematic = target.isKinematic; - } - if (previousValue.gravityScale != target.gravityScale) - { - CmdChangeGravityScale(target.gravityScale); - previousValue.gravityScale = target.gravityScale; - } - if (previousValue.drag != target.drag) - { - CmdSendDrag(target.drag); - previousValue.drag = target.drag; - } - if (previousValue.angularDrag != target.angularDrag) - { - CmdSendAngularDrag(target.angularDrag); - previousValue.angularDrag = target.angularDrag; - } - } - - /// - /// Called when only Velocity has changed on the client - /// - [Command] - void CmdSendVelocity(Vector2 velocity) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.velocity = velocity; - target.velocity = velocity; - } - - /// - /// Called when angularVelocity has changed on the client - /// - [Command] - void CmdSendVelocityAndAngular(Vector2 velocity, float angularVelocity) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - if (syncVelocity) - { - this.velocity = velocity; - - target.velocity = velocity; - - } - this.angularVelocity = angularVelocity; - target.angularVelocity = angularVelocity; - } - - [Command] - void CmdSendIsKinematic(bool isKinematic) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.isKinematic = isKinematic; - target.isKinematic = isKinematic; - } - - [Command] - void CmdChangeGravityScale(float gravityScale) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.gravityScale = gravityScale; - target.gravityScale = gravityScale; - } - - [Command] - void CmdSendDrag(float drag) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.drag = drag; - target.drag = drag; - } - - [Command] - void CmdSendAngularDrag(float angularDrag) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - this.angularDrag = angularDrag; - target.angularDrag = angularDrag; - } - - /// - /// holds previously synced values - /// - public class ClientSyncState - { - /// - /// Next sync time that velocity will be synced, based on syncInterval. - /// - public float nextSyncTime; - public Vector2 velocity; - public float angularVelocity; - public bool isKinematic; - public float gravityScale; - public float drag; - public float angularDrag; - } - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta b/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta deleted file mode 100644 index df466bd..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ab2cbc52526ea384ba280d13cd1a57b9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkTransform.cs b/Assets/Mirror/Components/Experimental/NetworkTransform.cs deleted file mode 100644 index 288a5e6..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransform.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace Mirror.Experimental -{ - [DisallowMultipleComponent] - [AddComponentMenu("Network/Experimental/NetworkTransformExperimental")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkTransform.html")] - public class NetworkTransform : NetworkTransformBase - { - protected override Transform targetTransform => transform; - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta deleted file mode 100644 index 2bc16dd..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransform.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 741bbe11f5357b44593b15c0d11b16bd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs deleted file mode 100644 index 9e03218..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs +++ /dev/null @@ -1,529 +0,0 @@ -// vis2k: -// base class for NetworkTransform and NetworkTransformChild. -// New method is simple and stupid. No more 1500 lines of code. -// -// Server sends current data. -// Client saves it and interpolates last and latest data points. -// Update handles transform movement / rotation -// FixedUpdate handles rigidbody movement / rotation -// -// Notes: -// * Built-in Teleport detection in case of lags / teleport / obstacles -// * Quaternion > EulerAngles because gimbal lock and Quaternion.Slerp -// * Syncs XYZ. Works 3D and 2D. Saving 4 bytes isn't worth 1000 lines of code. -// * Initial delay might happen if server sends packet immediately after moving -// just 1cm, hence we move 1cm and then wait 100ms for next packet -// * Only way for smooth movement is to use a fixed movement speed during -// interpolation. interpolation over time is never that good. -// -using System; -using UnityEngine; - -namespace Mirror.Experimental -{ - public abstract class NetworkTransformBase : NetworkBehaviour - { - // target transform to sync. can be on a child. - protected abstract Transform targetTransform { get; } - - [Header("Authority")] - - [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] - [SyncVar] - public bool clientAuthority; - - [Tooltip("Set to true if updates from server should be ignored by owner")] - [SyncVar] - public bool excludeOwnerUpdate = true; - - [Header("Synchronization")] - - [Tooltip("Set to true if position should be synchronized")] - [SyncVar] - public bool syncPosition = true; - - [Tooltip("Set to true if rotation should be synchronized")] - [SyncVar] - public bool syncRotation = true; - - [Tooltip("Set to true if scale should be synchronized")] - [SyncVar] - public bool syncScale = true; - - [Header("Interpolation")] - - [Tooltip("Set to true if position should be interpolated")] - [SyncVar] - public bool interpolatePosition = true; - - [Tooltip("Set to true if rotation should be interpolated")] - [SyncVar] - public bool interpolateRotation = true; - - [Tooltip("Set to true if scale should be interpolated")] - [SyncVar] - public bool interpolateScale = true; - - // Sensitivity is added for VR where human players tend to have micro movements so this can quiet down - // the network traffic. Additionally, rigidbody drift should send less traffic, e.g very slow sliding / rolling. - [Header("Sensitivity")] - - [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] - [SyncVar] - public float localPositionSensitivity = .01f; - - [Tooltip("If rotation exceeds this angle, it will be transmitted on the network")] - [SyncVar] - public float localRotationSensitivity = .01f; - - [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] - [SyncVar] - public float localScaleSensitivity = .01f; - - [Header("Diagnostics")] - - // server - public Vector3 lastPosition; - public Quaternion lastRotation; - public Vector3 lastScale; - - // client - // use local position/rotation for VR support - [Serializable] - public struct DataPoint - { - public float timeStamp; - public Vector3 localPosition; - public Quaternion localRotation; - public Vector3 localScale; - public float movementSpeed; - - public bool isValid => timeStamp != 0; - } - - // Is this a client with authority over this transform? - // This component could be on the player object or any object that has been assigned authority to this client. - bool IsOwnerWithClientAuthority => hasAuthority && clientAuthority; - - // interpolation start and goal - public DataPoint start = new DataPoint(); - public DataPoint goal = new DataPoint(); - - // We need to store this locally on the server so clients can't request Authority when ever they like - bool clientAuthorityBeforeTeleport; - - void FixedUpdate() - { - // if server then always sync to others. - // let the clients know that this has moved - if (isServer && HasEitherMovedRotatedScaled()) - { - ServerUpdate(); - } - - if (isClient) - { - // send to server if we have local authority (and aren't the server) - // -> only if connectionToServer has been initialized yet too - if (IsOwnerWithClientAuthority) - { - ClientAuthorityUpdate(); - } - else if (goal.isValid) - { - ClientRemoteUpdate(); - } - } - } - - void ServerUpdate() - { - RpcMove(targetTransform.localPosition, targetTransform.localRotation, targetTransform.localScale); - } - - void ClientAuthorityUpdate() - { - if (!isServer && HasEitherMovedRotatedScaled()) - { - // serialize - // local position/rotation for VR support - // send to server - CmdClientToServerSync(targetTransform.localPosition, targetTransform.localRotation, targetTransform.localScale); - } - } - - void ClientRemoteUpdate() - { - // teleport or interpolate - if (NeedsTeleport()) - { - // local position/rotation for VR support - ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); - - // reset data points so we don't keep interpolating - start = new DataPoint(); - goal = new DataPoint(); - } - else - { - // local position/rotation for VR support - ApplyPositionRotationScale(InterpolatePosition(start, goal, targetTransform.localPosition), - InterpolateRotation(start, goal, targetTransform.localRotation), - InterpolateScale(start, goal, targetTransform.localScale)); - } - } - - // moved or rotated or scaled since last time we checked it? - bool HasEitherMovedRotatedScaled() - { - // Save last for next frame to compare only if change was detected, otherwise - // slow moving objects might never sync because of C#'s float comparison tolerance. - // See also: https://github.com/vis2k/Mirror/pull/428) - bool changed = HasMoved || HasRotated || HasScaled; - if (changed) - { - // local position/rotation for VR support - if (syncPosition) lastPosition = targetTransform.localPosition; - if (syncRotation) lastRotation = targetTransform.localRotation; - if (syncScale) lastScale = targetTransform.localScale; - } - return changed; - } - - // local position/rotation for VR support - // SqrMagnitude is faster than Distance per Unity docs - // https://docs.unity3d.com/ScriptReference/Vector3-sqrMagnitude.html - - bool HasMoved => syncPosition && Vector3.SqrMagnitude(lastPosition - targetTransform.localPosition) > localPositionSensitivity * localPositionSensitivity; - bool HasRotated => syncRotation && Quaternion.Angle(lastRotation, targetTransform.localRotation) > localRotationSensitivity; - bool HasScaled => syncScale && Vector3.SqrMagnitude(lastScale - targetTransform.localScale) > localScaleSensitivity * localScaleSensitivity; - - // teleport / lag / stuck detection - // - checking distance is not enough since there could be just a tiny fence between us and the goal - // - checking time always works, this way we just teleport if we still didn't reach the goal after too much time has elapsed - bool NeedsTeleport() - { - // calculate time between the two data points - float startTime = start.isValid ? start.timeStamp : Time.time - Time.fixedDeltaTime; - float goalTime = goal.isValid ? goal.timeStamp : Time.time; - float difference = goalTime - startTime; - float timeSinceGoalReceived = Time.time - goalTime; - return timeSinceGoalReceived > difference * 5; - } - - // local authority client sends sync message to server for broadcasting - [Command] - void CmdClientToServerSync(Vector3 position, Quaternion rotation, Vector3 scale) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - // deserialize payload - SetGoal(position, rotation, scale); - - // server-only mode does no interpolation to save computations, but let's set the position directly - if (isServer && !isClient) - ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); - - RpcMove(position, rotation, scale); - } - - [ClientRpc] - void RpcMove(Vector3 position, Quaternion rotation, Vector3 scale) - { - if (hasAuthority && excludeOwnerUpdate) return; - - if (!isServer) - SetGoal(position, rotation, scale); - } - - // serialization is needed by OnSerialize and by manual sending from authority - void SetGoal(Vector3 position, Quaternion rotation, Vector3 scale) - { - // put it into a data point immediately - DataPoint temp = new DataPoint - { - // deserialize position - localPosition = position, - localRotation = rotation, - localScale = scale, - timeStamp = Time.time - }; - - // movement speed: based on how far it moved since last time has to be calculated before 'start' is overwritten - temp.movementSpeed = EstimateMovementSpeed(goal, temp, targetTransform, Time.fixedDeltaTime); - - // reassign start wisely - // first ever data point? then make something up for previous one so that we can start interpolation without waiting for next. - if (start.timeStamp == 0) - { - start = new DataPoint - { - timeStamp = Time.time - Time.fixedDeltaTime, - // local position/rotation for VR support - localPosition = targetTransform.localPosition, - localRotation = targetTransform.localRotation, - localScale = targetTransform.localScale, - movementSpeed = temp.movementSpeed - }; - } - // second or nth data point? then update previous - // but: we start at where ever we are right now, so that it's perfectly smooth and we don't jump anywhere - // - // example if we are at 'x': - // - // A--x->B - // - // and then receive a new point C: - // - // A--x--B - // | - // | - // C - // - // then we don't want to just jump to B and start interpolation: - // - // x - // | - // | - // C - // - // we stay at 'x' and interpolate from there to C: - // - // x..B - // \ . - // \. - // C - // - else - { - float oldDistance = Vector3.Distance(start.localPosition, goal.localPosition); - float newDistance = Vector3.Distance(goal.localPosition, temp.localPosition); - - start = goal; - - // local position/rotation for VR support - // teleport / lag / obstacle detection: only continue at current position if we aren't too far away - // XC < AB + BC (see comments above) - if (Vector3.Distance(targetTransform.localPosition, start.localPosition) < oldDistance + newDistance) - { - start.localPosition = targetTransform.localPosition; - start.localRotation = targetTransform.localRotation; - start.localScale = targetTransform.localScale; - } - } - - // set new destination in any case. new data is best data. - goal = temp; - } - - // try to estimate movement speed for a data point based on how far it moved since the previous one - // - if this is the first time ever then we use our best guess: - // - delta based on transform.localPosition - // - elapsed based on send interval hoping that it roughly matches - static float EstimateMovementSpeed(DataPoint from, DataPoint to, Transform transform, float sendInterval) - { - Vector3 delta = to.localPosition - (from.localPosition != transform.localPosition ? from.localPosition : transform.localPosition); - float elapsed = from.isValid ? to.timeStamp - from.timeStamp : sendInterval; - - // avoid NaN - return elapsed > 0 ? delta.magnitude / elapsed : 0; - } - - // set position carefully depending on the target component - void ApplyPositionRotationScale(Vector3 position, Quaternion rotation, Vector3 scale) - { - // local position/rotation for VR support - if (syncPosition) targetTransform.localPosition = position; - if (syncRotation) targetTransform.localRotation = rotation; - if (syncScale) targetTransform.localScale = scale; - } - - // where are we in the timeline between start and goal? [0,1] - Vector3 InterpolatePosition(DataPoint start, DataPoint goal, Vector3 currentPosition) - { - if (!interpolatePosition) - return currentPosition; - - if (start.movementSpeed != 0) - { - // Option 1: simply interpolate based on time, but stutter will happen, it's not that smooth. - // This is especially noticeable if the camera automatically follows the player - // - Tell SonarCloud this isn't really commented code but actual comments and to stfu about it - // - float t = CurrentInterpolationFactor(); - // - return Vector3.Lerp(start.position, goal.position, t); - - // Option 2: always += speed - // speed is 0 if we just started after idle, so always use max for best results - float speed = Mathf.Max(start.movementSpeed, goal.movementSpeed); - return Vector3.MoveTowards(currentPosition, goal.localPosition, speed * Time.deltaTime); - } - - return currentPosition; - } - - Quaternion InterpolateRotation(DataPoint start, DataPoint goal, Quaternion defaultRotation) - { - if (!interpolateRotation) - return defaultRotation; - - if (start.localRotation != goal.localRotation) - { - float t = CurrentInterpolationFactor(start, goal); - return Quaternion.Slerp(start.localRotation, goal.localRotation, t); - } - - return defaultRotation; - } - - Vector3 InterpolateScale(DataPoint start, DataPoint goal, Vector3 currentScale) - { - if (!interpolateScale) - return currentScale; - - if (start.localScale != goal.localScale) - { - float t = CurrentInterpolationFactor(start, goal); - return Vector3.Lerp(start.localScale, goal.localScale, t); - } - - return currentScale; - } - - static float CurrentInterpolationFactor(DataPoint start, DataPoint goal) - { - if (start.isValid) - { - float difference = goal.timeStamp - start.timeStamp; - - // the moment we get 'goal', 'start' is supposed to start, so elapsed time is based on: - float elapsed = Time.time - goal.timeStamp; - - // avoid NaN - return difference > 0 ? elapsed / difference : 1; - } - return 1; - } - - #region Server Teleport (force move player) - - /// - /// This method will override this GameObject's current Transform.localPosition to the specified Vector3 and update all clients. - /// NOTE: position must be in LOCAL space if the transform has a parent - /// - /// Where to teleport this GameObject - [Server] - public void ServerTeleport(Vector3 localPosition) - { - Quaternion localRotation = targetTransform.localRotation; - ServerTeleport(localPosition, localRotation); - } - - /// - /// This method will override this GameObject's current Transform.localPosition and Transform.localRotation - /// to the specified Vector3 and Quaternion and update all clients. - /// NOTE: localPosition must be in LOCAL space if the transform has a parent - /// NOTE: localRotation must be in LOCAL space if the transform has a parent - /// - /// Where to teleport this GameObject - /// Which rotation to set this GameObject - [Server] - public void ServerTeleport(Vector3 localPosition, Quaternion localRotation) - { - // To prevent applying the position updates received from client (if they have ClientAuth) while being teleported. - // clientAuthorityBeforeTeleport defaults to false when not teleporting, if it is true then it means that teleport - // was previously called but not finished therefore we should keep it as true so that 2nd teleport call doesn't clear authority - clientAuthorityBeforeTeleport = clientAuthority || clientAuthorityBeforeTeleport; - clientAuthority = false; - - DoTeleport(localPosition, localRotation); - - // tell all clients about new values - RpcTeleport(localPosition, localRotation, clientAuthorityBeforeTeleport); - } - - void DoTeleport(Vector3 newLocalPosition, Quaternion newLocalRotation) - { - targetTransform.localPosition = newLocalPosition; - targetTransform.localRotation = newLocalRotation; - - // Since we are overriding the position we don't need a goal and start. - // Reset them to null for fresh start - goal = new DataPoint(); - start = new DataPoint(); - lastPosition = newLocalPosition; - lastRotation = newLocalRotation; - } - - [ClientRpc] - void RpcTeleport(Vector3 newPosition, Quaternion newRotation, bool isClientAuthority) - { - DoTeleport(newPosition, newRotation); - - // only send finished if is owner and is ClientAuthority on server - if (hasAuthority && isClientAuthority) - CmdTeleportFinished(); - } - - /// - /// This RPC will be invoked on server after client finishes overriding the position. - /// - /// - [Command] - void CmdTeleportFinished() - { - if (clientAuthorityBeforeTeleport) - { - clientAuthority = true; - - // reset value so doesnt effect future calls, see note in ServerTeleport - clientAuthorityBeforeTeleport = false; - } - else - { - Debug.LogWarning("Client called TeleportFinished when clientAuthority was false on server", this); - } - } - - #endregion - - #region Debug Gizmos - - // draw the data points for easier debugging - void OnDrawGizmos() - { - // draw start and goal points and a line between them - if (start.localPosition != goal.localPosition) - { - DrawDataPointGizmo(start, Color.yellow); - DrawDataPointGizmo(goal, Color.green); - DrawLineBetweenDataPoints(start, goal, Color.cyan); - } - } - - static void DrawDataPointGizmo(DataPoint data, Color color) - { - // use a little offset because transform.localPosition might be in the ground in many cases - Vector3 offset = Vector3.up * 0.01f; - - // draw position - Gizmos.color = color; - Gizmos.DrawSphere(data.localPosition + offset, 0.5f); - - // draw forward and up like unity move tool - Gizmos.color = Color.blue; - Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.forward); - Gizmos.color = Color.green; - Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.up); - } - - static void DrawLineBetweenDataPoints(DataPoint data1, DataPoint data2, Color color) - { - Gizmos.color = color; - Gizmos.DrawLine(data1.localPosition, data2.localPosition); - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta deleted file mode 100644 index d737bed..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransformBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ea7c690c4fbf8c4439726f4c62eda6d3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs deleted file mode 100644 index 4494bd1..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs +++ /dev/null @@ -1,18 +0,0 @@ -using UnityEngine; - -namespace Mirror.Experimental -{ - /// - /// A component to synchronize the position of child transforms of networked objects. - /// There must be a NetworkTransform on the root object of the hierarchy. There can be multiple NetworkTransformChild components on an object. This does not use physics for synchronization, it simply synchronizes the localPosition and localRotation of the child transform and lerps towards the recieved values. - /// - [AddComponentMenu("Network/Experimental/NetworkTransformChildExperimentalExperimental")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkTransformChild.html")] - public class NetworkTransformChild : NetworkTransformBase - { - [Header("Target")] - public Transform target; - - protected override Transform targetTransform => target; - } -} diff --git a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta b/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta deleted file mode 100644 index 30f0d89..0000000 --- a/Assets/Mirror/Components/Experimental/NetworkTransformChild.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f65214da13a861f4a8ae309d3daea1c6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef b/Assets/Mirror/Components/Mirror.Components.asmdef deleted file mode 100644 index a61c7db..0000000 --- a/Assets/Mirror/Components/Mirror.Components.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Mirror.Components", - "references": [ - "Mirror" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef.meta b/Assets/Mirror/Components/Mirror.Components.asmdef.meta deleted file mode 100644 index 263b6f0..0000000 --- a/Assets/Mirror/Components/Mirror.Components.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 72872094b21c16e48b631b2224833d49 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkAnimator.cs b/Assets/Mirror/Components/NetworkAnimator.cs deleted file mode 100644 index 47cf158..0000000 --- a/Assets/Mirror/Components/NetworkAnimator.cs +++ /dev/null @@ -1,636 +0,0 @@ -using System.Linq; -using UnityEngine; -using UnityEngine.Serialization; - -namespace Mirror -{ - /// - /// A component to synchronize Mecanim animation states for networked objects. - /// - /// - /// The animation of game objects can be networked by this component. There are two models of authority for networked movement: - /// If the object has authority on the client, then it should be animated locally on the owning client. The animation state information will be sent from the owning client to the server, then broadcast to all of the other clients. This is common for player objects. - /// If the object has authority on the server, then it should be animated on the server and state information will be sent to all clients. This is common for objects not related to a specific client, such as an enemy unit. - /// The NetworkAnimator synchronizes all animation parameters of the selected Animator. It does not automatically sychronize triggers. The function SetTrigger can by used by an object with authority to fire an animation trigger on other clients. - /// - [AddComponentMenu("Network/NetworkAnimator")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkAnimator.html")] - public class NetworkAnimator : NetworkBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkAnimator)); - - [Header("Authority")] - [Tooltip("Set to true if animations come from owner client, set to false if animations always come from server")] - public bool clientAuthority; - - /// - /// The animator component to synchronize. - /// - [FormerlySerializedAs("m_Animator")] - [Header("Animator")] - [Tooltip("Animator that will have parameters synchronized")] - public Animator animator; - - - /// - /// Syncs animator.speed - /// - [SyncVar(hook = nameof(onAnimatorSpeedChanged))] - float animatorSpeed; - float previousSpeed; - - // Note: not an object[] array because otherwise initialization is real annoying - int[] lastIntParameters; - float[] lastFloatParameters; - bool[] lastBoolParameters; - AnimatorControllerParameter[] parameters; - - // multiple layers - int[] animationHash; - int[] transitionHash; - float[] layerWeight; - float nextSendTime; - - bool SendMessagesAllowed - { - get - { - if (isServer) - { - if (!clientAuthority) - return true; - - // This is a special case where we have client authority but we have not assigned the client who has - // authority over it, no animator data will be sent over the network by the server. - // - // So we check here for a connectionToClient and if it is null we will - // let the server send animation data until we receive an owner. - if (netIdentity != null && netIdentity.connectionToClient == null) - return true; - } - - return (hasAuthority && clientAuthority); - } - } - - void Awake() - { - // store the animator parameters in a variable - the "Animator.parameters" getter allocates - // a new parameter array every time it is accessed so we should avoid doing it in a loop - parameters = animator.parameters - .Where(par => !animator.IsParameterControlledByCurve(par.nameHash)) - .ToArray(); - lastIntParameters = new int[parameters.Length]; - lastFloatParameters = new float[parameters.Length]; - lastBoolParameters = new bool[parameters.Length]; - - animationHash = new int[animator.layerCount]; - transitionHash = new int[animator.layerCount]; - layerWeight = new float[animator.layerCount]; - } - - void FixedUpdate() - { - if (!SendMessagesAllowed) - return; - - if (!animator.enabled) - return; - - CheckSendRate(); - - for (int i = 0; i < animator.layerCount; i++) - { - int stateHash; - float normalizedTime; - if (!CheckAnimStateChanged(out stateHash, out normalizedTime, i)) - { - continue; - } - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - WriteParameters(writer); - SendAnimationMessage(stateHash, normalizedTime, i, layerWeight[i], writer.ToArray()); - } - } - - CheckSpeed(); - } - - void CheckSpeed() - { - float newSpeed = animator.speed; - if (Mathf.Abs(previousSpeed - newSpeed) > 0.001f) - { - previousSpeed = newSpeed; - if (isServer) - { - animatorSpeed = newSpeed; - } - else if (ClientScene.readyConnection != null) - { - CmdSetAnimatorSpeed(newSpeed); - } - } - } - - void CmdSetAnimatorSpeed(float newSpeed) - { - // set animator - animator.speed = newSpeed; - animatorSpeed = newSpeed; - } - - void onAnimatorSpeedChanged(float _, float value) - { - // skip if host or client with authoity - // they will have already set the speed so dont set again - if (isServer || (hasAuthority && clientAuthority)) - return; - - animator.speed = value; - } - - bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layerId) - { - bool change = false; - stateHash = 0; - normalizedTime = 0; - - float lw = animator.GetLayerWeight(layerId); - if (Mathf.Abs(lw - layerWeight[layerId]) > 0.001f) - { - layerWeight[layerId] = lw; - change = true; - } - - if (animator.IsInTransition(layerId)) - { - AnimatorTransitionInfo tt = animator.GetAnimatorTransitionInfo(layerId); - if (tt.fullPathHash != transitionHash[layerId]) - { - // first time in this transition - transitionHash[layerId] = tt.fullPathHash; - animationHash[layerId] = 0; - return true; - } - return change; - } - - AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(layerId); - if (st.fullPathHash != animationHash[layerId]) - { - // first time in this animation state - if (animationHash[layerId] != 0) - { - // came from another animation directly - from Play() - stateHash = st.fullPathHash; - normalizedTime = st.normalizedTime; - } - transitionHash[layerId] = 0; - animationHash[layerId] = st.fullPathHash; - return true; - } - return change; - } - - void CheckSendRate() - { - float now = Time.time; - if (SendMessagesAllowed && syncInterval >= 0 && now > nextSendTime) - { - nextSendTime = now + syncInterval; - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - if (WriteParameters(writer)) - SendAnimationParametersMessage(writer.ToArray()); - } - } - } - - void SendAnimationMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) - { - if (isServer) - { - RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); - } - else if (ClientScene.readyConnection != null) - { - CmdOnAnimationServerMessage(stateHash, normalizedTime, layerId, weight, parameters); - } - } - - void SendAnimationParametersMessage(byte[] parameters) - { - if (isServer) - { - RpcOnAnimationParametersClientMessage(parameters); - } - else if (ClientScene.readyConnection != null) - { - CmdOnAnimationParametersServerMessage(parameters); - } - } - - void HandleAnimMsg(int stateHash, float normalizedTime, int layerId, float weight, NetworkReader reader) - { - if (hasAuthority && clientAuthority) - return; - - // usually transitions will be triggered by parameters, if not, play anims directly. - // NOTE: this plays "animations", not transitions, so any transitions will be skipped. - // NOTE: there is no API to play a transition(?) - if (stateHash != 0 && animator.enabled) - { - animator.Play(stateHash, layerId, normalizedTime); - } - - animator.SetLayerWeight(layerId, weight); - - ReadParameters(reader); - } - - void HandleAnimParamsMsg(NetworkReader reader) - { - if (hasAuthority && clientAuthority) - return; - - ReadParameters(reader); - } - - void HandleAnimTriggerMsg(int hash) - { - if (animator.enabled) - animator.SetTrigger(hash); - } - - void HandleAnimResetTriggerMsg(int hash) - { - if (animator.enabled) - animator.ResetTrigger(hash); - } - - ulong NextDirtyBits() - { - ulong dirtyBits = 0; - for (int i = 0; i < parameters.Length; i++) - { - AnimatorControllerParameter par = parameters[i]; - bool changed = false; - if (par.type == AnimatorControllerParameterType.Int) - { - int newIntValue = animator.GetInteger(par.nameHash); - changed = newIntValue != lastIntParameters[i]; - if (changed) - lastIntParameters[i] = newIntValue; - } - else if (par.type == AnimatorControllerParameterType.Float) - { - float newFloatValue = animator.GetFloat(par.nameHash); - changed = Mathf.Abs(newFloatValue - lastFloatParameters[i]) > 0.001f; - // only set lastValue if it was changed, otherwise value could slowly drift within the 0.001f limit each frame - if (changed) - lastFloatParameters[i] = newFloatValue; - } - else if (par.type == AnimatorControllerParameterType.Bool) - { - bool newBoolValue = animator.GetBool(par.nameHash); - changed = newBoolValue != lastBoolParameters[i]; - if (changed) - lastBoolParameters[i] = newBoolValue; - } - if (changed) - { - dirtyBits |= 1ul << i; - } - } - return dirtyBits; - } - - bool WriteParameters(NetworkWriter writer, bool forceAll = false) - { - ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits(); - writer.WritePackedUInt64(dirtyBits); - for (int i = 0; i < parameters.Length; i++) - { - if ((dirtyBits & (1ul << i)) == 0) - continue; - - AnimatorControllerParameter par = parameters[i]; - if (par.type == AnimatorControllerParameterType.Int) - { - int newIntValue = animator.GetInteger(par.nameHash); - writer.WritePackedInt32(newIntValue); - } - else if (par.type == AnimatorControllerParameterType.Float) - { - float newFloatValue = animator.GetFloat(par.nameHash); - writer.WriteSingle(newFloatValue); - } - else if (par.type == AnimatorControllerParameterType.Bool) - { - bool newBoolValue = animator.GetBool(par.nameHash); - writer.WriteBoolean(newBoolValue); - } - } - return dirtyBits != 0; - } - - void ReadParameters(NetworkReader reader) - { - bool animatorEnabled = animator.enabled; - // need to read values from NetworkReader even if animator is disabled - - ulong dirtyBits = reader.ReadPackedUInt64(); - for (int i = 0; i < parameters.Length; i++) - { - if ((dirtyBits & (1ul << i)) == 0) - continue; - - AnimatorControllerParameter par = parameters[i]; - if (par.type == AnimatorControllerParameterType.Int) - { - int newIntValue = reader.ReadPackedInt32(); - if (animatorEnabled) - animator.SetInteger(par.nameHash, newIntValue); - } - else if (par.type == AnimatorControllerParameterType.Float) - { - float newFloatValue = reader.ReadSingle(); - if (animatorEnabled) - animator.SetFloat(par.nameHash, newFloatValue); - } - else if (par.type == AnimatorControllerParameterType.Bool) - { - bool newBoolValue = reader.ReadBoolean(); - if (animatorEnabled) - animator.SetBool(par.nameHash, newBoolValue); - } - } - } - - /// - /// Custom Serialization - /// - /// - /// - /// - public override bool OnSerialize(NetworkWriter writer, bool initialState) - { - bool changed = base.OnSerialize(writer, initialState); - if (initialState) - { - for (int i = 0; i < animator.layerCount; i++) - { - if (animator.IsInTransition(i)) - { - AnimatorStateInfo st = animator.GetNextAnimatorStateInfo(i); - writer.WriteInt32(st.fullPathHash); - writer.WriteSingle(st.normalizedTime); - } - else - { - AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(i); - writer.WriteInt32(st.fullPathHash); - writer.WriteSingle(st.normalizedTime); - } - writer.WriteSingle(animator.GetLayerWeight(i)); - } - WriteParameters(writer, initialState); - return true; - } - return changed; - } - - /// - /// Custom Deserialization - /// - /// - /// - public override void OnDeserialize(NetworkReader reader, bool initialState) - { - base.OnDeserialize(reader, initialState); - if (initialState) - { - for (int i = 0; i < animator.layerCount; i++) - { - int stateHash = reader.ReadInt32(); - float normalizedTime = reader.ReadSingle(); - animator.SetLayerWeight(i, reader.ReadSingle()); - animator.Play(stateHash, i, normalizedTime); - } - - ReadParameters(reader); - } - } - - /// - /// Causes an animation trigger to be invoked for a networked object. - /// If local authority is set, and this is called from the client, then the trigger will be invoked on the server and all clients. If not, then this is called on the server, and the trigger will be called on all clients. - /// - /// Name of trigger. - public void SetTrigger(string triggerName) - { - SetTrigger(Animator.StringToHash(triggerName)); - } - - /// - /// Causes an animation trigger to be invoked for a networked object. - /// - /// Hash id of trigger (from the Animator). - public void SetTrigger(int hash) - { - if (clientAuthority) - { - if (!isClient) - { - logger.LogWarning("Tried to set animation in the server for a client-controlled animator"); - return; - } - - if (!hasAuthority) - { - logger.LogWarning("Only the client with authority can set animations"); - return; - } - - if (ClientScene.readyConnection != null) - CmdOnAnimationTriggerServerMessage(hash); - - // call on client right away - HandleAnimTriggerMsg(hash); - } - else - { - if (!isServer) - { - logger.LogWarning("Tried to set animation in the client for a server-controlled animator"); - return; - } - - HandleAnimTriggerMsg(hash); - RpcOnAnimationTriggerClientMessage(hash); - } - } - - /// - /// Causes an animation trigger to be reset for a networked object. - /// If local authority is set, and this is called from the client, then the trigger will be reset on the server and all clients. If not, then this is called on the server, and the trigger will be reset on all clients. - /// - /// Name of trigger. - public void ResetTrigger(string triggerName) - { - ResetTrigger(Animator.StringToHash(triggerName)); - } - - /// - /// Causes an animation trigger to be reset for a networked object. - /// - /// Hash id of trigger (from the Animator). - public void ResetTrigger(int hash) - { - if (clientAuthority) - { - if (!isClient) - { - logger.LogWarning("Tried to reset animation in the server for a client-controlled animator"); - return; - } - - if (!hasAuthority) - { - logger.LogWarning("Only the client with authority can reset animations"); - return; - } - - if (ClientScene.readyConnection != null) - CmdOnAnimationResetTriggerServerMessage(hash); - - // call on client right away - HandleAnimResetTriggerMsg(hash); - } - else - { - if (!isServer) - { - logger.LogWarning("Tried to reset animation in the client for a server-controlled animator"); - return; - } - - HandleAnimResetTriggerMsg(hash); - RpcOnAnimationResetTriggerClientMessage(hash); - } - } - - #region server message handlers - - [Command] - void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - if (logger.LogEnabled()) logger.Log("OnAnimationMessage for netId=" + netId); - - // handle and broadcast - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) - { - HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); - RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); - } - } - - [Command] - void CmdOnAnimationParametersServerMessage(byte[] parameters) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - // handle and broadcast - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) - { - HandleAnimParamsMsg(networkReader); - RpcOnAnimationParametersClientMessage(parameters); - } - } - - [Command] - void CmdOnAnimationTriggerServerMessage(int hash) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - // handle and broadcast - // host should have already the trigger - bool isHostOwner = isClient && hasAuthority; - if (!isHostOwner) - { - HandleAnimTriggerMsg(hash); - } - - RpcOnAnimationTriggerClientMessage(hash); - } - - [Command] - void CmdOnAnimationResetTriggerServerMessage(int hash) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - // handle and broadcast - // host should have already the trigger - bool isHostOwner = isClient && hasAuthority; - if (!isHostOwner) - { - HandleAnimResetTriggerMsg(hash); - } - - RpcOnAnimationResetTriggerClientMessage(hash); - } - - #endregion - - #region client message handlers - - [ClientRpc] - void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) - { - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) - HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); - } - - [ClientRpc] - void RpcOnAnimationParametersClientMessage(byte[] parameters) - { - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters)) - HandleAnimParamsMsg(networkReader); - } - - [ClientRpc] - void RpcOnAnimationTriggerClientMessage(int hash) - { - // host/owner handles this before it is sent - if (isServer || (clientAuthority && hasAuthority)) return; - - HandleAnimTriggerMsg(hash); - } - - [ClientRpc] - void RpcOnAnimationResetTriggerClientMessage(int hash) - { - // host/owner handles this before it is sent - if (isServer || (clientAuthority && hasAuthority)) return; - - HandleAnimResetTriggerMsg(hash); - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/NetworkAnimator.cs.meta b/Assets/Mirror/Components/NetworkAnimator.cs.meta deleted file mode 100644 index 211ce78..0000000 --- a/Assets/Mirror/Components/NetworkAnimator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7f6f3bf89aa97405989c802ba270f815 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs b/Assets/Mirror/Components/NetworkLobbyManager.cs deleted file mode 100644 index 5301e39..0000000 --- a/Assets/Mirror/Components/NetworkLobbyManager.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// This is a specialized NetworkManager that includes a networked lobby. - /// - /// - /// The lobby has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkLobbyPlayer component be on the lobby player objects. - /// NetworkLobbyManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkLobbyManager, there are new virtual functions on the NetworkLobbyManager that begin with "OnLobby". These should be used on classes derived from NetworkLobbyManager instead of the virtual functions on NetworkManager. - /// The OnLobby*() functions have empty implementations on the NetworkLobbyManager base class, so the base class functions do not have to be called. - /// - [AddComponentMenu("Network/NetworkLobbyManager")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkRoomManager.html")] - [Obsolete("Use / inherit from NetworkRoomManager instead")] - public class NetworkLobbyManager : NetworkRoomManager { } -} diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs.meta b/Assets/Mirror/Components/NetworkLobbyManager.cs.meta deleted file mode 100644 index a32c8c7..0000000 --- a/Assets/Mirror/Components/NetworkLobbyManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a4c96e6dd99826849ab1431f94547141 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs b/Assets/Mirror/Components/NetworkLobbyPlayer.cs deleted file mode 100644 index 2e65465..0000000 --- a/Assets/Mirror/Components/NetworkLobbyPlayer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// This component works in conjunction with the NetworkLobbyManager to make up the multiplayer lobby system. - /// The LobbyPrefab object of the NetworkLobbyManager must have this component on it. This component holds basic lobby player data required for the lobby to function. Game specific data for lobby players can be put in other components on the LobbyPrefab or in scripts derived from NetworkLobbyPlayer. - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkLobbyPlayer")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkRoomPlayer.html")] - [Obsolete("Use / inherit from NetworkRoomPlayer instead")] - public class NetworkLobbyPlayer : NetworkRoomPlayer { } -} diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta b/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta deleted file mode 100644 index 7a21eec..0000000 --- a/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 777a368af85f2e84da7ea5666581921b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkMatchChecker.cs b/Assets/Mirror/Components/NetworkMatchChecker.cs deleted file mode 100644 index c3e949c..0000000 --- a/Assets/Mirror/Components/NetworkMatchChecker.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - /// - /// Component that controls visibility of networked objects based on match id. - /// Any object with this component on it will only be visible to other objects in the same match. - /// This would be used to isolate players to their respective matches within a single game server instance. - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkMatchChecker")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkMatchChecker.html")] - public class NetworkMatchChecker : NetworkVisibility - { - static readonly Dictionary> matchPlayers = new Dictionary>(); - - Guid currentMatch = Guid.Empty; - - [Header("Diagnostics")] - [SyncVar] - public string currentMatchDebug; - - /// - /// Set this to the same value on all networked objects that belong to a given match - /// - public Guid matchId - { - get { return currentMatch; } - set - { - if (currentMatch == value) return; - - // cache previous match so observers in that match can be rebuilt - Guid previousMatch = currentMatch; - - // Set this to the new match this object just entered ... - currentMatch = value; - // ... and copy the string for the inspector because Unity can't show Guid directly - currentMatchDebug = currentMatch.ToString(); - - if (previousMatch != Guid.Empty) - { - // Remove this object from the hashset of the match it just left - matchPlayers[previousMatch].Remove(netIdentity); - - // RebuildObservers of all NetworkIdentity's in the match this object just left - RebuildMatchObservers(previousMatch); - } - - if (currentMatch != Guid.Empty) - { - // Make sure this new match is in the dictionary - if (!matchPlayers.ContainsKey(currentMatch)) - matchPlayers.Add(currentMatch, new HashSet()); - - // Add this object to the hashset of the new match - matchPlayers[currentMatch].Add(netIdentity); - - // RebuildObservers of all NetworkIdentity's in the match this object just entered - RebuildMatchObservers(currentMatch); - } - else - { - // Not in any match now...RebuildObservers will clear and add self - netIdentity.RebuildObservers(false); - } - } - } - - public override void OnStartServer() - { - if (currentMatch == Guid.Empty) return; - - if (!matchPlayers.ContainsKey(currentMatch)) - matchPlayers.Add(currentMatch, new HashSet()); - - matchPlayers[currentMatch].Add(netIdentity); - - // No need to rebuild anything here. - // identity.RebuildObservers is called right after this from NetworkServer.SpawnObject - } - - void RebuildMatchObservers(Guid specificMatch) - { - foreach (NetworkIdentity networkIdentity in matchPlayers[specificMatch]) - if (networkIdentity != null) - networkIdentity.RebuildObservers(false); - } - - #region Observers - - /// - /// Callback used by the visibility system to determine if an observer (player) can see this object. - /// If this function returns true, the network connection will be added as an observer. - /// - /// Network connection of a player. - /// True if the player can see this object. - public override bool OnCheckObserver(NetworkConnection conn) - { - // Not Visible if not in a match - if (matchId == Guid.Empty) - return false; - - NetworkMatchChecker networkMatchChecker = conn.identity.GetComponent(); - - if (networkMatchChecker == null) - return false; - - return networkMatchChecker.matchId == matchId; - } - - /// - /// Callback used by the visibility system to (re)construct the set of observers that can see this object. - /// Implementations of this callback should add network connections of players that can see this object to the observers set. - /// - /// The new set of observers for this object. - /// True if the set of observers is being built for the first time. - public override void OnRebuildObservers(HashSet observers, bool initialize) - { - if (currentMatch == Guid.Empty) return; - - foreach (NetworkIdentity networkIdentity in matchPlayers[currentMatch]) - if (networkIdentity != null && networkIdentity.connectionToClient != null) - observers.Add(networkIdentity.connectionToClient); - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/NetworkMatchChecker.cs.meta b/Assets/Mirror/Components/NetworkMatchChecker.cs.meta deleted file mode 100644 index 7c7d6cf..0000000 --- a/Assets/Mirror/Components/NetworkMatchChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1020a74962faada4b807ac5dc053a4cf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs b/Assets/Mirror/Components/NetworkPingDisplay.cs deleted file mode 100644 index 46863bf..0000000 --- a/Assets/Mirror/Components/NetworkPingDisplay.cs +++ /dev/null @@ -1,41 +0,0 @@ -using UnityEngine; - -namespace Mirror -{ - /// - /// Component that will display the clients ping in milliseconds - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkPingDisplay")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkPingDisplay.html")] - public class NetworkPingDisplay : MonoBehaviour - { - [SerializeField] bool showPing = true; - [SerializeField] Vector2 position = new Vector2(200, 0); - [SerializeField] int fontSize = 24; - [SerializeField] Color textColor = new Color32(255, 255, 255, 80); - - GUIStyle style; - - void Awake() - { - style = new GUIStyle(); - style.alignment = TextAnchor.UpperLeft; - style.fontSize = fontSize; - style.normal.textColor = textColor; - } - - void OnGUI() - { - if (!showPing) { return; } - - string text = string.Format("{0}ms", (int)(NetworkTime.rtt * 1000)); - - int width = Screen.width; - int height = Screen.height; - Rect rect = new Rect(position.x, position.y, width - 200, height * 2 / 100); - - GUI.Label(rect, text, style); - } - } -} diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs.meta b/Assets/Mirror/Components/NetworkPingDisplay.cs.meta deleted file mode 100644 index 221a745..0000000 --- a/Assets/Mirror/Components/NetworkPingDisplay.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bc654f29862fc2643b948f772ebb9e68 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkProximityChecker.cs b/Assets/Mirror/Components/NetworkProximityChecker.cs deleted file mode 100644 index 719ae07..0000000 --- a/Assets/Mirror/Components/NetworkProximityChecker.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - /// - /// Component that controls visibility of networked objects for players. - /// Any object with this component on it will not be visible to players more than a (configurable) distance away. - /// - [AddComponentMenu("Network/NetworkProximityChecker")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkProximityChecker.html")] - public class NetworkProximityChecker : NetworkVisibility - { - /// - /// The maximim range that objects will be visible at. - /// - [Tooltip("The maximum range that objects will be visible at.")] - public int visRange = 10; - - /// - /// How often (in seconds) that this object should update the list of observers that can see it. - /// - [Tooltip("How often (in seconds) that this object should update the list of observers that can see it.")] - public float visUpdateInterval = 1; - - /// - /// Flag to force this object to be hidden for players. - /// If this object is a player object, it will not be hidden for that player. - /// - [Tooltip("Enable to force this object to be hidden from players.")] - public bool forceHidden; - - - public override void OnStartServer() - { - InvokeRepeating(nameof(RebuildObservers), 0, visUpdateInterval); - } - public override void OnStopServer() - { - CancelInvoke(nameof(RebuildObservers)); - } - - void RebuildObservers() - { - netIdentity.RebuildObservers(false); - } - - /// - /// Callback used by the visibility system to determine if an observer (player) can see this object. - /// If this function returns true, the network connection will be added as an observer. - /// - /// Network connection of a player. - /// True if the player can see this object. - public override bool OnCheckObserver(NetworkConnection conn) - { - if (forceHidden) - return false; - - return Vector3.Distance(conn.identity.transform.position, transform.position) < visRange; - } - - /// - /// Callback used by the visibility system to (re)construct the set of observers that can see this object. - /// Implementations of this callback should add network connections of players that can see this object to the observers set. - /// - /// The new set of observers for this object. - /// True if the set of observers is being built for the first time. - public override void OnRebuildObservers(HashSet observers, bool initialize) - { - // if force hidden then return without adding any observers. - if (forceHidden) - return; - - // 'transform.' calls GetComponent, only do it once - Vector3 position = transform.position; - - // brute force distance check - // -> only player connections can be observers, so it's enough if we - // go through all connections instead of all spawned identities. - // -> compared to UNET's sphere cast checking, this one is orders of - // magnitude faster. if we have 10k monsters and run a sphere - // cast 10k times, we will see a noticeable lag even with physics - // layers. but checking to every connection is fast. - foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) - { - if (conn != null && conn.identity != null) - { - // check distance - if (Vector3.Distance(conn.identity.transform.position, position) < visRange) - { - observers.Add(conn); - } - } - } - } - } -} diff --git a/Assets/Mirror/Components/NetworkProximityChecker.cs.meta b/Assets/Mirror/Components/NetworkProximityChecker.cs.meta deleted file mode 100644 index c5aa112..0000000 --- a/Assets/Mirror/Components/NetworkProximityChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1731d8de2d0c84333b08ebe1e79f4118 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs b/Assets/Mirror/Components/NetworkRoomManager.cs deleted file mode 100644 index e6d873e..0000000 --- a/Assets/Mirror/Components/NetworkRoomManager.cs +++ /dev/null @@ -1,697 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.Serialization; - -namespace Mirror -{ - /// - /// This is a specialized NetworkManager that includes a networked room. - /// - /// - /// The room has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkRoomPlayer component be on the room player objects. - /// NetworkRoomManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkRoomManager, there are new virtual functions on the NetworkRoomManager that begin with "OnRoom". These should be used on classes derived from NetworkRoomManager instead of the virtual functions on NetworkManager. - /// The OnRoom*() functions have empty implementations on the NetworkRoomManager base class, so the base class functions do not have to be called. - /// - [AddComponentMenu("Network/NetworkRoomManager")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkRoomManager.html")] - public class NetworkRoomManager : NetworkManager - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkRoomManager)); - - public struct PendingPlayer - { - public NetworkConnection conn; - public GameObject roomPlayer; - } - - [Header("Room Settings")] - - [FormerlySerializedAs("m_ShowRoomGUI")] - [SerializeField] - [Tooltip("This flag controls whether the default UI is shown for the room")] - internal bool showRoomGUI = true; - - [FormerlySerializedAs("m_MinPlayers")] - [SerializeField] - [Tooltip("Minimum number of players to auto-start the game")] - protected int minPlayers = 1; - - [FormerlySerializedAs("m_RoomPlayerPrefab")] - [SerializeField] - [Tooltip("Prefab to use for the Room Player")] - protected NetworkRoomPlayer roomPlayerPrefab; - - /// - /// The scene to use for the room. This is similar to the offlineScene of the NetworkManager. - /// - [Scene] - public string RoomScene; - - /// - /// The scene to use for the playing the game from the room. This is similar to the onlineScene of the NetworkManager. - /// - [Scene] - public string GameplayScene; - - /// - /// List of players that are in the Room - /// - [FormerlySerializedAs("m_PendingPlayers")] - public List pendingPlayers = new List(); - - [Header("Diagnostics")] - - /// - /// True when all players have submitted a Ready message - /// - [Tooltip("Diagnostic flag indicating all players are ready to play")] - [FormerlySerializedAs("allPlayersReady")] - [SerializeField] bool _allPlayersReady; - - /// - /// These slots track players that enter the room. - /// The slotId on players is global to the game - across all players. - /// - [Tooltip("List of Room Player objects")] - public List roomSlots = new List(); - - public bool allPlayersReady - { - get => _allPlayersReady; - set - { - bool wasReady = _allPlayersReady; - bool nowReady = value; - - if (wasReady != nowReady) - { - _allPlayersReady = value; - - if (nowReady) - { - OnRoomServerPlayersReady(); - } - else - { - OnRoomServerPlayersNotReady(); - } - } - } - } - - public override void OnValidate() - { - // always >= 0 - maxConnections = Mathf.Max(maxConnections, 0); - - // always <= maxConnections - minPlayers = Mathf.Min(minPlayers, maxConnections); - - // always >= 0 - minPlayers = Mathf.Max(minPlayers, 0); - - if (roomPlayerPrefab != null) - { - NetworkIdentity identity = roomPlayerPrefab.GetComponent(); - if (identity == null) - { - roomPlayerPrefab = null; - logger.LogError("RoomPlayer prefab must have a NetworkIdentity component."); - } - } - - base.OnValidate(); - } - - internal void ReadyStatusChanged() - { - int CurrentPlayers = 0; - int ReadyPlayers = 0; - - foreach (NetworkRoomPlayer item in roomSlots) - { - if (item != null) - { - CurrentPlayers++; - if (item.readyToBegin) - ReadyPlayers++; - } - } - - if (CurrentPlayers == ReadyPlayers) - CheckReadyToBegin(); - else - allPlayersReady = false; - } - - /// - /// Called on the server when a client is ready. - /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. - /// - /// Connection from client. - public override void OnServerReady(NetworkConnection conn) - { - logger.Log("NetworkRoomManager OnServerReady"); - base.OnServerReady(conn); - - if (conn != null && conn.identity != null) - { - GameObject roomPlayer = conn.identity.gameObject; - - // if null or not a room player, dont replace it - if (roomPlayer != null && roomPlayer.GetComponent() != null) - SceneLoadedForPlayer(conn, roomPlayer); - } - } - - void SceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer) - { - if (logger.LogEnabled()) logger.LogFormat(LogType.Log, "NetworkRoom SceneLoadedForPlayer scene: {0} {1}", SceneManager.GetActiveScene().path, conn); - - if (IsSceneActive(RoomScene)) - { - // cant be ready in room, add to ready list - PendingPlayer pending; - pending.conn = conn; - pending.roomPlayer = roomPlayer; - pendingPlayers.Add(pending); - return; - } - - GameObject gamePlayer = OnRoomServerCreateGamePlayer(conn, roomPlayer); - if (gamePlayer == null) - { - // get start position from base class - Transform startPos = GetStartPosition(); - gamePlayer = startPos != null - ? Instantiate(playerPrefab, startPos.position, startPos.rotation) - : Instantiate(playerPrefab, Vector3.zero, Quaternion.identity); - } - - if (!OnRoomServerSceneLoadedForPlayer(conn, roomPlayer, gamePlayer)) - return; - - // replace room player with game player - NetworkServer.ReplacePlayerForConnection(conn, gamePlayer, true); - } - - /// - /// CheckReadyToBegin checks all of the players in the room to see if their readyToBegin flag is set. - /// If all of the players are ready, then the server switches from the RoomScene to the PlayScene, essentially starting the game. This is called automatically in response to NetworkRoomPlayer.CmdChangeReadyState. - /// - public void CheckReadyToBegin() - { - if (!IsSceneActive(RoomScene)) - return; - - int numberOfReadyPlayers = NetworkServer.connections.Count(conn => conn.Value != null && conn.Value.identity.gameObject.GetComponent().readyToBegin); - bool enoughReadyPlayers = minPlayers <= 0 || numberOfReadyPlayers >= minPlayers; - if (enoughReadyPlayers) - { - pendingPlayers.Clear(); - allPlayersReady = true; - } - else - { - allPlayersReady = false; - } - } - - internal void CallOnClientEnterRoom() - { - OnRoomClientEnter(); - foreach (NetworkRoomPlayer player in roomSlots) - if (player != null) - { - player.OnClientEnterRoom(); - } - } - - internal void CallOnClientExitRoom() - { - OnRoomClientExit(); - foreach (NetworkRoomPlayer player in roomSlots) - if (player != null) - { - player.OnClientExitRoom(); - } - } - - #region server handlers - - /// - /// Called on the server when a new client connects. - /// Unity calls this on the Server when a Client connects to the Server. Use an override to tell the NetworkManager what to do when a client connects to the server. - /// - /// Connection from client. - public override void OnServerConnect(NetworkConnection conn) - { - if (numPlayers >= maxConnections) - { - conn.Disconnect(); - return; - } - - // cannot join game in progress - if (!IsSceneActive(RoomScene)) - { - conn.Disconnect(); - return; - } - - base.OnServerConnect(conn); - OnRoomServerConnect(conn); - } - - /// - /// Called on the server when a client disconnects. - /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. - /// - /// Connection from client. - public override void OnServerDisconnect(NetworkConnection conn) - { - if (conn.identity != null) - { - NetworkRoomPlayer roomPlayer = conn.identity.GetComponent(); - - if (roomPlayer != null) - roomSlots.Remove(roomPlayer); - - foreach (NetworkIdentity clientOwnedObject in conn.clientOwnedObjects) - { - roomPlayer = clientOwnedObject.GetComponent(); - if (roomPlayer != null) - roomSlots.Remove(roomPlayer); - } - } - - allPlayersReady = false; - - foreach (NetworkRoomPlayer player in roomSlots) - { - if (player != null) - player.GetComponent().readyToBegin = false; - } - - if (IsSceneActive(RoomScene)) - RecalculateRoomPlayerIndices(); - - OnRoomServerDisconnect(conn); - base.OnServerDisconnect(conn); - } - - // Sequential index used in round-robin deployment of players into instances and score positioning - public int clientIndex; - - /// - /// Called on the server when a client adds a new player with ClientScene.AddPlayer. - /// The default implementation for this function creates a new player object from the playerPrefab. - /// - /// Connection from client. - public override void OnServerAddPlayer(NetworkConnection conn) - { - // increment the index before adding the player, so first player starts at 1 - clientIndex++; - - if (IsSceneActive(RoomScene)) - { - if (roomSlots.Count == maxConnections) - return; - - allPlayersReady = false; - - if (logger.LogEnabled()) logger.LogFormat(LogType.Log, "NetworkRoomManager.OnServerAddPlayer playerPrefab:{0}", roomPlayerPrefab.name); - - GameObject newRoomGameObject = OnRoomServerCreateRoomPlayer(conn); - if (newRoomGameObject == null) - newRoomGameObject = Instantiate(roomPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity); - - NetworkServer.AddPlayerForConnection(conn, newRoomGameObject); - } - else - OnRoomServerAddPlayer(conn); - } - - [Server] - public void RecalculateRoomPlayerIndices() - { - if (roomSlots.Count > 0) - { - for (int i = 0; i < roomSlots.Count; i++) - { - roomSlots[i].index = i; - } - } - } - - /// - /// This causes the server to switch scenes and sets the networkSceneName. - /// Clients that connect to this server will automatically switch to this scene. This is called autmatically if onlineScene or offlineScene are set, but it can be called from user code to switch scenes again while the game is in progress. This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready() again to participate in the new scene. - /// - /// - public override void ServerChangeScene(string newSceneName) - { - if (newSceneName == RoomScene) - { - foreach (NetworkRoomPlayer roomPlayer in roomSlots) - { - if (roomPlayer == null) - continue; - - // find the game-player object for this connection, and destroy it - NetworkIdentity identity = roomPlayer.GetComponent(); - - if (NetworkServer.active) - { - // re-add the room object - roomPlayer.GetComponent().readyToBegin = false; - NetworkServer.ReplacePlayerForConnection(identity.connectionToClient, roomPlayer.gameObject); - } - } - - allPlayersReady = false; - } - - base.ServerChangeScene(newSceneName); - } - - /// - /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). - /// - /// The name of the new scene. - public override void OnServerSceneChanged(string sceneName) - { - if (sceneName != RoomScene) - { - // call SceneLoadedForPlayer on any players that become ready while we were loading the scene. - foreach (PendingPlayer pending in pendingPlayers) - SceneLoadedForPlayer(pending.conn, pending.roomPlayer); - - pendingPlayers.Clear(); - } - - OnRoomServerSceneChanged(sceneName); - } - - /// - /// This is invoked when a server is started - including when a host is started. - /// StartServer has multiple signatures, but they all cause this hook to be called. - /// - public override void OnStartServer() - { - if (string.IsNullOrEmpty(RoomScene)) - { - logger.LogError("NetworkRoomManager RoomScene is empty. Set the RoomScene in the inspector for the NetworkRoomMangaer"); - return; - } - - if (string.IsNullOrEmpty(GameplayScene)) - { - logger.LogError("NetworkRoomManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkRoomMangaer"); - return; - } - - OnRoomStartServer(); - } - - /// - /// This is invoked when a host is started. - /// StartHost has multiple signatures, but they all cause this hook to be called. - /// - public override void OnStartHost() - { - OnRoomStartHost(); - } - - /// - /// This is called when a server is stopped - including when a host is stopped. - /// - public override void OnStopServer() - { - roomSlots.Clear(); - OnRoomStopServer(); - } - - /// - /// This is called when a host is stopped. - /// - public override void OnStopHost() - { - OnRoomStopHost(); - } - - #endregion - - #region client handlers - - /// - /// This is invoked when the client is started. - /// - public override void OnStartClient() - { - if (roomPlayerPrefab == null || roomPlayerPrefab.gameObject == null) - logger.LogError("NetworkRoomManager no RoomPlayer prefab is registered. Please add a RoomPlayer prefab."); - else - ClientScene.RegisterPrefab(roomPlayerPrefab.gameObject); - - if (playerPrefab == null) - logger.LogError("NetworkRoomManager no GamePlayer prefab is registered. Please add a GamePlayer prefab."); - - OnRoomStartClient(); - } - - /// - /// Called on the client when connected to a server. - /// The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects. - /// - /// Connection to the server. - public override void OnClientConnect(NetworkConnection conn) - { - OnRoomClientConnect(conn); - base.OnClientConnect(conn); - } - - /// - /// Called on clients when disconnected from a server. - /// This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects. - /// - /// Connection to the server. - public override void OnClientDisconnect(NetworkConnection conn) - { - OnRoomClientDisconnect(conn); - base.OnClientDisconnect(conn); - } - - /// - /// This is called when a client is stopped. - /// - public override void OnStopClient() - { - OnRoomStopClient(); - CallOnClientExitRoom(); - roomSlots.Clear(); - } - - /// - /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. - /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. - /// - /// Connection of the client - public override void OnClientSceneChanged(NetworkConnection conn) - { - if (IsSceneActive(RoomScene)) - { - if (NetworkClient.isConnected) - CallOnClientEnterRoom(); - } - else - CallOnClientExitRoom(); - - base.OnClientSceneChanged(conn); - OnRoomClientSceneChanged(conn); - } - - #endregion - - #region room server virtuals - - /// - /// This is called on the host when a host is started. - /// - public virtual void OnRoomStartHost() { } - - /// - /// This is called on the host when the host is stopped. - /// - public virtual void OnRoomStopHost() { } - - /// - /// This is called on the server when the server is started - including when a host is started. - /// - public virtual void OnRoomStartServer() { } - - /// - /// This is called on the server when the server is started - including when a host is stopped. - /// - public virtual void OnRoomStopServer() { } - - /// - /// This is called on the server when a new client connects to the server. - /// - /// The new connection. - public virtual void OnRoomServerConnect(NetworkConnection conn) { } - - /// - /// This is called on the server when a client disconnects. - /// - /// The connection that disconnected. - public virtual void OnRoomServerDisconnect(NetworkConnection conn) { } - - /// - /// This is called on the server when a networked scene finishes loading. - /// - /// Name of the new scene. - public virtual void OnRoomServerSceneChanged(string sceneName) { } - - /// - /// This allows customization of the creation of the room-player object on the server. - /// By default the roomPlayerPrefab is used to create the room-player, but this function allows that behaviour to be customized. - /// - /// The connection the player object is for. - /// The new room-player object. - public virtual GameObject OnRoomServerCreateRoomPlayer(NetworkConnection conn) - { - return null; - } - - /// - /// This allows customization of the creation of the GamePlayer object on the server. - /// By default the gamePlayerPrefab is used to create the game-player, but this function allows that behaviour to be customized. The object returned from the function will be used to replace the room-player on the connection. - /// - /// The connection the player object is for. - /// The room player object for this connection. - /// A new GamePlayer object. - public virtual GameObject OnRoomServerCreateGamePlayer(NetworkConnection conn, GameObject roomPlayer) - { - return null; - } - - /// - /// This allows customization of the creation of the GamePlayer object on the server. - /// This is only called for subsequent GamePlay scenes after the first one. - /// See OnRoomServerCreateGamePlayer(NetworkConnection, GameObject) to customize the player object for the initial GamePlay scene. - /// - /// The connection the player object is for. - public virtual void OnRoomServerAddPlayer(NetworkConnection conn) - { - base.OnServerAddPlayer(conn); - } - - // for users to apply settings from their room player object to their in-game player object - /// - /// This is called on the server when it is told that a client has finished switching from the room scene to a game player scene. - /// When switching from the room, the room-player is replaced with a game-player object. This callback function gives an opportunity to apply state from the room-player to the game-player object. - /// - /// The connection of the player - /// The room player object. - /// The game player object. - /// False to not allow this player to replace the room player. - public virtual bool OnRoomServerSceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer, GameObject gamePlayer) - { - return true; - } - - /// - /// This is called on the server when all the players in the room are ready. - /// The default implementation of this function uses ServerChangeScene() to switch to the game player scene. By implementing this callback you can customize what happens when all the players in the room are ready, such as adding a countdown or a confirmation for a group leader. - /// - public virtual void OnRoomServerPlayersReady() - { - // all players are readyToBegin, start the game - ServerChangeScene(GameplayScene); - } - - /// - /// This is called on the server when CheckReadyToBegin finds that players are not ready - /// May be called multiple times while not ready players are joining - /// - public virtual void OnRoomServerPlayersNotReady() { } - - #endregion - - #region room client virtuals - - /// - /// This is a hook to allow custom behaviour when the game client enters the room. - /// - public virtual void OnRoomClientEnter() { } - - /// - /// This is a hook to allow custom behaviour when the game client exits the room. - /// - public virtual void OnRoomClientExit() { } - - /// - /// This is called on the client when it connects to server. - /// - /// The connection that connected. - public virtual void OnRoomClientConnect(NetworkConnection conn) { } - - /// - /// This is called on the client when disconnected from a server. - /// - /// The connection that disconnected. - public virtual void OnRoomClientDisconnect(NetworkConnection conn) { } - - /// - /// This is called on the client when a client is started. - /// - /// The connection for the room. - public virtual void OnRoomStartClient() { } - - /// - /// This is called on the client when the client stops. - /// - public virtual void OnRoomStopClient() { } - - /// - /// This is called on the client when the client is finished loading a new networked scene. - /// - /// The connection that finished loading a new networked scene. - public virtual void OnRoomClientSceneChanged(NetworkConnection conn) { } - - /// - /// Called on the client when adding a player to the room fails. - /// This could be because the room is full, or the connection is not allowed to have more players. - /// - public virtual void OnRoomClientAddPlayerFailed() { } - - #endregion - - #region optional UI - - /// - /// virtual so inheriting classes can roll their own - /// - public virtual void OnGUI() - { - if (!showRoomGUI) - return; - - if (NetworkServer.active && IsSceneActive(GameplayScene)) - { - GUILayout.BeginArea(new Rect(Screen.width - 150f, 10f, 140f, 30f)); - if (GUILayout.Button("Return to Room")) - ServerChangeScene(RoomScene); - GUILayout.EndArea(); - } - - if (IsSceneActive(RoomScene)) - GUI.Box(new Rect(10f, 180f, 520f, 150f), "PLAYERS"); - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs.meta b/Assets/Mirror/Components/NetworkRoomManager.cs.meta deleted file mode 100644 index 76e7d42..0000000 --- a/Assets/Mirror/Components/NetworkRoomManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 615e6c6589cf9e54cad646b5a11e0529 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs b/Assets/Mirror/Components/NetworkRoomPlayer.cs deleted file mode 100644 index 7bfcbe5..0000000 --- a/Assets/Mirror/Components/NetworkRoomPlayer.cs +++ /dev/null @@ -1,198 +0,0 @@ -using UnityEngine; - -namespace Mirror -{ - /// - /// This component works in conjunction with the NetworkRoomManager to make up the multiplayer room system. - /// The RoomPrefab object of the NetworkRoomManager must have this component on it. This component holds basic room player data required for the room to function. Game specific data for room players can be put in other components on the RoomPrefab or in scripts derived from NetworkRoomPlayer. - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkRoomPlayer")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkRoomPlayer.html")] - public class NetworkRoomPlayer : NetworkBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkRoomPlayer)); - - /// - /// This flag controls whether the default UI is shown for the room player. - /// As this UI is rendered using the old GUI system, it is only recommended for testing purposes. - /// - [Tooltip("This flag controls whether the default UI is shown for the room player")] - public bool showRoomGUI = true; - - [Header("Diagnostics")] - - /// - /// Diagnostic flag indicating whether this player is ready for the game to begin. - /// Invoke CmdChangeReadyState method on the client to set this flag. - /// When all players are ready to begin, the game will start. This should not be set directly, CmdChangeReadyState should be called on the client to set it on the server. - /// - [Tooltip("Diagnostic flag indicating whether this player is ready for the game to begin")] - [SyncVar(hook = nameof(ReadyStateChanged))] - public bool readyToBegin; - - /// - /// Diagnostic index of the player, e.g. Player1, Player2, etc. - /// - [Tooltip("Diagnostic index of the player, e.g. Player1, Player2, etc.")] - [SyncVar(hook = nameof(IndexChanged))] - public int index; - - #region Unity Callbacks - - /// - /// Do not use Start - Override OnStartrHost / OnStartClient instead! - /// - public void Start() - { - if (NetworkManager.singleton is NetworkRoomManager room) - { - // NetworkRoomPlayer object must be set to DontDestroyOnLoad along with NetworkRoomManager - // in server and all clients, otherwise it will be respawned in the game scene which would - // have undesireable effects. - if (room.dontDestroyOnLoad) - DontDestroyOnLoad(gameObject); - - room.roomSlots.Add(this); - - if (NetworkServer.active) - room.RecalculateRoomPlayerIndices(); - - if (NetworkClient.active) - room.CallOnClientEnterRoom(); - } - else - logger.LogError("RoomPlayer could not find a NetworkRoomManager. The RoomPlayer requires a NetworkRoomManager object to function. Make sure that there is one in the scene."); - } - - public virtual void OnDisable() - { - if (NetworkClient.active && NetworkManager.singleton is NetworkRoomManager room) - { - // only need to call this on client as server removes it before object is destroyed - room.roomSlots.Remove(this); - - room.CallOnClientExitRoom(); - } - } - - #endregion - - #region Commands - - [Command] - public void CmdChangeReadyState(bool readyState) - { - readyToBegin = readyState; - NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; - if (room != null) - { - room.ReadyStatusChanged(); - } - } - - #endregion - - #region SyncVar Hooks - - /// - /// This is a hook that is invoked on clients when the index changes. - /// - /// The old index value - /// The new index value - public virtual void IndexChanged(int oldIndex, int newIndex) { } - - /// - /// This is a hook that is invoked on clients when a RoomPlayer switches between ready or not ready. - /// This function is called when the a client player calls CmdChangeReadyState. - /// - /// New Ready State - public virtual void ReadyStateChanged(bool oldReadyState, bool newReadyState) { } - - #endregion - - #region Room Client Virtuals - - /// - /// This is a hook that is invoked on clients for all room player objects when entering the room. - /// Note: isLocalPlayer is not guaranteed to be set until OnStartLocalPlayer is called. - /// - public virtual void OnClientEnterRoom() { } - - /// - /// This is a hook that is invoked on clients for all room player objects when exiting the room. - /// - public virtual void OnClientExitRoom() { } - - #endregion - - #region Optional UI - - /// - /// Render a UI for the room. Override to provide your on UI - /// - public virtual void OnGUI() - { - if (!showRoomGUI) - return; - - NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; - if (room) - { - if (!room.showRoomGUI) - return; - - if (!NetworkManager.IsSceneActive(room.RoomScene)) - return; - - DrawPlayerReadyState(); - DrawPlayerReadyButton(); - } - } - - void DrawPlayerReadyState() - { - GUILayout.BeginArea(new Rect(20f + (index * 100), 200f, 90f, 130f)); - - GUILayout.Label($"Player [{index + 1}]"); - - if (readyToBegin) - GUILayout.Label("Ready"); - else - GUILayout.Label("Not Ready"); - - if (((isServer && index > 0) || isServerOnly) && GUILayout.Button("REMOVE")) - { - // This button only shows on the Host for all players other than the Host - // Host and Players can't remove themselves (stop the client instead) - // Host can kick a Player this way. - GetComponent().connectionToClient.Disconnect(); - } - - GUILayout.EndArea(); - } - - void DrawPlayerReadyButton() - { - if (NetworkClient.active && isLocalPlayer) - { - GUILayout.BeginArea(new Rect(20f, 300f, 120f, 20f)); - - if (readyToBegin) - { - if (GUILayout.Button("Cancel")) - CmdChangeReadyState(false); - } - else - { - if (GUILayout.Button("Ready")) - CmdChangeReadyState(true); - } - - GUILayout.EndArea(); - } - } - - #endregion - } -} diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta b/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta deleted file mode 100644 index 0299bea..0000000 --- a/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 79874ac94d5b1314788ecf0e86bd23fd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkSceneChecker.cs b/Assets/Mirror/Components/NetworkSceneChecker.cs deleted file mode 100644 index 4e50315..0000000 --- a/Assets/Mirror/Components/NetworkSceneChecker.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirror -{ - /// - /// Component that controls visibility of networked objects between scenes. - /// Any object with this component on it will only be visible to other objects in the same scene - /// This would be used when the server has multiple additive subscenes loaded to isolate players to their respective subscenes - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkSceneChecker")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkSceneChecker.html")] - public class NetworkSceneChecker : NetworkVisibility - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkSceneChecker)); - - /// - /// Flag to force this object to be hidden from all observers. - /// If this object is a player object, it will not be hidden for that client. - /// - [Tooltip("Enable to force this object to be hidden from all observers.")] - public bool forceHidden; - - // Use Scene instead of string scene.name because when additively loading multiples of a subscene the name won't be unique - static readonly Dictionary> sceneCheckerObjects = new Dictionary>(); - - Scene currentScene; - - [ServerCallback] - void Awake() - { - currentScene = gameObject.scene; - if (logger.LogEnabled()) logger.Log($"NetworkSceneChecker.Awake currentScene: {currentScene}"); - } - - public override void OnStartServer() - { - if (!sceneCheckerObjects.ContainsKey(currentScene)) - sceneCheckerObjects.Add(currentScene, new HashSet()); - - sceneCheckerObjects[currentScene].Add(netIdentity); - } - - [ServerCallback] - void Update() - { - if (currentScene == gameObject.scene) - return; - - // This object is in a new scene so observers in the prior scene - // and the new scene need to rebuild their respective observers lists. - - // Remove this object from the hashset of the scene it just left - sceneCheckerObjects[currentScene].Remove(netIdentity); - - // RebuildObservers of all NetworkIdentity's in the scene this object just left - RebuildSceneObservers(); - - // Set this to the new scene this object just entered - currentScene = gameObject.scene; - - // Make sure this new scene is in the dictionary - if (!sceneCheckerObjects.ContainsKey(currentScene)) - sceneCheckerObjects.Add(currentScene, new HashSet()); - - // Add this object to the hashset of the new scene - sceneCheckerObjects[currentScene].Add(netIdentity); - - // RebuildObservers of all NetworkIdentity's in the scene this object just entered - RebuildSceneObservers(); - } - - void RebuildSceneObservers() - { - foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) - if (networkIdentity != null) - networkIdentity.RebuildObservers(false); - } - - /// - /// Callback used by the visibility system to determine if an observer (player) can see this object. - /// If this function returns true, the network connection will be added as an observer. - /// - /// Network connection of a player. - /// True if the player can see this object. - public override bool OnCheckObserver(NetworkConnection conn) - { - if (forceHidden) - return false; - - return conn.identity.gameObject.scene == gameObject.scene; - } - - /// - /// Callback used by the visibility system to (re)construct the set of observers that can see this object. - /// Implementations of this callback should add network connections of players that can see this object to the observers set. - /// - /// The new set of observers for this object. - /// True if the set of observers is being built for the first time. - public override void OnRebuildObservers(HashSet observers, bool initialize) - { - // If forceHidden then return without adding any observers. - if (forceHidden) - return; - - // Add everything in the hashset for this object's current scene - foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) - if (networkIdentity != null && networkIdentity.connectionToClient != null) - observers.Add(networkIdentity.connectionToClient); - } - } -} diff --git a/Assets/Mirror/Components/NetworkSceneChecker.cs.meta b/Assets/Mirror/Components/NetworkSceneChecker.cs.meta deleted file mode 100644 index b451655..0000000 --- a/Assets/Mirror/Components/NetworkSceneChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7fdb599e1359924bad6255660370252 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkTransform.cs b/Assets/Mirror/Components/NetworkTransform.cs deleted file mode 100644 index c6b7adc..0000000 --- a/Assets/Mirror/Components/NetworkTransform.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace Mirror -{ - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkTransform")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkTransform.html")] - public class NetworkTransform : NetworkTransformBase - { - protected override Transform targetComponent => transform; - } -} diff --git a/Assets/Mirror/Components/NetworkTransform.cs.meta b/Assets/Mirror/Components/NetworkTransform.cs.meta deleted file mode 100644 index a569990..0000000 --- a/Assets/Mirror/Components/NetworkTransform.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2f74aedd71d9a4f55b3ce499326d45fb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransformBase.cs deleted file mode 100644 index 20b96ec..0000000 --- a/Assets/Mirror/Components/NetworkTransformBase.cs +++ /dev/null @@ -1,508 +0,0 @@ -// vis2k: -// base class for NetworkTransform and NetworkTransformChild. -// New method is simple and stupid. No more 1500 lines of code. -// -// Server sends current data. -// Client saves it and interpolates last and latest data points. -// Update handles transform movement / rotation -// FixedUpdate handles rigidbody movement / rotation -// -// Notes: -// * Built-in Teleport detection in case of lags / teleport / obstacles -// * Quaternion > EulerAngles because gimbal lock and Quaternion.Slerp -// * Syncs XYZ. Works 3D and 2D. Saving 4 bytes isn't worth 1000 lines of code. -// * Initial delay might happen if server sends packet immediately after moving -// just 1cm, hence we move 1cm and then wait 100ms for next packet -// * Only way for smooth movement is to use a fixed movement speed during -// interpolation. interpolation over time is never that good. -// -using UnityEngine; - -namespace Mirror -{ - public abstract class NetworkTransformBase : NetworkBehaviour - { - [Header("Authority")] - [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")] - public bool clientAuthority; - - /// - /// We need to store this locally on the server so clients can't request Authority when ever they like - /// - bool clientAuthorityBeforeTeleport; - - // Is this a client with authority over this transform? - // This component could be on the player object or any object that has been assigned authority to this client. - bool IsClientWithAuthority => hasAuthority && clientAuthority; - - // Sensitivity is added for VR where human players tend to have micro movements so this can quiet down - // the network traffic. Additionally, rigidbody drift should send less traffic, e.g very slow sliding / rolling. - [Header("Sensitivity")] - [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] - public float localPositionSensitivity = .01f; - [Tooltip("If rotation exceeds this angle, it will be transmitted on the network")] - public float localRotationSensitivity = .01f; - [Tooltip("Changes to the transform must exceed these values to be transmitted on the network.")] - public float localScaleSensitivity = .01f; - - // target transform to sync. can be on a child. - protected abstract Transform targetComponent { get; } - - // server - Vector3 lastPosition; - Quaternion lastRotation; - Vector3 lastScale; - - // client - public class DataPoint - { - public float timeStamp; - // use local position/rotation for VR support - public Vector3 localPosition; - public Quaternion localRotation; - public Vector3 localScale; - public float movementSpeed; - } - // interpolation start and goal - DataPoint start; - DataPoint goal; - - // local authority send time - float lastClientSendTime; - - // serialization is needed by OnSerialize and by manual sending from authority - // public only for tests - public static void SerializeIntoWriter(NetworkWriter writer, Vector3 position, Quaternion rotation, Vector3 scale) - { - // serialize position, rotation, scale - // note: we do NOT compress rotation. - // we are CPU constrained, not bandwidth constrained. - // the code needs to WORK for the next 5-10 years of development. - writer.WriteVector3(position); - writer.WriteQuaternion(rotation); - writer.WriteVector3(scale); - } - - public override bool OnSerialize(NetworkWriter writer, bool initialState) - { - // use local position/rotation/scale for VR support - SerializeIntoWriter(writer, targetComponent.transform.localPosition, targetComponent.transform.localRotation, targetComponent.transform.localScale); - return true; - } - - // try to estimate movement speed for a data point based on how far it - // moved since the previous one - // => if this is the first time ever then we use our best guess: - // -> delta based on transform.localPosition - // -> elapsed based on send interval hoping that it roughly matches - static float EstimateMovementSpeed(DataPoint from, DataPoint to, Transform transform, float sendInterval) - { - Vector3 delta = to.localPosition - (from != null ? from.localPosition : transform.localPosition); - float elapsed = from != null ? to.timeStamp - from.timeStamp : sendInterval; - // avoid NaN - return elapsed > 0 ? delta.magnitude / elapsed : 0; - } - - // serialization is needed by OnSerialize and by manual sending from authority - void DeserializeFromReader(NetworkReader reader) - { - // put it into a data point immediately - DataPoint temp = new DataPoint - { - // deserialize position - localPosition = reader.ReadVector3() - }; - - // deserialize rotation & scale - temp.localRotation = reader.ReadQuaternion(); - temp.localScale = reader.ReadVector3(); - - temp.timeStamp = Time.time; - - // movement speed: based on how far it moved since last time - // has to be calculated before 'start' is overwritten - temp.movementSpeed = EstimateMovementSpeed(goal, temp, targetComponent.transform, syncInterval); - - // reassign start wisely - // -> first ever data point? then make something up for previous one - // so that we can start interpolation without waiting for next. - if (start == null) - { - start = new DataPoint - { - timeStamp = Time.time - syncInterval, - // local position/rotation for VR support - localPosition = targetComponent.transform.localPosition, - localRotation = targetComponent.transform.localRotation, - localScale = targetComponent.transform.localScale, - movementSpeed = temp.movementSpeed - }; - } - // -> second or nth data point? then update previous, but: - // we start at where ever we are right now, so that it's - // perfectly smooth and we don't jump anywhere - // - // example if we are at 'x': - // - // A--x->B - // - // and then receive a new point C: - // - // A--x--B - // | - // | - // C - // - // then we don't want to just jump to B and start interpolation: - // - // x - // | - // | - // C - // - // we stay at 'x' and interpolate from there to C: - // - // x..B - // \ . - // \. - // C - // - else - { - float oldDistance = Vector3.Distance(start.localPosition, goal.localPosition); - float newDistance = Vector3.Distance(goal.localPosition, temp.localPosition); - - start = goal; - - // teleport / lag / obstacle detection: only continue at current - // position if we aren't too far away - // - // local position/rotation for VR support - if (Vector3.Distance(targetComponent.transform.localPosition, start.localPosition) < oldDistance + newDistance) - { - start.localPosition = targetComponent.transform.localPosition; - start.localRotation = targetComponent.transform.localRotation; - start.localScale = targetComponent.transform.localScale; - } - } - - // set new destination in any case. new data is best data. - goal = temp; - } - - public override void OnDeserialize(NetworkReader reader, bool initialState) - { - // deserialize - DeserializeFromReader(reader); - } - - // local authority client sends sync message to server for broadcasting - [Command] - void CmdClientToServerSync(byte[] payload) - { - // Ignore messages from client if not in client authority mode - if (!clientAuthority) - return; - - // deserialize payload - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(payload)) - DeserializeFromReader(networkReader); - - // server-only mode does no interpolation to save computations, - // but let's set the position directly - if (isServer && !isClient) - ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); - - // set dirty so that OnSerialize broadcasts it - SetDirtyBit(1UL); - } - - // where are we in the timeline between start and goal? [0,1] - static float CurrentInterpolationFactor(DataPoint start, DataPoint goal) - { - if (start != null) - { - float difference = goal.timeStamp - start.timeStamp; - - // the moment we get 'goal', 'start' is supposed to - // start, so elapsed time is based on: - float elapsed = Time.time - goal.timeStamp; - // avoid NaN - return difference > 0 ? elapsed / difference : 0; - } - return 0; - } - - static Vector3 InterpolatePosition(DataPoint start, DataPoint goal, Vector3 currentPosition) - { - if (start != null) - { - // Option 1: simply interpolate based on time. but stutter - // will happen, it's not that smooth. especially noticeable if - // the camera automatically follows the player - // float t = CurrentInterpolationFactor(); - // return Vector3.Lerp(start.position, goal.position, t); - - // Option 2: always += speed - // -> speed is 0 if we just started after idle, so always use max - // for best results - float speed = Mathf.Max(start.movementSpeed, goal.movementSpeed); - return Vector3.MoveTowards(currentPosition, goal.localPosition, speed * Time.deltaTime); - } - return currentPosition; - } - - static Quaternion InterpolateRotation(DataPoint start, DataPoint goal, Quaternion defaultRotation) - { - if (start != null) - { - float t = CurrentInterpolationFactor(start, goal); - return Quaternion.Slerp(start.localRotation, goal.localRotation, t); - } - return defaultRotation; - } - - static Vector3 InterpolateScale(DataPoint start, DataPoint goal, Vector3 currentScale) - { - if (start != null) - { - float t = CurrentInterpolationFactor(start, goal); - return Vector3.Lerp(start.localScale, goal.localScale, t); - } - return currentScale; - } - - // teleport / lag / stuck detection - // -> checking distance is not enough since there could be just a tiny - // fence between us and the goal - // -> checking time always works, this way we just teleport if we still - // didn't reach the goal after too much time has elapsed - bool NeedsTeleport() - { - // calculate time between the two data points - float startTime = start != null ? start.timeStamp : Time.time - syncInterval; - float goalTime = goal != null ? goal.timeStamp : Time.time; - float difference = goalTime - startTime; - float timeSinceGoalReceived = Time.time - goalTime; - return timeSinceGoalReceived > difference * 5; - } - - // moved since last time we checked it? - bool HasEitherMovedRotatedScaled() - { - // moved or rotated or scaled? - // local position/rotation/scale for VR support - bool moved = Vector3.Distance(lastPosition, targetComponent.transform.localPosition) > localPositionSensitivity; - bool scaled = Vector3.Distance(lastScale, targetComponent.transform.localScale) > localScaleSensitivity; - bool rotated = Quaternion.Angle(lastRotation, targetComponent.transform.localRotation) > localRotationSensitivity; - - // save last for next frame to compare - // (only if change was detected. otherwise slow moving objects might - // never sync because of C#'s float comparison tolerance. see also: - // https://github.com/vis2k/Mirror/pull/428) - bool change = moved || rotated || scaled; - if (change) - { - // local position/rotation for VR support - lastPosition = targetComponent.transform.localPosition; - lastRotation = targetComponent.transform.localRotation; - lastScale = targetComponent.transform.localScale; - } - return change; - } - - // set position carefully depending on the target component - void ApplyPositionRotationScale(Vector3 position, Quaternion rotation, Vector3 scale) - { - // local position/rotation for VR support - targetComponent.transform.localPosition = position; - targetComponent.transform.localRotation = rotation; - targetComponent.transform.localScale = scale; - } - - void Update() - { - // if server then always sync to others. - if (isServer) - { - // just use OnSerialize via SetDirtyBit only sync when position - // changed. set dirty bits 0 or 1 - SetDirtyBit(HasEitherMovedRotatedScaled() ? 1UL : 0UL); - } - - // no 'else if' since host mode would be both - if (isClient) - { - // send to server if we have local authority (and aren't the server) - // -> only if connectionToServer has been initialized yet too - if (!isServer && IsClientWithAuthority) - { - // check only each 'syncInterval' - if (Time.time - lastClientSendTime >= syncInterval) - { - if (HasEitherMovedRotatedScaled()) - { - // serialize - // local position/rotation for VR support - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - SerializeIntoWriter(writer, targetComponent.transform.localPosition, targetComponent.transform.localRotation, targetComponent.transform.localScale); - - // send to server - CmdClientToServerSync(writer.ToArray()); - } - } - lastClientSendTime = Time.time; - } - } - - // apply interpolation on client for all players - // unless this client has authority over the object. could be - // himself or another object that he was assigned authority over - if (!IsClientWithAuthority) - { - // received one yet? (initialized?) - if (goal != null) - { - // teleport or interpolate - if (NeedsTeleport()) - { - // local position/rotation for VR support - ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale); - - // reset data points so we don't keep interpolating - start = null; - goal = null; - } - else - { - // local position/rotation for VR support - ApplyPositionRotationScale(InterpolatePosition(start, goal, targetComponent.transform.localPosition), - InterpolateRotation(start, goal, targetComponent.transform.localRotation), - InterpolateScale(start, goal, targetComponent.transform.localScale)); - } - } - } - } - } - - #region Server Teleport (force move player) - /// - /// Server side teleportation. - /// This method will override this GameObject's current Transform.Position to the Vector3 you have provided - /// and send it to all other Clients to override it at their side too. - /// - /// Where to teleport this GameObject - [Server] - public void ServerTeleport(Vector3 position) - { - Quaternion rotation = transform.rotation; - ServerTeleport(position, rotation); - } - - /// - /// Server side teleportation. - /// This method will override this GameObject's current Transform.Position and Transform.Rotation - /// to the Vector3 you have provided - /// and send it to all other Clients to override it at their side too. - /// - /// Where to teleport this GameObject - /// Which rotation to set this GameObject - [Server] - public void ServerTeleport(Vector3 position, Quaternion rotation) - { - // To prevent applying the position updates received from client (if they have ClientAuth) while being teleported. - - // clientAuthorityBeforeTeleport defaults to false when not teleporting, if it is true then it means that teleport was previously called but not finished - // therefore we should keep it as true so that 2nd teleport call doesn't clear authority - clientAuthorityBeforeTeleport = clientAuthority || clientAuthorityBeforeTeleport; - clientAuthority = false; - - DoTeleport(position, rotation); - - // tell all clients about new values - RpcTeleport(position, rotation, clientAuthorityBeforeTeleport); - } - - void DoTeleport(Vector3 newPosition, Quaternion newRotation) - { - transform.position = newPosition; - transform.rotation = newRotation; - - // Since we are overriding the position we don't need a goal and start. - // Reset them to null for fresh start - goal = null; - start = null; - lastPosition = newPosition; - lastRotation = newRotation; - } - - [ClientRpc] - void RpcTeleport(Vector3 newPosition, Quaternion newRotation, bool isClientAuthority) - { - DoTeleport(newPosition, newRotation); - - // only send finished if is owner and is ClientAuthority on server - if (hasAuthority && isClientAuthority) - CmdTeleportFinished(); - } - - /// - /// This RPC will be invoked on server after client finishes overriding the position. - /// - /// - [Command] - void CmdTeleportFinished() - { - if (clientAuthorityBeforeTeleport) - { - clientAuthority = true; - - // reset value so doesnt effect future calls, see note in ServerTeleport - clientAuthorityBeforeTeleport = false; - } - else - { - Debug.LogWarning("Client called TeleportFinished when clientAuthority was false on server", this); - } - } - #endregion - - static void DrawDataPointGizmo(DataPoint data, Color color) - { - // use a little offset because transform.localPosition might be in - // the ground in many cases - Vector3 offset = Vector3.up * 0.01f; - - // draw position - Gizmos.color = color; - Gizmos.DrawSphere(data.localPosition + offset, 0.5f); - - // draw forward and up - // like unity move tool - Gizmos.color = Color.blue; - Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.forward); - - // like unity move tool - Gizmos.color = Color.green; - Gizmos.DrawRay(data.localPosition + offset, data.localRotation * Vector3.up); - } - - static void DrawLineBetweenDataPoints(DataPoint data1, DataPoint data2, Color color) - { - Gizmos.color = color; - Gizmos.DrawLine(data1.localPosition, data2.localPosition); - } - - // draw the data points for easier debugging - void OnDrawGizmos() - { - // draw start and goal points - if (start != null) DrawDataPointGizmo(start, Color.gray); - if (goal != null) DrawDataPointGizmo(goal, Color.white); - - // draw line between them - if (start != null && goal != null) DrawLineBetweenDataPoints(start, goal, Color.cyan); - } - } -} diff --git a/Assets/Mirror/Components/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/NetworkTransformBase.cs.meta deleted file mode 100644 index ab649d9..0000000 --- a/Assets/Mirror/Components/NetworkTransformBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2e77294d8ccbc4e7cb8ca2bd0d3e99ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Components/NetworkTransformChild.cs b/Assets/Mirror/Components/NetworkTransformChild.cs deleted file mode 100644 index 84a0d31..0000000 --- a/Assets/Mirror/Components/NetworkTransformChild.cs +++ /dev/null @@ -1,18 +0,0 @@ -using UnityEngine; - -namespace Mirror -{ - /// - /// A component to synchronize the position of child transforms of networked objects. - /// There must be a NetworkTransform on the root object of the hierarchy. There can be multiple NetworkTransformChild components on an object. This does not use physics for synchronization, it simply synchronizes the localPosition and localRotation of the child transform and lerps towards the recieved values. - /// - [AddComponentMenu("Network/NetworkTransformChild")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkTransformChild.html")] - public class NetworkTransformChild : NetworkTransformBase - { - [Header("Target")] - public Transform target; - - protected override Transform targetComponent => target; - } -} diff --git a/Assets/Mirror/Components/NetworkTransformChild.cs.meta b/Assets/Mirror/Components/NetworkTransformChild.cs.meta deleted file mode 100644 index ae36756..0000000 --- a/Assets/Mirror/Components/NetworkTransformChild.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 734b48bea0b204338958ee3d885e11f0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor.meta b/Assets/Mirror/Editor.meta deleted file mode 100644 index f679511..0000000 --- a/Assets/Mirror/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2539267b6934a4026a505690a1e1eda2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs deleted file mode 100644 index 30b1acd..0000000 --- a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Unity 2019.3 has an experimental 'disable domain reload on play' -// feature. keeping any global state between sessions will break -// Mirror and most of our user's projects. don't allow it for now. -// https://blogs.unity3d.com/2019/11/05/enter-play-mode-faster-in-unity-2019-3/ -using UnityEditor; -using UnityEngine; - -namespace Mirror -{ - public class EnterPlayModeSettingsCheck : MonoBehaviour - { - [InitializeOnLoadMethod] - static void OnInitializeOnLoad() - { -#if UNITY_2019_3_OR_NEWER - // We can't support experimental "Enter Play Mode Options" mode - // Check immediately on load, and before entering play mode, and warn the user - CheckPlayModeOptions(); -#endif - - // Hook this event to see if we have a good weave every time - // user attempts to enter play mode or tries to do a build - EditorApplication.playModeStateChanged += OnPlayModeStateChanged; - } - - static void OnPlayModeStateChanged(PlayModeStateChange state) - { - // Per Unity docs, this fires "when exiting edit mode before the Editor is in play mode". - // This doesn't fire when closing the editor. - if (state == PlayModeStateChange.ExitingEditMode) - { - CheckSuccessfulWeave(); - -#if UNITY_2019_3_OR_NEWER - // We can't support experimental "Enter Play Mode Options" mode - // Check and prevent entering play mode if enabled - CheckPlayModeOptions(); -#endif - } - } - - static void CheckSuccessfulWeave() - { - // Check if last weave result was successful - if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) - { - // Last weave result was a failure...try to weave again - // Faults will show in the console that may have been cleared by "Clear on Play" - SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); - Weaver.CompilationFinishedHook.WeaveExistingAssemblies(); - - // Did that clear things up for us? - if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) - { - // Nope, still failed, and console has the issues logged - Debug.LogError("Can't enter play mode until weaver issues are resolved."); - EditorApplication.isPlaying = false; - } - } - } - -#if UNITY_2019_3_OR_NEWER - static void CheckPlayModeOptions() - { - // enabling the checkbox is enough. it controls all the other settings. - if (EditorSettings.enterPlayModeOptionsEnabled) - { - Debug.LogError("Enter Play Mode Options are not supported by Mirror. Please disable 'ProjectSettings -> Editor -> Enter Play Mode Settings (Experimental)'."); - EditorApplication.isPlaying = false; - } - } -#endif - } -} diff --git a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta b/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta deleted file mode 100644 index 79a200d..0000000 --- a/Assets/Mirror/Editor/EnterPlayModeSettingsCheck.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b15a0d2ca0909400eb53dd6fe894cddd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/InspectorHelper.cs b/Assets/Mirror/Editor/InspectorHelper.cs deleted file mode 100644 index 40d2f1e..0000000 --- a/Assets/Mirror/Editor/InspectorHelper.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using UnityEngine; - -namespace Mirror -{ - public static class InspectorHelper - { - /// - /// Gets all public and private fields for a type - /// - /// - /// Stops at this base type (exclusive) - /// - public static IEnumerable GetAllFields(Type type, Type deepestBaseType) - { - const BindingFlags publicFields = BindingFlags.Public | BindingFlags.Instance; - const BindingFlags privateFields = BindingFlags.NonPublic | BindingFlags.Instance; - - // get public fields (includes fields from base type) - FieldInfo[] allPublicFields = type.GetFields(publicFields); - foreach (FieldInfo field in allPublicFields) - { - yield return field; - } - - // get private fields in current type, then move to base type - while (type != null) - { - FieldInfo[] allPrivateFields = type.GetFields(privateFields); - foreach (FieldInfo field in allPrivateFields) - { - yield return field; - } - - type = type.BaseType; - - // stop early - if (type == deepestBaseType) - { - break; - } - } - } - - public static bool IsSyncVar(this FieldInfo field) - { - object[] fieldMarkers = field.GetCustomAttributes(typeof(SyncVarAttribute), true); - return fieldMarkers.Length > 0; - } - public static bool IsSerializeField(this FieldInfo field) - { - object[] fieldMarkers = field.GetCustomAttributes(typeof(SerializeField), true); - return fieldMarkers.Length > 0; - } - public static bool IsVisibleField(this FieldInfo field) - { - return field.IsPublic || IsSerializeField(field); - } - - public static bool IsSyncObject(this FieldInfo field) - { - return typeof(SyncObject).IsAssignableFrom(field.FieldType); - } - public static bool HasShowInInspector(this FieldInfo field) - { - object[] fieldMarkers = field.GetCustomAttributes(typeof(ShowInInspectorAttribute), true); - return fieldMarkers.Length > 0; - } - public static bool IsVisibleSyncObject(this FieldInfo field) - { - return field.IsPublic || HasShowInInspector(field); - } - } -} diff --git a/Assets/Mirror/Editor/InspectorHelper.cs.meta b/Assets/Mirror/Editor/InspectorHelper.cs.meta deleted file mode 100644 index 852ff71..0000000 --- a/Assets/Mirror/Editor/InspectorHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 047c894c2a5ccc1438b7e59302f62744 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/LogLevelWindow.cs b/Assets/Mirror/Editor/LogLevelWindow.cs deleted file mode 100644 index 82e5275..0000000 --- a/Assets/Mirror/Editor/LogLevelWindow.cs +++ /dev/null @@ -1 +0,0 @@ -// File moved to Mirror/Editor/Logging/LogLevelWindow.cs \ No newline at end of file diff --git a/Assets/Mirror/Editor/LogLevelWindow.cs.meta b/Assets/Mirror/Editor/LogLevelWindow.cs.meta deleted file mode 100644 index b8cbaeb..0000000 --- a/Assets/Mirror/Editor/LogLevelWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f28def2148ed5194abe70af012a4e3e0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Logging.meta b/Assets/Mirror/Editor/Logging.meta deleted file mode 100644 index 257467f..0000000 --- a/Assets/Mirror/Editor/Logging.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4d97731cd74ac8b4b8aad808548ef9cd -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Logging/LogLevelWindow.cs b/Assets/Mirror/Editor/Logging/LogLevelWindow.cs deleted file mode 100644 index 1d80f52..0000000 --- a/Assets/Mirror/Editor/Logging/LogLevelWindow.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Mirror.Logging; -using UnityEditor; -using UnityEngine; - -namespace Mirror.EditorScripts.Logging -{ - public class LogLevelWindow : EditorWindow - { - [Header("Log Settings Asset")] - [SerializeField] LogSettings settings = null; - - SerializedObject serializedObject; - SerializedProperty settingsProp; - Vector2 dictionaryScrollPosition; - - void OnEnable() - { - serializedObject = new SerializedObject(this); - settingsProp = serializedObject.FindProperty(nameof(settings)); - - LogSettings existingSettings = EditorLogSettingsLoader.FindLogSettings(); - if (existingSettings != null) - { - settingsProp.objectReferenceValue = existingSettings; - serializedObject.ApplyModifiedProperties(); - } - } - - void OnGUI() - { - using (EditorGUILayout.ScrollViewScope scrollScope = new EditorGUILayout.ScrollViewScope(dictionaryScrollPosition, GUIStyle.none, GUI.skin.verticalScrollbar)) - { - dictionaryScrollPosition = scrollScope.scrollPosition; - - using (new EditorGUILayout.VerticalScope()) - { - using (new EditorGUILayout.VerticalScope()) - { - serializedObject.Update(); - EditorGUILayout.PropertyField(settingsProp); - serializedObject.ApplyModifiedProperties(); - - if (settings == null) - { - LogSettings newSettings = LogLevelsGUI.DrawCreateNewButton(); - if (newSettings != null) - { - settingsProp.objectReferenceValue = newSettings; - serializedObject.ApplyModifiedProperties(); - } - } - else - { - LogLevelsGUI.DrawLogFactoryDictionary(settings); - } - } - } - } - } - - [MenuItem("Window/Analysis/Mirror Log Levels", priority = 20002)] - public static void ShowWindow() - { - LogLevelWindow window = GetWindow(); - window.minSize = new Vector2(200, 100); - window.titleContent = new GUIContent("Mirror Log Levels"); - window.Show(); - } - } -} diff --git a/Assets/Mirror/Editor/Logging/LogLevelWindow.cs.meta b/Assets/Mirror/Editor/Logging/LogLevelWindow.cs.meta deleted file mode 100644 index 832876f..0000000 --- a/Assets/Mirror/Editor/Logging/LogLevelWindow.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c3dbf48190d77d243b87962a82c3b164 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs b/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs deleted file mode 100644 index 2aaa855..0000000 --- a/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using Mirror.Logging; -using UnityEditor; -using UnityEngine; - -namespace Mirror.EditorScripts.Logging -{ - public static class LogLevelsGUI - { - public static LogSettings DrawCreateNewButton() - { - if (GUILayout.Button("Create New")) - { - return ScriptableObjectUtility.CreateAsset(nameof(LogSettings)); - } - - return null; - } - - public static void DrawLogFactoryDictionary(LogSettings settings) - { - using (EditorGUI.ChangeCheckScope scope = new EditorGUI.ChangeCheckScope()) - { - if (LogFactory.loggers.Count == 0) - { - EditorGUILayout.LabelField("No Keys found in LogFactory.loggers\nPlay the game for default log values to be added to LogFactory", EditorStyles.wordWrappedLabel); - } - else - { - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Logging Components", EditorStyles.boldLabel); - - foreach (KeyValuePair item in LogFactory.loggers) - { - DrawLoggerField(item); - } - - if (scope.changed) - { - settings.SaveFromDictionary(LogFactory.loggers); - } - } - } - } - - static void DrawLoggerField(KeyValuePair item) - { - ILogger logger = item.Value; - string name = item.Key; - - const float fieldWidth = 100f; - const float inspectorMargin = 25f; - - using (new EditorGUILayout.HorizontalScope()) - { - EditorGUILayout.LabelField(new GUIContent(ObjectNames.NicifyVariableName(name)), GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - fieldWidth - inspectorMargin)); - logger.filterLogType = (LogType)EditorGUILayout.EnumPopup(logger.filterLogType, GUILayout.Width(fieldWidth)); - } - } - } -} diff --git a/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs.meta b/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs.meta deleted file mode 100644 index 3214b08..0000000 --- a/Assets/Mirror/Editor/Logging/LogLevelsGUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9d6ce9d62a2d2ec4d8cef8a0d22b8dd2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs b/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs deleted file mode 100644 index 2579ae4..0000000 --- a/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Mirror.Logging; -using UnityEditor; -using UnityEngine; - -namespace Mirror.EditorScripts.Logging -{ - [CustomEditor(typeof(LogSettings))] - public class LogSettingsEditor : Editor - { - public override void OnInspectorGUI() - { - CurrentScriptField(); - - LogLevelsGUI.DrawLogFactoryDictionary(target as LogSettings); - } - - public void CurrentScriptField() - { - GUI.enabled = false; - EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script")); - GUI.enabled = true; - } - } -} diff --git a/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs.meta deleted file mode 100644 index 2c1fac4..0000000 --- a/Assets/Mirror/Editor/Logging/LogSettingsEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8f4ecb3d81ce9ff44b91f311ee46d4ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs b/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs deleted file mode 100644 index 56e172f..0000000 --- a/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Mirror.Logging; -using UnityEditor; - -namespace Mirror.EditorScripts.Logging -{ - [CustomEditor(typeof(NetworkLogSettings))] - public class NetworkLogSettingsEditor : Editor - { - public override void OnInspectorGUI() - { - DrawDefaultInspector(); - - NetworkLogSettings target = this.target as NetworkLogSettings; - - if (target.settings == null) - { - LogSettings newSettings = LogLevelsGUI.DrawCreateNewButton(); - if (newSettings != null) - { - SerializedProperty settingsProp = serializedObject.FindProperty("settings"); - settingsProp.objectReferenceValue = newSettings; - serializedObject.ApplyModifiedProperties(); - } - } - else - { - LogLevelsGUI.DrawLogFactoryDictionary(target.settings); - } - } - } -} diff --git a/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs.meta b/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs.meta deleted file mode 100644 index b4c277d..0000000 --- a/Assets/Mirror/Editor/Logging/NetworkLogSettingsEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 37fb96d5bbf965d47acfc5c8589a1b71 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef b/Assets/Mirror/Editor/Mirror.Editor.asmdef deleted file mode 100644 index 3ed7e2f..0000000 --- a/Assets/Mirror/Editor/Mirror.Editor.asmdef +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "Mirror.Editor", - "references": [ - "Mirror", - "Mirror.Weaver" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta b/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta deleted file mode 100644 index e2e6f2a..0000000 --- a/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1c7c33eb5480dd24c9e29a8250c1a775 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs deleted file mode 100644 index 45740a0..0000000 --- a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using UnityEditor; -using UnityEngine; - -namespace Mirror -{ - [CustomEditor(typeof(NetworkBehaviour), true)] - [CanEditMultipleObjects] - public class NetworkBehaviourInspector : Editor - { - /// - /// List of all visible syncVars in target class - /// - protected List syncVarNames = new List(); - bool syncsAnything; - SyncListDrawer syncListDrawer; - - // does this type sync anything? otherwise we don't need to show syncInterval - bool SyncsAnything(Type scriptClass) - { - // check for all SyncVar fields, they don't have to be visible - foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) - { - if (field.IsSyncVar()) - { - return true; - } - } - - // has OnSerialize that is not in NetworkBehaviour? - // then it either has a syncvar or custom OnSerialize. either way - // this means we have something to sync. - MethodInfo method = scriptClass.GetMethod("OnSerialize"); - if (method != null && method.DeclaringType != typeof(NetworkBehaviour)) - { - return true; - } - - // SyncObjects are serialized in NetworkBehaviour.OnSerialize, which - // is always there even if we don't use SyncObjects. so we need to - // search for SyncObjects manually. - // Any SyncObject should be added to syncObjects when unity creates an - // object so we can cheeck length of list so see if sync objects exists - FieldInfo syncObjectsField = scriptClass.GetField("syncObjects", BindingFlags.NonPublic | BindingFlags.Instance); - List syncObjects = (List)syncObjectsField.GetValue(serializedObject.targetObject); - - return syncObjects.Count > 0; - } - - void OnEnable() - { - if (target == null) { Debug.LogWarning("NetworkBehaviourInspector had no target object"); return; } - - // If target's base class is changed from NetworkBehaviour to MonoBehaviour - // then Unity temporarily keep using this Inspector causing things to break - if (!(target is NetworkBehaviour)) { return; } - - Type scriptClass = target.GetType(); - - syncVarNames = new List(); - foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) - { - if (field.IsSyncVar() && field.IsVisibleField()) - { - syncVarNames.Add(field.Name); - } - } - - syncListDrawer = new SyncListDrawer(serializedObject.targetObject); - - syncsAnything = SyncsAnything(scriptClass); - } - - public override void OnInspectorGUI() - { - DrawDefaultInspector(); - DrawDefaultSyncLists(); - DrawDefaultSyncSettings(); - } - - /// - /// Draws Sync Objects that are IEnumerable - /// - protected void DrawDefaultSyncLists() - { - // Need this check incase OnEnable returns early - if (syncListDrawer == null) { return; } - - syncListDrawer.Draw(); - } - - /// - /// Draws SyncSettings if the NetworkBehaviour has anything to sync - /// - protected void DrawDefaultSyncSettings() - { - // does it sync anything? then show extra properties - // (no need to show it if the class only has Cmds/Rpcs and no sync) - if (!syncsAnything) - { - return; - } - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Sync Settings", EditorStyles.boldLabel); - - EditorGUILayout.PropertyField(serializedObject.FindProperty("syncMode")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("syncInterval")); - - // apply - serializedObject.ApplyModifiedProperties(); - } - } - public class SyncListDrawer - { - readonly UnityEngine.Object targetObject; - readonly List syncListFields; - - public SyncListDrawer(UnityEngine.Object targetObject) - { - this.targetObject = targetObject; - syncListFields = new List(); - foreach (FieldInfo field in InspectorHelper.GetAllFields(targetObject.GetType(), typeof(NetworkBehaviour))) - { - if (field.IsSyncObject() && field.IsVisibleSyncObject()) - { - syncListFields.Add(new SyncListField(field)); - } - } - } - - public void Draw() - { - if (syncListFields.Count == 0) { return; } - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Sync Lists", EditorStyles.boldLabel); - - for (int i = 0; i < syncListFields.Count; i++) - { - DrawSyncList(syncListFields[i]); - } - } - - void DrawSyncList(SyncListField syncListField) - { - syncListField.visible = EditorGUILayout.Foldout(syncListField.visible, syncListField.label); - if (syncListField.visible) - { - using (new EditorGUI.IndentLevelScope()) - { - object fieldValue = syncListField.field.GetValue(targetObject); - if (fieldValue is IEnumerable synclist) - { - int index = 0; - foreach (object item in synclist) - { - string itemValue = item != null ? item.ToString() : "NULL"; - string itemLabel = "Element " + index; - EditorGUILayout.LabelField(itemLabel, itemValue); - - index++; - } - } - } - } - } - - class SyncListField - { - public bool visible; - public readonly FieldInfo field; - public readonly string label; - - public SyncListField(FieldInfo field) - { - this.field = field; - visible = false; - label = field.Name + " [" + field.FieldType.Name + "]"; - } - } - } -} //namespace diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta deleted file mode 100644 index 78d9fa8..0000000 --- a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f02853db46b6346e4866594a96c3b0e7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs b/Assets/Mirror/Editor/NetworkInformationPreview.cs deleted file mode 100644 index 0c30298..0000000 --- a/Assets/Mirror/Editor/NetworkInformationPreview.cs +++ /dev/null @@ -1,305 +0,0 @@ -using System.Collections.Generic; -using UnityEditor; -using UnityEngine; - -namespace Mirror -{ - [CustomPreview(typeof(GameObject))] - class NetworkInformationPreview : ObjectPreview - { - struct NetworkIdentityInfo - { - public GUIContent name; - public GUIContent value; - } - - struct NetworkBehaviourInfo - { - // This is here just so we can check if it's enabled/disabled - public NetworkBehaviour behaviour; - public GUIContent name; - } - - class Styles - { - public GUIStyle labelStyle = new GUIStyle(EditorStyles.label); - public GUIStyle componentName = new GUIStyle(EditorStyles.boldLabel); - public GUIStyle disabledName = new GUIStyle(EditorStyles.miniLabel); - - public Styles() - { - Color fontColor = new Color(0.7f, 0.7f, 0.7f); - labelStyle.padding.right += 20; - labelStyle.normal.textColor = fontColor; - labelStyle.active.textColor = fontColor; - labelStyle.focused.textColor = fontColor; - labelStyle.hover.textColor = fontColor; - labelStyle.onNormal.textColor = fontColor; - labelStyle.onActive.textColor = fontColor; - labelStyle.onFocused.textColor = fontColor; - labelStyle.onHover.textColor = fontColor; - - componentName.normal.textColor = fontColor; - componentName.active.textColor = fontColor; - componentName.focused.textColor = fontColor; - componentName.hover.textColor = fontColor; - componentName.onNormal.textColor = fontColor; - componentName.onActive.textColor = fontColor; - componentName.onFocused.textColor = fontColor; - componentName.onHover.textColor = fontColor; - - disabledName.normal.textColor = fontColor; - disabledName.active.textColor = fontColor; - disabledName.focused.textColor = fontColor; - disabledName.hover.textColor = fontColor; - disabledName.onNormal.textColor = fontColor; - disabledName.onActive.textColor = fontColor; - disabledName.onFocused.textColor = fontColor; - disabledName.onHover.textColor = fontColor; - } - } - - GUIContent title; - Styles styles = new Styles(); - - public override GUIContent GetPreviewTitle() - { - if (title == null) - { - title = new GUIContent("Network Information"); - } - return title; - } - - public override bool HasPreviewGUI() - { - // need to check if target is null to stop MissingReferenceException - return target != null && target is GameObject gameObject && gameObject.GetComponent() != null; - } - - public override void OnPreviewGUI(Rect r, GUIStyle background) - { - if (Event.current.type != EventType.Repaint) - return; - - if (target == null) - return; - - GameObject targetGameObject = target as GameObject; - - if (targetGameObject == null) - return; - - NetworkIdentity identity = targetGameObject.GetComponent(); - - if (identity == null) - return; - - if (styles == null) - styles = new Styles(); - - - // padding - RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); - Rect paddedr = previewPadding.Add(r); - - //Centering - float initialX = paddedr.x + 10; - float Y = paddedr.y + 10; - - Y = DrawNetworkIdentityInfo(identity, initialX, Y); - - Y = DrawNetworkBehaviors(identity, initialX, Y); - - Y = DrawObservers(identity, initialX, Y); - - _ = DrawOwner(identity, initialX, Y); - - } - - float DrawNetworkIdentityInfo(NetworkIdentity identity, float initialX, float Y) - { - IEnumerable infos = GetNetworkIdentityInfo(identity); - // Get required label size for the names of the information values we're going to show - // There are two columns, one with label for the name of the info and the next for the value - Vector2 maxNameLabelSize = new Vector2(140, 16); - Vector2 maxValueLabelSize = GetMaxNameLabelSize(infos); - - Rect labelRect = new Rect(initialX, Y, maxNameLabelSize.x, maxNameLabelSize.y); - Rect idLabelRect = new Rect(maxNameLabelSize.x, Y, maxValueLabelSize.x, maxValueLabelSize.y); - - foreach (NetworkIdentityInfo info in infos) - { - GUI.Label(labelRect, info.name, styles.labelStyle); - GUI.Label(idLabelRect, info.value, styles.componentName); - labelRect.y += labelRect.height; - labelRect.x = initialX; - idLabelRect.y += idLabelRect.height; - } - - return labelRect.y; - } - - float DrawNetworkBehaviors(NetworkIdentity identity, float initialX, float Y) - { - IEnumerable behavioursInfo = GetNetworkBehaviorInfo(identity); - - // Show behaviours list in a different way than the name/value pairs above - Vector2 maxBehaviourLabelSize = GetMaxBehaviourLabelSize(behavioursInfo); - Rect behaviourRect = new Rect(initialX, Y + 10, maxBehaviourLabelSize.x, maxBehaviourLabelSize.y); - - GUI.Label(behaviourRect, new GUIContent("Network Behaviours"), styles.labelStyle); - // indent names - behaviourRect.x += 20; - behaviourRect.y += behaviourRect.height; - - foreach (NetworkBehaviourInfo info in behavioursInfo) - { - if (info.behaviour == null) - { - // could be the case in the editor after existing play mode. - continue; - } - - GUI.Label(behaviourRect, info.name, info.behaviour.enabled ? styles.componentName : styles.disabledName); - behaviourRect.y += behaviourRect.height; - Y = behaviourRect.y; - } - - return Y; - } - - float DrawObservers(NetworkIdentity identity, float initialX, float Y) - { - if (identity.observers != null && identity.observers.Count > 0) - { - Rect observerRect = new Rect(initialX, Y + 10, 200, 20); - - GUI.Label(observerRect, new GUIContent("Network observers"), styles.labelStyle); - // indent names - observerRect.x += 20; - observerRect.y += observerRect.height; - - foreach (KeyValuePair kvp in identity.observers) - { - GUI.Label(observerRect, kvp.Value.address + ":" + kvp.Value, styles.componentName); - observerRect.y += observerRect.height; - Y = observerRect.y; - } - } - - return Y; - } - - float DrawOwner(NetworkIdentity identity, float initialX, float Y) - { - if (identity.connectionToClient != null) - { - Rect ownerRect = new Rect(initialX, Y + 10, 400, 20); - GUI.Label(ownerRect, new GUIContent("Client Authority: " + identity.connectionToClient), styles.labelStyle); - Y += ownerRect.height; - } - return Y; - } - - // Get the maximum size used by the value of information items - Vector2 GetMaxNameLabelSize(IEnumerable infos) - { - Vector2 maxLabelSize = Vector2.zero; - foreach (NetworkIdentityInfo info in infos) - { - Vector2 labelSize = styles.labelStyle.CalcSize(info.value); - if (maxLabelSize.x < labelSize.x) - { - maxLabelSize.x = labelSize.x; - } - if (maxLabelSize.y < labelSize.y) - { - maxLabelSize.y = labelSize.y; - } - } - return maxLabelSize; - } - - Vector2 GetMaxBehaviourLabelSize(IEnumerable behavioursInfo) - { - Vector2 maxLabelSize = Vector2.zero; - foreach (NetworkBehaviourInfo behaviour in behavioursInfo) - { - Vector2 labelSize = styles.labelStyle.CalcSize(behaviour.name); - if (maxLabelSize.x < labelSize.x) - { - maxLabelSize.x = labelSize.x; - } - if (maxLabelSize.y < labelSize.y) - { - maxLabelSize.y = labelSize.y; - } - } - return maxLabelSize; - } - - IEnumerable GetNetworkIdentityInfo(NetworkIdentity identity) - { - List infos = new List - { - GetAssetId(identity), - GetString("Scene ID", identity.sceneId.ToString("X")) - }; - - if (Application.isPlaying) - { - infos.Add(GetString("Network ID", identity.netId.ToString())); - infos.Add(GetBoolean("Is Client", identity.isClient)); - infos.Add(GetBoolean("Is Server", identity.isServer)); - infos.Add(GetBoolean("Has Authority", identity.hasAuthority)); - infos.Add(GetBoolean("Is Local Player", identity.isLocalPlayer)); - } - return infos; - } - - IEnumerable GetNetworkBehaviorInfo(NetworkIdentity identity) - { - List behaviourInfos = new List(); - - NetworkBehaviour[] behaviours = identity.GetComponents(); - foreach (NetworkBehaviour behaviour in behaviours) - { - behaviourInfos.Add(new NetworkBehaviourInfo - { - name = new GUIContent(behaviour.GetType().FullName), - behaviour = behaviour - }); - } - return behaviourInfos; - } - - NetworkIdentityInfo GetAssetId(NetworkIdentity identity) - { - string assetId = identity.assetId.ToString(); - if (string.IsNullOrEmpty(assetId)) - { - assetId = ""; - } - return GetString("Asset ID", assetId); - } - - static NetworkIdentityInfo GetString(string name, string value) - { - return new NetworkIdentityInfo - { - name = new GUIContent(name), - value = new GUIContent(value) - }; - } - - static NetworkIdentityInfo GetBoolean(string name, bool value) - { - return new NetworkIdentityInfo - { - name = new GUIContent(name), - value = new GUIContent((value ? "Yes" : "No")) - }; - } - } -} diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta b/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta deleted file mode 100644 index 9bf2de4..0000000 --- a/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 51a99294efe134232932c34606737356 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs b/Assets/Mirror/Editor/NetworkManagerEditor.cs deleted file mode 100644 index 315db46..0000000 --- a/Assets/Mirror/Editor/NetworkManagerEditor.cs +++ /dev/null @@ -1,113 +0,0 @@ -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; - -namespace Mirror -{ - [CustomEditor(typeof(NetworkManager), true)] - [CanEditMultipleObjects] - public class NetworkManagerEditor : Editor - { - SerializedProperty spawnListProperty; - - ReorderableList spawnList; - - protected NetworkManager networkManager; - - protected void Init() - { - if (spawnList == null) - { - - networkManager = target as NetworkManager; - - spawnListProperty = serializedObject.FindProperty("spawnPrefabs"); - - spawnList = new ReorderableList(serializedObject, spawnListProperty) - { - drawHeaderCallback = DrawHeader, - drawElementCallback = DrawChild, - onReorderCallback = Changed, - onRemoveCallback = RemoveButton, - onChangedCallback = Changed, - onAddCallback = AddButton, - // this uses a 16x16 icon. other sizes make it stretch. - elementHeight = 16 - }; - } - } - - public override void OnInspectorGUI() - { - Init(); - DrawDefaultInspector(); - EditorGUI.BeginChangeCheck(); - spawnList.DoLayoutList(); - if (EditorGUI.EndChangeCheck()) - { - serializedObject.ApplyModifiedProperties(); - } - } - - static void DrawHeader(Rect headerRect) - { - GUI.Label(headerRect, "Registered Spawnable Prefabs:"); - } - - internal void DrawChild(Rect r, int index, bool isActive, bool isFocused) - { - SerializedProperty prefab = spawnListProperty.GetArrayElementAtIndex(index); - GameObject go = (GameObject)prefab.objectReferenceValue; - - GUIContent label; - if (go == null) - { - label = new GUIContent("Empty", "Drag a prefab with a NetworkIdentity here"); - } - else - { - NetworkIdentity identity = go.GetComponent(); - label = new GUIContent(go.name, identity != null ? "AssetId: [" + identity.assetId + "]" : "No Network Identity"); - } - - GameObject newGameObject = (GameObject)EditorGUI.ObjectField(r, label, go, typeof(GameObject), false); - - if (newGameObject != go) - { - if (newGameObject != null && !newGameObject.GetComponent()) - { - Debug.LogError("Prefab " + newGameObject + " cannot be added as spawnable as it doesn't have a NetworkIdentity."); - return; - } - prefab.objectReferenceValue = newGameObject; - } - } - - internal void Changed(ReorderableList list) - { - EditorUtility.SetDirty(target); - } - - internal void AddButton(ReorderableList list) - { - spawnListProperty.arraySize += 1; - list.index = spawnListProperty.arraySize - 1; - - SerializedProperty obj = spawnListProperty.GetArrayElementAtIndex(spawnListProperty.arraySize - 1); - obj.objectReferenceValue = null; - - spawnList.index = spawnList.count - 1; - - Changed(list); - } - - internal void RemoveButton(ReorderableList list) - { - spawnListProperty.DeleteArrayElementAtIndex(spawnList.index); - if (list.index >= spawnListProperty.arraySize) - { - list.index = spawnListProperty.arraySize - 1; - } - } - } -} diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta b/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta deleted file mode 100644 index 7fe8dbc..0000000 --- a/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 519712eb07f7a44039df57664811c2c5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs b/Assets/Mirror/Editor/NetworkScenePostProcess.cs deleted file mode 100644 index cb66328..0000000 --- a/Assets/Mirror/Editor/NetworkScenePostProcess.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEditor; -using UnityEditor.Callbacks; -using UnityEngine; - -namespace Mirror -{ - public class NetworkScenePostProcess : MonoBehaviour - { - [PostProcessScene] - public static void OnPostProcessScene() - { - // find all NetworkIdentities in all scenes - // => can't limit it to GetActiveScene() because that wouldn't work - // for additive scene loads (the additively loaded scene is never - // the active scene) - // => ignore DontDestroyOnLoad scene! this avoids weird situations - // like in NetworkZones when we destroy the local player and - // load another scene afterwards, yet the local player is still - // in the FindObjectsOfType result with scene=DontDestroyOnLoad - // for some reason - // => OfTypeAll so disabled objects are included too - // => Unity 2019 returns prefabs here too, so filter them out. - IEnumerable identities = Resources.FindObjectsOfTypeAll() - .Where(identity => identity.gameObject.hideFlags != HideFlags.NotEditable && - identity.gameObject.hideFlags != HideFlags.HideAndDontSave && - identity.gameObject.scene.name != "DontDestroyOnLoad" && - !PrefabUtility.IsPartOfPrefabAsset(identity.gameObject)); - - foreach (NetworkIdentity identity in identities) - { - // if we had a [ConflictComponent] attribute that would be better than this check. - // also there is no context about which scene this is in. - if (identity.GetComponent() != null) - { - Debug.LogError("NetworkManager has a NetworkIdentity component. This will cause the NetworkManager object to be disabled, so it is not recommended."); - } - - // not spawned before? - // OnPostProcessScene is called after additive scene loads too, - // and we don't want to set main scene's objects inactive again - if (!identity.isClient && !identity.isServer) - { - // valid scene object? - // otherwise it might be an unopened scene that still has null - // sceneIds. builds are interrupted if they contain 0 sceneIds, - // but it's still possible that we call LoadScene in Editor - // for a previously unopened scene. - // (and only do SetActive if this was actually a scene object) - if (identity.sceneId != 0) - { - PrepareSceneObject(identity); - } - // throwing an exception would only show it for one object - // because this function would return afterwards. - else Debug.LogError("Scene " + identity.gameObject.scene.path + " needs to be opened and resaved, because the scene object " + identity.name + " has no valid sceneId yet."); - } - } - } - - static void PrepareSceneObject(NetworkIdentity identity) - { - // set scene hash - identity.SetSceneIdSceneHashPartInternal(); - - // disable it - // note: NetworkIdentity.OnDisable adds itself to the - // spawnableObjects dictionary (only if sceneId != 0) - identity.gameObject.SetActive(false); - - // safety check for prefabs with more than one NetworkIdentity -#if UNITY_2018_2_OR_NEWER - GameObject prefabGO = PrefabUtility.GetCorrespondingObjectFromSource(identity.gameObject); -#else - GameObject prefabGO = PrefabUtility.GetPrefabParent(identity.gameObject); -#endif - if (prefabGO) - { -#if UNITY_2018_3_OR_NEWER - GameObject prefabRootGO = prefabGO.transform.root.gameObject; -#else - GameObject prefabRootGO = PrefabUtility.FindPrefabRoot(prefabGO); -#endif - if (prefabRootGO != null && prefabRootGO.GetComponentsInChildren().Length > 1) - { - Debug.LogWarningFormat("Prefab '{0}' has several NetworkIdentity components attached to itself or its children, this is not supported.", prefabRootGO.name); - } - } - } - } -} diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta b/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta deleted file mode 100644 index b567cc9..0000000 --- a/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a3ec1c414d821444a9e77f18a2c130ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/SceneDrawer.cs b/Assets/Mirror/Editor/SceneDrawer.cs deleted file mode 100644 index a234c3f..0000000 --- a/Assets/Mirror/Editor/SceneDrawer.cs +++ /dev/null @@ -1,47 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace Mirror -{ - [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.LogError($"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.name == sceneName) - { - return sceneAsset; - } - } - return null; - } - } -} diff --git a/Assets/Mirror/Editor/SceneDrawer.cs.meta b/Assets/Mirror/Editor/SceneDrawer.cs.meta deleted file mode 100644 index 6a996dc..0000000 --- a/Assets/Mirror/Editor/SceneDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b24704a46211b4ea294aba8f58715cea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/ScriptableObjectUtility.cs b/Assets/Mirror/Editor/ScriptableObjectUtility.cs deleted file mode 100644 index e6a36bd..0000000 --- a/Assets/Mirror/Editor/ScriptableObjectUtility.cs +++ /dev/null @@ -1,54 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace Mirror.EditorScripts -{ - public static class ScriptableObjectUtility - { - /// - // This makes it easy to create, name and place unique new ScriptableObject asset files. - /// - public static T CreateAsset(string defaultName) where T : ScriptableObject - { - string path = SavePanel(defaultName); - // user click cancel - if (string.IsNullOrEmpty(path)) { return null; } - - T asset = ScriptableObject.CreateInstance(); - - SaveAsset(path, asset); - - return asset; - } - - static string SavePanel(string name) - { - string path = EditorUtility.SaveFilePanel( - "Save ScriptableObject", - "Assets/Mirror/", - name + ".asset", - "asset"); - - // user click cancel, return early - if (string.IsNullOrEmpty(path)) { return path; } - - // Unity only wants path from Assets - if (path.StartsWith(Application.dataPath)) - { - path = "Assets" + path.Substring(Application.dataPath.Length); - } - - return path; - } - - static void SaveAsset(string path, ScriptableObject asset) - { - string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path); - - AssetDatabase.CreateAsset(asset, assetPathAndName); - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - } -} diff --git a/Assets/Mirror/Editor/ScriptableObjectUtility.cs.meta b/Assets/Mirror/Editor/ScriptableObjectUtility.cs.meta deleted file mode 100644 index a1a0af3..0000000 --- a/Assets/Mirror/Editor/ScriptableObjectUtility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4d54a29ddd5b52b4eaa07ed39c0e3e83 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs deleted file mode 100644 index f7b018a..0000000 --- a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace Mirror -{ - [CustomPropertyDrawer(typeof(SyncVarAttribute))] - public class SyncVarAttributeDrawer : PropertyDrawer - { - static readonly GUIContent syncVarIndicatorContent = new GUIContent("SyncVar", "This variable has been marked with the [SyncVar] attribute."); - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - Vector2 syncVarIndicatorRect = EditorStyles.miniLabel.CalcSize(syncVarIndicatorContent); - float valueWidth = position.width - syncVarIndicatorRect.x; - - Rect valueRect = new Rect(position.x, position.y, valueWidth, position.height); - Rect labelRect = new Rect(position.x + valueWidth, position.y, syncVarIndicatorRect.x, position.height); - - EditorGUI.PropertyField(valueRect, property, true); - GUI.Label(labelRect, syncVarIndicatorContent, EditorStyles.miniLabel); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - return EditorGUI.GetPropertyHeight(property); - } - } -} //namespace diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta deleted file mode 100644 index 6311f1d..0000000 --- a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 27821afc81c4d064d8348fbeb00c0ce8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver.meta b/Assets/Mirror/Editor/Weaver.meta deleted file mode 100644 index 121fbf4..0000000 --- a/Assets/Mirror/Editor/Weaver.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d9f8e6274119b4ce29e498cfb8aca8a4 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs deleted file mode 100644 index 08b43f5..0000000 --- a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Mirror.Tests")] diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta deleted file mode 100644 index d356af8..0000000 --- a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 929924d95663264478d4238d4910d22e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs b/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs deleted file mode 100644 index 55346fa..0000000 --- a/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditor.Compilation; -using UnityEngine; -using UnityAssembly = UnityEditor.Compilation.Assembly; - -namespace Mirror.Weaver -{ - public static class CompilationFinishedHook - { - const string MirrorRuntimeAssemblyName = "Mirror"; - const string MirrorWeaverAssemblyName = "Mirror.Weaver"; - - // delegate for subscription to Weaver debug messages - public static Action OnWeaverMessage; - // delegate for subscription to Weaver warning messages - public static Action OnWeaverWarning; - // delete for subscription to Weaver error messages - public static Action OnWeaverError; - - // controls whether we weave any assemblies when CompilationPipeline delegates are invoked - public static bool WeaverEnabled { get; set; } - // controls weather Weaver errors are reported direct to the Unity console (tests enable this) - public static bool UnityLogEnabled = true; - - // warning message handler that also calls OnWarningMethod delegate - static void HandleWarning(string msg) - { - if (UnityLogEnabled) Debug.LogWarning(msg); - if (OnWeaverWarning != null) OnWeaverWarning.Invoke(msg); - } - - // error message handler that also calls OnErrorMethod delegate - static void HandleError(string msg) - { - if (UnityLogEnabled) Debug.LogError(msg); - if (OnWeaverError != null) OnWeaverError.Invoke(msg); - } - - [InitializeOnLoadMethod] - public static void OnInitializeOnLoad() - { - CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished; - - // We only need to run this once per session - // after that, all assemblies will be weaved by the event - if (!SessionState.GetBool("MIRROR_WEAVED", false)) - { - // reset session flag - SessionState.SetBool("MIRROR_WEAVED", true); - SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); - - WeaveExistingAssemblies(); - } - } - - public static void WeaveExistingAssemblies() - { - foreach (UnityAssembly assembly in CompilationPipeline.GetAssemblies()) - { - if (File.Exists(assembly.outputPath)) - { - OnCompilationFinished(assembly.outputPath, new CompilerMessage[0]); - } - } - -#if UNITY_2019_3_OR_NEWER - EditorUtility.RequestScriptReload(); -#else - UnityEditorInternal.InternalEditorUtility.RequestScriptReload(); -#endif - } - - static string FindMirrorRuntime() - { - foreach (UnityAssembly assembly in CompilationPipeline.GetAssemblies()) - { - if (assembly.name == MirrorRuntimeAssemblyName) - { - return assembly.outputPath; - } - } - return ""; - } - - static bool CompilerMessagesContainError(CompilerMessage[] messages) - { - return messages.Any(msg => msg.type == CompilerMessageType.Error); - } - - static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) - { - // Do nothing if there were compile errors on the target - if (CompilerMessagesContainError(messages)) - { - Debug.Log("Weaver: stop because compile errors on target"); - return; - } - - // Should not run on the editor only assemblies - if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) - { - return; - } - - // don't weave mirror files - string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); - if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) - { - return; - } - - // find Mirror.dll - string mirrorRuntimeDll = FindMirrorRuntime(); - if (string.IsNullOrEmpty(mirrorRuntimeDll)) - { - Debug.LogError("Failed to find Mirror runtime assembly"); - return; - } - if (!File.Exists(mirrorRuntimeDll)) - { - // this is normal, it happens with any assembly that is built before mirror - // such as unity packages or your own assemblies - // those don't need to be weaved - // if any assembly depends on mirror, then it will be built after - return; - } - - // find UnityEngine.CoreModule.dll - string unityEngineCoreModuleDLL = UnityEditorInternal.InternalEditorUtility.GetEngineCoreModuleAssemblyPath(); - if (string.IsNullOrEmpty(unityEngineCoreModuleDLL)) - { - Debug.LogError("Failed to find UnityEngine assembly"); - return; - } - - HashSet dependencyPaths = GetDependecyPaths(assemblyPath); - dependencyPaths.Add(Path.GetDirectoryName(mirrorRuntimeDll)); - dependencyPaths.Add(Path.GetDirectoryName(unityEngineCoreModuleDLL)); - Log.WarningMethod = HandleWarning; - Log.ErrorMethod = HandleError; - - if (!Weaver.WeaveAssembly(assemblyPath, dependencyPaths.ToArray())) - { - // Set false...will be checked in \Editor\EnterPlayModeSettingsCheck.CheckSuccessfulWeave() - SessionState.SetBool("MIRROR_WEAVE_SUCCESS", false); - if (UnityLogEnabled) Debug.LogError("Weaving failed for: " + assemblyPath); - } - } - - static HashSet GetDependecyPaths(string assemblyPath) - { - // build directory list for later asm/symbol resolving using CompilationPipeline refs - HashSet dependencyPaths = new HashSet - { - Path.GetDirectoryName(assemblyPath) - }; - foreach (UnityAssembly unityAsm in CompilationPipeline.GetAssemblies()) - { - if (unityAsm.outputPath != assemblyPath) - continue; - - foreach (string unityAsmRef in unityAsm.compiledAssemblyReferences) - { - dependencyPaths.Add(Path.GetDirectoryName(unityAsmRef)); - } - } - - return dependencyPaths; - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs.meta b/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs.meta deleted file mode 100644 index ed537ab..0000000 --- a/Assets/Mirror/Editor/Weaver/CompilationFinishedHook.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: de2aeb2e8068f421a9a1febe408f7051 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs b/Assets/Mirror/Editor/Weaver/Extensions.cs deleted file mode 100644 index 74bd1cf..0000000 --- a/Assets/Mirror/Editor/Weaver/Extensions.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Mono.CecilX; - -namespace Mirror.Weaver -{ - public static class Extensions - { - public static bool Is(this TypeReference td, Type t) - { - if (t.IsGenericType) - { - return td.GetElementType().FullName == t.FullName; - } - return td.FullName == t.FullName; - } - - public static bool Is(this TypeReference td) => Is(td, typeof(T)); - - public static bool IsDerivedFrom(this TypeDefinition td) => IsDerivedFrom(td, typeof(T)); - - public static bool IsDerivedFrom(this TypeDefinition td, Type baseClass) - { - - if (!td.IsClass) - return false; - - // are ANY parent classes of baseClass? - TypeReference parent = td.BaseType; - - if (parent == null) - return false; - - if (parent.Is(baseClass)) - return true; - - if (parent.CanBeResolved()) - return IsDerivedFrom(parent.Resolve(), baseClass); - - return false; - } - - public static TypeReference GetEnumUnderlyingType(this TypeDefinition td) - { - foreach (FieldDefinition field in td.Fields) - { - if (!field.IsStatic) - return field.FieldType; - } - throw new ArgumentException($"Invalid enum {td.FullName}"); - } - - public static bool ImplementsInterface(this TypeDefinition td) - { - TypeDefinition typedef = td; - - while (typedef != null) - { - foreach (InterfaceImplementation iface in typedef.Interfaces) - { - if (iface.InterfaceType.Is()) - return true; - } - - try - { - TypeReference parent = typedef.BaseType; - typedef = parent?.Resolve(); - } - catch (AssemblyResolutionException) - { - // this can happen for pluins. - //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); - break; - } - } - - return false; - } - - public static bool IsMultidimensionalArray(this TypeReference tr) - { - return tr is ArrayType arrayType && arrayType.Rank > 1; - } - - public static bool CanBeResolved(this TypeReference parent) - { - while (parent != null) - { - if (parent.Scope.Name == "Windows") - { - return false; - } - - if (parent.Scope.Name == "mscorlib") - { - TypeDefinition resolved = parent.Resolve(); - return resolved != null; - } - - try - { - parent = parent.Resolve().BaseType; - } - catch - { - return false; - } - } - return true; - } - - - /// - /// 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 Weaver.CurrentAssembly.MainModule.ImportReference(reference); - } - - /// - /// Given a field of a generic class such as Writer.write, - /// 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 - /// - /// - /// Generic Instance eg Writer - /// - public static FieldReference SpecializeField(this FieldReference self, GenericInstanceType instanceType) - { - FieldReference reference = new FieldReference(self.Name, self.FieldType, instanceType); - - return Weaver.CurrentAssembly.MainModule.ImportReference(reference); - } - - public static CustomAttribute GetCustomAttribute(this ICustomAttributeProvider method) - { - foreach (CustomAttribute ca in method.CustomAttributes) - { - if (ca.AttributeType.Is()) - return ca; - } - return null; - } - - public static bool HasCustomAttribute(this ICustomAttributeProvider attributeProvider) - { - // Linq allocations don't matter in weaver - return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is()); - } - - public static T GetField(this CustomAttribute ca, string field, T defaultValue) - { - foreach (CustomAttributeNamedArgument customField in ca.Fields) - { - if (customField.Name == field) - { - return (T)customField.Argument.Value; - } - } - - return defaultValue; - } - - public static MethodDefinition GetMethod(this TypeDefinition td, string methodName) - { - // Linq allocations don't matter in weaver - return td.Methods.FirstOrDefault(method => method.Name == methodName); - } - - public static List GetMethods(this TypeDefinition td, string methodName) - { - // Linq allocations don't matter in weaver - return td.Methods.Where(method => method.Name == methodName).ToList(); - } - - public static MethodDefinition GetMethodInBaseType(this TypeDefinition td, string methodName) - { - TypeDefinition typedef = td; - while (typedef != null) - { - foreach (MethodDefinition md in typedef.Methods) - { - if (md.Name == methodName) - return md; - } - - try - { - TypeReference parent = typedef.BaseType; - typedef = parent?.Resolve(); - } - catch (AssemblyResolutionException) - { - // this can happen for plugins. - break; - } - } - - return null; - } - - /// - /// Finds public fields in type and base type - /// - /// - /// - public static IEnumerable FindAllPublicFields(this TypeReference variable) - { - return FindAllPublicFields(variable.Resolve()); - } - - /// - /// Finds public fields in type and base type - /// - /// - /// - public static IEnumerable FindAllPublicFields(this TypeDefinition typeDefinition) - { - while (typeDefinition != null) - { - foreach (FieldDefinition field in typeDefinition.Fields) - { - if (field.IsStatic || field.IsPrivate) - continue; - - if (field.IsNotSerialized) - continue; - - yield return field; - } - - try - { - typeDefinition = typeDefinition.BaseType?.Resolve(); - } - catch (AssemblyResolutionException) - { - break; - } - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs.meta b/Assets/Mirror/Editor/Weaver/Extensions.cs.meta deleted file mode 100644 index 78660f9..0000000 --- a/Assets/Mirror/Editor/Weaver/Extensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 562a5cf0254cc45738e9aa549a7100b2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs b/Assets/Mirror/Editor/Weaver/Helpers.cs deleted file mode 100644 index 44398fd..0000000 --- a/Assets/Mirror/Editor/Weaver/Helpers.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Diagnostics; -using System.IO; -using System.Reflection; - -namespace Mirror.Weaver -{ - static class Helpers - { - // This code is taken from SerializationWeaver - - public static string UnityEngineDllDirectoryName() - { - string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); - return directoryName?.Replace(@"file:\", ""); - } - - public static string DestinationFileFor(string outputDir, string assemblyPath) - { - string fileName = Path.GetFileName(assemblyPath); - Debug.Assert(fileName != null, "fileName != null"); - - return Path.Combine(outputDir, fileName); - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs.meta b/Assets/Mirror/Editor/Weaver/Helpers.cs.meta deleted file mode 100644 index 231f539..0000000 --- a/Assets/Mirror/Editor/Weaver/Helpers.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6c4ed76daf48547c5abb7c58f8d20886 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Log.cs b/Assets/Mirror/Editor/Weaver/Log.cs deleted file mode 100644 index 75d0932..0000000 --- a/Assets/Mirror/Editor/Weaver/Log.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace Mirror.Weaver -{ - public static class Log - { - public static Action WarningMethod; - public static Action ErrorMethod; - - public static void Warning(string msg) - { - WarningMethod(msg); - } - - public static void Error(string msg) - { - ErrorMethod(msg); - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Log.cs.meta b/Assets/Mirror/Editor/Weaver/Log.cs.meta deleted file mode 100644 index 3f62978..0000000 --- a/Assets/Mirror/Editor/Weaver/Log.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2a21c60c40a4c4d679c2b71a7c40882e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef b/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef deleted file mode 100644 index 673d347..0000000 --- a/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "Mirror.Weaver", - "references": [ - "Mirror" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef.meta b/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef.meta deleted file mode 100644 index b65a0cd..0000000 --- a/Assets/Mirror/Editor/Weaver/Mirror.Weaver.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1d0b9d21c3ff546a4aa32399dfd33474 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors.meta b/Assets/Mirror/Editor/Weaver/Processors.meta deleted file mode 100644 index eb719b4..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e538d627280d2471b8c72fdea822ca49 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs deleted file mode 100644 index c028e9c..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - /// - /// Processes [Command] methods in NetworkBehaviour - /// - public static class CommandProcessor - { - /* - // generates code like: - public void CmdThrust(float thrusting, int spin) - { - NetworkWriter networkWriter = new NetworkWriter(); - networkWriter.Write(thrusting); - networkWriter.WritePackedUInt32((uint)spin); - base.SendCommandInternal(cmdName, networkWriter, cmdName); - } - - public void CallCmdThrust(float thrusting, int spin) - { - // whatever the user was doing before - } - - Originally HLAPI put the send message code inside the Call function - and then proceeded to replace every call to CmdTrust with CallCmdTrust - - This method moves all the user's code into the "CallCmd" method - and replaces the body of the original method with the send message code. - This way we do not need to modify the code anywhere else, and this works - correctly in dependent assemblies - */ - public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr) - { - MethodDefinition cmd = MethodProcessor.SubstituteMethod(td, md); - - ILProcessor worker = md.Body.GetILProcessor(); - - NetworkBehaviourProcessor.WriteSetupLocals(worker); - - // NetworkWriter writer = new NetworkWriter(); - NetworkBehaviourProcessor.WriteCreateWriter(worker); - - // write all the arguments that the user passed to the Cmd call - if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.Command)) - return null; - - string cmdName = md.Name; - int channel = commandAttr.GetField("channel", 0); - bool ignoreAuthority = commandAttr.GetField("ignoreAuthority", false); - - // invoke internal send and return - // load 'base.' to call the SendCommand function with - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldtoken, td)); - // invokerClass - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference)); - worker.Append(worker.Create(OpCodes.Ldstr, cmdName)); - // writer - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Ldc_I4, channel)); - worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.sendCommandInternal)); - - NetworkBehaviourProcessor.WriteRecycleWriter(worker); - - worker.Append(worker.Create(OpCodes.Ret)); - - return cmd; - } - - /* - // generates code like: - protected static void InvokeCmdCmdThrust(NetworkBehaviour obj, NetworkReader reader, NetworkConnection senderConnection) - { - if (!NetworkServer.active) - { - return; - } - ((ShipControl)obj).CmdThrust(reader.ReadSingle(), (int)reader.ReadPackedUInt32()); - } - */ - public static MethodDefinition ProcessCommandInvoke(TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc) - { - MethodDefinition cmd = new MethodDefinition(Weaver.InvokeRpcPrefix + method.Name, - MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - ILProcessor worker = cmd.Body.GetILProcessor(); - Instruction label = worker.Create(OpCodes.Nop); - - NetworkBehaviourProcessor.WriteServerActiveCheck(worker, method.Name, label, "Command"); - - // setup for reader - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Castclass, td)); - - if (!NetworkBehaviourProcessor.ReadArguments(method, worker, RemoteCallType.Command)) - return null; - - AddSenderConnection(method, worker); - - // invoke actual command function - worker.Append(worker.Create(OpCodes.Callvirt, cmdCallFunc)); - worker.Append(worker.Create(OpCodes.Ret)); - - NetworkBehaviourProcessor.AddInvokeParameters(cmd.Parameters); - - td.Methods.Add(cmd); - return cmd; - } - - static void AddSenderConnection(MethodDefinition method, ILProcessor worker) - { - foreach (ParameterDefinition param in method.Parameters) - { - if (NetworkBehaviourProcessor.IsSenderConnection(param, RemoteCallType.Command)) - { - // NetworkConnection is 3nd arg (arg0 is "obj" not "this" because method is static) - // exmaple: static void InvokeCmdCmdSendCommand(NetworkBehaviour obj, NetworkReader reader, NetworkConnection connection) - worker.Append(worker.Create(OpCodes.Ldarg_2)); - } - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta deleted file mode 100644 index 20c3e15..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 73f6c9cdbb9e54f65b3a0a35cc8e55c2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs +++ /dev/null @@ -1 +0,0 @@ -// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta deleted file mode 100644 index 685f914..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fd67b3f7c2d66074a9bc7a23787e2ffb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs deleted file mode 100644 index b38f171..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// removed Oct 5 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs.meta deleted file mode 100644 index cbea4d6..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MessageClassProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e25c00c88fc134f6ea7ab00ae4db8083 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs deleted file mode 100644 index 6ea5663..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - public static class MethodProcessor - { - private const string RpcPrefix = "UserCode_"; - - // creates a method substitute - // For example, if we have this: - // public void CmdThrust(float thrusting, int spin) - // { - // xxxxx - // } - // - // it will substitute the method and move the code to a new method with a provided name - // for example: - // - // public void CmdTrust(float thrusting, int spin) - // { - // } - // - // public void (float thrusting, int spin) - // { - // xxxxx - // } - // - // Note that all the calls to the method remain untouched - // - // the original method definition loses all code - // this returns the newly created method with all the user provided code - public static MethodDefinition SubstituteMethod(TypeDefinition td, MethodDefinition md) - { - string newName = RpcPrefix + md.Name; - MethodDefinition cmd = new MethodDefinition(newName, md.Attributes, md.ReturnType); - - // add parameters - foreach (ParameterDefinition pd in md.Parameters) - { - cmd.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType)); - } - - // swap bodies - (cmd.Body, md.Body) = (md.Body, cmd.Body); - - // Move over all the debugging information - foreach (SequencePoint sequencePoint in md.DebugInformation.SequencePoints) - cmd.DebugInformation.SequencePoints.Add(sequencePoint); - md.DebugInformation.SequencePoints.Clear(); - - foreach (CustomDebugInformation customInfo in md.CustomDebugInformations) - cmd.CustomDebugInformations.Add(customInfo); - md.CustomDebugInformations.Clear(); - - (md.DebugInformation.Scope, cmd.DebugInformation.Scope) = (cmd.DebugInformation.Scope, md.DebugInformation.Scope); - - td.Methods.Add(cmd); - - FixRemoteCallToBaseMethod(td, cmd); - return cmd; - } - - /// - /// Finds and fixes call to base methods within remote calls - /// For example, changes `base.CmdDoSomething` to `base.CallCmdDoSomething` within `this.CallCmdDoSomething` - /// - /// - /// - public static void FixRemoteCallToBaseMethod(TypeDefinition type, MethodDefinition method) - { - string callName = method.Name; - - // Cmd/rpc start with Weaver.RpcPrefix - // eg CallCmdDoSomething - if (!callName.StartsWith(RpcPrefix)) - return; - - // eg CmdDoSomething - string baseRemoteCallName = method.Name.Substring(RpcPrefix.Length); - - foreach (Instruction instruction in method.Body.Instructions) - { - // if call to base.CmdDoSomething within this.CallCmdDoSomething - if (IsCallToMethod(instruction, out MethodDefinition calledMethod) && - calledMethod.Name == baseRemoteCallName) - { - TypeDefinition baseType = type.BaseType.Resolve(); - MethodDefinition baseMethod = baseType.GetMethodInBaseType(callName); - - if (baseMethod == null) - { - Weaver.Error($"Could not find base method for {callName}", method); - return; - } - - if (!baseMethod.IsVirtual) - { - Weaver.Error($"Could not find base method that was virutal {callName}", method); - return; - } - - instruction.Operand = baseMethod; - - Weaver.DLog(type, "Replacing call to '{0}' with '{1}' inside '{2}'", calledMethod.FullName, baseMethod.FullName, method.FullName); - } - } - } - - static 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; - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta deleted file mode 100644 index 3c81894..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 661e1af528e3441f79e1552fb5ec4e0e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs deleted file mode 100644 index 5f24487..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Mono.CecilX; - -namespace Mirror.Weaver -{ - /// - /// only shows warnings in case we use SyncVars etc. for MonoBehaviour. - /// - static class MonoBehaviourProcessor - { - public static void Process(TypeDefinition td) - { - ProcessSyncVars(td); - ProcessMethods(td); - } - - static void ProcessSyncVars(TypeDefinition td) - { - // find syncvars - foreach (FieldDefinition fd in td.Fields) - { - if (fd.HasCustomAttribute()) - Weaver.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); - - if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) - { - Weaver.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); - } - } - } - - static void ProcessMethods(TypeDefinition td) - { - // find command and RPC functions - foreach (MethodDefinition md in td.Methods) - { - if (md.HasCustomAttribute()) - Weaver.Error($"Command {md.Name} must be declared inside a NetworkBehaviour", md); - if (md.HasCustomAttribute()) - Weaver.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md); - if (md.HasCustomAttribute()) - Weaver.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md); - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta deleted file mode 100644 index ef3f5f4..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 35c16722912b64af894e4f6668f2e54c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs deleted file mode 100644 index 682fe82..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs +++ /dev/null @@ -1,1099 +0,0 @@ -using System.Collections.Generic; -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - public enum RemoteCallType - { - Command, - ClientRpc, - TargetRpc - } - - - /// - /// processes SyncVars, Cmds, Rpcs, etc. of NetworkBehaviours - /// - class NetworkBehaviourProcessor - { - List syncVars = new List(); - List syncObjects = new List(); - // - Dictionary syncVarNetIds = new Dictionary(); - readonly List commands = new List(); - readonly List clientRpcs = new List(); - readonly List targetRpcs = new List(); - readonly List commandInvocationFuncs = new List(); - readonly List clientRpcInvocationFuncs = new List(); - readonly List targetRpcInvocationFuncs = new List(); - - readonly TypeDefinition netBehaviourSubclass; - - public struct CmdResult - { - public MethodDefinition method; - public bool ignoreAuthority; - } - - public struct ClientRpcResult - { - public MethodDefinition method; - public bool excludeOwner; - } - - public NetworkBehaviourProcessor(TypeDefinition td) - { - Weaver.DLog(td, "NetworkBehaviourProcessor"); - netBehaviourSubclass = td; - } - - // return true if modified - public bool Process() - { - // only process once - if (WasProcessed(netBehaviourSubclass)) - { - return false; - } - Weaver.DLog(netBehaviourSubclass, "Found NetworkBehaviour " + netBehaviourSubclass.FullName); - - if (netBehaviourSubclass.HasGenericParameters) - { - Weaver.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass); - // originally Process returned true in every case, except if already processed. - // maybe return false here in the future. - return true; - } - Weaver.DLog(netBehaviourSubclass, "Process Start"); - MarkAsProcessed(netBehaviourSubclass); - - // deconstruct tuple and set fields - (syncVars, syncVarNetIds) = SyncVarProcessor.ProcessSyncVars(netBehaviourSubclass); - - syncObjects = SyncObjectProcessor.FindSyncObjectsFields(netBehaviourSubclass); - - ProcessMethods(); - if (Weaver.WeavingFailed) - { - // originally Process returned true in every case, except if already processed. - // maybe return false here in the future. - return true; - } - GenerateConstants(); - - GenerateSerialization(); - if (Weaver.WeavingFailed) - { - // originally Process returned true in every case, except if already processed. - // maybe return false here in the future. - return true; - } - - GenerateDeSerialization(); - Weaver.DLog(netBehaviourSubclass, "Process Done"); - return true; - } - - /* - generates code like: - if (!NetworkClient.active) - Debug.LogError((object) "Command function CmdRespawn called on server."); - - which is used in InvokeCmd, InvokeRpc, etc. - */ - public static void WriteClientActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString) - { - // client active check - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkClientGetActive)); - worker.Append(worker.Create(OpCodes.Brtrue, label)); - - worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on server.")); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); - worker.Append(worker.Create(OpCodes.Ret)); - worker.Append(label); - } - /* - generates code like: - if (!NetworkServer.active) - Debug.LogError((object) "Command CmdMsgWhisper called on client."); - */ - public static void WriteServerActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString) - { - // server active check - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetActive)); - worker.Append(worker.Create(OpCodes.Brtrue, label)); - - worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on client.")); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); - worker.Append(worker.Create(OpCodes.Ret)); - worker.Append(label); - } - - public static void WriteSetupLocals(ILProcessor worker) - { - worker.Body.InitLocals = true; - worker.Body.Variables.Add(new VariableDefinition(WeaverTypes.Import())); - } - - public static void WriteCreateWriter(ILProcessor worker) - { - // create writer - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.GetPooledWriterReference)); - worker.Append(worker.Create(OpCodes.Stloc_0)); - } - - public static void WriteRecycleWriter(ILProcessor worker) - { - // NetworkWriterPool.Recycle(writer); - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.RecycleWriterReference)); - } - - public static bool WriteArguments(ILProcessor worker, MethodDefinition method, RemoteCallType callType) - { - // write each argument - // example result - /* - writer.WritePackedInt32(someNumber); - writer.WriteNetworkIdentity(someTarget); - */ - - bool skipFirst = callType == RemoteCallType.TargetRpc - && TargetRpcProcessor.HasNetworkConnectionParameter(method); - - // arg of calling function, arg 0 is "this" so start counting at 1 - int argNum = 1; - foreach (ParameterDefinition param in method.Parameters) - { - // NetworkConnection is not sent via the NetworkWriter so skip it here - // skip first for NetworkConnection in TargetRpc - if (argNum == 1 && skipFirst) - { - argNum += 1; - continue; - } - // skip SenderConnection in Command - if (IsSenderConnection(param, callType)) - { - argNum += 1; - continue; - } - - MethodReference writeFunc = Writers.GetWriteFunc(param.ParameterType); - if (writeFunc == null) - { - Weaver.Error($"{method.Name} has invalid parameter {param}", method); - return false; - } - - // use built-in writer func on writer object - // NetworkWriter object - worker.Append(worker.Create(OpCodes.Ldloc_0)); - // add argument to call - worker.Append(worker.Create(OpCodes.Ldarg, argNum)); - // call writer extension method - worker.Append(worker.Create(OpCodes.Call, writeFunc)); - argNum += 1; - } - return true; - } - - #region mark / check type as processed - public const string ProcessedFunctionName = "MirrorProcessed"; - - // by adding an empty MirrorProcessed() function - public static bool WasProcessed(TypeDefinition td) - { - return td.GetMethod(ProcessedFunctionName) != null; - } - - public static void MarkAsProcessed(TypeDefinition td) - { - if (!WasProcessed(td)) - { - MethodDefinition versionMethod = new MethodDefinition(ProcessedFunctionName, MethodAttributes.Private, WeaverTypes.Import(typeof(void))); - ILProcessor worker = versionMethod.Body.GetILProcessor(); - worker.Append(worker.Create(OpCodes.Ret)); - td.Methods.Add(versionMethod); - } - } - #endregion - - void GenerateConstants() - { - if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0 && syncObjects.Count == 0) - return; - - Weaver.DLog(netBehaviourSubclass, " GenerateConstants "); - - // find static constructor - MethodDefinition cctor = netBehaviourSubclass.GetMethod(".cctor"); - bool cctorFound = cctor != null; - if (cctor != null) - { - // remove the return opcode from end of function. will add our own later. - if (cctor.Body.Instructions.Count != 0) - { - Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1]; - if (retInstr.OpCode == OpCodes.Ret) - { - cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1); - } - else - { - Weaver.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor); - return; - } - } - } - else - { - // make one! - cctor = new MethodDefinition(".cctor", MethodAttributes.Private | - MethodAttributes.HideBySig | - MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName | - MethodAttributes.Static, - WeaverTypes.Import(typeof(void))); - } - - // find instance constructor - MethodDefinition ctor = netBehaviourSubclass.GetMethod(".ctor"); - - if (ctor == null) - { - Weaver.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass); - return; - } - - Instruction ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1]; - if (ret.OpCode == OpCodes.Ret) - { - ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1); - } - else - { - Weaver.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor); - return; - } - - // TODO: find out if the order below matters. If it doesn't split code below into 2 functions - ILProcessor ctorWorker = ctor.Body.GetILProcessor(); - ILProcessor cctorWorker = cctor.Body.GetILProcessor(); - - for (int i = 0; i < commands.Count; ++i) - { - CmdResult cmdResult = commands[i]; - GenerateRegisterCommandDelegate(cctorWorker, WeaverTypes.registerCommandDelegateReference, commandInvocationFuncs[i], cmdResult); - } - - for (int i = 0; i < clientRpcs.Count; ++i) - { - ClientRpcResult clientRpcResult = clientRpcs[i]; - GenerateRegisterRemoteDelegate(cctorWorker, WeaverTypes.registerRpcDelegateReference, clientRpcInvocationFuncs[i], clientRpcResult.method.Name); - } - - for (int i = 0; i < targetRpcs.Count; ++i) - { - GenerateRegisterRemoteDelegate(cctorWorker, WeaverTypes.registerRpcDelegateReference, targetRpcInvocationFuncs[i], targetRpcs[i].Name); - } - - foreach (FieldDefinition fd in syncObjects) - { - SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, fd); - } - - cctorWorker.Append(cctorWorker.Create(OpCodes.Ret)); - if (!cctorFound) - { - netBehaviourSubclass.Methods.Add(cctor); - } - - // finish ctor - ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); - - // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late - netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit; - } - - /* - // This generates code like: - NetworkBehaviour.RegisterCommandDelegate(base.GetType(), "CmdThrust", new NetworkBehaviour.CmdDelegate(ShipControl.InvokeCmdCmdThrust)); - */ - void GenerateRegisterRemoteDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, string cmdName) - { - worker.Append(worker.Create(OpCodes.Ldtoken, netBehaviourSubclass)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference)); - worker.Append(worker.Create(OpCodes.Ldstr, cmdName)); - worker.Append(worker.Create(OpCodes.Ldnull)); - worker.Append(worker.Create(OpCodes.Ldftn, func)); - - worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor)); - // - worker.Append(worker.Create(OpCodes.Call, registerMethod)); - } - - void GenerateRegisterCommandDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, CmdResult cmdResult) - { - string cmdName = cmdResult.method.Name; - bool ignoreAuthority = cmdResult.ignoreAuthority; - - worker.Append(worker.Create(OpCodes.Ldtoken, netBehaviourSubclass)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference)); - worker.Append(worker.Create(OpCodes.Ldstr, cmdName)); - worker.Append(worker.Create(OpCodes.Ldnull)); - worker.Append(worker.Create(OpCodes.Ldftn, func)); - - worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor)); - - worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); - - worker.Append(worker.Create(OpCodes.Call, registerMethod)); - } - - void GenerateSerialization() - { - Weaver.DLog(netBehaviourSubclass, " GenerateSerialization"); - - const string SerializeMethodName = "SerializeSyncVars"; - if (netBehaviourSubclass.GetMethod(SerializeMethodName) != null) - return; - - if (syncVars.Count == 0) - { - // no synvars, no need for custom OnSerialize - return; - } - - MethodDefinition serialize = new MethodDefinition(SerializeMethodName, - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - WeaverTypes.Import()); - - serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import())); - serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, WeaverTypes.Import())); - ILProcessor worker = serialize.Body.GetILProcessor(); - - serialize.Body.InitLocals = true; - - // loc_0, this local variable is to determine if any variable was dirty - VariableDefinition dirtyLocal = new VariableDefinition(WeaverTypes.Import()); - serialize.Body.Variables.Add(dirtyLocal); - - MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, SerializeMethodName); - if (baseSerialize != null) - { - // base - worker.Append(worker.Create(OpCodes.Ldarg_0)); - // writer - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // forceAll - worker.Append(worker.Create(OpCodes.Ldarg_2)); - worker.Append(worker.Create(OpCodes.Call, baseSerialize)); - // set dirtyLocal to result of base.OnSerialize() - worker.Append(worker.Create(OpCodes.Stloc_0)); - } - - // Generates: if (forceAll); - Instruction initialStateLabel = worker.Create(OpCodes.Nop); - // forceAll - worker.Append(worker.Create(OpCodes.Ldarg_2)); - worker.Append(worker.Create(OpCodes.Brfalse, initialStateLabel)); - - foreach (FieldDefinition syncVar in syncVars) - { - // Generates a writer call for each sync variable - // writer - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // this - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, syncVar)); - MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType); - if (writeFunc != null) - { - worker.Append(worker.Create(OpCodes.Call, writeFunc)); - } - else - { - Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); - return; - } - } - - // always return true if forceAll - - // Generates: return true - worker.Append(worker.Create(OpCodes.Ldc_I4_1)); - worker.Append(worker.Create(OpCodes.Ret)); - - // Generates: end if (forceAll); - worker.Append(initialStateLabel); - - // write dirty bits before the data fields - // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ()); - // writer - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // base - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference)); - MethodReference writeUint64Func = Writers.GetWriteFunc(WeaverTypes.Import()); - worker.Append(worker.Create(OpCodes.Call, writeUint64Func)); - - // generate a writer call for any dirty variable in this class - - // start at number of syncvars in parent - int dirtyBit = Weaver.WeaveLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); - foreach (FieldDefinition syncVar in syncVars) - { - Instruction varLabel = worker.Create(OpCodes.Nop); - - // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) - // base - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference)); - // 8 bytes = long - worker.Append(worker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); - worker.Append(worker.Create(OpCodes.And)); - worker.Append(worker.Create(OpCodes.Brfalse, varLabel)); - - // Generates a call to the writer for that field - // writer - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // base - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, syncVar)); - - MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType); - if (writeFunc != null) - { - worker.Append(worker.Create(OpCodes.Call, writeFunc)); - } - else - { - Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); - return; - } - - // something was dirty - worker.Append(worker.Create(OpCodes.Ldc_I4_1)); - // set dirtyLocal to true - worker.Append(worker.Create(OpCodes.Stloc_0)); - - worker.Append(varLabel); - dirtyBit += 1; - } - - if (Weaver.GenerateLogErrors) - { - worker.Append(worker.Create(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.Name)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); - } - - // generate: return dirtyLocal - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Ret)); - netBehaviourSubclass.Methods.Add(serialize); - } - - void DeserializeField(FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize) - { - // check for Hook function - MethodDefinition hookMethod = SyncVarProcessor.GetHookMethod(netBehaviourSubclass, syncVar); - - if (IsNetworkIdentityField(syncVar)) - { - DeserializeNetworkIdentityField(syncVar, worker, deserialize, hookMethod); - } - else - { - DeserializeNormalField(syncVar, worker, deserialize, hookMethod); - } - } - - /// - /// Is the field a NetworkIdentity or GameObject - /// - /// - /// - static bool IsNetworkIdentityField(FieldDefinition syncVar) - { - return syncVar.FieldType.Is() || - syncVar.FieldType.Is(); - } - - /// - /// [SyncVar] GameObject/NetworkIdentity? - /// - /// - /// - /// - /// - /// - void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, MethodDefinition hookMethod) - { - /* - Generates code like: - uint oldNetId = ___qNetId; - // returns GetSyncVarGameObject(___qNetId) - GameObject oldSyncVar = syncvar.getter; - ___qNetId = reader.ReadPackedUInt32(); - if (!SyncVarEqual(oldNetId, ref ___goNetId)) - { - // getter returns GetSyncVarGameObject(___qNetId) - OnSetQ(oldSyncVar, syncvar.getter); - } - */ - - // GameObject/NetworkIdentity SyncVar: - // OnSerialize sends writer.Write(go); - // OnDeserialize reads to __netId manually so we can use - // lookups in the getter (so it still works if objects - // move in and out of range repeatedly) - FieldDefinition netIdField = syncVarNetIds[syncVar]; - - // uint oldNetId = ___qNetId; - VariableDefinition oldNetId = new VariableDefinition(WeaverTypes.Import()); - deserialize.Body.Variables.Add(oldNetId); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, netIdField)); - worker.Append(worker.Create(OpCodes.Stloc, oldNetId)); - - // GameObject/NetworkIdentity oldSyncVar = syncvar.getter; - VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType); - deserialize.Body.Variables.Add(oldSyncVar); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, syncVar)); - worker.Append(worker.Create(OpCodes.Stloc, oldSyncVar)); - - // read id and store in netId field BEFORE calling the hook - // -> this makes way more sense. by definition, the hook is - // supposed to be called after it was changed. not before. - // -> setting it BEFORE calling the hook fixes the following bug: - // https://github.com/vis2k/Mirror/issues/1151 in host mode - // where the value during the Hook call would call Cmds on - // the host server, and they would all happen and compare - // values BEFORE the hook even returned and hence BEFORE the - // actual value was even set. - // put 'this.' onto stack for 'this.netId' below - worker.Append(worker.Create(OpCodes.Ldarg_0)); - // reader. for 'reader.Read()' below - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // Read() - worker.Append(worker.Create(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import()))); - // netId - worker.Append(worker.Create(OpCodes.Stfld, netIdField)); - - if (hookMethod != null) - { - // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32())) - // because we send/receive the netID, not the GameObject/NetworkIdentity - // but only if SyncVar changed. otherwise a client would - // get hook calls for all initial values, even if they - // didn't change from the default values on the client. - // see also: https://github.com/vis2k/Mirror/issues/1278 - - // IMPORTANT: for GameObjects/NetworkIdentities we usually - // use SyncVarGameObjectEqual to compare equality. - // in this case however, we can just use - // SyncVarEqual with the two uint netIds. - // => this is easier weaver code because we don't - // have to get the GameObject/NetworkIdentity - // from the uint netId - // => this is faster because we void one - // GetComponent call for GameObjects to get - // their NetworkIdentity when comparing. - - // Generates: if (!SyncVarEqual); - Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop); - - // 'this.' for 'this.SyncVarEqual' - worker.Append(worker.Create(OpCodes.Ldarg_0)); - // 'oldNetId' - worker.Append(worker.Create(OpCodes.Ldloc, oldNetId)); - // 'ref this.__netId' - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, netIdField)); - // call the function - GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference); - syncVarEqualGm.GenericArguments.Add(netIdField.FieldType); - worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm)); - worker.Append(worker.Create(OpCodes.Brtrue, syncVarEqualLabel)); - - // call the hook - // Generates: OnValueChanged(oldValue, this.syncVar); - SyncVarProcessor.WriteCallHookMethodUsingField(worker, hookMethod, oldSyncVar, syncVar); - - // Generates: end if (!SyncVarEqual); - worker.Append(syncVarEqualLabel); - } - } - - /// - /// [SyncVar] int/float/struct/etc.? - /// - /// - /// - /// - /// - /// - void DeserializeNormalField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize, MethodDefinition hookMethod) - { - /* - Generates code like: - // for hook - int oldValue = a; - Networka = reader.ReadPackedInt32(); - if (!SyncVarEqual(oldValue, ref a)) - { - OnSetA(oldValue, Networka); - } - */ - - MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType); - if (readFunc == null) - { - Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); - return; - } - - // T oldValue = value; - VariableDefinition oldValue = new VariableDefinition(syncVar.FieldType); - deserialize.Body.Variables.Add(oldValue); - serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); - serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); - serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue)); - - // read value and store in syncvar BEFORE calling the hook - // -> this makes way more sense. by definition, the hook is - // supposed to be called after it was changed. not before. - // -> setting it BEFORE calling the hook fixes the following bug: - // https://github.com/vis2k/Mirror/issues/1151 in host mode - // where the value during the Hook call would call Cmds on - // the host server, and they would all happen and compare - // values BEFORE the hook even returned and hence BEFORE the - // actual value was even set. - // put 'this.' onto stack for 'this.syncvar' below - serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); - // reader. for 'reader.Read()' below - serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); - // reader.Read() - serWorker.Append(serWorker.Create(OpCodes.Call, readFunc)); - // syncvar - serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar)); - - if (hookMethod != null) - { - // call hook - // but only if SyncVar changed. otherwise a client would - // get hook calls for all initial values, even if they - // didn't change from the default values on the client. - // see also: https://github.com/vis2k/Mirror/issues/1278 - - // Generates: if (!SyncVarEqual); - Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop); - - // 'this.' for 'this.SyncVarEqual' - serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); - // 'oldValue' - serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue)); - // 'ref this.syncVar' - serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); - serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar)); - // call the function - GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference); - syncVarEqualGm.GenericArguments.Add(syncVar.FieldType); - serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm)); - serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel)); - - // call the hook - // Generates: OnValueChanged(oldValue, this.syncVar); - SyncVarProcessor.WriteCallHookMethodUsingField(serWorker, hookMethod, oldValue, syncVar); - - // Generates: end if (!SyncVarEqual); - serWorker.Append(syncVarEqualLabel); - } - } - - void GenerateDeSerialization() - { - Weaver.DLog(netBehaviourSubclass, " GenerateDeSerialization"); - - const string DeserializeMethodName = "DeserializeSyncVars"; - if (netBehaviourSubclass.GetMethod(DeserializeMethodName) != null) - return; - - if (syncVars.Count == 0) - { - // no synvars, no need for custom OnDeserialize - return; - } - - MethodDefinition serialize = new MethodDefinition(DeserializeMethodName, - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, WeaverTypes.Import())); - serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, WeaverTypes.Import())); - ILProcessor serWorker = serialize.Body.GetILProcessor(); - // setup local for dirty bits - serialize.Body.InitLocals = true; - VariableDefinition dirtyBitsLocal = new VariableDefinition(WeaverTypes.Import()); - serialize.Body.Variables.Add(dirtyBitsLocal); - - MethodReference baseDeserialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, DeserializeMethodName); - if (baseDeserialize != null) - { - // base - serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); - // reader - serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); - // initialState - serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); - serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize)); - } - - // Generates: if (initialState); - Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); - - serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); - serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); - - foreach (FieldDefinition syncVar in syncVars) - { - DeserializeField(syncVar, serWorker, serialize); - } - - serWorker.Append(serWorker.Create(OpCodes.Ret)); - - // Generates: end if (initialState); - serWorker.Append(initialStateLabel); - - // get dirty bits - serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); - serWorker.Append(serWorker.Create(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import()))); - serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); - - // conditionally read each syncvar - // start at number of syncvars in parent - int dirtyBit = Weaver.WeaveLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); - foreach (FieldDefinition syncVar in syncVars) - { - Instruction varLabel = serWorker.Create(OpCodes.Nop); - - // check if dirty bit is set - serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); - serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); - serWorker.Append(serWorker.Create(OpCodes.And)); - serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); - - DeserializeField(syncVar, serWorker, serialize); - - serWorker.Append(varLabel); - dirtyBit += 1; - } - - if (Weaver.GenerateLogErrors) - { - serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Deserialize " + netBehaviourSubclass.Name)); - serWorker.Append(serWorker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); - } - - serWorker.Append(serWorker.Create(OpCodes.Ret)); - netBehaviourSubclass.Methods.Add(serialize); - } - - public static bool ReadArguments(MethodDefinition method, ILProcessor worker, RemoteCallType callType) - { - // read each argument - // example result - /* - CallCmdDoSomething(reader.ReadPackedInt32(), reader.ReadNetworkIdentity()); - */ - - bool skipFirst = callType == RemoteCallType.TargetRpc - && TargetRpcProcessor.HasNetworkConnectionParameter(method); - - // arg of calling function, arg 0 is "this" so start counting at 1 - int argNum = 1; - foreach (ParameterDefinition param in method.Parameters) - { - // NetworkConnection is not sent via the NetworkWriter so skip it here - // skip first for NetworkConnection in TargetRpc - if (argNum == 1 && skipFirst) - { - argNum += 1; - continue; - } - // skip SenderConnection in Command - if (IsSenderConnection(param, callType)) - { - argNum += 1; - continue; - } - - - MethodReference readFunc = Readers.GetReadFunc(param.ParameterType); - - if (readFunc == null) - { - Weaver.Error($"{method.Name} has invalid parameter {param}. Unsupported type {param.ParameterType}, use a supported Mirror type instead", method); - return false; - } - - worker.Append(worker.Create(OpCodes.Ldarg_1)); - worker.Append(worker.Create(OpCodes.Call, readFunc)); - - // conversion.. is this needed? - if (param.ParameterType.Is()) - { - worker.Append(worker.Create(OpCodes.Conv_R4)); - } - else if (param.ParameterType.Is()) - { - worker.Append(worker.Create(OpCodes.Conv_R8)); - } - } - return true; - } - - public static void AddInvokeParameters(ICollection collection) - { - collection.Add(new ParameterDefinition("obj", ParameterAttributes.None, WeaverTypes.Import())); - collection.Add(new ParameterDefinition("reader", ParameterAttributes.None, WeaverTypes.Import())); - // senderConnection is only used for commands but NetworkBehaviour.CmdDelegate is used for all remote calls - collection.Add(new ParameterDefinition("senderConnection", ParameterAttributes.None, WeaverTypes.Import())); - } - - // check if a Command/TargetRpc/Rpc function & parameters are valid for weaving - public static bool ValidateRemoteCallAndParameters(MethodDefinition method, RemoteCallType callType) - { - if (method.IsStatic) - { - Weaver.Error($"{method.Name} must not be static", method); - return false; - } - - return ValidateFunction(method) && - ValidateParameters(method, callType); - } - - // check if a Command/TargetRpc/Rpc function is valid for weaving - static bool ValidateFunction(MethodReference md) - { - if (md.ReturnType.Is()) - { - Weaver.Error($"{md.Name} cannot be a coroutine", md); - return false; - } - if (!md.ReturnType.Is(typeof(void))) - { - Weaver.Error($"{md.Name} cannot return a value. Make it void instead", md); - return false; - } - if (md.HasGenericParameters) - { - Weaver.Error($"{md.Name} cannot have generic parameters", md); - return false; - } - return true; - } - - // check if all Command/TargetRpc/Rpc function's parameters are valid for weaving - static bool ValidateParameters(MethodReference method, RemoteCallType callType) - { - for (int i = 0; i < method.Parameters.Count; ++i) - { - ParameterDefinition param = method.Parameters[i]; - if (!ValidateParameter(method, param, callType, i == 0)) - { - return false; - } - } - return true; - } - - // validate parameters for a remote function call like Rpc/Cmd - static bool ValidateParameter(MethodReference method, ParameterDefinition param, RemoteCallType callType, bool firstParam) - { - bool isNetworkConnection = param.ParameterType.Is(); - bool isSenderConnection = IsSenderConnection(param, callType); - - if (param.IsOut) - { - Weaver.Error($"{method.Name} cannot have out parameters", method); - return false; - } - - - // if not SenderConnection And not TargetRpc NetworkConnection first param - if (!isSenderConnection && isNetworkConnection && !(callType == RemoteCallType.TargetRpc && firstParam)) - { - if (callType == RemoteCallType.Command) - { - Weaver.Error($"{method.Name} has invalid parameter {param}, Cannot pass NetworkConnections. Instead use 'NetworkConnectionToClient conn = null' to get the sender's connection on the server", method); - } - else - { - Weaver.Error($"{method.Name} has invalid parameter {param}. Cannot pass NetworkConnections", method); - } - return false; - } - - // sender connection can be optional - if (param.IsOptional && !isSenderConnection) - { - Weaver.Error($"{method.Name} cannot have optional parameters", method); - return false; - } - - return true; - } - - public static bool IsSenderConnection(ParameterDefinition param, RemoteCallType callType) - { - if (callType != RemoteCallType.Command) - { - return false; - } - - TypeReference type = param.ParameterType; - - return type.Is() - || type.Resolve().IsDerivedFrom(); - } - - void ProcessMethods() - { - HashSet names = new HashSet(); - - // copy the list of methods because we will be adding methods in the loop - List methods = new List(netBehaviourSubclass.Methods); - // find command and RPC functions - foreach (MethodDefinition md in methods) - { - foreach (CustomAttribute ca in md.CustomAttributes) - { - if (ca.AttributeType.Is()) - { - ProcessCommand(names, md, ca); - break; - } - - if (ca.AttributeType.Is()) - { - ProcessTargetRpc(names, md, ca); - break; - } - - if (ca.AttributeType.Is()) - { - ProcessClientRpc(names, md, ca); - break; - } - } - } - } - - void ProcessClientRpc(HashSet names, MethodDefinition md, CustomAttribute clientRpcAttr) - { - if (md.IsAbstract) - { - Weaver.Error("Abstract ClientRpc are currently not supported, use virtual method instead", md); - return; - } - - if (!ValidateRemoteCallAndParameters(md, RemoteCallType.ClientRpc)) - { - return; - } - - if (names.Contains(md.Name)) - { - Weaver.Error($"Duplicate ClientRpc name {md.Name}", md); - return; - } - - bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false); - - names.Add(md.Name); - clientRpcs.Add(new ClientRpcResult - { - method = md, - excludeOwner = excludeOwner - }); - - MethodDefinition rpcCallFunc = RpcProcessor.ProcessRpcCall(netBehaviourSubclass, md, clientRpcAttr); - // need null check here because ProcessRpcCall returns null if it can't write all the args - if (rpcCallFunc == null) { return; } - - MethodDefinition rpcFunc = RpcProcessor.ProcessRpcInvoke(netBehaviourSubclass, md, rpcCallFunc); - if (rpcFunc != null) - { - clientRpcInvocationFuncs.Add(rpcFunc); - } - } - - void ProcessTargetRpc(HashSet names, MethodDefinition md, CustomAttribute targetRpcAttr) - { - if (md.IsAbstract) - { - Weaver.Error("Abstract TargetRpc are currently not supported, use virtual method instead", md); - return; - } - - if (!ValidateRemoteCallAndParameters(md, RemoteCallType.TargetRpc)) - return; - - if (names.Contains(md.Name)) - { - Weaver.Error($"Duplicate Target Rpc name {md.Name}", md); - return; - } - names.Add(md.Name); - targetRpcs.Add(md); - - MethodDefinition rpcCallFunc = TargetRpcProcessor.ProcessTargetRpcCall(netBehaviourSubclass, md, targetRpcAttr); - - MethodDefinition rpcFunc = TargetRpcProcessor.ProcessTargetRpcInvoke(netBehaviourSubclass, md, rpcCallFunc); - if (rpcFunc != null) - { - targetRpcInvocationFuncs.Add(rpcFunc); - } - } - - void ProcessCommand(HashSet names, MethodDefinition md, CustomAttribute commandAttr) - { - if (md.IsAbstract) - { - Weaver.Error("Abstract Commands are currently not supported, use virtual method instead", md); - return; - } - - if (!ValidateRemoteCallAndParameters(md, RemoteCallType.Command)) - return; - - if (names.Contains(md.Name)) - { - Weaver.Error($"Duplicate Command name {md.Name}", md); - return; - } - - bool ignoreAuthority = commandAttr.GetField("ignoreAuthority", false); - - names.Add(md.Name); - commands.Add(new CmdResult - { - method = md, - ignoreAuthority = ignoreAuthority - }); - - MethodDefinition cmdCallFunc = CommandProcessor.ProcessCommandCall(netBehaviourSubclass, md, commandAttr); - - MethodDefinition cmdFunc = CommandProcessor.ProcessCommandInvoke(netBehaviourSubclass, md, cmdCallFunc); - if (cmdFunc != null) - { - commandInvocationFuncs.Add(cmdFunc); - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta deleted file mode 100644 index 67c27dc..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8118d606be3214e5d99943ec39530dd8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs deleted file mode 100644 index 8380232..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - public static class PropertySiteProcessor - { - public static void Process(ModuleDefinition moduleDef) - { - DateTime startTime = DateTime.Now; - - //Search through the types - foreach (TypeDefinition td in moduleDef.Types) - { - if (td.IsClass) - { - ProcessSiteClass(td); - } - } - - Console.WriteLine(" ProcessSitesModule " + moduleDef.Name + " elapsed time:" + (DateTime.Now - startTime)); - } - - static void ProcessSiteClass(TypeDefinition td) - { - //Console.WriteLine(" ProcessSiteClass " + td); - foreach (MethodDefinition md in td.Methods) - { - ProcessSiteMethod(md); - } - - foreach (TypeDefinition nested in td.NestedTypes) - { - ProcessSiteClass(nested); - } - } - - static void ProcessSiteMethod(MethodDefinition md) - { - // process all references to replaced members with properties - //Weaver.DLog(td, " ProcessSiteMethod " + md); - - if (md.Name == ".cctor" || - md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || - md.Name.StartsWith(Weaver.InvokeRpcPrefix)) - return; - - if (md.IsAbstract) - { - return; - } - - if (md.Body != null && md.Body.Instructions != null) - { - for (int iCount = 0; iCount < md.Body.Instructions.Count;) - { - Instruction instr = md.Body.Instructions[iCount]; - iCount += ProcessInstruction(md, instr, iCount); - } - } - } - - // replaces syncvar write access with the NetworkXYZ.get property calls - static void ProcessInstructionSetterField(MethodDefinition md, Instruction i, FieldDefinition opField) - { - // dont replace property call sites in constructors - if (md.Name == ".ctor") - return; - - // does it set a field that we replaced? - if (Weaver.WeaveLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) - { - //replace with property - //DLog(td, " replacing " + md.Name + ":" + i); - i.OpCode = OpCodes.Call; - i.Operand = replacement; - //DLog(td, " replaced " + md.Name + ":" + i); - } - } - - // replaces syncvar read access with the NetworkXYZ.get property calls - static void ProcessInstructionGetterField(MethodDefinition md, Instruction i, FieldDefinition opField) - { - // dont replace property call sites in constructors - if (md.Name == ".ctor") - return; - - // does it set a field that we replaced? - if (Weaver.WeaveLists.replacementGetterProperties.TryGetValue(opField, out MethodDefinition replacement)) - { - //replace with property - //DLog(td, " replacing " + md.Name + ":" + i); - i.OpCode = OpCodes.Call; - i.Operand = replacement; - //DLog(td, " replaced " + md.Name + ":" + i); - } - } - - static int ProcessInstruction(MethodDefinition md, Instruction instr, int iCount) - { - if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldDefinition opFieldst) - { - // this instruction sets the value of a field. cache the field reference. - ProcessInstructionSetterField(md, instr, opFieldst); - } - - if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldDefinition opFieldld) - { - // this instruction gets the value of a field. cache the field reference. - ProcessInstructionGetterField(md, instr, opFieldld); - } - - if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldDefinition opFieldlda) - { - // loading a field by reference, watch out for initobj instruction - // see https://github.com/vis2k/Mirror/issues/696 - return ProcessInstructionLoadAddress(md, instr, opFieldlda, iCount); - } - - return 1; - } - - static int ProcessInstructionLoadAddress(MethodDefinition md, Instruction instr, FieldDefinition opField, int iCount) - { - // dont replace property call sites in constructors - if (md.Name == ".ctor") - return 1; - - // does it set a field that we replaced? - if (Weaver.WeaveLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) - { - // we have a replacement for this property - // is the next instruction a initobj? - Instruction nextInstr = md.Body.Instructions[iCount + 1]; - - if (nextInstr.OpCode == OpCodes.Initobj) - { - // we need to replace this code with: - // var tmp = new MyStruct(); - // this.set_Networkxxxx(tmp); - ILProcessor worker = md.Body.GetILProcessor(); - VariableDefinition tmpVariable = new VariableDefinition(opField.FieldType); - md.Body.Variables.Add(tmpVariable); - - worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable)); - worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType)); - worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable)); - worker.InsertBefore(instr, worker.Create(OpCodes.Call, replacement)); - - worker.Remove(instr); - worker.Remove(nextInstr); - return 4; - } - } - - return 1; - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta deleted file mode 100644 index e8c2500..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/PropertySiteProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d48f1ab125e9940a995603796bccc59e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs deleted file mode 100644 index 4b150e9..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs +++ /dev/null @@ -1,175 +0,0 @@ -// finds all readers and writers and register them -using System; -using System.Linq; -using Mono.CecilX; -using Mono.CecilX.Cil; -using UnityEditor; -using UnityEditor.Compilation; -using UnityEngine; - -namespace Mirror.Weaver -{ - public static class ReaderWriterProcessor - { - public static bool Process(AssemblyDefinition CurrentAssembly) - { - Readers.Init(); - Writers.Init(); - foreach (Assembly unityAsm in CompilationPipeline.GetAssemblies()) - { - if (unityAsm.name == "Mirror") - { - using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver()) - using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(unityAsm.outputPath, new ReaderParameters { ReadWrite = false, ReadSymbols = false, AssemblyResolver = asmResolver })) - { - ProcessAssemblyClasses(CurrentAssembly, assembly); - } - } - } - - return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly); - } - - static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly) - { - bool modified = false; - foreach (TypeDefinition klass in assembly.MainModule.Types) - { - // extension methods only live in static classes - // static classes are represented as sealed and abstract - if (klass.IsAbstract && klass.IsSealed) - { - // if asmebly has any declared writers then it is "modified" - modified |= LoadDeclaredWriters(CurrentAssembly, klass); - modified |= LoadDeclaredReaders(CurrentAssembly, klass); - } - } - - foreach (TypeDefinition klass in assembly.MainModule.Types) - { - // if asmebly has any network message then it is modified - modified |= LoadMessageReadWriter(CurrentAssembly.MainModule, klass); - } - return modified; - } - - static bool LoadMessageReadWriter(ModuleDefinition module, TypeDefinition klass) - { - bool modified = false; - if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface()) - { - Readers.GetReadFunc(module.ImportReference(klass)); - Writers.GetWriteFunc(module.ImportReference(klass)); - modified = true; - } - - foreach (TypeDefinition td in klass.NestedTypes) - { - modified |= LoadMessageReadWriter(module, td); - } - return modified; - } - - static bool LoadDeclaredWriters(AssemblyDefinition currentAssembly, TypeDefinition klass) - { - // register all the writers in this class. Skip the ones with wrong signature - bool modified = false; - foreach (MethodDefinition method in klass.Methods) - { - if (method.Parameters.Count != 2) - continue; - - if (!method.Parameters[0].ParameterType.Is()) - continue; - - if (!method.ReturnType.Is(typeof(void))) - continue; - - if (!method.HasCustomAttribute()) - continue; - - if (method.HasGenericParameters) - continue; - - TypeReference dataType = method.Parameters[1].ParameterType; - Writers.Register(dataType, currentAssembly.MainModule.ImportReference(method)); - modified = true; - } - return modified; - } - - static bool LoadDeclaredReaders(AssemblyDefinition currentAssembly, TypeDefinition klass) - { - // register all the reader in this class. Skip the ones with wrong signature - bool modified = false; - foreach (MethodDefinition method in klass.Methods) - { - if (method.Parameters.Count != 1) - continue; - - if (!method.Parameters[0].ParameterType.Is()) - continue; - - if (method.ReturnType.Is(typeof(void))) - continue; - - if (!method.HasCustomAttribute()) - continue; - - if (method.HasGenericParameters) - continue; - - Readers.Register(method.ReturnType, currentAssembly.MainModule.ImportReference(method)); - modified = true; - } - return modified; - } - - static bool IsEditorAssembly(AssemblyDefinition currentAssembly) - { - return currentAssembly.MainModule.AssemblyReferences.Any(assemblyReference => - assemblyReference.Name == nameof(UnityEditor) - ); - } - - /// - /// Creates a method that will store all the readers and writers into - /// and - /// - /// The method will be marked InitializeOnLoadMethodAttribute so it gets - /// executed before mirror runtime code - /// - /// - public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly) - { - MethodDefinition rwInitializer = new MethodDefinition("InitReadWriters", MethodAttributes.Public | - MethodAttributes.Static, - WeaverTypes.Import(typeof(void))); - - System.Reflection.ConstructorInfo attributeconstructor = typeof(RuntimeInitializeOnLoadMethodAttribute).GetConstructor(new[] { typeof(RuntimeInitializeLoadType) }); - - CustomAttribute customAttributeRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(attributeconstructor)); - customAttributeRef.ConstructorArguments.Add(new CustomAttributeArgument(WeaverTypes.Import(), RuntimeInitializeLoadType.BeforeSceneLoad)); - rwInitializer.CustomAttributes.Add(customAttributeRef); - - if (IsEditorAssembly(currentAssembly)) - { - // editor assembly, add InitializeOnLoadMethod too. Useful for the editor tests - System.Reflection.ConstructorInfo initializeOnLoadConstructor = typeof(InitializeOnLoadMethodAttribute).GetConstructor(new Type[0]); - CustomAttribute initializeCustomConstructorRef = new CustomAttribute(currentAssembly.MainModule.ImportReference(initializeOnLoadConstructor)); - rwInitializer.CustomAttributes.Add(initializeCustomConstructorRef); - } - - ILProcessor worker = rwInitializer.Body.GetILProcessor(); - - Writers.InitializeWriters(worker); - Readers.InitializeReaders(worker); - - worker.Append(worker.Create(OpCodes.Ret)); - - TypeDefinition generateClass = Weaver.WeaveLists.generateContainerClass; - - generateClass.Methods.Add(rwInitializer); - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta deleted file mode 100644 index c14d6fa..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f3263602f0a374ecd8d08588b1fc2f76 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs deleted file mode 100644 index 420f6da..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - /// - /// Processes [Rpc] methods in NetworkBehaviour - /// - public static class RpcProcessor - { - public static MethodDefinition ProcessRpcInvoke(TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc) - { - MethodDefinition rpc = new MethodDefinition( - Weaver.InvokeRpcPrefix + md.Name, - MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - ILProcessor worker = rpc.Body.GetILProcessor(); - Instruction label = worker.Create(OpCodes.Nop); - - NetworkBehaviourProcessor.WriteClientActiveCheck(worker, md.Name, label, "RPC"); - - // setup for reader - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Castclass, td)); - - if (!NetworkBehaviourProcessor.ReadArguments(md, worker, RemoteCallType.ClientRpc)) - return null; - - // invoke actual command function - worker.Append(worker.Create(OpCodes.Callvirt, rpcCallFunc)); - worker.Append(worker.Create(OpCodes.Ret)); - - NetworkBehaviourProcessor.AddInvokeParameters(rpc.Parameters); - td.Methods.Add(rpc); - return rpc; - } - - /* - * generates code like: - - public void RpcTest (int param) - { - NetworkWriter writer = new NetworkWriter (); - writer.WritePackedUInt32((uint)param); - base.SendRPCInternal(typeof(class),"RpcTest", writer, 0); - } - public void CallRpcTest (int param) - { - // whatever the user did before - } - - Originally HLAPI put the send message code inside the Call function - and then proceeded to replace every call to RpcTest with CallRpcTest - - This method moves all the user's code into the "CallRpc" method - and replaces the body of the original method with the send message code. - This way we do not need to modify the code anywhere else, and this works - correctly in dependent assemblies - */ - public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr) - { - MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md); - - ILProcessor worker = md.Body.GetILProcessor(); - - NetworkBehaviourProcessor.WriteSetupLocals(worker); - - if (Weaver.GenerateLogErrors) - { - worker.Append(worker.Create(OpCodes.Ldstr, "Call ClientRpc function " + md.Name)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); - } - - NetworkBehaviourProcessor.WriteCreateWriter(worker); - - // write all the arguments that the user passed to the Rpc call - if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.ClientRpc)) - return null; - - string rpcName = md.Name; - int channel = clientRpcAttr.GetField("channel", 0); - bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false); - - // invoke SendInternal and return - // this - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldtoken, td)); - // invokerClass - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference)); - worker.Append(worker.Create(OpCodes.Ldstr, rpcName)); - // writer - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Ldc_I4, channel)); - worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); - worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendRpcInternal)); - - NetworkBehaviourProcessor.WriteRecycleWriter(worker); - - worker.Append(worker.Create(OpCodes.Ret)); - - return rpc; - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta deleted file mode 100644 index 22375ba..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a3cb7051ff41947e59bba58bdd2b73fc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs deleted file mode 100644 index c653f93..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Injects server/client active checks for [Server/Client] attributes -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - static class ServerClientAttributeProcessor - { - public static bool Process(TypeDefinition td) - { - bool modified = false; - foreach (MethodDefinition md in td.Methods) - { - modified |= ProcessSiteMethod(md); - } - - foreach (TypeDefinition nested in td.NestedTypes) - { - modified |= Process(nested); - } - return modified; - } - - static bool ProcessSiteMethod(MethodDefinition md) - { - if (md.Name == ".cctor" || - md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || - md.Name.StartsWith(Weaver.InvokeRpcPrefix)) - return false; - - if (md.IsAbstract) - { - if (HasServerClientAttribute(md)) - { - Weaver.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md); - } - return false; - } - - if (md.Body != null && md.Body.Instructions != null) - { - return ProcessMethodAttributes(md); - } - return false; - } - - public static bool HasServerClientAttribute(MethodDefinition md) - { - foreach (CustomAttribute attr in md.CustomAttributes) - { - switch (attr.Constructor.DeclaringType.ToString()) - { - case "Mirror.ServerAttribute": - case "Mirror.ServerCallbackAttribute": - case "Mirror.ClientAttribute": - case "Mirror.ClientCallbackAttribute": - return true; - default: - break; - } - } - return false; - } - - public static bool ProcessMethodAttributes(MethodDefinition md) - { - if (md.HasCustomAttribute()) - InjectServerGuard(md, true); - else if (md.HasCustomAttribute()) - InjectServerGuard(md, false); - else if (md.HasCustomAttribute()) - InjectClientGuard(md, true); - else if (md.HasCustomAttribute()) - InjectClientGuard(md, false); - else - return false; - - return true; - } - - static void InjectServerGuard(MethodDefinition md, bool logWarning) - { - ILProcessor worker = md.Body.GetILProcessor(); - Instruction top = md.Body.Instructions[0]; - - worker.InsertBefore(top, worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetActive)); - worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); - if (logWarning) - { - worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Server] function '{md.FullName}' called when server was not active")); - worker.InsertBefore(top, worker.Create(OpCodes.Call, WeaverTypes.logWarningReference)); - } - InjectGuardParameters(md, worker, top); - InjectGuardReturnValue(md, worker, top); - worker.InsertBefore(top, worker.Create(OpCodes.Ret)); - } - - static void InjectClientGuard(MethodDefinition md, bool logWarning) - { - ILProcessor worker = md.Body.GetILProcessor(); - Instruction top = md.Body.Instructions[0]; - - worker.InsertBefore(top, worker.Create(OpCodes.Call, WeaverTypes.NetworkClientGetActive)); - worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); - if (logWarning) - { - worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Client] function '{md.FullName}' called when client was not active")); - worker.InsertBefore(top, worker.Create(OpCodes.Call, WeaverTypes.logWarningReference)); - } - - InjectGuardParameters(md, worker, top); - InjectGuardReturnValue(md, worker, top); - worker.InsertBefore(top, worker.Create(OpCodes.Ret)); - } - - // this is required to early-out from a function with "ref" or "out" parameters - static void InjectGuardParameters(MethodDefinition md, ILProcessor worker, Instruction top) - { - int offset = md.Resolve().IsStatic ? 0 : 1; - for (int index = 0; index < md.Parameters.Count; index++) - { - ParameterDefinition param = md.Parameters[index]; - if (param.IsOut) - { - TypeReference elementType = param.ParameterType.GetElementType(); - - md.Body.Variables.Add(new VariableDefinition(elementType)); - md.Body.InitLocals = true; - - worker.InsertBefore(top, worker.Create(OpCodes.Ldarg, index + offset)); - worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); - worker.InsertBefore(top, worker.Create(OpCodes.Initobj, elementType)); - worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); - worker.InsertBefore(top, worker.Create(OpCodes.Stobj, elementType)); - } - } - } - - // this is required to early-out from a function with a return value. - static void InjectGuardReturnValue(MethodDefinition md, ILProcessor worker, Instruction top) - { - if (!md.ReturnType.Is(typeof(void))) - { - md.Body.Variables.Add(new VariableDefinition(md.ReturnType)); - md.Body.InitLocals = true; - - worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); - worker.InsertBefore(top, worker.Create(OpCodes.Initobj, md.ReturnType)); - worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta deleted file mode 100644 index 5a5451d..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 024f251bf693bb345b90b9177892d534 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs.meta deleted file mode 100644 index 0a7c2aa..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 29e4a45f69822462ab0b15adda962a29 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs deleted file mode 100644 index 2fdbc52..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// removed 2020-09 diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs.meta deleted file mode 100644 index 81b9576..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncEventProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a5d8b25543a624384944b599e5a832a8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs deleted file mode 100644 index a88144a..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs +++ /dev/null @@ -1 +0,0 @@ -// Removed Oct 1 2020 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs.meta deleted file mode 100644 index b73b047..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4f3445268e45d437fac325837aff3246 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs deleted file mode 100644 index b404fc3..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - public static class SyncObjectInitializer - { - public static void GenerateSyncObjectInitializer(ILProcessor worker, FieldDefinition fd) - { - // register syncobject in network behaviour - GenerateSyncObjectRegistration(worker, fd); - } - - public static bool ImplementsSyncObject(TypeReference typeRef) - { - try - { - // value types cant inherit from SyncObject - if (typeRef.IsValueType) - { - return false; - } - - return typeRef.Resolve().ImplementsInterface(); - } - catch - { - // sometimes this will fail if we reference a weird library that can't be resolved, so we just swallow that exception and return false - } - - return false; - } - - /* - // generates code like: - this.InitSyncObject(m_sizes); - */ - static void GenerateSyncObjectRegistration(ILProcessor worker, FieldDefinition fd) - { - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, fd)); - - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.InitSyncObjectReference)); - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta deleted file mode 100644 index 22f976e..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d02219b00b3674e59a2151f41e791688 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs deleted file mode 100644 index c5b3a11..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using Mono.CecilX; - -namespace Mirror.Weaver -{ - public static class SyncObjectProcessor - { - /// - /// Finds SyncObjects fields in a type - /// Type should be a NetworkBehaviour - /// - /// - /// - public static List FindSyncObjectsFields(TypeDefinition td) - { - List syncObjects = new List(); - - foreach (FieldDefinition fd in td.Fields) - { - if (fd.FieldType.Resolve().ImplementsInterface()) - { - if (fd.IsStatic) - { - Weaver.Error($"{fd.Name} cannot be static", fd); - continue; - } - - GenerateReadersAndWriters(fd.FieldType); - - syncObjects.Add(fd); - } - } - - - return syncObjects; - } - - /// - /// Generates serialization methods for synclists - /// - /// The synclist class - /// the base SyncObject td inherits from - static void GenerateReadersAndWriters(TypeReference tr) - { - if (tr is GenericInstanceType genericInstance) - { - foreach (TypeReference argument in genericInstance.GenericArguments) - { - if (!argument.IsGenericParameter) - { - Readers.GetReadFunc(argument); - Writers.GetWriteFunc(argument); - } - } - } - - if (tr != null) - { - GenerateReadersAndWriters(tr.Resolve().BaseType); - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta deleted file mode 100644 index 0efe434..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 78f71efc83cde4917b7d21efa90bcc9a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs deleted file mode 100644 index 9bcac1d..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs +++ /dev/null @@ -1,434 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - /// - /// Processes [SyncVar] in NetworkBehaviour - /// - public static class SyncVarProcessor - { - // ulong = 64 bytes - const int SyncVarLimit = 64; - - - static string HookParameterMessage(string hookName, TypeReference ValueType) - => string.Format("void {0}({1} oldValue, {1} newValue)", hookName, ValueType); - - // Get hook method if any - public static MethodDefinition GetHookMethod(TypeDefinition td, FieldDefinition syncVar) - { - CustomAttribute syncVarAttr = syncVar.GetCustomAttribute(); - - if (syncVarAttr == null) - return null; - - string hookFunctionName = syncVarAttr.GetField("hook", null); - - if (hookFunctionName == null) - return null; - - return FindHookMethod(td, syncVar, hookFunctionName); - } - - static MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, string hookFunctionName) - { - List methods = td.GetMethods(hookFunctionName); - - List methodsWith2Param = new List(methods.Where(m => m.Parameters.Count == 2)); - - if (methodsWith2Param.Count == 0) - { - Weaver.Error($"Could not find hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + - $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", - syncVar); - - return null; - } - - foreach (MethodDefinition method in methodsWith2Param) - { - if (MatchesParameters(syncVar, method)) - { - return method; - } - } - - Weaver.Error($"Wrong type for Parameter in hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + - $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", - syncVar); - - return null; - } - - static bool MatchesParameters(FieldDefinition syncVar, MethodDefinition method) - { - // matches void onValueChange(T oldValue, T newValue) - return method.Parameters[0].ParameterType.FullName == syncVar.FieldType.FullName && - method.Parameters[1].ParameterType.FullName == syncVar.FieldType.FullName; - } - - public static MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string originalName, FieldDefinition netFieldId) - { - //Create the get method - MethodDefinition get = new MethodDefinition( - "get_Network" + originalName, MethodAttributes.Public | - MethodAttributes.SpecialName | - MethodAttributes.HideBySig, - fd.FieldType); - - ILProcessor worker = get.Body.GetILProcessor(); - - // [SyncVar] GameObject? - if (fd.FieldType.Is()) - { - // return this.GetSyncVarGameObject(ref field, uint netId); - // this. - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, netFieldId)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, fd)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarGameObjectReference)); - worker.Append(worker.Create(OpCodes.Ret)); - } - // [SyncVar] NetworkIdentity? - else if (fd.FieldType.Is()) - { - // return this.GetSyncVarNetworkIdentity(ref field, uint netId); - // this. - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, netFieldId)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, fd)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarNetworkIdentityReference)); - worker.Append(worker.Create(OpCodes.Ret)); - } - // [SyncVar] int, string, etc. - else - { - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, fd)); - worker.Append(worker.Create(OpCodes.Ret)); - } - - get.Body.Variables.Add(new VariableDefinition(fd.FieldType)); - get.Body.InitLocals = true; - get.SemanticsAttributes = MethodSemanticsAttributes.Getter; - - return get; - } - - public static MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId) - { - //Create the set method - MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public | - MethodAttributes.SpecialName | - MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - ILProcessor worker = set.Body.GetILProcessor(); - - // if (!SyncVarEqual(value, ref playerData)) - Instruction endOfMethod = worker.Create(OpCodes.Nop); - - // this - worker.Append(worker.Create(OpCodes.Ldarg_0)); - // new value to set - worker.Append(worker.Create(OpCodes.Ldarg_1)); - // reference to field to set - // make generic version of SetSyncVar with field type - if (fd.FieldType.Is()) - { - // reference to netId Field to set - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, netFieldId)); - - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarGameObjectEqualReference)); - } - else if (fd.FieldType.Is()) - { - // reference to netId Field to set - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, netFieldId)); - - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarNetworkIdentityEqualReference)); - } - else - { - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, fd)); - - GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference); - syncVarEqualGm.GenericArguments.Add(fd.FieldType); - worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm)); - } - - worker.Append(worker.Create(OpCodes.Brtrue, endOfMethod)); - - // T oldValue = value; - // TODO for GO/NI we need to backup the netId don't we? - VariableDefinition oldValue = new VariableDefinition(fd.FieldType); - set.Body.Variables.Add(oldValue); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldfld, fd)); - worker.Append(worker.Create(OpCodes.Stloc, oldValue)); - - // this - worker.Append(worker.Create(OpCodes.Ldarg_0)); - - // new value to set - worker.Append(worker.Create(OpCodes.Ldarg_1)); - - // reference to field to set - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, fd)); - - // dirty bit - // 8 byte integer aka long - worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit)); - - if (fd.FieldType.Is()) - { - // reference to netId Field to set - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, netFieldId)); - - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarGameObjectReference)); - } - else if (fd.FieldType.Is()) - { - // reference to netId Field to set - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldflda, netFieldId)); - - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarNetworkIdentityReference)); - } - else - { - // make generic version of SetSyncVar with field type - GenericInstanceMethod gm = new GenericInstanceMethod(WeaverTypes.setSyncVarReference); - gm.GenericArguments.Add(fd.FieldType); - - // invoke SetSyncVar - worker.Append(worker.Create(OpCodes.Call, gm)); - } - - MethodDefinition hookMethod = GetHookMethod(td, fd); - - if (hookMethod != null) - { - //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit)) - Instruction label = worker.Create(OpCodes.Nop); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetLocalClientActive)); - worker.Append(worker.Create(OpCodes.Brfalse, label)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarHookGuard)); - worker.Append(worker.Create(OpCodes.Brtrue, label)); - - // setSyncVarHookGuard(dirtyBit, true); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit)); - worker.Append(worker.Create(OpCodes.Ldc_I4_1)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard)); - - // call hook (oldValue, newValue) - // Generates: OnValueChanged(oldValue, value); - WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue); - - // setSyncVarHookGuard(dirtyBit, false); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit)); - worker.Append(worker.Create(OpCodes.Ldc_I4_0)); - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard)); - - worker.Append(label); - } - - worker.Append(endOfMethod); - - worker.Append(worker.Create(OpCodes.Ret)); - - set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); - set.SemanticsAttributes = MethodSemanticsAttributes.Setter; - - return set; - } - - public static void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVarNetIds, long dirtyBit) - { - string originalName = fd.Name; - Weaver.DLog(td, "Sync Var " + fd.Name + " " + fd.FieldType); - - // GameObject/NetworkIdentity SyncVars have a new field for netId - FieldDefinition netIdField = null; - if (fd.FieldType.Is() || - fd.FieldType.Is()) - { - netIdField = new FieldDefinition("___" + fd.Name + "NetId", - FieldAttributes.Private, - WeaverTypes.Import()); - - syncVarNetIds[fd] = netIdField; - } - - MethodDefinition get = GenerateSyncVarGetter(fd, originalName, netIdField); - MethodDefinition set = GenerateSyncVarSetter(td, fd, originalName, dirtyBit, netIdField); - - //NOTE: is property even needed? Could just use a setter function? - //create the property - PropertyDefinition propertyDefinition = new PropertyDefinition("Network" + originalName, PropertyAttributes.None, fd.FieldType) - { - GetMethod = get, - SetMethod = set - }; - - //add the methods and property to the type. - td.Methods.Add(get); - td.Methods.Add(set); - td.Properties.Add(propertyDefinition); - Weaver.WeaveLists.replacementSetterProperties[fd] = set; - - // replace getter field if GameObject/NetworkIdentity so it uses - // netId instead - // -> only for GameObjects, otherwise an int syncvar's getter would - // end up in recursion. - if (fd.FieldType.Is() || - fd.FieldType.Is()) - { - Weaver.WeaveLists.replacementGetterProperties[fd] = get; - } - } - - public static (List syncVars, Dictionary syncVarNetIds) ProcessSyncVars(TypeDefinition td) - { - List syncVars = new List(); - Dictionary syncVarNetIds = new Dictionary(); - - // the mapping of dirtybits to sync-vars is implicit in the order of the fields here. this order is recorded in m_replacementProperties. - // start assigning syncvars at the place the base class stopped, if any - int dirtyBitCounter = Weaver.WeaveLists.GetSyncVarStart(td.BaseType.FullName); - - // find syncvars - foreach (FieldDefinition fd in td.Fields) - { - if (fd.HasCustomAttribute()) - { - if ((fd.Attributes & FieldAttributes.Static) != 0) - { - Weaver.Error($"{fd.Name} cannot be static", fd); - continue; - } - - if (fd.FieldType.IsArray) - { - Weaver.Error($"{fd.Name} has invalid type. Use SyncLists instead of arrays", fd); - continue; - } - - if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) - { - Weaver.Warning($"{fd.Name} has [SyncVar] attribute. SyncLists should not be marked with SyncVar", fd); - } - else - { - syncVars.Add(fd); - - ProcessSyncVar(td, fd, syncVarNetIds, 1L << dirtyBitCounter); - dirtyBitCounter += 1; - - if (dirtyBitCounter == SyncVarLimit) - { - Weaver.Error($"{td.Name} has too many SyncVars. Consider refactoring your class into multiple components", td); - continue; - } - } - } - } - - // add all the new SyncVar __netId fields - foreach (FieldDefinition fd in syncVarNetIds.Values) - { - td.Fields.Add(fd); - } - Weaver.WeaveLists.SetNumSyncVars(td.FullName, syncVars.Count); - - return (syncVars, syncVarNetIds); - } - - public static void WriteCallHookMethodUsingArgument(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue) - { - WriteCallHookMethod(worker, hookMethod, oldValue, null); - } - - public static void WriteCallHookMethodUsingField(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue) - { - if (newValue == null) - { - Weaver.Error("NewValue field was null when writing SyncVar hook"); - } - - WriteCallHookMethod(worker, hookMethod, oldValue, newValue); - } - - static void WriteCallHookMethod(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue) - { - WriteStartFunctionCall(); - - // write args - WriteOldValue(); - WriteNewValue(); - - WriteEndFunctionCall(); - - - // *** Local functions used to write OpCodes *** - // Local functions have access to function variables, no need to pass in args - - void WriteOldValue() - { - worker.Append(worker.Create(OpCodes.Ldloc, oldValue)); - } - - void WriteNewValue() - { - // write arg1 or this.field - if (newValue == null) - { - worker.Append(worker.Create(OpCodes.Ldarg_1)); - } - else - { - // this. - worker.Append(worker.Create(OpCodes.Ldarg_0)); - // syncvar.get - worker.Append(worker.Create(OpCodes.Ldfld, newValue)); - } - } - - // Writes this before method if it is not static - void WriteStartFunctionCall() - { - // dont add this (Ldarg_0) if method is static - if (!hookMethod.IsStatic) - { - // this before method call - // eg this.onValueChanged - worker.Append(worker.Create(OpCodes.Ldarg_0)); - } - } - - // Calls method - void WriteEndFunctionCall() - { - // only use Callvirt when not static - OpCode opcode = hookMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt; - worker.Append(worker.Create(opcode, hookMethod)); - } - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta deleted file mode 100644 index 982f768..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncVarProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f52c39bddd95d42b88f9cd554dfd9198 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs deleted file mode 100644 index 1317332..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs +++ /dev/null @@ -1,134 +0,0 @@ -using Mono.CecilX; -using Mono.CecilX.Cil; - -namespace Mirror.Weaver -{ - /// - /// Processes [TargetRpc] methods in NetworkBehaviour - /// - public static class TargetRpcProcessor - { - // helper functions to check if the method has a NetworkConnection parameter - public static bool HasNetworkConnectionParameter(MethodDefinition md) - { - return md.Parameters.Count > 0 && - md.Parameters[0].ParameterType.Is(); - } - - public static MethodDefinition ProcessTargetRpcInvoke(TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc) - { - MethodDefinition rpc = new MethodDefinition(Weaver.InvokeRpcPrefix + md.Name, MethodAttributes.Family | - MethodAttributes.Static | - MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - ILProcessor worker = rpc.Body.GetILProcessor(); - Instruction label = worker.Create(OpCodes.Nop); - - NetworkBehaviourProcessor.WriteClientActiveCheck(worker, md.Name, label, "TargetRPC"); - - // setup for reader - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Castclass, td)); - - // NetworkConnection parameter is optional - if (HasNetworkConnectionParameter(md)) - { - // if call has NetworkConnection write clients connection as first arg - //ClientScene.readyconnection - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.ReadyConnectionReference)); - } - - // process reader parameters and skip first one if first one is NetworkConnection - if (!NetworkBehaviourProcessor.ReadArguments(md, worker, RemoteCallType.TargetRpc)) - return null; - - // invoke actual command function - worker.Append(worker.Create(OpCodes.Callvirt, rpcCallFunc)); - worker.Append(worker.Create(OpCodes.Ret)); - - NetworkBehaviourProcessor.AddInvokeParameters(rpc.Parameters); - td.Methods.Add(rpc); - return rpc; - } - - /* generates code like: - public void TargetTest (NetworkConnection conn, int param) - { - NetworkWriter writer = new NetworkWriter (); - writer.WritePackedUInt32 ((uint)param); - base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val); - } - public void CallTargetTest (NetworkConnection conn, int param) - { - // whatever the user did before - } - - or if optional: - public void TargetTest (int param) - { - NetworkWriter writer = new NetworkWriter (); - writer.WritePackedUInt32 ((uint)param); - base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val); - } - public void CallTargetTest (int param) - { - // whatever the user did before - } - - Originally HLAPI put the send message code inside the Call function - and then proceeded to replace every call to TargetTest with CallTargetTest - - This method moves all the user's code into the "CallTargetRpc" method - and replaces the body of the original method with the send message code. - This way we do not need to modify the code anywhere else, and this works - correctly in dependent assemblies - - */ - public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDefinition md, CustomAttribute targetRpcAttr) - { - MethodDefinition rpc = MethodProcessor.SubstituteMethod(td, md); - - ILProcessor worker = md.Body.GetILProcessor(); - - NetworkBehaviourProcessor.WriteSetupLocals(worker); - - NetworkBehaviourProcessor.WriteCreateWriter(worker); - - // write all the arguments that the user passed to the TargetRpc call - // (skip first one if first one is NetworkConnection) - if (!NetworkBehaviourProcessor.WriteArguments(worker, md, RemoteCallType.TargetRpc)) - return null; - - string rpcName = md.Name; - - // invoke SendInternal and return - // this - worker.Append(worker.Create(OpCodes.Ldarg_0)); - if (HasNetworkConnectionParameter(md)) - { - // connection - worker.Append(worker.Create(OpCodes.Ldarg_1)); - } - else - { - // null - worker.Append(worker.Create(OpCodes.Ldnull)); - } - worker.Append(worker.Create(OpCodes.Ldtoken, td)); - // invokerClass - worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference)); - worker.Append(worker.Create(OpCodes.Ldstr, rpcName)); - // writer - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0))); - worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendTargetRpcInternal)); - - NetworkBehaviourProcessor.WriteRecycleWriter(worker); - - worker.Append(worker.Create(OpCodes.Ret)); - - return rpc; - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta deleted file mode 100644 index 0ff7cc5..0000000 --- a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb3ce6c6f3f2942ae88178b86f5a8282 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Program.cs b/Assets/Mirror/Editor/Weaver/Program.cs deleted file mode 100644 index a214b81..0000000 --- a/Assets/Mirror/Editor/Weaver/Program.cs +++ /dev/null @@ -1 +0,0 @@ -// Removed 05/09/20 diff --git a/Assets/Mirror/Editor/Weaver/Program.cs.meta b/Assets/Mirror/Editor/Weaver/Program.cs.meta deleted file mode 100644 index 0a14018..0000000 --- a/Assets/Mirror/Editor/Weaver/Program.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0152994c9591626408fcfec96fcc7933 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs b/Assets/Mirror/Editor/Weaver/Readers.cs deleted file mode 100644 index 514a040..0000000 --- a/Assets/Mirror/Editor/Weaver/Readers.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using System.Collections.Generic; -using Mono.CecilX; -using Mono.CecilX.Cil; -using Mono.CecilX.Rocks; - -namespace Mirror.Weaver -{ - public static class Readers - { - static Dictionary readFuncs; - - public static void Init() - { - readFuncs = new Dictionary(); - } - - internal static void Register(TypeReference dataType, MethodReference methodReference) - { - readFuncs[dataType.FullName] = methodReference; - } - - public static MethodReference GetReadFunc(TypeReference variableReference) - { - if (readFuncs.TryGetValue(variableReference.FullName, out MethodReference foundFunc)) - { - return foundFunc; - } - - // Arrays are special, if we resolve them, we get teh element type, - // so the following ifs might choke on it for scriptable objects - // or other objects that require a custom serializer - // thus check if it is an array and skip all the checks. - if (variableReference.IsArray) - { - if (variableReference.IsMultidimensionalArray()) - { - Weaver.Error($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); - return null; - } - - return GenerateReadCollection(variableReference, variableReference.GetElementType(), nameof(NetworkReaderExtensions.ReadArray)); - } - - TypeDefinition variableDefinition = variableReference.Resolve(); - if (variableDefinition == null) - { - Weaver.Error($"{variableReference.Name} is not a supported type", variableReference); - return null; - } - if (variableDefinition.IsDerivedFrom()) - { - Weaver.Error($"Cannot generate reader for component type {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - if (variableReference.Is()) - { - Weaver.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - if (variableReference.Is()) - { - Weaver.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - if (variableReference.IsByReference) - { - // error?? - Weaver.Error($"Cannot pass type {variableReference.Name} by reference", variableReference); - return null; - } - if (variableDefinition.HasGenericParameters && !variableDefinition.Is(typeof(ArraySegment<>)) && !variableDefinition.Is(typeof(List<>))) - { - Weaver.Error($"Cannot generate reader for generic variable {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - if (variableDefinition.IsInterface) - { - Weaver.Error($"Cannot generate reader for interface {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - if (variableDefinition.IsAbstract) - { - Weaver.Error($"Cannot generate reader for abstract class {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); - return null; - } - - if (variableDefinition.IsEnum) - { - return GenerateEnumReadFunc(variableReference); - } - else if (variableDefinition.Is(typeof(ArraySegment<>))) - { - return GenerateArraySegmentReadFunc(variableReference); - } - else if (variableDefinition.Is(typeof(List<>))) - { - GenericInstanceType genericInstance = (GenericInstanceType)variableReference; - TypeReference elementType = genericInstance.GenericArguments[0]; - - return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList)); - } - - return GenerateClassOrStructReadFunction(variableReference); - } - - static void RegisterReadFunc(TypeReference typeReference, MethodDefinition newReaderFunc) - { - readFuncs[typeReference.FullName] = newReaderFunc; - - Weaver.WeaveLists.generateContainerClass.Methods.Add(newReaderFunc); - } - - static MethodDefinition GenerateEnumReadFunc(TypeReference variable) - { - MethodDefinition readerFunc = GenerateReaderFunction(variable); - - ILProcessor worker = readerFunc.Body.GetILProcessor(); - - worker.Append(worker.Create(OpCodes.Ldarg_0)); - - TypeReference underlyingType = variable.Resolve().GetEnumUnderlyingType(); - MethodReference underlyingFunc = GetReadFunc(underlyingType); - - worker.Append(worker.Create(OpCodes.Call, underlyingFunc)); - worker.Append(worker.Create(OpCodes.Ret)); - return readerFunc; - } - - static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable) - { - GenericInstanceType genericInstance = (GenericInstanceType)variable; - TypeReference elementType = genericInstance.GenericArguments[0]; - - MethodDefinition readerFunc = GenerateReaderFunction(variable); - - ILProcessor worker = readerFunc.Body.GetILProcessor(); - - // $array = reader.Read<[T]>() - ArrayType arrayType = elementType.MakeArrayType(); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Call, GetReadFunc(arrayType))); - - // return new ArraySegment($array); - worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance))); - worker.Append(worker.Create(OpCodes.Ret)); - return readerFunc; - } - - private static MethodDefinition GenerateReaderFunction(TypeReference variable) - { - string functionName = "_Read_" + variable.FullName; - - // create new reader for this type - MethodDefinition readerFunc = new MethodDefinition(functionName, - MethodAttributes.Public | - MethodAttributes.Static | - MethodAttributes.HideBySig, - Weaver.CurrentAssembly.MainModule.ImportReference(variable)); - - readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, WeaverTypes.Import())); - readerFunc.Body.InitLocals = true; - RegisterReadFunc(variable, readerFunc); - - return readerFunc; - } - - static MethodDefinition GenerateReadCollection(TypeReference variable, TypeReference elementType, string readerFunction) - { - MethodDefinition readerFunc = GenerateReaderFunction(variable); - // generate readers for the element - GetReadFunc(elementType); - - ModuleDefinition module = Weaver.CurrentAssembly.MainModule; - TypeReference readerExtensions = module.ImportReference(typeof(NetworkReaderExtensions)); - MethodReference listReader = Resolvers.ResolveMethod(readerExtensions, Weaver.CurrentAssembly, readerFunction); - - GenericInstanceMethod methodRef = new GenericInstanceMethod(listReader); - methodRef.GenericArguments.Add(elementType); - - // generates - // return reader.ReadList(); - - ILProcessor worker = readerFunc.Body.GetILProcessor(); - worker.Append(worker.Create(OpCodes.Ldarg_0)); // reader - worker.Append(worker.Create(OpCodes.Call, methodRef)); // Read - - worker.Append(worker.Create(OpCodes.Ret)); - - return readerFunc; - } - - static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable) - { - MethodDefinition readerFunc = GenerateReaderFunction(variable); - - // create local for return value - readerFunc.Body.Variables.Add(new VariableDefinition(variable)); - - ILProcessor worker = readerFunc.Body.GetILProcessor(); - - TypeDefinition td = variable.Resolve(); - - if (!td.IsValueType) - GenerateNullCheck(worker); - - CreateNew(variable, worker, td); - ReadAllFields(variable, worker); - - worker.Append(worker.Create(OpCodes.Ldloc_0)); - worker.Append(worker.Create(OpCodes.Ret)); - return readerFunc; - } - - private static void GenerateNullCheck(ILProcessor worker) - { - // if (!reader.ReadBoolean()) { - // return null; - // } - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Call, GetReadFunc(WeaverTypes.Import()))); - - Instruction labelEmptyArray = worker.Create(OpCodes.Nop); - worker.Append(worker.Create(OpCodes.Brtrue, labelEmptyArray)); - // return null - worker.Append(worker.Create(OpCodes.Ldnull)); - worker.Append(worker.Create(OpCodes.Ret)); - worker.Append(labelEmptyArray); - } - - // Initialize the local variable with a new instance - static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td) - { - if (variable.IsValueType) - { - // structs are created with Initobj - worker.Append(worker.Create(OpCodes.Ldloca, 0)); - worker.Append(worker.Create(OpCodes.Initobj, variable)); - } - else if (td.IsDerivedFrom()) - { - GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(WeaverTypes.ScriptableObjectCreateInstanceMethod); - genericInstanceMethod.GenericArguments.Add(variable); - worker.Append(worker.Create(OpCodes.Call, genericInstanceMethod)); - worker.Append(worker.Create(OpCodes.Stloc_0)); - } - else - { - // classes are created with their constructor - MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); - if (ctor == null) - { - Weaver.Error($"{variable.Name} can't be deserialized because it has no default constructor", variable); - return; - } - - MethodReference ctorRef = Weaver.CurrentAssembly.MainModule.ImportReference(ctor); - - worker.Append(worker.Create(OpCodes.Newobj, ctorRef)); - worker.Append(worker.Create(OpCodes.Stloc_0)); - } - } - - static void ReadAllFields(TypeReference variable, ILProcessor worker) - { - uint fields = 0; - foreach (FieldDefinition field in variable.FindAllPublicFields()) - { - // mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime - OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc; - worker.Append(worker.Create(opcode, 0)); - - MethodReference readFunc = GetReadFunc(field.FieldType); - if (readFunc != null) - { - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Call, readFunc)); - } - else - { - Weaver.Error($"{field.Name} has an unsupported type", field); - } - FieldReference fieldRef = Weaver.CurrentAssembly.MainModule.ImportReference(field); - - worker.Append(worker.Create(OpCodes.Stfld, fieldRef)); - fields++; - } - } - - /// - /// Save a delegate for each one of the readers into - /// - /// - internal static void InitializeReaders(ILProcessor worker) - { - ModuleDefinition module = Weaver.CurrentAssembly.MainModule; - - TypeReference genericReaderClassRef = module.ImportReference(typeof(Reader<>)); - - System.Reflection.FieldInfo fieldInfo = typeof(Reader<>).GetField(nameof(Reader.read)); - FieldReference fieldRef = module.ImportReference(fieldInfo); - TypeReference networkReaderRef = module.ImportReference(typeof(NetworkReader)); - TypeReference funcRef = module.ImportReference(typeof(Func<,>)); - MethodReference funcConstructorRef = module.ImportReference(typeof(Func<,>).GetConstructors()[0]); - - foreach (MethodReference readFunc in readFuncs.Values) - { - TypeReference dataType = readFunc.ReturnType; - - // create a Func delegate - worker.Append(worker.Create(OpCodes.Ldnull)); - worker.Append(worker.Create(OpCodes.Ldftn, readFunc)); - GenericInstanceType funcGenericInstance = funcRef.MakeGenericInstanceType(networkReaderRef, dataType); - MethodReference funcConstructorInstance = funcConstructorRef.MakeHostInstanceGeneric(funcGenericInstance); - worker.Append(worker.Create(OpCodes.Newobj, funcConstructorInstance)); - - // save it in Writer.write - GenericInstanceType genericInstance = genericReaderClassRef.MakeGenericInstanceType(dataType); - FieldReference specializedField = fieldRef.SpecializeField(genericInstance); - worker.Append(worker.Create(OpCodes.Stsfld, specializedField)); - } - - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs.meta b/Assets/Mirror/Editor/Weaver/Readers.cs.meta deleted file mode 100644 index 838ff59..0000000 --- a/Assets/Mirror/Editor/Weaver/Readers.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: be40277098a024539bf63d0205cae824 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs b/Assets/Mirror/Editor/Weaver/Resolvers.cs deleted file mode 100644 index 9bfbb3c..0000000 --- a/Assets/Mirror/Editor/Weaver/Resolvers.cs +++ /dev/null @@ -1,86 +0,0 @@ -// all the resolve functions for the weaver -// NOTE: these functions should be made extensions, but right now they still -// make heavy use of Weaver.fail and we'd have to check each one's return -// value for null otherwise. -// (original FieldType.Resolve returns null if not found too, so -// exceptions would be a bit inconsistent here) -using Mono.CecilX; - -namespace Mirror.Weaver -{ - public static class Resolvers - { - public static MethodReference ResolveMethod(TypeReference tr, AssemblyDefinition scriptDef, string name) - { - if (tr == null) - { - Weaver.Error($"Cannot resolve method {name} without a class"); - return null; - } - MethodReference method = ResolveMethod(tr, scriptDef, m => m.Name == name); - if (method == null) - { - Weaver.Error($"Method not found with name {name} in type {tr.Name}", tr); - } - return method; - } - - public static MethodReference ResolveMethod(TypeReference t, AssemblyDefinition scriptDef, System.Func predicate) - { - foreach (MethodDefinition methodRef in t.Resolve().Methods) - { - if (predicate(methodRef)) - { - return scriptDef.MainModule.ImportReference(methodRef); - } - } - - Weaver.Error($"Method not found in type {t.Name}", t); - return null; - } - - public static MethodReference TryResolveMethodInParents(TypeReference tr, AssemblyDefinition scriptDef, string name) - { - if (tr == null) - { - return null; - } - foreach (MethodDefinition methodRef in tr.Resolve().Methods) - { - if (methodRef.Name == name) - { - return scriptDef.MainModule.ImportReference(methodRef); - } - } - - // Could not find the method in this class, try the parent - return TryResolveMethodInParents(tr.Resolve().BaseType, scriptDef, name); - } - - public static MethodDefinition ResolveDefaultPublicCtor(TypeReference variable) - { - foreach (MethodDefinition methodRef in variable.Resolve().Methods) - { - if (methodRef.Name == ".ctor" && - methodRef.Resolve().IsPublic && - methodRef.Parameters.Count == 0) - { - return methodRef; - } - } - return null; - } - - public static MethodReference ResolveProperty(TypeReference tr, AssemblyDefinition scriptDef, string name) - { - foreach (PropertyDefinition pd in tr.Resolve().Properties) - { - if (pd.Name == name) - { - return scriptDef.MainModule.ImportReference(pd.GetMethod); - } - } - return null; - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta b/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta deleted file mode 100644 index f4f6602..0000000 --- a/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3039a59c76aec43c797ad66930430367 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs b/Assets/Mirror/Editor/Weaver/Weaver.cs deleted file mode 100644 index b390031..0000000 --- a/Assets/Mirror/Editor/Weaver/Weaver.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Mono.CecilX; - -namespace Mirror.Weaver -{ - // This data is flushed each time - if we are run multiple times in the same process/domain - class WeaverLists - { - // setter functions that replace [SyncVar] member variable references. dict - public Dictionary replacementSetterProperties = new Dictionary(); - // getter functions that replace [SyncVar] member variable references. dict - public Dictionary replacementGetterProperties = new Dictionary(); - - public TypeDefinition generateContainerClass; - - // amount of SyncVars per class. dict - public Dictionary numSyncVars = new Dictionary(); - - public int GetSyncVarStart(string className) - { - return numSyncVars.ContainsKey(className) - ? numSyncVars[className] - : 0; - } - - public void SetNumSyncVars(string className, int num) - { - numSyncVars[className] = num; - } - - public WeaverLists() - { - generateContainerClass = new TypeDefinition("Mirror", "GeneratedNetworkCode", - TypeAttributes.BeforeFieldInit | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Abstract | TypeAttributes.Sealed, - WeaverTypes.Import()); - } - } - - internal static class Weaver - { - public static string InvokeRpcPrefix => "InvokeUserCode_"; - - public static WeaverLists WeaveLists { get; private set; } - public static AssemblyDefinition CurrentAssembly { get; private set; } - public static bool WeavingFailed { get; private set; } - public static bool GenerateLogErrors { get; set; } - - // private properties - static readonly bool DebugLogEnabled = true; - - public static void DLog(TypeDefinition td, string fmt, params object[] args) - { - if (!DebugLogEnabled) - return; - - Console.WriteLine("[" + td.Name + "] " + string.Format(fmt, args)); - } - - // display weaver error - // and mark process as failed - public static void Error(string message) - { - Log.Error(message); - WeavingFailed = true; - } - - public static void Error(string message, MemberReference mr) - { - Log.Error($"{message} (at {mr})"); - WeavingFailed = true; - } - - public static void Warning(string message, MemberReference mr) - { - Log.Warning($"{message} (at {mr})"); - } - - - static void CheckMonoBehaviour(TypeDefinition td) - { - if (td.IsDerivedFrom()) - { - MonoBehaviourProcessor.Process(td); - } - } - - static bool WeaveNetworkBehavior(TypeDefinition td) - { - if (!td.IsClass) - return false; - - if (!td.IsDerivedFrom()) - { - CheckMonoBehaviour(td); - return false; - } - - // process this and base classes from parent to child order - - List behaviourClasses = new List(); - - TypeDefinition parent = td; - while (parent != null) - { - if (parent.Is()) - { - break; - } - - try - { - behaviourClasses.Insert(0, parent); - parent = parent.BaseType.Resolve(); - } - catch (AssemblyResolutionException) - { - // this can happen for plugins. - //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); - break; - } - } - - bool modified = false; - foreach (TypeDefinition behaviour in behaviourClasses) - { - modified |= new NetworkBehaviourProcessor(behaviour).Process(); - } - return modified; - } - - static bool WeaveModule(ModuleDefinition moduleDefinition) - { - try - { - bool modified = false; - - System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); - - watch.Start(); - foreach (TypeDefinition td in moduleDefinition.Types) - { - if (td.IsClass && td.BaseType.CanBeResolved()) - { - modified |= WeaveNetworkBehavior(td); - modified |= ServerClientAttributeProcessor.Process(td); - } - } - watch.Stop(); - Console.WriteLine("Weave behaviours and messages took" + watch.ElapsedMilliseconds + " milliseconds"); - - return modified; - } - catch (Exception ex) - { - Error(ex.ToString()); - throw new Exception(ex.Message, ex); - } - } - - static bool Weave(string assName, IEnumerable dependencies) - { - using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver()) - using (CurrentAssembly = AssemblyDefinition.ReadAssembly(assName, new ReaderParameters { ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver })) - { - asmResolver.AddSearchDirectory(Path.GetDirectoryName(assName)); - asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName()); - if (dependencies != null) - { - foreach (string path in dependencies) - { - asmResolver.AddSearchDirectory(path); - } - } - - WeaverTypes.SetupTargetTypes(CurrentAssembly); - // WeaverList depends on WeaverTypes setup because it uses Import - WeaveLists = new WeaverLists(); - - - System.Diagnostics.Stopwatch rwstopwatch = System.Diagnostics.Stopwatch.StartNew(); - // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages - bool modified = ReaderWriterProcessor.Process(CurrentAssembly); - rwstopwatch.Stop(); - Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds"); - - ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; - Console.WriteLine($"Script Module: {moduleDefinition.Name}"); - - modified |= WeaveModule(moduleDefinition); - - if (WeavingFailed) - { - return false; - } - - if (modified) - { - PropertySiteProcessor.Process(moduleDefinition); - - // add class that holds read/write functions - moduleDefinition.Types.Add(WeaveLists.generateContainerClass); - - ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly); - - // write to outputDir if specified, otherwise perform in-place write - WriterParameters writeParams = new WriterParameters { WriteSymbols = true }; - CurrentAssembly.Write(writeParams); - } - } - - return true; - } - - public static bool WeaveAssembly(string assembly, IEnumerable dependencies) - { - WeavingFailed = false; - - try - { - return Weave(assembly, dependencies); - } - catch (Exception e) - { - Log.Error("Exception :" + e); - return false; - } - } - - } -} diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs.meta b/Assets/Mirror/Editor/Weaver/Weaver.cs.meta deleted file mode 100644 index 0ea2dfe..0000000 --- a/Assets/Mirror/Editor/Weaver/Weaver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: de160f52931054064852f2afd7e7a86f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs deleted file mode 100644 index e7bcd7d..0000000 --- a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Mono.CecilX; - -namespace Mirror.Weaver -{ - [Serializable] - public abstract class WeaverException : Exception - { - public MemberReference MemberReference { get; } - - protected WeaverException(string message, MemberReference member) : base(message) - { - MemberReference = member; - } - - protected WeaverException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } - } - - [Serializable] - public class GenerateWriterException : WeaverException - { - public GenerateWriterException(string message, MemberReference member) : base(message, member) { } - protected GenerateWriterException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } - } -} diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta deleted file mode 100644 index 68643b2..0000000 --- a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8aaaf6193bad7424492677f8e81f1b30 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs deleted file mode 100644 index 9195855..0000000 --- a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using Mono.CecilX; - -namespace Mirror.Weaver -{ - public static class WeaverTypes - { - public static MethodReference ScriptableObjectCreateInstanceMethod; - - public static MethodReference NetworkBehaviourDirtyBitsReference; - public static MethodReference GetPooledWriterReference; - public static MethodReference RecycleWriterReference; - - public static MethodReference ReadyConnectionReference; - - public static MethodReference CmdDelegateConstructor; - - public static MethodReference NetworkServerGetActive; - public static MethodReference NetworkServerGetLocalClientActive; - public static MethodReference NetworkClientGetActive; - - // custom attribute types - public static MethodReference InitSyncObjectReference; - - // array segment - public static MethodReference ArraySegmentConstructorReference; - public static MethodReference ArraySegmentArrayReference; - public static MethodReference ArraySegmentOffsetReference; - public static MethodReference ArraySegmentCountReference; - - // list - public static MethodReference ListConstructorReference; - public static MethodReference ListCountReference; - public static MethodReference ListGetItemReference; - public static MethodReference ListAddReference; - - public static MethodReference syncVarEqualReference; - public static MethodReference syncVarNetworkIdentityEqualReference; - public static MethodReference syncVarGameObjectEqualReference; - public static MethodReference setSyncVarReference; - public static MethodReference setSyncVarHookGuard; - public static MethodReference getSyncVarHookGuard; - public static MethodReference setSyncVarGameObjectReference; - public static MethodReference getSyncVarGameObjectReference; - public static MethodReference setSyncVarNetworkIdentityReference; - public static MethodReference getSyncVarNetworkIdentityReference; - public static MethodReference registerCommandDelegateReference; - public static MethodReference registerRpcDelegateReference; - public static MethodReference getTypeReference; - public static MethodReference getTypeFromHandleReference; - public static MethodReference logErrorReference; - public static MethodReference logWarningReference; - public static MethodReference sendCommandInternal; - public static MethodReference sendRpcInternal; - public static MethodReference sendTargetRpcInternal; - - private static AssemblyDefinition currentAssembly; - - public static TypeReference Import() => Import(typeof(T)); - - public static TypeReference Import(Type t) => currentAssembly.MainModule.ImportReference(t); - - public static void SetupTargetTypes(AssemblyDefinition currentAssembly) - { - // system types - WeaverTypes.currentAssembly = currentAssembly; - - TypeReference ArraySegmentType = Import(typeof(ArraySegment<>)); - ArraySegmentArrayReference = Resolvers.ResolveProperty(ArraySegmentType, currentAssembly, "Array"); - ArraySegmentCountReference = Resolvers.ResolveProperty(ArraySegmentType, currentAssembly, "Count"); - ArraySegmentOffsetReference = Resolvers.ResolveProperty(ArraySegmentType, currentAssembly, "Offset"); - ArraySegmentConstructorReference = Resolvers.ResolveMethod(ArraySegmentType, currentAssembly, ".ctor"); - - TypeReference ListType = Import(typeof(System.Collections.Generic.List<>)); - ListCountReference = Resolvers.ResolveProperty(ListType, currentAssembly, "Count"); - ListGetItemReference = Resolvers.ResolveMethod(ListType, currentAssembly, "get_Item"); - ListAddReference = Resolvers.ResolveMethod(ListType, currentAssembly, "Add"); - ListConstructorReference = Resolvers.ResolveMethod(ListType, currentAssembly, ".ctor"); - - TypeReference NetworkServerType = Import(typeof(NetworkServer)); - NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, currentAssembly, "get_active"); - NetworkServerGetLocalClientActive = Resolvers.ResolveMethod(NetworkServerType, currentAssembly, "get_localClientActive"); - TypeReference NetworkClientType = Import(typeof(NetworkClient)); - NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, currentAssembly, "get_active"); - - TypeReference cmdDelegateReference = Import(); - CmdDelegateConstructor = Resolvers.ResolveMethod(cmdDelegateReference, currentAssembly, ".ctor"); - - TypeReference NetworkBehaviourType = Import(); - TypeReference RemoteCallHelperType = Import(typeof(RemoteCalls.RemoteCallHelper)); - - TypeReference ScriptableObjectType = Import(); - - ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod( - ScriptableObjectType, currentAssembly, - md => md.Name == "CreateInstance" && md.HasGenericParameters); - - NetworkBehaviourDirtyBitsReference = Resolvers.ResolveProperty(NetworkBehaviourType, currentAssembly, "syncVarDirtyBits"); - TypeReference NetworkWriterPoolType = Import(typeof(NetworkWriterPool)); - GetPooledWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, currentAssembly, "GetWriter"); - RecycleWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, currentAssembly, "Recycle"); - - TypeReference ClientSceneType = Import(typeof(ClientScene)); - ReadyConnectionReference = Resolvers.ResolveMethod(ClientSceneType, currentAssembly, "get_readyConnection"); - - syncVarEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SyncVarEqual"); - syncVarNetworkIdentityEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SyncVarNetworkIdentityEqual"); - syncVarGameObjectEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SyncVarGameObjectEqual"); - setSyncVarReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SetSyncVar"); - setSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "setSyncVarHookGuard"); - getSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "getSyncVarHookGuard"); - - setSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SetSyncVarGameObject"); - getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "GetSyncVarGameObject"); - setSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SetSyncVarNetworkIdentity"); - getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "GetSyncVarNetworkIdentity"); - registerCommandDelegateReference = Resolvers.ResolveMethod(RemoteCallHelperType, currentAssembly, "RegisterCommandDelegate"); - registerRpcDelegateReference = Resolvers.ResolveMethod(RemoteCallHelperType, currentAssembly, "RegisterRpcDelegate"); - TypeReference unityDebug = Import(typeof(UnityEngine.Debug)); - logErrorReference = Resolvers.ResolveMethod(unityDebug, currentAssembly, "LogError"); - logWarningReference = Resolvers.ResolveMethod(unityDebug, currentAssembly, "LogWarning"); - - TypeReference typeType = Import(typeof(Type)); - getTypeFromHandleReference = Resolvers.ResolveMethod(typeType, currentAssembly, "GetTypeFromHandle"); - sendCommandInternal = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SendCommandInternal"); - sendRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SendRPCInternal"); - sendTargetRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "SendTargetRPCInternal"); - - InitSyncObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, currentAssembly, "InitSyncObject"); - } - } -} diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta deleted file mode 100644 index d71c33f..0000000 --- a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 2585961bf7fe4c10a9143f4087efdf6f -timeCreated: 1596486854 \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs b/Assets/Mirror/Editor/Weaver/Writers.cs deleted file mode 100644 index 3b00e7d..0000000 --- a/Assets/Mirror/Editor/Weaver/Writers.cs +++ /dev/null @@ -1,309 +0,0 @@ -using System; -using System.Collections.Generic; -using Mono.CecilX; -using Mono.CecilX.Cil; -using Mono.CecilX.Rocks; - -namespace Mirror.Weaver -{ - public static class Writers - { - static Dictionary writeFuncs; - - public static void Init() - { - writeFuncs = new Dictionary(); - } - - public static void Register(TypeReference dataType, MethodReference methodReference) - { - writeFuncs[dataType.FullName] = methodReference; - } - - static void RegisterWriteFunc(TypeReference typeReference, MethodDefinition newWriterFunc) - { - writeFuncs[typeReference.FullName] = newWriterFunc; - - Weaver.WeaveLists.generateContainerClass.Methods.Add(newWriterFunc); - } - - /// - /// Finds existing writer for type, if non exists trys to create one - /// This method is recursive - /// - /// - /// - /// Returns or null - public static MethodReference GetWriteFunc(TypeReference variable) - { - if (writeFuncs.TryGetValue(variable.FullName, out MethodReference foundFunc)) - { - return foundFunc; - } - else - { - // this try/catch will be removed in future PR and make `GetWriteFunc` throw instead - try - { - return GenerateWriter(variable); - } - catch (GenerateWriterException e) - { - Weaver.Error(e.Message, e.MemberReference); - return null; - } - } - } - - /// Throws when writer could not be generated for type - static MethodDefinition GenerateWriter(TypeReference variableReference) - { - if (variableReference.IsByReference) - { - throw new GenerateWriterException($"Cannot pass {variableReference.Name} by reference", variableReference); - } - - // Arrays are special, if we resolve them, we get the element type, - // eg int[] resolves to int - // therefore process this before checks below - if (variableReference.IsArray) - { - if (variableReference.IsMultidimensionalArray()) - { - throw new GenerateWriterException($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); - } - TypeReference elementType = variableReference.GetElementType(); - return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArray)); - } - - if (variableReference.Resolve()?.IsEnum ?? false) - { - // serialize enum as their base type - return GenerateEnumWriteFunc(variableReference); - } - - // check for collections - if (variableReference.Is(typeof(ArraySegment<>))) - { - GenericInstanceType genericInstance = (GenericInstanceType)variableReference; - TypeReference elementType = genericInstance.GenericArguments[0]; - - return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArraySegment)); - } - if (variableReference.Is(typeof(List<>))) - { - GenericInstanceType genericInstance = (GenericInstanceType)variableReference; - TypeReference elementType = genericInstance.GenericArguments[0]; - - return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList)); - } - - // check for invalid types - TypeDefinition variableDefinition = variableReference.Resolve(); - if (variableDefinition == null) - { - throw new GenerateWriterException($"{variableReference.Name} is not a supported type. Use a supported type or provide a custom writer", variableReference); - } - if (variableDefinition.IsDerivedFrom()) - { - throw new GenerateWriterException($"Cannot generate writer for component type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - if (variableReference.Is()) - { - throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - if (variableReference.Is()) - { - throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - if (variableDefinition.HasGenericParameters) - { - throw new GenerateWriterException($"Cannot generate writer for generic type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - if (variableDefinition.IsInterface) - { - throw new GenerateWriterException($"Cannot generate writer for interface {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - if (variableDefinition.IsAbstract) - { - throw new GenerateWriterException($"Cannot generate writer for abstract class {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); - } - - // generate writer for class/struct - return GenerateClassOrStructWriterFunction(variableReference); - } - - private static MethodDefinition GenerateEnumWriteFunc(TypeReference variable) - { - MethodDefinition writerFunc = GenerateWriterFunc(variable); - - ILProcessor worker = writerFunc.Body.GetILProcessor(); - - MethodReference underlyingWriter = GetWriteFunc(variable.Resolve().GetEnumUnderlyingType()); - - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldarg_1)); - worker.Append(worker.Create(OpCodes.Call, underlyingWriter)); - - worker.Append(worker.Create(OpCodes.Ret)); - return writerFunc; - } - - private static MethodDefinition GenerateWriterFunc(TypeReference variable) - { - string functionName = "_Write_" + variable.FullName; - // create new writer for this type - MethodDefinition writerFunc = new MethodDefinition(functionName, - MethodAttributes.Public | - MethodAttributes.Static | - MethodAttributes.HideBySig, - WeaverTypes.Import(typeof(void))); - - writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import())); - writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(variable))); - writerFunc.Body.InitLocals = true; - - RegisterWriteFunc(variable, writerFunc); - return writerFunc; - } - - static MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variable) - { - MethodDefinition writerFunc = GenerateWriterFunc(variable); - - ILProcessor worker = writerFunc.Body.GetILProcessor(); - - if (!variable.Resolve().IsValueType) - WriteNullCheck(worker); - - if (!WriteAllFields(variable, worker)) - return null; - - worker.Append(worker.Create(OpCodes.Ret)); - return writerFunc; - } - - private static void WriteNullCheck(ILProcessor worker) - { - // if (value == null) - // { - // writer.WriteBoolean(false); - // return; - // } - // - - Instruction labelNotNull = worker.Create(OpCodes.Nop); - worker.Append(worker.Create(OpCodes.Ldarg_1)); - worker.Append(worker.Create(OpCodes.Brtrue, labelNotNull)); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldc_I4_0)); - worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.Import()))); - worker.Append(worker.Create(OpCodes.Ret)); - worker.Append(labelNotNull); - - // write.WriteBoolean(true); - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldc_I4_1)); - worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.Import()))); - } - - /// - /// Find all fields in type and write them - /// - /// - /// - /// false if fail - static bool WriteAllFields(TypeReference variable, ILProcessor worker) - { - uint fields = 0; - foreach (FieldDefinition field in variable.FindAllPublicFields()) - { - MethodReference writeFunc = GetWriteFunc(field.FieldType); - // need this null check till later PR when GetWriteFunc throws exception instead - if (writeFunc == null) { return false; } - - FieldReference fieldRef = Weaver.CurrentAssembly.MainModule.ImportReference(field); - - fields++; - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Ldarg_1)); - worker.Append(worker.Create(OpCodes.Ldfld, fieldRef)); - worker.Append(worker.Create(OpCodes.Call, writeFunc)); - } - - return true; - } - - static MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeReference elementType, string writerFunction) - { - - MethodDefinition writerFunc = GenerateWriterFunc(variable); - - MethodReference elementWriteFunc = GetWriteFunc(elementType); - MethodReference intWriterFunc = GetWriteFunc(WeaverTypes.Import()); - - // need this null check till later PR when GetWriteFunc throws exception instead - if (elementWriteFunc == null) - { - Weaver.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable); - return writerFunc; - } - - ModuleDefinition module = Weaver.CurrentAssembly.MainModule; - TypeReference readerExtensions = module.ImportReference(typeof(NetworkWriterExtensions)); - MethodReference collectionWriter = Resolvers.ResolveMethod(readerExtensions, Weaver.CurrentAssembly, writerFunction); - - GenericInstanceMethod methodRef = new GenericInstanceMethod(collectionWriter); - methodRef.GenericArguments.Add(elementType); - - // generates - // reader.WriteArray(array); - - ILProcessor worker = writerFunc.Body.GetILProcessor(); - worker.Append(worker.Create(OpCodes.Ldarg_0)); // writer - worker.Append(worker.Create(OpCodes.Ldarg_1)); // collection - - worker.Append(worker.Create(OpCodes.Call, methodRef)); // WriteArray - - worker.Append(worker.Create(OpCodes.Ret)); - - return writerFunc; - } - - /// - /// Save a delegate for each one of the writers into - /// - /// - internal static void InitializeWriters(ILProcessor worker) - { - ModuleDefinition module = Weaver.CurrentAssembly.MainModule; - - TypeReference genericWriterClassRef = module.ImportReference(typeof(Writer<>)); - - System.Reflection.FieldInfo fieldInfo = typeof(Writer<>).GetField(nameof(Writer.write)); - FieldReference fieldRef = module.ImportReference(fieldInfo); - TypeReference networkWriterRef = module.ImportReference(typeof(NetworkWriter)); - TypeReference actionRef = module.ImportReference(typeof(Action<,>)); - MethodReference actionConstructorRef = module.ImportReference(typeof(Action<,>).GetConstructors()[0]); - - foreach (MethodReference writerMethod in writeFuncs.Values) - { - - TypeReference dataType = writerMethod.Parameters[1].ParameterType; - - // create a Action delegate - worker.Append(worker.Create(OpCodes.Ldnull)); - worker.Append(worker.Create(OpCodes.Ldftn, writerMethod)); - GenericInstanceType actionGenericInstance = actionRef.MakeGenericInstanceType(networkWriterRef, dataType); - MethodReference actionRefInstance = actionConstructorRef.MakeHostInstanceGeneric(actionGenericInstance); - worker.Append(worker.Create(OpCodes.Newobj, actionRefInstance)); - - // save it in Writer.write - GenericInstanceType genericInstance = genericWriterClassRef.MakeGenericInstanceType(dataType); - FieldReference specializedField = fieldRef.SpecializeField(genericInstance); - worker.Append(worker.Create(OpCodes.Stsfld, specializedField)); - } - } - - } -} diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs.meta b/Assets/Mirror/Editor/Weaver/Writers.cs.meta deleted file mode 100644 index 3769f7f..0000000 --- a/Assets/Mirror/Editor/Weaver/Writers.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a90060ad76ea044aba613080dd922709 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Icon.meta b/Assets/Mirror/Icon.meta deleted file mode 100644 index 7338187..0000000 --- a/Assets/Mirror/Icon.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b5f1356ad059a1243910a4e82cd68c5f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Icon/MirrorIcon.png b/Assets/Mirror/Icon/MirrorIcon.png deleted file mode 100644 index a77ca23..0000000 --- a/Assets/Mirror/Icon/MirrorIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5f1ee2247319c7a4e5d1ab13ad4981c21c5a408299ae4158050a63ac7f1eba47 -size 138247 diff --git a/Assets/Mirror/Icon/MirrorIcon.png.meta b/Assets/Mirror/Icon/MirrorIcon.png.meta deleted file mode 100644 index 8049382..0000000 --- a/Assets/Mirror/Icon/MirrorIcon.png.meta +++ /dev/null @@ -1,110 +0,0 @@ -fileFormatVersion: 2 -guid: 7453abfe9e8b2c04a8a47eb536fe21eb -TextureImporter: - fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 9 - 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: 1 - spriteTessellationDetail: -1 - textureType: 0 - 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 - - serializedVersion: 2 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - serializedVersion: 2 - buildTarget: WebGL - 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/Assets/Mirror/Notice.txt b/Assets/Mirror/Notice.txt deleted file mode 100644 index 5eeaf88..0000000 --- a/Assets/Mirror/Notice.txt +++ /dev/null @@ -1,123 +0,0 @@ -This asset is governed by the Asset Store EULA; however, the following -components are governed by the licenses indicated below: - --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -Mirror -MIT License - -Copyright (c) 2015, Unity Technologies -Copyright (c) 2019, vis2k, Paul and Contributors - -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. - --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -kcp2k -MIT License - -Copyright (c) 2016 limpo1989 -Copyright (c) 2020 Paul Pacheco -Copyright (c) 2020 Lymdun -Copyright (c) 2020 vis2k - -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. - --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -Mono.Cecil -MIT License - -Copyright (c) 2008 - 2015 Jb Evain -Copyright (c) 2008 - 2011 Novell, Inc. - -https://github.com/jbevain/cecil - -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. - --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- - -Telepathy -MIT License - -Copyright (c) 2018, vis2k - -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. - - --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- \ No newline at end of file diff --git a/Assets/Mirror/Notice.txt.meta b/Assets/Mirror/Notice.txt.meta deleted file mode 100644 index 3281bd8..0000000 --- a/Assets/Mirror/Notice.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1a7b49ad188074707b004e7bb8824857 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins.meta b/Assets/Mirror/Plugins.meta deleted file mode 100644 index 9504239..0000000 --- a/Assets/Mirror/Plugins.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 05eb4061e2eb94061b9a08c918fff99b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil.meta b/Assets/Mirror/Plugins/Mono.Cecil.meta deleted file mode 100644 index a104e2e..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ce126b4e1a7d13b4c865cd92929f13c3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil/License.txt b/Assets/Mirror/Plugins/Mono.Cecil/License.txt deleted file mode 100644 index 5f10030..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/License.txt +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2008 - 2015 Jb Evain -Copyright (c) 2008 - 2011 Novell, Inc. - -https://github.com/jbevain/cecil - -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/Assets/Mirror/Plugins/Mono.Cecil/License.txt.meta b/Assets/Mirror/Plugins/Mono.Cecil/License.txt.meta deleted file mode 100644 index 9477cb6..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/License.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ab858db5ebbb0d542a9acd197669cb5a -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll deleted file mode 100644 index 2e23eed..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2634466c09fd41920a98e773c050ce3c9438900a70f93859fc3055fd8e95ee05 -size 43520 diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll.meta b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll.meta deleted file mode 100644 index d5555bf..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: a078fc7c0dc14d047a28dea9c93fd259 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - platformData: - - first: - '': Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: None - - 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: x86 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll deleted file mode 100644 index fdeac72..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:524e1c46f47cedf1e10255551d6020609baee7c7fd54741b882cf6465b10e4c9 -size 87552 diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll.meta b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll.meta deleted file mode 100644 index 3ab420f..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: 534d998d93b238041bddcd864f7f1088 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - platformData: - - first: - '': Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: None - - 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: x86 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll deleted file mode 100644 index 5eed7c0..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3894a25bcc175dc107ed5ab78c807791ddd218af43fc92876567552d28faf3ff -size 27648 diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll.meta b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll.meta deleted file mode 100644 index aff0237..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll.meta +++ /dev/null @@ -1,92 +0,0 @@ -fileFormatVersion: 2 -guid: 7526641fb3ae25144aa0a96aad853745 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - platformData: - - first: - '': Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: None - - 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: x86 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll deleted file mode 100644 index 1a85983..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:95e4c2a039bd231183625b608e50b8c7edf85536d6a74faeac8e19db2779497b -size 340992 diff --git a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll.meta b/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll.meta deleted file mode 100644 index f87dc69..0000000 --- a/Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll.meta +++ /dev/null @@ -1,94 +0,0 @@ -fileFormatVersion: 2 -guid: 307911e5ad044dd42b1649eb8637aaf3 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - platformData: - - first: - '': Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux: 1 - Exclude Linux64: 1 - Exclude LinuxUniversal: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Facebook: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Facebook: Win64 - second: - enabled: 0 - settings: - CPU: None - - 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: x86 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Readme.txt b/Assets/Mirror/Readme.txt deleted file mode 100644 index fb011f3..0000000 --- a/Assets/Mirror/Readme.txt +++ /dev/null @@ -1,15 +0,0 @@ -Mirror is a MMO Scale Networking library for Unity, used in uMMORPG, uSurvival -and several MMO projects in development. - -*** IMPORTANT -- You must restart Unity after importing Mirror for the Components Menu to update! *** - -Requirements: - Unity 2018.4 LTS - Runtime .Net 4.x (Project Settings > Player > Other Settings) - -Documentation: - https://mirror-networking.com/docs/ - -Support: - Discord: https://discordapp.com/invite/N9QVxbM - Bug Reports: https://github.com/vis2k/Mirror/issues diff --git a/Assets/Mirror/Readme.txt.meta b/Assets/Mirror/Readme.txt.meta deleted file mode 100644 index d52ccce..0000000 --- a/Assets/Mirror/Readme.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f6d84e019c68446f28415a923b460a03 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime.meta b/Assets/Mirror/Runtime.meta deleted file mode 100644 index 85ee3eb..0000000 --- a/Assets/Mirror/Runtime.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9f4328ccc5f724e45afe2215d275b5d5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/AssemblyInfo.cs b/Assets/Mirror/Runtime/AssemblyInfo.cs deleted file mode 100644 index 5af6857..0000000 --- a/Assets/Mirror/Runtime/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Mirror.Tests.Common")] -[assembly: InternalsVisibleTo("Mirror.Tests")] -[assembly: InternalsVisibleTo("Mirror.Tests.Generated")] -[assembly: InternalsVisibleTo("Mirror.Tests.Runtime")] -[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Editor")] -[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Runtime")] -[assembly: InternalsVisibleTo("Mirror.Editor")] diff --git a/Assets/Mirror/Runtime/AssemblyInfo.cs.meta b/Assets/Mirror/Runtime/AssemblyInfo.cs.meta deleted file mode 100644 index cf3201c..0000000 --- a/Assets/Mirror/Runtime/AssemblyInfo.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e28d5f410e25b42e6a76a2ffc10e4675 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/ClientScene.cs b/Assets/Mirror/Runtime/ClientScene.cs deleted file mode 100644 index 851f8db..0000000 --- a/Assets/Mirror/Runtime/ClientScene.cs +++ /dev/null @@ -1,1047 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using Guid = System.Guid; -using Object = UnityEngine.Object; - -namespace Mirror -{ - /// - /// A client manager which contains static client information and functions. - /// This manager contains references to tracked static local objects such as spawner registrations. It also has the default message handlers used by clients when they registered none themselves. The manager handles adding/removing player objects to the game after a client connection has been set as ready. - /// The ClientScene is a singleton, and it has static convenience methods such as ClientScene.Ready(). - /// The ClientScene is used by the NetworkManager, but it can be used by itself. - /// As the ClientScene manages player objects on the client, it is where clients request to add players. The NetworkManager does this via the ClientScene automatically when auto-add-players is set, but it can be done through code using the function ClientScene.AddPlayer(). This sends an AddPlayer message to the server and will cause a player object to be created for this client. - /// Like NetworkServer, the ClientScene understands the concept of the local client. The function ClientScene.ConnectLocalServer() is used to become a host by starting a local client (when a server is already running). - /// - public static class ClientScene - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(ClientScene)); - - static bool isSpawnFinished; - static NetworkIdentity _localPlayer; - - /// - /// NetworkIdentity of the localPlayer - /// - public static NetworkIdentity localPlayer - { - get => _localPlayer; - private set - { - NetworkIdentity oldPlayer = _localPlayer; - NetworkIdentity newPlayer = value; - if (oldPlayer != newPlayer) - { - _localPlayer = value; - onLocalPlayerChanged?.Invoke(oldPlayer, newPlayer); - } - } - } - - public delegate void LocalplayerChanged(NetworkIdentity oldPlayer, NetworkIdentity newPlayer); - public static event LocalplayerChanged onLocalPlayerChanged; - - /// - /// Returns true when a client's connection has been set to ready. - /// A client that is ready recieves state updates from the server, while a client that is not ready does not. This useful when the state of the game is not normal, such as a scene change or end-of-game. - /// This is read-only. To change the ready state of a client, use ClientScene.Ready(). The server is able to set the ready state of clients using NetworkServer.SetClientReady(), NetworkServer.SetClientNotReady() and NetworkServer.SetAllClientsNotReady(). - /// This is done when changing scenes so that clients don't receive state update messages during scene loading. - /// - public static bool ready { get; set; } - - /// - /// The NetworkConnection object that is currently "ready". This is the connection to the server where objects are spawned from. - /// This connection can be used to send messages to the server. There can only be one ClientScene and ready connection at a time. - /// - public static NetworkConnection readyConnection { get; private set; } - - /// - /// This is a dictionary of the prefabs that are registered on the client with ClientScene.RegisterPrefab(). - /// The key to the dictionary is the prefab asset Id. - /// - public static readonly Dictionary prefabs = new Dictionary(); - - /// - /// This is dictionary of the disabled NetworkIdentity objects in the scene that could be spawned by messages from the server. - /// The key to the dictionary is the NetworkIdentity sceneId. - /// - public static readonly Dictionary spawnableObjects = new Dictionary(); - - // spawn handlers - internal static readonly Dictionary spawnHandlers = new Dictionary(); - internal static readonly Dictionary unspawnHandlers = new Dictionary(); - - internal static void Shutdown() - { - ClearSpawners(); - spawnableObjects.Clear(); - readyConnection = null; - ready = false; - isSpawnFinished = false; - DestroyAllClientObjects(); - } - - /// - /// this is called from message handler for Owner message - /// - /// - internal static void InternalAddPlayer(NetworkIdentity identity) - { - logger.Log("ClientScene.InternalAddPlayer"); - - // NOTE: It can be "normal" when changing scenes for the player to be destroyed and recreated. - // But, the player structures are not cleaned up, we'll just replace the old player - localPlayer = identity; - - // NOTE: we DONT need to set isClient=true here, because OnStartClient - // is called before OnStartLocalPlayer, hence it's already set. - // localPlayer.isClient = true; - - if (readyConnection != null) - { - readyConnection.identity = identity; - } - else - { - logger.LogWarning("No ready connection found for setting player controller during InternalAddPlayer"); - } - } - - /// - /// Sets localPlayer to null - /// Should be called when the local player object is destroyed - /// - internal static void ClearLocalPlayer() - { - logger.Log("ClientScene.ClearLocalPlayer"); - - localPlayer = null; - } - - /// - /// This adds a player GameObject for this client. This causes an AddPlayer message to be sent to the server, and NetworkManager.OnServerAddPlayer is called. - /// - /// The connection to become ready for this client. - /// True if AddPlayer message was sent - public static bool AddPlayer(NetworkConnection readyConn) - { - // ensure valid ready connection - if (readyConn != null) - { - ready = true; - readyConnection = readyConn; - } - - if (!ready) - { - logger.LogError("Must call AddPlayer() with a connection the first time to become ready."); - return false; - } - - if (readyConnection.identity != null) - { - logger.LogError("ClientScene.AddPlayer: a PlayerController was already added. Did you call AddPlayer twice?"); - return false; - } - - if (logger.LogEnabled()) logger.Log("ClientScene.AddPlayer() called with connection [" + readyConnection + "]"); - - readyConnection.Send(new AddPlayerMessage()); - return true; - } - - /// - /// Signal that the client connection is ready to enter the game. - /// This could be for example when a client enters an ongoing game and has finished loading the current scene. The server should respond to the SYSTEM_READY event with an appropriate handler which instantiates the players object for example. - /// - /// The client connection which is ready. - /// True if succcessful - public static bool Ready(NetworkConnection conn) - { - if (ready) - { - logger.LogError("A connection has already been set as ready. There can only be one."); - return false; - } - - if (logger.LogEnabled()) logger.Log("ClientScene.Ready() called with connection [" + conn + "]"); - - if (conn != null) - { - // Set these before sending the ReadyMessage, otherwise host client - // will fail in InternalAddPlayer with null readyConnection. - ready = true; - readyConnection = conn; - readyConnection.isReady = true; - - // Tell server we're ready to have a player object spawned - conn.Send(new ReadyMessage()); - - return true; - } - logger.LogError("Ready() called with invalid connection object: conn=null"); - return false; - } - - internal static void HandleClientDisconnect(NetworkConnection conn) - { - if (readyConnection == conn && ready) - { - ready = false; - readyConnection = null; - } - } - - /// - /// Checks if identity is not spawned yet, not hidden and has sceneId - /// - static bool ConsiderForSpawning(NetworkIdentity identity) - { - // not spawned yet, not hidden, etc.? - return !identity.gameObject.activeSelf && - identity.gameObject.hideFlags != HideFlags.NotEditable && - identity.gameObject.hideFlags != HideFlags.HideAndDontSave && - identity.sceneId != 0; - } - - /// - /// Call this after loading/unloading a scene in the client after connection to register the spawnable objects - /// - public static void PrepareToSpawnSceneObjects() - { - // remove existing items, they will be re-added below - spawnableObjects.Clear(); - - // finds all NetworkIdentity currently loaded by unity (includes disabled objects) - NetworkIdentity[] allIdentities = Resources.FindObjectsOfTypeAll(); - foreach (NetworkIdentity identity in allIdentities) - { - // add all unspawned NetworkIdentities to spawnable objects - if (ConsiderForSpawning(identity)) - { - spawnableObjects.Add(identity.sceneId, identity); - } - } - } - - /// - /// Find the registered prefab for this asset id. - /// Useful for debuggers - /// - /// asset id of the prefab - /// the prefab gameobject - /// true if prefab was registered - public static bool GetPrefab(Guid assetId, out GameObject prefab) - { - prefab = null; - return assetId != Guid.Empty && - prefabs.TryGetValue(assetId, out prefab) && prefab != null; - } - - /// - /// Valids Prefab then adds it to prefabs dictionary - /// - /// NetworkIdentity on Prefab GameObject - static void RegisterPrefabIdentity(NetworkIdentity prefab) - { - if (prefab.assetId == Guid.Empty) - { - logger.LogError($"Can not Register '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); - return; - } - - if (prefab.sceneId != 0) - { - logger.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); - return; - } - - NetworkIdentity[] identities = prefab.GetComponentsInChildren(); - if (identities.Length > 1) - { - logger.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); - } - - if (prefabs.ContainsKey(prefab.assetId)) - { - GameObject existingPrefab = prefabs[prefab.assetId]; - logger.LogWarning($"Replacing existing prefab with assetId '{prefab.assetId}'. Old prefab '{existingPrefab.name}', New prefab '{prefab.name}'"); - } - - if (spawnHandlers.ContainsKey(prefab.assetId) || unspawnHandlers.ContainsKey(prefab.assetId)) - { - logger.LogWarning($"Adding prefab '{prefab.name}' with assetId '{prefab.assetId}' when spawnHandlers with same assetId already exists."); - } - - if (logger.LogEnabled()) logger.Log($"Registering prefab '{prefab.name}' as asset:{prefab.assetId}"); - - prefabs[prefab.assetId] = prefab.gameObject; - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// NOTE: newAssetId can not be set on GameObjects that already have an assetId - /// - /// A GameObject that will be spawned. - /// An assetId to be assigned to this GameObject. This allows a dynamically created game object to be registered for an already known asset Id. - public static void RegisterPrefab(GameObject prefab, Guid newAssetId) - { - if (prefab == null) - { - logger.LogError("Could not register prefab because it was null"); - return; - } - - if (newAssetId == Guid.Empty) - { - logger.LogError($"Could not register '{prefab.name}' with new assetId because the new assetId was empty"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); - return; - } - - if (identity.assetId != Guid.Empty && identity.assetId != newAssetId) - { - logger.LogError($"Could not register '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}"); - return; - } - - identity.assetId = newAssetId; - - RegisterPrefabIdentity(identity); - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// - /// A Prefab that will be spawned. - public static void RegisterPrefab(GameObject prefab) - { - if (prefab == null) - { - logger.LogError("Could not register prefab because it was null"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); - return; - } - - RegisterPrefabIdentity(identity); - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// NOTE: newAssetId can not be set on GameObjects that already have an assetId - /// - /// A GameObject that will be spawned. - /// An assetId to be assigned to this GameObject. This allows a dynamically created game object to be registered for an already known asset Id. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - // We need this check here because we don't want a null handler in the lambda expression below - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {newAssetId}"); - return; - } - - RegisterPrefab(prefab, newAssetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// - /// A Prefab that will be spawned. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - if (prefab == null) - { - logger.LogError("Could not register handler for prefab because the prefab was null"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component"); - return; - } - - if (identity.sceneId != 0) - { - logger.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); - return; - } - - Guid assetId = identity.assetId; - - if (assetId == Guid.Empty) - { - logger.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); - return; - } - - // We need this check here because we don't want a null handler in the lambda expression below - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {assetId}"); - return; - } - - RegisterPrefab(prefab, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// NOTE: newAssetId can not be set on GameObjects that already have an assetId - /// - /// A GameObject that will be spawned. - /// An assetId to be assigned to this GameObject. This allows a dynamically created game object to be registered for an already known asset Id. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - if (newAssetId == Guid.Empty) - { - logger.LogError($"Could not register handler for '{prefab.name}' with new assetId because the new assetId was empty"); - return; - } - - if (prefab == null) - { - logger.LogError("Could not register handler for prefab because the prefab was null"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component"); - return; - } - - if (identity.assetId != Guid.Empty && identity.assetId != newAssetId) - { - logger.LogError($"Could not register Handler for '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}"); - return; - } - - if (identity.sceneId != 0) - { - logger.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); - return; - } - - identity.assetId = newAssetId; - Guid assetId = identity.assetId; - - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {assetId}"); - return; - } - - if (unspawnHandler == null) - { - logger.LogError($"Can not Register null UnSpawnHandler for {assetId}"); - return; - } - - if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) - { - logger.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'"); - } - - if (prefabs.ContainsKey(assetId)) - { - // this is error because SpawnPrefab checks prefabs before handler - logger.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler"); - } - - NetworkIdentity[] identities = prefab.GetComponentsInChildren(); - if (identities.Length > 1) - { - logger.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); - } - - if (logger.LogEnabled()) logger.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName()); - - spawnHandlers[assetId] = spawnHandler; - unspawnHandlers[assetId] = unspawnHandler; - } - - /// - /// Registers a prefab with the spawning system. - /// When a NetworkIdentity object is spawned on a server with NetworkServer.SpawnObject(), and the prefab that the object was created from was registered with RegisterPrefab(), the client will use that prefab to instantiate a corresponding client object with the same netId. - /// The NetworkManager has a list of spawnable prefabs, it uses this function to register those prefabs with the ClientScene. - /// The set of current spawnable object is available in the ClientScene static member variable ClientScene.prefabs, which is a dictionary of NetworkAssetIds and prefab references. - /// - /// A Prefab that will be spawned. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - if (prefab == null) - { - logger.LogError("Could not register handler for prefab because the prefab was null"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component"); - return; - } - - if (identity.sceneId != 0) - { - logger.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); - return; - } - - Guid assetId = identity.assetId; - - if (assetId == Guid.Empty) - { - logger.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); - return; - } - - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {assetId}"); - return; - } - - if (unspawnHandler == null) - { - logger.LogError($"Can not Register null UnSpawnHandler for {assetId}"); - return; - } - - if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) - { - logger.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'"); - } - - if (prefabs.ContainsKey(assetId)) - { - // this is error because SpawnPrefab checks prefabs before handler - logger.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler"); - } - - NetworkIdentity[] identities = prefab.GetComponentsInChildren(); - if (identities.Length > 1) - { - logger.LogWarning($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); - } - - if (logger.LogEnabled()) logger.Log("Registering custom prefab '" + prefab.name + "' as asset:" + assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName()); - - spawnHandlers[assetId] = spawnHandler; - unspawnHandlers[assetId] = unspawnHandler; - } - - /// - /// Removes a registered spawn prefab that was setup with ClientScene.RegisterPrefab. - /// - /// The prefab to be removed from registration. - public static void UnregisterPrefab(GameObject prefab) - { - if (prefab == null) - { - logger.LogError("Could not unregister prefab because it was null"); - return; - } - - NetworkIdentity identity = prefab.GetComponent(); - if (identity == null) - { - logger.LogError("Could not unregister '" + prefab.name + "' since it contains no NetworkIdentity component"); - return; - } - - Guid assetId = identity.assetId; - - prefabs.Remove(assetId); - spawnHandlers.Remove(assetId); - unspawnHandlers.Remove(assetId); - } - - /// - /// This is an advanced spawning function that registers a custom assetId with the UNET spawning system. - /// This can be used to register custom spawning methods for an assetId - instead of the usual method of registering spawning methods for a prefab. This should be used when no prefab exists for the spawned objects - such as when they are constructed dynamically at runtime from configuration data. - /// - /// Custom assetId string. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterSpawnHandler(Guid assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - // We need this check here because we don't want a null handler in the lambda expression below - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {assetId}"); - return; - } - - RegisterSpawnHandler(assetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); - } - - /// - /// This is an advanced spawning function that registers a custom assetId with the UNET spawning system. - /// This can be used to register custom spawning methods for an assetId - instead of the usual method of registering spawning methods for a prefab. This should be used when no prefab exists for the spawned objects - such as when they are constructed dynamically at runtime from configuration data. - /// - /// Custom assetId string. - /// A method to use as a custom spawnhandler on clients. - /// A method to use as a custom un-spawnhandler on clients. - public static void RegisterSpawnHandler(Guid assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) - { - if (spawnHandler == null) - { - logger.LogError($"Can not Register null SpawnHandler for {assetId}"); - return; - } - - if (unspawnHandler == null) - { - logger.LogError($"Can not Register null UnSpawnHandler for {assetId}"); - return; - } - - if (assetId == Guid.Empty) - { - logger.LogError("Can not Register SpawnHandler for empty Guid"); - return; - } - - if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) - { - logger.LogWarning($"Replacing existing spawnHandlers for {assetId}"); - } - - if (prefabs.ContainsKey(assetId)) - { - // this is error because SpawnPrefab checks prefabs before handler - logger.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}'"); - } - - if (logger.LogEnabled()) logger.Log("RegisterSpawnHandler asset '" + assetId + "' " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName()); - - spawnHandlers[assetId] = spawnHandler; - unspawnHandlers[assetId] = unspawnHandler; - } - - /// - /// Removes a registered spawn handler function that was registered with ClientScene.RegisterHandler(). - /// - /// The assetId for the handler to be removed for. - public static void UnregisterSpawnHandler(Guid assetId) - { - spawnHandlers.Remove(assetId); - unspawnHandlers.Remove(assetId); - } - - /// - /// This clears the registered spawn prefabs and spawn handler functions for this client. - /// - public static void ClearSpawners() - { - prefabs.Clear(); - spawnHandlers.Clear(); - unspawnHandlers.Clear(); - } - - static bool InvokeUnSpawnHandler(Guid assetId, GameObject obj) - { - if (unspawnHandlers.TryGetValue(assetId, out UnSpawnDelegate handler) && handler != null) - { - handler(obj); - return true; - } - return false; - } - - /// - /// Destroys all networked objects on the client. - /// This can be used to clean up when a network connection is closed. - /// - public static void DestroyAllClientObjects() - { - // user can modify spawned lists which causes InvalidOperationException - // list can modified either in UnSpawnHandler or in OnDisable/OnDestroy - // we need the Try/Catch so that the rest of the shutdown does not get stopped - try - { - foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values) - { - if (identity != null && identity.gameObject != null) - { - identity.OnStopClient(); - bool wasUnspawned = InvokeUnSpawnHandler(identity.assetId, identity.gameObject); - if (!wasUnspawned) - { - if (identity.sceneId == 0) - { - Object.Destroy(identity.gameObject); - } - else - { - identity.Reset(); - identity.gameObject.SetActive(false); - } - } - } - } - NetworkIdentity.spawned.Clear(); - } - catch (InvalidOperationException e) - { - logger.LogException(e); - logger.LogError("Could not DestroyAllClientObjects because spawned list was modified during loop, make sure you are not modifying NetworkIdentity.spawned by calling NetworkServer.Destroy or NetworkServer.Spawn in OnDestroy or OnDisable."); - } - } - - internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage msg) - { - if (msg.assetId != Guid.Empty) - identity.assetId = msg.assetId; - - if (!identity.gameObject.activeSelf) - { - identity.gameObject.SetActive(true); - } - - // apply local values for VR support - identity.transform.localPosition = msg.position; - identity.transform.localRotation = msg.rotation; - identity.transform.localScale = msg.scale; - identity.hasAuthority = msg.isOwner; - identity.netId = msg.netId; - - if (msg.isLocalPlayer) - InternalAddPlayer(identity); - - // deserialize components if any payload - // (Count is 0 if there were no components) - if (msg.payload.Count > 0) - { - using (PooledNetworkReader payloadReader = NetworkReaderPool.GetReader(msg.payload)) - { - identity.OnDeserializeAllSafely(payloadReader, true); - } - } - - NetworkIdentity.spawned[msg.netId] = identity; - - // objects spawned as part of initial state are started on a second pass - if (isSpawnFinished) - { - identity.NotifyAuthority(); - identity.OnStartClient(); - CheckForLocalPlayer(identity); - } - } - - internal static void OnSpawn(SpawnMessage msg) - { - if (logger.LogEnabled()) logger.Log($"Client spawn handler instantiating netId={msg.netId} assetID={msg.assetId} sceneId={msg.sceneId:X} pos={msg.position}"); - - if (FindOrSpawnObject(msg, out NetworkIdentity identity)) - { - ApplySpawnPayload(identity, msg); - } - } - - /// - /// Finds Existing Object with NetId or spawns a new one using AssetId or sceneId - /// - internal static bool FindOrSpawnObject(SpawnMessage msg, out NetworkIdentity identity) - { - // was the object already spawned? - identity = GetExistingObject(msg.netId); - - // if found, return early - if (identity != null) - { - return true; - } - - if (msg.assetId == Guid.Empty && msg.sceneId == 0) - { - logger.LogError($"OnSpawn message with netId '{msg.netId}' has no AssetId or sceneId"); - return false; - } - - identity = msg.sceneId == 0 ? SpawnPrefab(msg) : SpawnSceneObject(msg); - - if (identity == null) - { - logger.LogError($"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}"); - return false; - } - - return true; - } - - static NetworkIdentity GetExistingObject(uint netid) - { - NetworkIdentity.spawned.TryGetValue(netid, out NetworkIdentity localObject); - return localObject; - } - - static NetworkIdentity SpawnPrefab(SpawnMessage msg) - { - if (GetPrefab(msg.assetId, out GameObject prefab)) - { - GameObject obj = Object.Instantiate(prefab, msg.position, msg.rotation); - if (logger.LogEnabled()) - { - logger.Log("Client spawn handler instantiating [netId:" + msg.netId + " asset ID:" + msg.assetId + " pos:" + msg.position + " rotation: " + msg.rotation + "]"); - } - - return obj.GetComponent(); - } - if (spawnHandlers.TryGetValue(msg.assetId, out SpawnHandlerDelegate handler)) - { - GameObject obj = handler(msg); - if (obj == null) - { - logger.LogError($"Spawn Handler returned null, Handler assetId '{msg.assetId}'"); - return null; - } - NetworkIdentity identity = obj.GetComponent(); - if (identity == null) - { - logger.LogError($"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{msg.assetId}'"); - return null; - } - return identity; - } - logger.LogError($"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={msg.assetId} netId={msg.netId}"); - return null; - } - - static NetworkIdentity SpawnSceneObject(SpawnMessage msg) - { - NetworkIdentity identity = GetAndRemoveSceneObject(msg.sceneId); - if (identity == null) - { - logger.LogError($"Spawn scene object not found for {msg.sceneId:X} SpawnableObjects.Count={spawnableObjects.Count}"); - - // dump the whole spawnable objects dict for easier debugging - if (logger.LogEnabled()) - { - foreach (KeyValuePair kvp in spawnableObjects) - logger.Log($"Spawnable: SceneId={kvp.Key:X} name={kvp.Value.name}"); - } - } - else - { - // only log this when successful - if (logger.LogEnabled()) logger.Log($"Client spawn for [netId:{msg.netId}] [sceneId:{msg.sceneId:X}] obj:{identity}"); - } - - return identity; - } - - static NetworkIdentity GetAndRemoveSceneObject(ulong sceneId) - { - if (spawnableObjects.TryGetValue(sceneId, out NetworkIdentity identity)) - { - spawnableObjects.Remove(sceneId); - return identity; - } - return null; - } - - internal static void OnObjectSpawnStarted(ObjectSpawnStartedMessage _) - { - if (logger.LogEnabled()) logger.Log("SpawnStarted"); - - PrepareToSpawnSceneObjects(); - isSpawnFinished = false; - } - - internal static void OnObjectSpawnFinished(ObjectSpawnFinishedMessage _) - { - logger.Log("SpawnFinished"); - - ClearNullFromSpawned(); - - // paul: Initialize the objects in the same order as they were initialized - // in the server. This is important if spawned objects - // use data from scene objects - foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values.OrderBy(uv => uv.netId)) - { - identity.NotifyAuthority(); - identity.OnStartClient(); - CheckForLocalPlayer(identity); - } - isSpawnFinished = true; - } - - static readonly List toRemoveFromSpawned = new List(); - static void ClearNullFromSpawned() - { - // spawned has null objects after changing scenes on client using NetworkManager.ServerChangeScene - // remove them here so that 2nd loop below does not get NullReferenceException - // see https://github.com/vis2k/Mirror/pull/2240 - // TODO fix scene logic so that client scene doesn't have null objects - foreach (KeyValuePair kvp in NetworkIdentity.spawned) - { - if (kvp.Value == null) - { - toRemoveFromSpawned.Add(kvp.Key); - } - } - - // can't modifiy NetworkIdentity.spawned inside foreach so need 2nd loop to remove - foreach (uint id in toRemoveFromSpawned) - { - NetworkIdentity.spawned.Remove(id); - } - toRemoveFromSpawned.Clear(); - } - - internal static void OnObjectHide(ObjectHideMessage msg) - { - DestroyObject(msg.netId); - } - - internal static void OnObjectDestroy(ObjectDestroyMessage msg) - { - DestroyObject(msg.netId); - } - - static void DestroyObject(uint netId) - { - if (logger.LogEnabled()) logger.Log("ClientScene.OnObjDestroy netId:" + netId); - - if (NetworkIdentity.spawned.TryGetValue(netId, out NetworkIdentity localObject) && localObject != null) - { - localObject.OnStopClient(); - - if (!InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject)) - { - // default handling - if (localObject.sceneId == 0) - { - Object.Destroy(localObject.gameObject); - } - else - { - // scene object.. disable it in scene instead of destroying - localObject.gameObject.SetActive(false); - spawnableObjects[localObject.sceneId] = localObject; - } - } - NetworkIdentity.spawned.Remove(netId); - localObject.Reset(); - } - else - { - if (logger.LogEnabled()) logger.LogWarning("Did not find target for destroy message for " + netId); - } - } - - internal static void OnHostClientObjectDestroy(ObjectDestroyMessage msg) - { - if (logger.LogEnabled()) logger.Log("ClientScene.OnLocalObjectObjDestroy netId:" + msg.netId); - - NetworkIdentity.spawned.Remove(msg.netId); - } - - internal static void OnHostClientObjectHide(ObjectHideMessage msg) - { - if (logger.LogEnabled()) logger.Log("ClientScene::OnLocalObjectObjHide netId:" + msg.netId); - - if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) - { - localObject.OnSetHostVisibility(false); - } - } - - internal static void OnHostClientSpawn(SpawnMessage msg) - { - if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) - { - if (msg.isLocalPlayer) - InternalAddPlayer(localObject); - - localObject.hasAuthority = msg.isOwner; - localObject.NotifyAuthority(); - localObject.OnStartClient(); - localObject.OnSetHostVisibility(true); - CheckForLocalPlayer(localObject); - } - } - - internal static void OnUpdateVarsMessage(UpdateVarsMessage msg) - { - if (logger.LogEnabled()) logger.Log("ClientScene.OnUpdateVarsMessage " + msg.netId); - - if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) - { - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload)) - localObject.OnDeserializeAllSafely(networkReader, false); - } - else - { - logger.LogWarning("Did not find target for sync message for " + msg.netId + " . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); - } - } - - internal static void OnRPCMessage(RpcMessage msg) - { - if (logger.LogEnabled()) logger.Log("ClientScene.OnRPCMessage hash:" + msg.functionHash + " netId:" + msg.netId); - - if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) - { - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload)) - identity.HandleRemoteCall(msg.componentIndex, msg.functionHash, MirrorInvokeType.ClientRpc, networkReader); - } - } - - static void CheckForLocalPlayer(NetworkIdentity identity) - { - if (identity == localPlayer) - { - // Set isLocalPlayer to true on this NetworkIdentity and trigger OnStartLocalPlayer in all scripts on the same GO - identity.connectionToServer = readyConnection; - identity.OnStartLocalPlayer(); - - if (logger.LogEnabled()) logger.Log("ClientScene.OnOwnerMessage - player=" + identity.name); - } - } - } -} diff --git a/Assets/Mirror/Runtime/ClientScene.cs.meta b/Assets/Mirror/Runtime/ClientScene.cs.meta deleted file mode 100644 index c4f3a09..0000000 --- a/Assets/Mirror/Runtime/ClientScene.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 96fc7967f813e4960b9119d7c2118494 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Compression.cs b/Assets/Mirror/Runtime/Compression.cs deleted file mode 100644 index 7ab4eef..0000000 --- a/Assets/Mirror/Runtime/Compression.cs +++ /dev/null @@ -1,225 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// Functions to Compress Quaternions and Floats - /// - /// - /// Uncompressed Quaternion = 32 * 4 = 128 bits => send 16 bytes - /// - /// - /// Quaternion is always normalized so we drop largest value and re-calculate it. - /// We can encode which one is the largest using 2 bits - /// - /// x^2 + y^2 + z^2 + w^2 = 1 - /// - /// - /// - /// - /// 2nd largest value has max size of 1/sqrt(2) - /// We can encode the smallest three components in [-1/sqrt(2),+1/sqrt(2)] instead of [-1,+1] - /// - /// c^2 + c^2 + 0 + 0 = 1 - /// - /// - /// - /// - /// Sign of largest value doesnt matter - /// - /// Q * vec3 == (-Q) * vec3 - /// - /// - /// - /// - /// - /// RotationPrecision
- /// - /// 2/sqrt(2) / (2^bitCount - 1) - /// - ///
- /// - /// - /// rotation precision +-0.00138 in range [-1,+1] - /// - /// 10 bits per value - /// 2 + 10 * 3 = 32 bits => send 4 bytes - /// - /// - ///
- /// - /// - /// Links for more info: - ///
GDC Talk - ///
Post on Snapshot Compression - ///
- ///
- public static class Compression - { - const float QuaternionMinValue = -1f / 1.414214f; // 1/ sqrt(2) - const float QuaternionMaxValue = 1f / 1.414214f; - - const int QuaternionBitLength = 10; - // same as Mathf.Pow(2, targetBitLength) - 1 - const uint QuaternionUintRange = (1 << QuaternionBitLength) - 1; - - /// - /// Used to Compress Quaternion into 4 bytes - /// - public static uint CompressQuaternion(Quaternion value) - { - value = value.normalized; - - int largestIndex = FindLargestIndex(value); - Vector3 small = GetSmallerDimensions(largestIndex, value); - // largest needs to be positive to be calculated by reader - // if largest is negative flip sign of others because Q = -Q - if (value[largestIndex] < 0) - { - small *= -1; - } - - uint a = ScaleToUInt(small.x, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - uint b = ScaleToUInt(small.y, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - uint c = ScaleToUInt(small.z, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - - // pack each 10 bits and extra 2 bits into uint32 - uint packed = a | b << 10 | c << 20 | (uint)largestIndex << 30; - - return packed; - } - - internal static int FindLargestIndex(Quaternion q) - { - int index = default; - float current = default; - - // check each value to see which one is largest (ignoring +-) - for (int i = 0; i < 4; i++) - { - float next = Mathf.Abs(q[i]); - if (next > current) - { - index = i; - current = next; - } - } - - return index; - } - - static Vector3 GetSmallerDimensions(int largestIndex, Quaternion value) - { - float x = value.x; - float y = value.y; - float z = value.z; - float w = value.w; - - switch (largestIndex) - { - case 0: - return new Vector3(y, z, w); - case 1: - return new Vector3(x, z, w); - case 2: - return new Vector3(x, y, w); - case 3: - return new Vector3(x, y, z); - default: - throw new IndexOutOfRangeException("Invalid Quaternion index!"); - } - } - - - /// - /// Used to read a Compressed Quaternion from 4 bytes - /// Quaternion is normalized - /// - public static Quaternion DecompressQuaternion(uint packed) - { - // 10 bits - const uint mask = 0b11_1111_1111; - Quaternion result; - - - uint a = packed & mask; - uint b = (packed >> 10) & mask; - uint c = (packed >> 20) & mask; - uint largestIndex = (packed >> 30) & mask; - - float x = ScaleFromUInt(a, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - float y = ScaleFromUInt(b, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - float z = ScaleFromUInt(c, QuaternionMinValue, QuaternionMaxValue, 0, QuaternionUintRange); - - Vector3 small = new Vector3(x, y, z); - result = FromSmallerDimensions(largestIndex, small); - return result; - } - - static Quaternion FromSmallerDimensions(uint largestIndex, Vector3 smallest) - { - float a = smallest.x; - float b = smallest.y; - float c = smallest.z; - - float largest = Mathf.Sqrt(1 - a * a - b * b - c * c); - switch (largestIndex) - { - case 0: - return new Quaternion(largest, a, b, c).normalized; - case 1: - return new Quaternion(a, largest, b, c).normalized; - case 2: - return new Quaternion(a, b, largest, c).normalized; - case 3: - return new Quaternion(a, b, c, largest).normalized; - default: - throw new IndexOutOfRangeException("Invalid Quaternion index!"); - - } - } - - - /// - /// Scales float from minFloat->maxFloat to minUint->maxUint - /// values out side of minFloat/maxFloat will return either 0 or maxUint - /// - public static uint ScaleToUInt(float value, float minFloat, float maxFloat, uint minUint, uint maxUint) - { - // if out of range return min/max - if (value > maxFloat) { return maxUint; } - if (value < minFloat) { return minUint; } - - float rangeFloat = maxFloat - minFloat; - uint rangeUint = maxUint - minUint; - - // scale value to 0->1 (as float) - float valueRelative = (value - minFloat) / rangeFloat; - // scale value to uMin->uMax - float outValue = valueRelative * rangeUint + minUint; - - return (uint)outValue; - } - - /// - /// Scales uint from minUint->maxUint to minFloat->maxFloat - /// - public static float ScaleFromUInt(uint value, float minFloat, float maxFloat, uint minUint, uint maxUint) - { - // if out of range return min/max - if (value > maxUint) { return maxFloat; } - if (value < minUint) { return minFloat; } - - float rangeFloat = maxFloat - minFloat; - uint rangeUint = maxUint - minUint; - - // scale value to 0->1 (as float) - // make sure divide is float - float valueRelative = (value - minUint) / (float)rangeUint; - // scale value to fMin->fMax - float outValue = valueRelative * rangeFloat + minFloat; - return outValue; - } - } -} diff --git a/Assets/Mirror/Runtime/Compression.cs.meta b/Assets/Mirror/Runtime/Compression.cs.meta deleted file mode 100644 index 5d3cf35..0000000 --- a/Assets/Mirror/Runtime/Compression.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5c28963f9c4b97e418252a55500fb91e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/CustomAttributes.cs b/Assets/Mirror/Runtime/CustomAttributes.cs deleted file mode 100644 index bd4f864..0000000 --- a/Assets/Mirror/Runtime/CustomAttributes.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// SyncVars are used to synchronize a variable from the server to all clients automatically. - /// Value must be changed on server, not directly by clients. Hook parameter allows you to define a client-side method to be invoked when the client gets an update from the server. - /// - [AttributeUsage(AttributeTargets.Field)] - public class SyncVarAttribute : PropertyAttribute - { - public string hook; - } - - /// - /// Call this from a client to run this function on the server. - /// Make sure to validate input etc. It's not possible to call this from a server. - /// - [AttributeUsage(AttributeTargets.Method)] - public class CommandAttribute : Attribute - { - // this is zero - public int channel = Channels.DefaultReliable; - public bool ignoreAuthority = false; - } - - /// - /// The server uses a Remote Procedure Call (RPC) to run this function on clients. - /// - [AttributeUsage(AttributeTargets.Method)] - public class ClientRpcAttribute : Attribute - { - // this is zero - public int channel = Channels.DefaultReliable; - public bool excludeOwner = false; - } - - /// - /// The server uses a Remote Procedure Call (RPC) to run this function on a specific client. - /// - [AttributeUsage(AttributeTargets.Method)] - public class TargetRpcAttribute : Attribute - { - // this is zero - public int channel = Channels.DefaultReliable; - } - - /// - /// Prevents clients from running this method. - /// Prints a warning if a client tries to execute this method. - /// - [AttributeUsage(AttributeTargets.Method)] - public class ServerAttribute : Attribute { } - - /// - /// Prevents clients from running this method. - /// No warning is thrown. - /// - [AttributeUsage(AttributeTargets.Method)] - public class ServerCallbackAttribute : Attribute { } - - /// - /// Prevents the server from running this method. - /// Prints a warning if the server tries to execute this method. - /// - [AttributeUsage(AttributeTargets.Method)] - public class ClientAttribute : Attribute { } - - /// - /// Prevents the server from running this method. - /// No warning is printed. - /// - [AttributeUsage(AttributeTargets.Method)] - public class ClientCallbackAttribute : Attribute { } - - /// - /// Converts a string property into a Scene property in the inspector - /// - public class SceneAttribute : PropertyAttribute { } - - /// - /// Used to show private SyncList in the inspector, - /// Use instead of SerializeField for non Serializable types - /// - [AttributeUsage(AttributeTargets.Field)] - public class ShowInInspectorAttribute : Attribute { } -} diff --git a/Assets/Mirror/Runtime/CustomAttributes.cs.meta b/Assets/Mirror/Runtime/CustomAttributes.cs.meta deleted file mode 100644 index 22a1db2..0000000 --- a/Assets/Mirror/Runtime/CustomAttributes.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c04c722ee2ffd49c8a56ab33667b10b0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/DotNetCompatibility.cs b/Assets/Mirror/Runtime/DotNetCompatibility.cs deleted file mode 100644 index fe57e17..0000000 --- a/Assets/Mirror/Runtime/DotNetCompatibility.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Mirror -{ - internal static class DotNetCompatibility - { - internal static string GetMethodName(this Delegate func) - { -#if NETFX_CORE - return func.GetMethodInfo().Name; -#else - return func.Method.Name; -#endif - } - } -} diff --git a/Assets/Mirror/Runtime/DotNetCompatibility.cs.meta b/Assets/Mirror/Runtime/DotNetCompatibility.cs.meta deleted file mode 100644 index 8742197..0000000 --- a/Assets/Mirror/Runtime/DotNetCompatibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b307f850ccbbe450295acf24d70e5c28 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/ExponentialMovingAverage.cs b/Assets/Mirror/Runtime/ExponentialMovingAverage.cs deleted file mode 100644 index f6ec793..0000000 --- a/Assets/Mirror/Runtime/ExponentialMovingAverage.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Mirror -{ - // implementation of N-day EMA - // it calculates an exponential moving average roughy equivalent to the last n observations - // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average - public class ExponentialMovingAverage - { - readonly float alpha; - bool initialized; - - public ExponentialMovingAverage(int n) - { - // standard N-day EMA alpha calculation - alpha = 2.0f / (n + 1); - } - - public void Add(double newValue) - { - // simple algorithm for EMA described here: - // https://en.wikipedia.org/wiki/Moving_average#Exponentially_weighted_moving_variance_and_standard_deviation - if (initialized) - { - double delta = newValue - Value; - Value += alpha * delta; - Var = (1 - alpha) * (Var + alpha * delta * delta); - } - else - { - Value = newValue; - initialized = true; - } - } - - public double Value { get; private set; } - - public double Var { get; private set; } - } -} diff --git a/Assets/Mirror/Runtime/ExponentialMovingAverage.cs.meta b/Assets/Mirror/Runtime/ExponentialMovingAverage.cs.meta deleted file mode 100644 index 5ce3055..0000000 --- a/Assets/Mirror/Runtime/ExponentialMovingAverage.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05e858cbaa54b4ce4a48c8c7f50c1914 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/FloatBytePacker.cs b/Assets/Mirror/Runtime/FloatBytePacker.cs deleted file mode 100644 index 26d1cc0..0000000 --- a/Assets/Mirror/Runtime/FloatBytePacker.cs +++ /dev/null @@ -1,2 +0,0 @@ -// File Removed 24-Mar-20 - keeping it in here so AssetStore updates overwrite -// the old one. diff --git a/Assets/Mirror/Runtime/FloatBytePacker.cs.meta b/Assets/Mirror/Runtime/FloatBytePacker.cs.meta deleted file mode 100644 index 92145fe..0000000 --- a/Assets/Mirror/Runtime/FloatBytePacker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: afd3cca6a786d4208b1d0f7f2b168901 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/LocalConnections.cs b/Assets/Mirror/Runtime/LocalConnections.cs deleted file mode 100644 index 6d4afcf..0000000 --- a/Assets/Mirror/Runtime/LocalConnections.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - // a server's connection TO a LocalClient. - // sending messages on this connection causes the client's handler function to be invoked directly - class ULocalConnectionToClient : NetworkConnectionToClient - { - internal ULocalConnectionToServer connectionToServer; - - public ULocalConnectionToClient() : base(LocalConnectionId) { } - - public override string address => "localhost"; - - internal override void Send(ArraySegment segment, int channelId = Channels.DefaultReliable) - { - connectionToServer.buffer.Write(segment); - } - - // true because local connections never timeout - /// - internal override bool IsAlive(float timeout) => true; - - internal void DisconnectInternal() - { - // set not ready and handle clientscene disconnect in any case - // (might be client or host mode here) - isReady = false; - RemoveObservers(); - } - - /// - /// Disconnects this connection. - /// - public override void Disconnect() - { - DisconnectInternal(); - connectionToServer.DisconnectInternal(); - } - } - - internal class LocalConnectionBuffer - { - readonly NetworkWriter writer = new NetworkWriter(); - readonly NetworkReader reader = new NetworkReader(default(ArraySegment)); - // The buffer is atleast 1500 bytes long. So need to keep track of - // packet count to know how many ArraySegments are in the buffer - int packetCount; - - public void Write(ArraySegment segment) - { - writer.WriteBytesAndSizeSegment(segment); - packetCount++; - - // update buffer incase writer's length has changed - reader.buffer = writer.ToArraySegment(); - } - - public bool HasPackets() - { - return packetCount > 0; - } - public ArraySegment GetNextPacket() - { - ArraySegment packet = reader.ReadBytesAndSizeSegment(); - packetCount--; - - return packet; - } - - public void ResetBuffer() - { - writer.Reset(); - reader.Position = 0; - } - } - - // a localClient's connection TO a server. - // send messages on this connection causes the server's handler function to be invoked directly. - internal class ULocalConnectionToServer : NetworkConnectionToServer - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(ULocalConnectionToClient)); - - internal ULocalConnectionToClient connectionToClient; - internal readonly LocalConnectionBuffer buffer = new LocalConnectionBuffer(); - - public override string address => "localhost"; - - internal override void Send(ArraySegment segment, int channelId = Channels.DefaultReliable) - { - if (segment.Count == 0) - { - logger.LogError("LocalConnection.SendBytes cannot send zero bytes"); - return; - } - - // handle the server's message directly - connectionToClient.TransportReceive(segment, channelId); - } - - internal void Update() - { - // process internal messages so they are applied at the correct time - while (buffer.HasPackets()) - { - ArraySegment packet = buffer.GetNextPacket(); - - // Treat host player messages exactly like connected client - // to avoid deceptive / misleading behavior differences - TransportReceive(packet, Channels.DefaultReliable); - } - - buffer.ResetBuffer(); - } - - /// - /// Disconnects this connection. - /// - internal void DisconnectInternal() - { - // set not ready and handle clientscene disconnect in any case - // (might be client or host mode here) - isReady = false; - ClientScene.HandleClientDisconnect(this); - } - - /// - /// Disconnects this connection. - /// - public override void Disconnect() - { - connectionToClient.DisconnectInternal(); - DisconnectInternal(); - } - - // true because local connections never timeout - /// - internal override bool IsAlive(float timeout) => true; - } -} diff --git a/Assets/Mirror/Runtime/LocalConnections.cs.meta b/Assets/Mirror/Runtime/LocalConnections.cs.meta deleted file mode 100644 index 2a332c4..0000000 --- a/Assets/Mirror/Runtime/LocalConnections.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a88758df7db2043d6a9d926e0b6d4191 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/LogFactory.cs b/Assets/Mirror/Runtime/LogFactory.cs deleted file mode 100644 index 433d09b..0000000 --- a/Assets/Mirror/Runtime/LogFactory.cs +++ /dev/null @@ -1 +0,0 @@ -// File moved to Mirror/Runtime/Logging/LogFactory.cs \ No newline at end of file diff --git a/Assets/Mirror/Runtime/LogFactory.cs.meta b/Assets/Mirror/Runtime/LogFactory.cs.meta deleted file mode 100644 index 0715501..0000000 --- a/Assets/Mirror/Runtime/LogFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 353c7c9e14e82f349b1679112050b196 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/LogFilter.cs b/Assets/Mirror/Runtime/LogFilter.cs deleted file mode 100644 index 3b225f7..0000000 --- a/Assets/Mirror/Runtime/LogFilter.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Mirror -{ - public static class LogFilter - { - public static bool Debug = false; - } -} diff --git a/Assets/Mirror/Runtime/LogFilter.cs.meta b/Assets/Mirror/Runtime/LogFilter.cs.meta deleted file mode 100644 index 41cab50..0000000 --- a/Assets/Mirror/Runtime/LogFilter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f6928b080072948f7b2909b4025fcc79 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging.meta b/Assets/Mirror/Runtime/Logging.meta deleted file mode 100644 index 867da74..0000000 --- a/Assets/Mirror/Runtime/Logging.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 63d647500ca1bfa4a845bc1f4cff9dcc -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs b/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs deleted file mode 100644 index a1b7d22..0000000 --- a/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror.Logging -{ - public class ConsoleColorLogHandler : ILogHandler - { - readonly bool showExceptionStackTrace; - - public ConsoleColorLogHandler(bool showExceptionStackTrace) - { - this.showExceptionStackTrace = showExceptionStackTrace; - } - - public void LogException(Exception exception, UnityEngine.Object context) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"Exception: {exception.Message}"); - if (showExceptionStackTrace) - { - Console.WriteLine($" {exception.StackTrace}"); - } - Console.ResetColor(); - } - - public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args) - { - switch (logType) - { - case LogType.Exception: - case LogType.Error: - case LogType.Assert: - Console.ForegroundColor = ConsoleColor.Red; - break; - case LogType.Warning: - Console.ForegroundColor = ConsoleColor.Yellow; - break; - } - - Console.WriteLine(string.Format(format, args)); - Console.ResetColor(); - } - } -} diff --git a/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs.meta b/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs.meta deleted file mode 100644 index 329c6eb..0000000 --- a/Assets/Mirror/Runtime/Logging/ConsoleColorLogHandler.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2a9618569c20a504aa86feb5913c70e9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs b/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs deleted file mode 100644 index 8f5c4e4..0000000 --- a/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs +++ /dev/null @@ -1,50 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace Mirror.Logging -{ -#if UNITY_EDITOR - public static class EditorLogSettingsLoader - { - [InitializeOnLoadMethod] - static void Init() - { - // load settings first time LogFactory is used in the editor - LoadLogSettingsIntoDictionary(); - } - - public static void LoadLogSettingsIntoDictionary() - { - LogSettings settings = FindLogSettings(); - if (settings != null) - { - settings.LoadIntoDictionary(LogFactory.loggers); - } - } - - static LogSettings cache; - public static LogSettings FindLogSettings() - { - if (cache != null) - return cache; - - string[] assetGuids = AssetDatabase.FindAssets("t:" + nameof(LogSettings)); - if (assetGuids.Length == 0) - return null; - - string firstGuid = assetGuids[0]; - - string path = AssetDatabase.GUIDToAssetPath(firstGuid); - cache = AssetDatabase.LoadAssetAtPath(path); - - if (assetGuids.Length > 2) - { - Debug.LogWarning("Found more than one LogSettings, Delete extra settings. Using first asset found: " + path); - } - Debug.Assert(cache != null, "Failed to load asset at: " + path); - - return cache; - } - } -#endif -} diff --git a/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs.meta b/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs.meta deleted file mode 100644 index 81b33e9..0000000 --- a/Assets/Mirror/Runtime/Logging/EditorLogSettingsLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a39aa1e48aa54eb4e964f0191c1dcdce -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/LogFactory.cs b/Assets/Mirror/Runtime/Logging/LogFactory.cs deleted file mode 100644 index 39edc23..0000000 --- a/Assets/Mirror/Runtime/Logging/LogFactory.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - public static class LogFactory - { - internal static readonly SortedDictionary loggers = new SortedDictionary(); - - public static SortedDictionary.ValueCollection AllLoggers => loggers.Values; - - /// - /// logHandler used for new loggers - /// - static ILogHandler defaultLogHandler = Debug.unityLogger; - - /// - /// if true sets all log level to LogType.Log - /// - static bool debugMode = false; - - public static ILogger GetLogger(LogType defaultLogLevel = LogType.Warning) - { - return GetLogger(typeof(T).Name, defaultLogLevel); - } - - public static ILogger GetLogger(System.Type type, LogType defaultLogLevel = LogType.Warning) - { - return GetLogger(type.Name, defaultLogLevel); - } - - public static ILogger GetLogger(string loggerName, LogType defaultLogLevel = LogType.Warning) - { - if (loggers.TryGetValue(loggerName, out ILogger logger)) - { - return logger; - } - - logger = new Logger(defaultLogHandler) - { - // by default, log warnings and up - filterLogType = debugMode ? LogType.Log : defaultLogLevel - }; - - loggers[loggerName] = logger; - return logger; - } - - /// - /// Makes all log levels LogType.Log, this is so that NetworkManger.showDebugMessages can still be used - /// - public static void EnableDebugMode() - { - debugMode = true; - - foreach (ILogger logger in loggers.Values) - { - logger.filterLogType = LogType.Log; - } - } - - /// - /// Replacing log handler for all existing loggers and sets defaultLogHandler for new loggers - /// - /// - public static void ReplaceLogHandler(ILogHandler logHandler) - { - defaultLogHandler = logHandler; - - foreach (ILogger logger in loggers.Values) - { - logger.logHandler = logHandler; - } - } - } - - - public static class ILoggerExtensions - { - public static void LogError(this ILogger logger, object message) - { - logger.Log(LogType.Error, message); - } - - public static void Assert(this ILogger logger, bool condition, string message) - { - if (!condition) - logger.Log(LogType.Assert, message); - } - - public static void LogWarning(this ILogger logger, object message) - { - logger.Log(LogType.Warning, message); - } - - public static bool LogEnabled(this ILogger logger) => logger.IsLogTypeAllowed(LogType.Log); - public static bool WarnEnabled(this ILogger logger) => logger.IsLogTypeAllowed(LogType.Warning); - public static bool ErrorEnabled(this ILogger logger) => logger.IsLogTypeAllowed(LogType.Error); - } -} diff --git a/Assets/Mirror/Runtime/Logging/LogFactory.cs.meta b/Assets/Mirror/Runtime/Logging/LogFactory.cs.meta deleted file mode 100644 index acf3b63..0000000 --- a/Assets/Mirror/Runtime/Logging/LogFactory.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d06522432d5a44e1587967a4731cd279 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/LogSettings.cs b/Assets/Mirror/Runtime/Logging/LogSettings.cs deleted file mode 100644 index abd91c1..0000000 --- a/Assets/Mirror/Runtime/Logging/LogSettings.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.Logging -{ - public class LogSettings : ScriptableObject - { - public List loglevels = new List(); - - [Serializable] - public struct LoggerSettings - { - public string name; - public LogType logLevel; - } - } - - public static class LogSettingsExt - { - public static void SaveFromDictionary(this LogSettings settings, SortedDictionary dictionary) - { - if (settings == null) - { - Debug.LogWarning("Could not SaveFromDictionary because LogSettings were null"); - return; - } - - settings.loglevels.Clear(); - - foreach (KeyValuePair kvp in dictionary) - { - settings.loglevels.Add(new LogSettings.LoggerSettings { name = kvp.Key, logLevel = kvp.Value.filterLogType }); - } - -#if UNITY_EDITOR - UnityEditor.EditorUtility.SetDirty(settings); -#endif - } - - public static void LoadIntoDictionary(this LogSettings settings, SortedDictionary dictionary) - { - if (settings == null) - { - Debug.LogWarning("Could not LoadIntoDictionary because LogSettings were null"); - return; - } - - foreach (LogSettings.LoggerSettings logLevel in settings.loglevels) - { - if (dictionary.TryGetValue(logLevel.name, out ILogger logger)) - { - logger.filterLogType = logLevel.logLevel; - } - else - { - logger = new Logger(Debug.unityLogger) - { - filterLogType = logLevel.logLevel - }; - - dictionary[logLevel.name] = logger; - } - } - } - } -} diff --git a/Assets/Mirror/Runtime/Logging/LogSettings.cs.meta b/Assets/Mirror/Runtime/Logging/LogSettings.cs.meta deleted file mode 100644 index 90c4e4d..0000000 --- a/Assets/Mirror/Runtime/Logging/LogSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 633889a39717fde4fa28dd6b948dfac7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs b/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs deleted file mode 100644 index 0b367b5..0000000 --- a/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs +++ /dev/null @@ -1,24 +0,0 @@ -using UnityEngine; - -namespace Mirror.Logging -{ - /// - /// Used to replace log hanlder with Console Color LogHandler - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkHeadlessLogger")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkHeadlessLogger.html")] - public class NetworkHeadlessLogger : MonoBehaviour - { -#pragma warning disable CS0414 // unused private members - [SerializeField] bool showExceptionStackTrace = false; -#pragma warning restore CS0414 // unused private members - - void Awake() - { -#if UNITY_SERVER - LogFactory.ReplaceLogHandler(new ConsoleColorLogHandler(showExceptionStackTrace)); -#endif - } - } -} diff --git a/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs.meta b/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs.meta deleted file mode 100644 index 221a61b..0000000 --- a/Assets/Mirror/Runtime/Logging/NetworkHeadlessLogger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7627623f2b9fad4484082517cd73e67 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs b/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs deleted file mode 100644 index cfa6f1c..0000000 --- a/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs +++ /dev/null @@ -1,46 +0,0 @@ -using UnityEngine; - -namespace Mirror.Logging -{ - /// - /// Used to load LogSettings in build - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkLogSettings")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkLogSettings.html")] - public class NetworkLogSettings : MonoBehaviour - { - [Header("Log Settings Asset")] - [SerializeField] internal LogSettings settings; - -#if UNITY_EDITOR - // called when component is added to GameObject - void Reset() - { - LogSettings existingSettings = EditorLogSettingsLoader.FindLogSettings(); - if (existingSettings != null) - { - settings = existingSettings; - - UnityEditor.EditorUtility.SetDirty(this); - } - } -#endif - - void Awake() - { - RefreshDictionary(); - } - - void OnValidate() - { - // if settings field is changed - RefreshDictionary(); - } - - void RefreshDictionary() - { - settings.LoadIntoDictionary(LogFactory.loggers); - } - } -} diff --git a/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs.meta b/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs.meta deleted file mode 100644 index 2f7ecdf..0000000 --- a/Assets/Mirror/Runtime/Logging/NetworkLogSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ac6e8eccf4b6f4dc7b24c276ef47fde8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/MessagePacker.cs b/Assets/Mirror/Runtime/MessagePacker.cs deleted file mode 100644 index e4f5604..0000000 --- a/Assets/Mirror/Runtime/MessagePacker.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - // message packing all in one place, instead of constructing headers in all - // kinds of different places - // - // MsgType (1-n bytes) - // Content (ContentSize bytes) - // - // -> we use varint for headers because most messages will result in 1 byte - // type/size headers then instead of always - // using 2 bytes for shorts. - // -> this reduces bandwidth by 10% if average message size is 20 bytes - // (probably even shorter) - public static class MessagePacker - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(MessagePacker)); - - public static int GetId() where T : NetworkMessage - { - return GetId(typeof(T)); - } - - public static int GetId(Type type) - { - // paul: 16 bits is enough to avoid collisions - // - keeps the message size small because it gets varinted - // - in case of collisions, Mirror will display an error - return type.FullName.GetStableHashCode() & 0xFFFF; - } - - // pack message before sending - // -> NetworkWriter passed as arg so that we can use .ToArraySegment - // and do an allocation free send before recycling it. - public static void Pack(T message, NetworkWriter writer) where T : NetworkMessage - { - // if it is a value type, just use typeof(T) to avoid boxing - // this works because value types cannot be derived - // if it is a reference type (for example NetworkMessage), - // ask the message for the real type - int msgType = GetId(default(T) != null ? typeof(T) : message.GetType()); - writer.WriteUInt16((ushort)msgType); - - // serialize message into writer - writer.Write(message); - } - - // unpack a message we received - public static T Unpack(byte[] data) where T : NetworkMessage - { - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(data)) - { - int msgType = GetId(); - - int id = networkReader.ReadUInt16(); - if (id != msgType) - throw new FormatException("Invalid message, could not unpack " + typeof(T).FullName); - - return networkReader.Read(); - } - } - - // unpack message after receiving - // -> pass NetworkReader so it's less strange if we create it in here - // and pass it upwards. - // -> NetworkReader will point at content afterwards! - public static bool UnpackMessage(NetworkReader messageReader, out int msgType) - { - // read message type (varint) - try - { - msgType = messageReader.ReadUInt16(); - return true; - } - catch (System.IO.EndOfStreamException) - { - msgType = 0; - return false; - } - } - - internal static NetworkMessageDelegate MessageHandler(Action handler, bool requireAuthenication) - where T : NetworkMessage - where C : NetworkConnection - => (conn, reader, channelId) => - { - // protect against DOS attacks if attackers try to send invalid - // data packets to crash the server/client. there are a thousand - // ways to cause an exception in data handling: - // - invalid headers - // - invalid message ids - // - invalid data causing exceptions - // - negative ReadBytesAndSize prefixes - // - invalid utf8 strings - // - etc. - // - // let's catch them all and then disconnect that connection to avoid - // further attacks. - T message = default; - try - { - if (requireAuthenication && !conn.isAuthenticated) - { - // message requires authentication, but the connection was not authenticated - logger.LogWarning($"Closing connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet"); - conn.Disconnect(); - return; - } - - // if it is a value type, just use defult(T) - // otherwise allocate a new instance - message = reader.Read(); - } - catch (Exception exception) - { - logger.LogError("Closed connection: " + conn + ". This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: " + exception); - conn.Disconnect(); - return; - } - finally - { - // TODO: Figure out the correct channel - NetworkDiagnostics.OnReceive(message, channelId, reader.Length); - } - - handler((C)conn, message); - }; - } -} diff --git a/Assets/Mirror/Runtime/MessagePacker.cs.meta b/Assets/Mirror/Runtime/MessagePacker.cs.meta deleted file mode 100644 index 7ca61aa..0000000 --- a/Assets/Mirror/Runtime/MessagePacker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2db134099f0df4d96a84ae7a0cd9b4bc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Messages.cs b/Assets/Mirror/Runtime/Messages.cs deleted file mode 100644 index 6242351..0000000 --- a/Assets/Mirror/Runtime/Messages.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - // Deprecated 10/06/2020 - [Obsolete("Implement NetworkMessage instead. Use extension methods instead of Serialize/Deserialize, see https://github.com/vis2k/Mirror/pull/2317", true)] - public interface IMessageBase { } - - // Deprecated 10/06/2020 - [Obsolete("Implement NetworkMessage instead. Use extension methods instead of Serialize/Deserialize, see https://github.com/vis2k/Mirror/pull/2317", true)] - public class MessageBase : IMessageBase { } - - public interface NetworkMessage { } - - #region Public System Messages - public struct ErrorMessage : NetworkMessage - { - public byte value; - - public ErrorMessage(byte v) - { - value = v; - } - } - - public struct ReadyMessage : NetworkMessage { } - - public struct NotReadyMessage : NetworkMessage { } - - public struct AddPlayerMessage : NetworkMessage { } - - public struct DisconnectMessage : NetworkMessage { } - - public struct ConnectMessage : NetworkMessage { } - - public struct SceneMessage : NetworkMessage - { - public string sceneName; - // Normal = 0, LoadAdditive = 1, UnloadAdditive = 2 - public SceneOperation sceneOperation; - public bool customHandling; - } - - public enum SceneOperation : byte - { - Normal, - LoadAdditive, - UnloadAdditive - } - - #endregion - - #region System Messages requried for code gen path - public struct CommandMessage : NetworkMessage - { - public uint netId; - public int componentIndex; - public int functionHash; - // the parameters for the Cmd function - // -> ArraySegment to avoid unnecessary allocations - public ArraySegment payload; - } - - public struct RpcMessage : NetworkMessage - { - public uint netId; - public int componentIndex; - public int functionHash; - // the parameters for the Cmd function - // -> ArraySegment to avoid unnecessary allocations - public ArraySegment payload; - } - #endregion - - #region Internal System Messages - public struct SpawnMessage : NetworkMessage - { - /// - /// netId of new or existing object - /// - public uint netId; - /// - /// Is the spawning object the local player. Sets ClientScene.localPlayer - /// - public bool isLocalPlayer; - /// - /// Sets hasAuthority on the spawned object - /// - public bool isOwner; - /// - /// The id of the scene object to spawn - /// - public ulong sceneId; - /// - /// The id of the prefab to spawn - /// If sceneId != 0 then it is used instead of assetId - /// - public Guid assetId; - /// - /// Local position - /// - public Vector3 position; - /// - /// Local rotation - /// - public Quaternion rotation; - /// - /// Local scale - /// - public Vector3 scale; - /// - /// The serialized component data - /// ArraySegment to avoid unnecessary allocations - /// - public ArraySegment payload; - } - - public struct ObjectSpawnStartedMessage : NetworkMessage { } - - public struct ObjectSpawnFinishedMessage : NetworkMessage { } - - public struct ObjectDestroyMessage : NetworkMessage - { - public uint netId; - } - - public struct ObjectHideMessage : NetworkMessage - { - public uint netId; - } - - public struct UpdateVarsMessage : NetworkMessage - { - public uint netId; - // the serialized component data - // -> ArraySegment to avoid unnecessary allocations - public ArraySegment payload; - } - - // A client sends this message to the server - // to calculate RTT and synchronize time - public struct NetworkPingMessage : NetworkMessage - { - public double clientTime; - - public NetworkPingMessage(double value) - { - clientTime = value; - } - } - - // The server responds with this message - // The client can use this to calculate RTT and sync time - public struct NetworkPongMessage : NetworkMessage - { - public double clientTime; - public double serverTime; - } - #endregion -} diff --git a/Assets/Mirror/Runtime/Messages.cs.meta b/Assets/Mirror/Runtime/Messages.cs.meta deleted file mode 100644 index 9afe21b..0000000 --- a/Assets/Mirror/Runtime/Messages.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 938f6f28a6c5b48a0bbd7782342d763b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Mirror.asmdef b/Assets/Mirror/Runtime/Mirror.asmdef deleted file mode 100644 index 1dedc5a..0000000 --- a/Assets/Mirror/Runtime/Mirror.asmdef +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "Mirror", - "references": [ - "Mirror.CompilerSymbols", - "Telepathy", - "kcp2k" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Mirror.asmdef.meta b/Assets/Mirror/Runtime/Mirror.asmdef.meta deleted file mode 100644 index 202009b..0000000 --- a/Assets/Mirror/Runtime/Mirror.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 30817c1a0e6d646d99c048fc403f5979 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkAuthenticator.cs b/Assets/Mirror/Runtime/NetworkAuthenticator.cs deleted file mode 100644 index 6786396..0000000 --- a/Assets/Mirror/Runtime/NetworkAuthenticator.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Events; - -namespace Mirror -{ - /// - /// Unity Event for the NetworkConnection - /// - [Serializable] public class UnityEventNetworkConnection : UnityEvent { } - - /// - /// Base class for implementing component-based authentication during the Connect phase - /// - [HelpURL("https://mirror-networking.com/docs/Guides/Authentication.html")] - public abstract class NetworkAuthenticator : MonoBehaviour - { - [Header("Event Listeners (optional)")] - - /// - /// Notify subscribers on the server when a client is authenticated - /// - [Tooltip("Mirror has an internal subscriber to this event. You can add your own here.")] - public UnityEventNetworkConnection OnServerAuthenticated = new UnityEventNetworkConnection(); - - /// - /// Notify subscribers on the client when the client is authenticated - /// - [Tooltip("Mirror has an internal subscriber to this event. You can add your own here.")] - public UnityEventNetworkConnection OnClientAuthenticated = new UnityEventNetworkConnection(); - - #region server - - /// - /// Called on server from StartServer to initialize the Authenticator - /// Server message handlers should be registered in this method. - /// - public virtual void OnStartServer() { } - - /// - /// Called on server from OnServerAuthenticateInternal when a client needs to authenticate - /// - /// Connection to client. - public abstract void OnServerAuthenticate(NetworkConnection conn); - - protected void ServerAccept(NetworkConnection conn) - { - OnServerAuthenticated.Invoke(conn); - } - - protected void ServerReject(NetworkConnection conn) - { - conn.Disconnect(); - } - - #endregion - - #region client - - /// - /// Called on client from StartClient to initialize the Authenticator - /// Client message handlers should be registered in this method. - /// - public virtual void OnStartClient() { } - - /// - /// Called on client from OnClientAuthenticateInternal when a client needs to authenticate - /// - /// Connection of the client. - public abstract void OnClientAuthenticate(NetworkConnection conn); - - protected void ClientAccept(NetworkConnection conn) - { - OnClientAuthenticated.Invoke(conn); - } - - protected void ClientReject(NetworkConnection conn) - { - // Set this on the client for local reference - conn.isAuthenticated = false; - - // disconnect the client - conn.Disconnect(); - } - - #endregion - - void OnValidate() - { -#if UNITY_EDITOR - // automatically assign authenticator field if we add this to NetworkManager - NetworkManager manager = GetComponent(); - if (manager != null && manager.authenticator == null) - { - manager.authenticator = this; - UnityEditor.Undo.RecordObject(gameObject, "Assigned NetworkManager authenticator"); - } -#endif - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkAuthenticator.cs.meta b/Assets/Mirror/Runtime/NetworkAuthenticator.cs.meta deleted file mode 100644 index c6bbca4..0000000 --- a/Assets/Mirror/Runtime/NetworkAuthenticator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 407fc95d4a8257f448799f26cdde0c2a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkBehaviour.cs b/Assets/Mirror/Runtime/NetworkBehaviour.cs deleted file mode 100644 index 80a4f12..0000000 --- a/Assets/Mirror/Runtime/NetworkBehaviour.cs +++ /dev/null @@ -1,682 +0,0 @@ -using System; -using System.Collections.Generic; -using Mirror.RemoteCalls; -using UnityEngine; - -namespace Mirror -{ - /// - /// Sync to everyone, or only to owner. - /// - public enum SyncMode { Observers, Owner } - - /// - /// Base class which should be inherited by scripts which contain networking functionality. - /// - /// - /// This is a MonoBehaviour class so scripts which need to use the networking feature should inherit this class instead of MonoBehaviour. It allows you to invoke networked actions, receive various callbacks, and automatically synchronize state from server-to-client. - /// The NetworkBehaviour component requires a NetworkIdentity on the game object. There can be multiple NetworkBehaviours on a single game object. For an object with sub-components in a hierarchy, the NetworkIdentity must be on the root object, and NetworkBehaviour scripts must also be on the root object. - /// Some of the built-in components of the networking system are derived from NetworkBehaviour, including NetworkTransport, NetworkAnimator and NetworkProximityChecker. - /// - [AddComponentMenu("")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Guides/NetworkBehaviour.html")] - public abstract class NetworkBehaviour : MonoBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkBehaviour)); - - internal float lastSyncTime; - - // hidden because NetworkBehaviourInspector shows it only if has OnSerialize. - /// - /// sync mode for OnSerialize - /// - [HideInInspector] public SyncMode syncMode = SyncMode.Observers; - - // hidden because NetworkBehaviourInspector shows it only if has OnSerialize. - /// - /// sync interval for OnSerialize (in seconds) - /// - [Tooltip("Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)")] - // [0,2] should be enough. anything >2s is too laggy anyway. - [Range(0, 2)] - [HideInInspector] public float syncInterval = 0.1f; - - /// - /// Returns true if this object is active on an active server. - /// This is only true if the object has been spawned. This is different from NetworkServer.active, which is true if the server itself is active rather than this object being active. - /// - public bool isServer => netIdentity.isServer; - - /// - /// Returns true if running as a client and this object was spawned by a server. - /// - public bool isClient => netIdentity.isClient; - - /// - /// This returns true if this object is the one that represents the player on the local machine. - /// In multiplayer games, there are multiple instances of the Player object. The client needs to know which one is for "themselves" so that only that player processes input and potentially has a camera attached. The IsLocalPlayer function will return true only for the player instance that belongs to the player on the local machine, so it can be used to filter out input for non-local players. - /// - public bool isLocalPlayer => netIdentity.isLocalPlayer; - - /// - /// True if this object only exists on the server - /// - public bool isServerOnly => isServer && !isClient; - - /// - /// True if this object exists on a client that is not also acting as a server - /// - public bool isClientOnly => isClient && !isServer; - - /// - /// This returns true if this object is the authoritative version of the object in the distributed network application. - /// The NetworkIdentity.hasAuthority value on the NetworkIdentity determines how authority is determined. For most objects, authority is held by the server. For objects with NetworkIdentity.hasAuthority set, authority is held by the client of that player. - /// - public bool hasAuthority => netIdentity.hasAuthority; - - /// - /// The unique network Id of this object. - /// This is assigned at runtime by the network server and will be unique for all objects for that network session. - /// - public uint netId => netIdentity.netId; - - /// - /// The NetworkConnection associated with this NetworkIdentity. This is only valid for player objects on the client. - /// - public NetworkConnection connectionToServer => netIdentity.connectionToServer; - - /// - /// The NetworkConnection associated with this NetworkIdentity. This is only valid for player objects on the server. - /// - public NetworkConnection connectionToClient => netIdentity.connectionToClient; - - protected ulong syncVarDirtyBits { get; private set; } - ulong syncVarHookGuard; - - protected bool getSyncVarHookGuard(ulong dirtyBit) - { - return (syncVarHookGuard & dirtyBit) != 0UL; - } - - protected void setSyncVarHookGuard(ulong dirtyBit, bool value) - { - if (value) - syncVarHookGuard |= dirtyBit; - else - syncVarHookGuard &= ~dirtyBit; - } - - /// - /// objects that can synchronize themselves, such as synclists - /// - protected readonly List syncObjects = new List(); - - /// - /// NetworkIdentity component caching for easier access - /// - NetworkIdentity netIdentityCache; - - /// - /// Returns the NetworkIdentity of this object - /// - public NetworkIdentity netIdentity - { - get - { - if (netIdentityCache is null) - { - netIdentityCache = GetComponent(); - // do this 2nd check inside first if so that we are not checking == twice on unity Object - if (netIdentityCache is null) - { - logger.LogError("There is no NetworkIdentity on " + name + ". Please add one."); - } - } - return netIdentityCache; - } - } - - /// - /// Returns the index of the component on this object - /// - public int ComponentIndex - { - get - { - // note: FindIndex causes allocations, we search manually instead - for (int i = 0; i < netIdentity.NetworkBehaviours.Length; i++) - { - NetworkBehaviour component = netIdentity.NetworkBehaviours[i]; - if (component == this) - return i; - } - - // this should never happen - logger.LogError("Could not find component in GameObject. You should not add/remove components in networked objects dynamically", this); - - return -1; - } - } - - // this gets called in the constructor by the weaver - // for every SyncObject in the component (e.g. SyncLists). - // We collect all of them and we synchronize them with OnSerialize/OnDeserialize - protected void InitSyncObject(SyncObject syncObject) - { - if (syncObject == null) - logger.LogError("Uninitialized SyncObject. Manually call the constructor on your SyncList, SyncSet or SyncDictionary", this); - else - syncObjects.Add(syncObject); - } - - #region Commands - protected void SendCommandInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId, bool ignoreAuthority = false) - { - // this was in Weaver before - // NOTE: we could remove this later to allow calling Cmds on Server - // to avoid Wrapper functions. a lot of people requested this. - if (!NetworkClient.active) - { - logger.LogError($"Command Function {cmdName} called without an active client."); - return; - } - // local players can always send commands, regardless of authority, other objects must have authority. - if (!(ignoreAuthority || isLocalPlayer || hasAuthority)) - { - logger.LogWarning($"Trying to send command for object without authority. {invokeClass.ToString()}.{cmdName}"); - return; - } - - if (ClientScene.readyConnection == null) - { - logger.LogError("Send command attempted with no client running [client=" + connectionToServer + "]."); - return; - } - - // construct the message - CommandMessage message = new CommandMessage - { - netId = netId, - componentIndex = ComponentIndex, - // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = RemoteCallHelper.GetMethodHash(invokeClass, cmdName), - // segment to avoid reader allocations - payload = writer.ToArraySegment() - }; - - ClientScene.readyConnection.Send(message, channelId); - } - - #endregion - - #region Client RPCs - protected void SendRPCInternal(Type invokeClass, string rpcName, NetworkWriter writer, int channelId, bool excludeOwner) - { - // this was in Weaver before - if (!NetworkServer.active) - { - logger.LogError("RPC Function " + rpcName + " called on Client."); - return; - } - // This cannot use NetworkServer.active, as that is not specific to this object. - if (!isServer) - { - logger.LogWarning("ClientRpc " + rpcName + " called on un-spawned object: " + name); - return; - } - - // construct the message - RpcMessage message = new RpcMessage - { - netId = netId, - componentIndex = ComponentIndex, - // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = RemoteCallHelper.GetMethodHash(invokeClass, rpcName), - // segment to avoid reader allocations - payload = writer.ToArraySegment() - }; - - // The public facing parameter is excludeOwner in [ClientRpc] - // so we negate it here to logically align with SendToReady. - bool includeOwner = !excludeOwner; - NetworkServer.SendToReady(netIdentity, message, includeOwner, channelId); - } - - protected void SendTargetRPCInternal(NetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId) - { - if (!NetworkServer.active) - { - logger.LogError($"TargetRPC {rpcName} called when server not active"); - return; - } - - if (!isServer) - { - logger.LogWarning($"TargetRpc {rpcName} called on {name} but that object has not been spawned or has been unspawned"); - return; - } - - // connection parameter is optional. assign if null. - if (conn is null) - { - conn = connectionToClient; - } - - // if still null - if (conn is null) - { - logger.LogError($"TargetRPC {rpcName} was given a null connection, make sure the object has an owner or you pass in the target connection"); - return; - } - - if (!(conn is NetworkConnectionToClient)) - { - logger.LogError($"TargetRPC {rpcName} requires a NetworkConnectionToClient but was given {conn.GetType().Name}"); - return; - } - - // construct the message - RpcMessage message = new RpcMessage - { - netId = netId, - componentIndex = ComponentIndex, - // type+func so Inventory.RpcUse != Equipment.RpcUse - functionHash = RemoteCallHelper.GetMethodHash(invokeClass, rpcName), - // segment to avoid reader allocations - payload = writer.ToArraySegment() - }; - - conn.Send(message, channelId); - } - - #endregion - - #region Helpers - - // helper function for [SyncVar] GameObjects. - // IMPORTANT: keep as 'protected', not 'internal', otherwise Weaver - // can't resolve it - protected bool SyncVarGameObjectEqual(GameObject newGameObject, uint netIdField) - { - uint newNetId = 0; - if (newGameObject != null) - { - NetworkIdentity identity = newGameObject.GetComponent(); - if (identity != null) - { - newNetId = identity.netId; - if (newNetId == 0) - { - logger.LogWarning("SetSyncVarGameObject GameObject " + newGameObject + " has a zero netId. Maybe it is not spawned yet?"); - } - } - } - - return newNetId == netIdField; - } - - // helper function for [SyncVar] GameObjects. - protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gameObjectField, ulong dirtyBit, ref uint netIdField) - { - if (getSyncVarHookGuard(dirtyBit)) - return; - - uint newNetId = 0; - if (newGameObject != null) - { - NetworkIdentity identity = newGameObject.GetComponent(); - if (identity != null) - { - newNetId = identity.netId; - if (newNetId == 0) - { - logger.LogWarning("SetSyncVarGameObject GameObject " + newGameObject + " has a zero netId. Maybe it is not spawned yet?"); - } - } - } - - if (logger.LogEnabled()) logger.Log("SetSyncVar GameObject " + GetType().Name + " bit [" + dirtyBit + "] netfieldId:" + netIdField + "->" + newNetId); - SetDirtyBit(dirtyBit); - // assign new one on the server, and in case we ever need it on client too - gameObjectField = newGameObject; - netIdField = newNetId; - } - - // helper function for [SyncVar] GameObjects. - // -> ref GameObject as second argument makes OnDeserialize processing easier - protected GameObject GetSyncVarGameObject(uint netId, ref GameObject gameObjectField) - { - // server always uses the field - if (isServer) - { - return gameObjectField; - } - - // client always looks up based on netId because objects might get in and out of range - // over and over again, which shouldn't null them forever - if (NetworkIdentity.spawned.TryGetValue(netId, out NetworkIdentity identity) && identity != null) - return gameObjectField = identity.gameObject; - return null; - } - - // helper function for [SyncVar] NetworkIdentities. - // IMPORTANT: keep as 'protected', not 'internal', otherwise Weaver - // can't resolve it - protected bool SyncVarNetworkIdentityEqual(NetworkIdentity newIdentity, uint netIdField) - { - uint newNetId = 0; - if (newIdentity != null) - { - newNetId = newIdentity.netId; - if (newNetId == 0) - { - logger.LogWarning("SetSyncVarNetworkIdentity NetworkIdentity " + newIdentity + " has a zero netId. Maybe it is not spawned yet?"); - } - } - - // netId changed? - return newNetId == netIdField; - } - - // helper function for [SyncVar] NetworkIdentities. - protected void SetSyncVarNetworkIdentity(NetworkIdentity newIdentity, ref NetworkIdentity identityField, ulong dirtyBit, ref uint netIdField) - { - if (getSyncVarHookGuard(dirtyBit)) - return; - - uint newNetId = 0; - if (newIdentity != null) - { - newNetId = newIdentity.netId; - if (newNetId == 0) - { - logger.LogWarning("SetSyncVarNetworkIdentity NetworkIdentity " + newIdentity + " has a zero netId. Maybe it is not spawned yet?"); - } - } - - if (logger.LogEnabled()) logger.Log("SetSyncVarNetworkIdentity NetworkIdentity " + GetType().Name + " bit [" + dirtyBit + "] netIdField:" + netIdField + "->" + newNetId); - SetDirtyBit(dirtyBit); - netIdField = newNetId; - // assign new one on the server, and in case we ever need it on client too - identityField = newIdentity; - } - - // helper function for [SyncVar] NetworkIdentities. - // -> ref GameObject as second argument makes OnDeserialize processing easier - protected NetworkIdentity GetSyncVarNetworkIdentity(uint netId, ref NetworkIdentity identityField) - { - // server always uses the field - if (isServer) - { - return identityField; - } - - // client always looks up based on netId because objects might get in and out of range - // over and over again, which shouldn't null them forever - NetworkIdentity.spawned.TryGetValue(netId, out identityField); - return identityField; - } - - protected bool SyncVarEqual(T value, ref T fieldValue) - { - // newly initialized or changed value? - return EqualityComparer.Default.Equals(value, fieldValue); - } - - protected void SetSyncVar(T value, ref T fieldValue, ulong dirtyBit) - { - if (logger.LogEnabled()) logger.Log("SetSyncVar " + GetType().Name + " bit [" + dirtyBit + "] " + fieldValue + "->" + value); - SetDirtyBit(dirtyBit); - fieldValue = value; - } - #endregion - - /// - /// Used to set the behaviour as dirty, so that a network update will be sent for the object. - /// these are masks, not bit numbers, ie. 0x004 not 2 - /// - /// Bit mask to set. - public void SetDirtyBit(ulong dirtyBit) - { - syncVarDirtyBits |= dirtyBit; - } - - /// - /// This clears all the dirty bits that were set on this script by SetDirtyBits(); - /// This is automatically invoked when an update is sent for this object, but can be called manually as well. - /// - public void ClearAllDirtyBits() - { - lastSyncTime = Time.time; - syncVarDirtyBits = 0L; - - // flush all unsynchronized changes in syncobjects - // note: don't use List.ForEach here, this is a hot path - // List.ForEach: 432b/frame - // for: 231b/frame - for (int i = 0; i < syncObjects.Count; ++i) - { - syncObjects[i].Flush(); - } - } - - bool AnySyncObjectDirty() - { - // note: don't use Linq here. 1200 networked objects: - // Linq: 187KB GC/frame;, 2.66ms time - // for: 8KB GC/frame; 1.28ms time - for (int i = 0; i < syncObjects.Count; ++i) - { - if (syncObjects[i].IsDirty) - { - return true; - } - } - return false; - } - - public bool IsDirty() - { - if (Time.time - lastSyncTime >= syncInterval) - { - return syncVarDirtyBits != 0L || AnySyncObjectDirty(); - } - return false; - } - - /// - /// Virtual function to override to send custom serialization data. The corresponding function to send serialization data is OnDeserialize(). - /// - /// - /// The initialState flag is useful to differentiate between the first time an object is serialized and when incremental updates can be sent. The first time an object is sent to a client, it must include a full state snapshot, but subsequent updates can save on bandwidth by including only incremental changes. Note that SyncVar hook functions are not called when initialState is true, only for incremental updates. - /// If a class has SyncVars, then an implementation of this function and OnDeserialize() are added automatically to the class. So a class that has SyncVars cannot also have custom serialization functions. - /// The OnSerialize function should return true to indicate that an update should be sent. If it returns true, then the dirty bits for that script are set to zero, if it returns false then the dirty bits are not changed. This allows multiple changes to a script to be accumulated over time and sent when the system is ready, instead of every frame. - /// - /// Writer to use to write to the stream. - /// If this is being called to send initial state. - /// True if data was written. - public virtual bool OnSerialize(NetworkWriter writer, bool initialState) - { - bool objectWritten = false; - // if initialState: write all SyncVars. - // otherwise write dirtyBits+dirty SyncVars - if (initialState) - { - objectWritten = SerializeObjectsAll(writer); - } - else - { - objectWritten = SerializeObjectsDelta(writer); - } - - bool syncVarWritten = SerializeSyncVars(writer, initialState); - - return objectWritten || syncVarWritten; - } - - - /// - /// Virtual function to override to receive custom serialization data. The corresponding function to send serialization data is OnSerialize(). - /// - /// Reader to read from the stream. - /// True if being sent initial state. - public virtual void OnDeserialize(NetworkReader reader, bool initialState) - { - if (initialState) - { - DeSerializeObjectsAll(reader); - } - else - { - DeSerializeObjectsDelta(reader); - } - - DeserializeSyncVars(reader, initialState); - } - - // Don't rename. Weaver uses this exact function name. - protected virtual bool SerializeSyncVars(NetworkWriter writer, bool initialState) - { - return false; - - // SyncVar are writen here in subclass - - // if initialState - // write all SyncVars - // else - // write syncVarDirtyBits - // write dirty SyncVars - } - - // Don't rename. Weaver uses this exact function name. - protected virtual void DeserializeSyncVars(NetworkReader reader, bool initialState) - { - // SyncVars are read here in subclass - - // if initialState - // read all SyncVars - // else - // read syncVarDirtyBits - // read dirty SyncVars - } - - internal ulong DirtyObjectBits() - { - ulong dirtyObjects = 0; - for (int i = 0; i < syncObjects.Count; i++) - { - SyncObject syncObject = syncObjects[i]; - if (syncObject.IsDirty) - { - dirtyObjects |= 1UL << i; - } - } - return dirtyObjects; - } - - public bool SerializeObjectsAll(NetworkWriter writer) - { - bool dirty = false; - for (int i = 0; i < syncObjects.Count; i++) - { - SyncObject syncObject = syncObjects[i]; - syncObject.OnSerializeAll(writer); - dirty = true; - } - return dirty; - } - - public bool SerializeObjectsDelta(NetworkWriter writer) - { - bool dirty = false; - // write the mask - writer.WritePackedUInt64(DirtyObjectBits()); - // serializable objects, such as synclists - for (int i = 0; i < syncObjects.Count; i++) - { - SyncObject syncObject = syncObjects[i]; - if (syncObject.IsDirty) - { - syncObject.OnSerializeDelta(writer); - dirty = true; - } - } - return dirty; - } - - internal void DeSerializeObjectsAll(NetworkReader reader) - { - for (int i = 0; i < syncObjects.Count; i++) - { - SyncObject syncObject = syncObjects[i]; - syncObject.OnDeserializeAll(reader); - } - } - - internal void DeSerializeObjectsDelta(NetworkReader reader) - { - ulong dirty = reader.ReadPackedUInt64(); - for (int i = 0; i < syncObjects.Count; i++) - { - SyncObject syncObject = syncObjects[i]; - if ((dirty & (1UL << i)) != 0) - { - syncObject.OnDeserializeDelta(reader); - } - } - } - - internal void ResetSyncObjects() - { - foreach (SyncObject syncObject in syncObjects) - { - syncObject.Reset(); - } - } - - /// - /// This is invoked on clients when the server has caused this object to be destroyed. - /// This can be used as a hook to invoke effects or do client specific cleanup. - /// - public virtual void OnStopClient() { } - - /// - /// This is invoked for NetworkBehaviour objects when they become active on the server. - /// This could be triggered by NetworkServer.Listen() for objects in the scene, or by NetworkServer.Spawn() for objects that are dynamically created. - /// This will be called for objects on a "host" as well as for object on a dedicated server. - /// - public virtual void OnStartServer() { } - - /// - /// Invoked on the server when the object is unspawned - /// Useful for saving object data in persistant storage - /// - public virtual void OnStopServer() { } - - /// - /// Called on every NetworkBehaviour when it is activated on a client. - /// Objects on the host have this function called, as there is a local client on the host. The values of SyncVars on object are guaranteed to be initialized correctly with the latest state from the server when this function is called on the client. - /// - public virtual void OnStartClient() { } - - /// - /// Called when the local player object has been set up. - /// This happens after OnStartClient(), as it is triggered by an ownership message from the server. This is an appropriate place to activate components or functionality that should only be active for the local player, such as cameras and input. - /// - public virtual void OnStartLocalPlayer() { } - - /// - /// This is invoked on behaviours that have authority, based on context and NetworkIdentity.hasAuthority. - /// This is called after OnStartServer and before OnStartClient. - /// When AssignClientAuthority is called on the server, this will be called on the client that owns the object. When an object is spawned with NetworkServer.Spawn with a NetworkConnection parameter included, this will be called on the client that owns the object. - /// - public virtual void OnStartAuthority() { } - - /// - /// This is invoked on behaviours when authority is removed. - /// When NetworkIdentity.RemoveClientAuthority is called on the server, this will be called on the client that owns the object. - /// - public virtual void OnStopAuthority() { } - } -} diff --git a/Assets/Mirror/Runtime/NetworkBehaviour.cs.meta b/Assets/Mirror/Runtime/NetworkBehaviour.cs.meta deleted file mode 100644 index 84e619d..0000000 --- a/Assets/Mirror/Runtime/NetworkBehaviour.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 655ee8cba98594f70880da5cc4dc442d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkClient.cs b/Assets/Mirror/Runtime/NetworkClient.cs deleted file mode 100644 index 2dadb4e..0000000 --- a/Assets/Mirror/Runtime/NetworkClient.cs +++ /dev/null @@ -1,384 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - public enum ConnectState - { - None, - Connecting, - Connected, - Disconnected - } - - /// - /// This is a network client class used by the networking system. It contains a NetworkConnection that is used to connect to a network server. - /// The NetworkClient handle connection state, messages handlers, and connection configuration. There can be many NetworkClient instances in a process at a time, but only one that is connected to a game server (NetworkServer) that uses spawned objects. - /// NetworkClient has an internal update function where it handles events from the transport layer. This includes asynchronous connect events, disconnect events and incoming data from a server. - /// The NetworkManager has a NetworkClient instance that it uses for games that it starts, but the NetworkClient may be used by itself. - /// - public static class NetworkClient - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkClient)); - - /// - /// The registered network message handlers. - /// - static readonly Dictionary handlers = new Dictionary(); - - /// - /// The NetworkConnection object this client is using. - /// - public static NetworkConnection connection { get; internal set; } - - internal static ConnectState connectState = ConnectState.None; - - /// - /// The IP address of the server that this client is connected to. - /// This will be empty if the client has not connected yet. - /// - public static string serverIp => connection.address; - - /// - /// active is true while a client is connecting/connected - /// (= while the network is active) - /// - public static bool active => connectState == ConnectState.Connecting || connectState == ConnectState.Connected; - - /// - /// This gives the current connection status of the client. - /// - public static bool isConnected => connectState == ConnectState.Connected; - - /// - /// NetworkClient can connect to local server in host mode too - /// - public static bool isLocalClient => connection is ULocalConnectionToServer; - - /// - /// Connect client to a NetworkServer instance. - /// - /// - public static void Connect(string address) - { - if (logger.LogEnabled()) logger.Log("Client Connect: " + address); - logger.Assert(Transport.activeTransport != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.activeTransport' first"); - - RegisterSystemHandlers(false); - Transport.activeTransport.enabled = true; - InitializeTransportHandlers(); - - connectState = ConnectState.Connecting; - Transport.activeTransport.ClientConnect(address); - - // setup all the handlers - connection = new NetworkConnectionToServer(); - connection.SetHandlers(handlers); - } - - /// - /// Connect client to a NetworkServer instance. - /// - /// Address of the server to connect to - public static void Connect(Uri uri) - { - if (logger.LogEnabled()) logger.Log("Client Connect: " + uri); - logger.Assert(Transport.activeTransport != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.activeTransport' first"); - - RegisterSystemHandlers(false); - Transport.activeTransport.enabled = true; - InitializeTransportHandlers(); - - connectState = ConnectState.Connecting; - Transport.activeTransport.ClientConnect(uri); - - // setup all the handlers - connection = new NetworkConnectionToServer(); - connection.SetHandlers(handlers); - } - - public static void ConnectHost() - { - logger.Log("Client Connect Host to Server"); - - RegisterSystemHandlers(true); - - connectState = ConnectState.Connected; - - // create local connection objects and connect them - ULocalConnectionToServer connectionToServer = new ULocalConnectionToServer(); - ULocalConnectionToClient connectionToClient = new ULocalConnectionToClient(); - connectionToServer.connectionToClient = connectionToClient; - connectionToClient.connectionToServer = connectionToServer; - - connection = connectionToServer; - connection.SetHandlers(handlers); - - // create server connection to local client - NetworkServer.SetLocalConnection(connectionToClient); - } - - /// - /// connect host mode - /// - public static void ConnectLocalServer() - { - NetworkServer.OnConnected(NetworkServer.localConnection); - NetworkServer.localConnection.Send(new ConnectMessage()); - } - - /// - /// disconnect host mode. this is needed to call DisconnectMessage for - /// the host client too. - /// - public static void DisconnectLocalServer() - { - // only if host connection is running - if (NetworkServer.localConnection != null) - { - // TODO ConnectLocalServer manually sends a ConnectMessage to the - // local connection. should we send a DisconnectMessage here too? - // (if we do then we get an Unknown Message ID log) - //NetworkServer.localConnection.Send(new DisconnectMessage()); - NetworkServer.OnDisconnected(NetworkServer.localConnection.connectionId); - } - } - - static void InitializeTransportHandlers() - { - Transport.activeTransport.OnClientConnected.AddListener(OnConnected); - Transport.activeTransport.OnClientDataReceived.AddListener(OnDataReceived); - Transport.activeTransport.OnClientDisconnected.AddListener(OnDisconnected); - Transport.activeTransport.OnClientError.AddListener(OnError); - } - - static void OnError(Exception exception) - { - logger.LogException(exception); - } - - static void OnDisconnected() - { - connectState = ConnectState.Disconnected; - - ClientScene.HandleClientDisconnect(connection); - - connection?.InvokeHandler(new DisconnectMessage(), -1); - } - - internal static void OnDataReceived(ArraySegment data, int channelId) - { - if (connection != null) - { - connection.TransportReceive(data, channelId); - } - else logger.LogError("Skipped Data message handling because connection is null."); - } - - static void OnConnected() - { - if (connection != null) - { - // reset network time stats - NetworkTime.Reset(); - - // the handler may want to send messages to the client - // thus we should set the connected state before calling the handler - connectState = ConnectState.Connected; - NetworkTime.UpdateClient(); - connection.InvokeHandler(new ConnectMessage(), -1); - } - else logger.LogError("Skipped Connect message handling because connection is null."); - } - - /// - /// Disconnect from server. - /// The disconnect message will be invoked. - /// - public static void Disconnect() - { - connectState = ConnectState.Disconnected; - ClientScene.HandleClientDisconnect(connection); - - // local or remote connection? - if (isLocalClient) - { - if (isConnected) - { - NetworkServer.localConnection.Send(new DisconnectMessage()); - } - NetworkServer.RemoveLocalConnection(); - } - else - { - if (connection != null) - { - connection.Disconnect(); - connection = null; - RemoveTransportHandlers(); - } - } - } - - static void RemoveTransportHandlers() - { - // so that we don't register them more than once - Transport.activeTransport.OnClientConnected.RemoveListener(OnConnected); - Transport.activeTransport.OnClientDataReceived.RemoveListener(OnDataReceived); - Transport.activeTransport.OnClientDisconnected.RemoveListener(OnDisconnected); - Transport.activeTransport.OnClientError.RemoveListener(OnError); - } - - /// - /// This sends a network message with a message Id to the server. This message is sent on channel zero, which by default is the reliable channel. - /// The message must be an instance of a class derived from MessageBase. - /// The message id passed to Send() is used to identify the handler function to invoke on the server when the message is received. - /// - /// The message type to unregister. - /// - /// - public static void Send(T message, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - if (connection != null) - { - if (connectState == ConnectState.Connected) - { - connection.Send(message, channelId); - } - else logger.LogError("NetworkClient Send when not connected to a server"); - } - else logger.LogError("NetworkClient Send with no connection"); - } - - public static void Update() - { - // local connection? - if (connection is ULocalConnectionToServer localConnection) - { - localConnection.Update(); - } - // remote connection? - else - { - // only update things while connected - if (active && connectState == ConnectState.Connected) - { - NetworkTime.UpdateClient(); - } - } - } - - internal static void RegisterSystemHandlers(bool hostMode) - { - // host mode client / regular client react to some messages differently. - // but we still need to add handlers for all of them to avoid - // 'message id not found' errors. - if (hostMode) - { - RegisterHandler(ClientScene.OnHostClientObjectDestroy); - RegisterHandler(ClientScene.OnHostClientObjectHide); - RegisterHandler((conn, msg) => { }, false); - RegisterHandler(ClientScene.OnHostClientSpawn); - // host mode doesn't need spawning - RegisterHandler((conn, msg) => { }); - // host mode doesn't need spawning - RegisterHandler((conn, msg) => { }); - RegisterHandler((conn, msg) => { }); - } - else - { - RegisterHandler(ClientScene.OnObjectDestroy); - RegisterHandler(ClientScene.OnObjectHide); - RegisterHandler(NetworkTime.OnClientPong, false); - RegisterHandler(ClientScene.OnSpawn); - RegisterHandler(ClientScene.OnObjectSpawnStarted); - RegisterHandler(ClientScene.OnObjectSpawnFinished); - RegisterHandler(ClientScene.OnUpdateVarsMessage); - } - RegisterHandler(ClientScene.OnRPCMessage); - } - - /// - /// Register a handler for a particular message type. - /// There are several system message types which you can add handlers for. You can also add your own message types. - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - int msgType = MessagePacker.GetId(); - if (handlers.ContainsKey(msgType)) - { - logger.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); - } - handlers[msgType] = MessagePacker.MessageHandler(handler, requireAuthentication); - } - - /// - /// Register a handler for a particular message type. - /// There are several system message types which you can add handlers for. You can also add your own message types. - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - RegisterHandler((NetworkConnection _, T value) => { handler(value); }, requireAuthentication); - } - - /// - /// Replaces a handler for a particular message type. - /// See also RegisterHandler(T)(Action(NetworkConnection, T), bool) - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - int msgType = MessagePacker.GetId(); - handlers[msgType] = MessagePacker.MessageHandler(handler, requireAuthentication); - } - - /// - /// Replaces a handler for a particular message type. - /// See also RegisterHandler(T)(Action(NetworkConnection, T), bool) - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - ReplaceHandler((NetworkConnection _, T value) => { handler(value); }, requireAuthentication); - } - - /// - /// Unregisters a network message handler. - /// - /// The message type to unregister. - public static bool UnregisterHandler() where T : NetworkMessage - { - // use int to minimize collisions - int msgType = MessagePacker.GetId(); - return handlers.Remove(msgType); - } - - /// - /// Shut down a client. - /// This should be done when a client is no longer going to be used. - /// - public static void Shutdown() - { - logger.Log("Shutting down client."); - ClientScene.Shutdown(); - connectState = ConnectState.None; - handlers.Clear(); - // disconnect the client connection. - // we do NOT call Transport.Shutdown, because someone only called - // NetworkClient.Shutdown. we can't assume that the server is - // supposed to be shut down too! - Transport.activeTransport.ClientDisconnect(); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkClient.cs.meta b/Assets/Mirror/Runtime/NetworkClient.cs.meta deleted file mode 100644 index b43b514..0000000 --- a/Assets/Mirror/Runtime/NetworkClient.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: abe6be14204d94224a3e7cd99dd2ea73 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkConnection.cs b/Assets/Mirror/Runtime/NetworkConnection.cs deleted file mode 100644 index d7082ee..0000000 --- a/Assets/Mirror/Runtime/NetworkConnection.cs +++ /dev/null @@ -1,301 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - /// - /// A High level network connection. This is used for connections from client-to-server and for connection from server-to-client. - /// - /// - /// A NetworkConnection corresponds to a specific connection for a host in the transport layer. It has a connectionId that is assigned by the transport layer and passed to the Initialize function. - /// A NetworkClient has one NetworkConnection. A NetworkServerSimple manages multiple NetworkConnections. The NetworkServer has multiple "remote" connections and a "local" connection for the local client. - /// The NetworkConnection class provides message sending and handling facilities. For sending data over a network, there are methods to send message objects, byte arrays, and NetworkWriter objects. To handle data arriving from the network, handler functions can be registered for message Ids, byte arrays can be processed by HandleBytes(), and NetworkReader object can be processed by HandleReader(). - /// NetworkConnection objects also act as observers for networked objects. When a connection is an observer of a networked object with a NetworkIdentity, then the object will be visible to corresponding client for the connection, and incremental state changes will be sent to the client. - /// There are many virtual functions on NetworkConnection that allow its behaviour to be customized. NetworkClient and NetworkServer can both be made to instantiate custom classes derived from NetworkConnection by setting their networkConnectionClass member variable. - /// - public abstract class NetworkConnection - { - public const int LocalConnectionId = 0; - static readonly ILogger logger = LogFactory.GetLogger(); - - // internal so it can be tested - internal readonly HashSet visList = new HashSet(); - - Dictionary messageHandlers; - - /// - /// Unique identifier for this connection that is assigned by the transport layer. - /// - /// - /// On a server, this Id is unique for every connection on the server. On a client this Id is local to the client, it is not the same as the Id on the server for this connection. - /// Transport layers connections begin at one. So on a client with a single connection to a server, the connectionId of that connection will be one. In NetworkServer, the connectionId of the local connection is zero. - /// Clients do not know their connectionId on the server, and do not know the connectionId of other clients on the server. - /// - public readonly int connectionId; - - /// - /// Flag that indicates the client has been authenticated. - /// - public bool isAuthenticated; - - /// - /// General purpose object to hold authentication data, character selection, tokens, etc. - /// associated with the connection for reference after Authentication completes. - /// - public object authenticationData; - - /// - /// Flag that tells if the connection has been marked as "ready" by a client calling ClientScene.Ready(). - /// This property is read-only. It is set by the system on the client when ClientScene.Ready() is called, and set by the system on the server when a ready message is received from a client. - /// A client that is ready is sent spawned objects by the server and updates to the state of spawned objects. A client that is not ready is not sent spawned objects. - /// - public bool isReady; - - /// - /// The IP address / URL / FQDN associated with the connection. - /// Can be useful for a game master to do IP Bans etc. - /// - public abstract string address { get; } - - /// - /// The last time that a message was received on this connection. - /// This includes internal system messages (such as Commands and ClientRpc calls) and user messages. - /// - public float lastMessageTime; - - /// - /// The NetworkIdentity for this connection. - /// - public NetworkIdentity identity { get; internal set; } - - /// - /// A list of the NetworkIdentity objects owned by this connection. This list is read-only. - /// This includes the player object for the connection - if it has localPlayerAutority set, and any objects spawned with local authority or set with AssignLocalAuthority. - /// This list can be used to validate messages from clients, to ensure that clients are only trying to control objects that they own. - /// - // IMPORTANT: this needs to be , not . fixes a bug where DestroyOwnedObjects wouldn't find - // the netId anymore: https://github.com/vis2k/Mirror/issues/1380 . Works fine with NetworkIdentity pointers though. - public readonly HashSet clientOwnedObjects = new HashSet(); - - /// - /// Creates a new NetworkConnection - /// - internal NetworkConnection() - { - // set lastTime to current time when creating connection to make sure it isn't instantly kicked for inactivity - lastMessageTime = Time.time; - } - - /// - /// Creates a new NetworkConnection with the specified connectionId - /// - /// - internal NetworkConnection(int networkConnectionId) : this() - { - connectionId = networkConnectionId; - } - - /// - /// Disconnects this connection. - /// - public abstract void Disconnect(); - - internal void SetHandlers(Dictionary handlers) - { - messageHandlers = handlers; - } - - /// - /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel. - /// - /// The message type to unregister. - /// The message to send. - /// The transport layer channel to send on. - public void Send(T msg, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - // pack message and send allocation free - MessagePacker.Pack(msg, writer); - NetworkDiagnostics.OnSend(msg, channelId, writer.Position, 1); - Send(writer.ToArraySegment(), channelId); - } - } - - // validate packet size before sending. show errors if too big/small. - // => it's best to check this here, we can't assume that all transports - // would check max size and show errors internally. best to do it - // in one place in hlapi. - // => it's important to log errors, so the user knows what went wrong. - protected internal static bool ValidatePacketSize(ArraySegment segment, int channelId) - { - if (segment.Count > Transport.activeTransport.GetMaxPacketSize(channelId)) - { - logger.LogError("NetworkConnection.ValidatePacketSize: cannot send packet larger than " + Transport.activeTransport.GetMaxPacketSize(channelId) + " bytes"); - return false; - } - - if (segment.Count == 0) - { - // zero length packets getting into the packet queues are bad. - logger.LogError("NetworkConnection.ValidatePacketSize: cannot send zero bytes"); - return false; - } - - // good size - return true; - } - - // internal because no one except Mirror should send bytes directly to - // the client. they would be detected as a message. send messages instead. - internal abstract void Send(ArraySegment segment, int channelId = Channels.DefaultReliable); - - public override string ToString() - { - return $"connection({connectionId})"; - } - - internal void AddToVisList(NetworkIdentity identity) - { - visList.Add(identity); - - // spawn identity for this conn - NetworkServer.ShowForConnection(identity, this); - } - - internal void RemoveFromVisList(NetworkIdentity identity, bool isDestroyed) - { - visList.Remove(identity); - - if (!isDestroyed) - { - // hide identity for this conn - NetworkServer.HideForConnection(identity, this); - } - } - - internal void RemoveObservers() - { - foreach (NetworkIdentity identity in visList) - { - identity.RemoveObserverInternal(this); - } - visList.Clear(); - } - - internal bool InvokeHandler(int msgType, NetworkReader reader, int channelId) - { - if (messageHandlers.TryGetValue(msgType, out NetworkMessageDelegate msgDelegate)) - { - msgDelegate(this, reader, channelId); - return true; - } - if (logger.LogEnabled()) logger.Log("Unknown message ID " + msgType + " " + this + ". May be due to no existing RegisterHandler for this message."); - return false; - } - - /// - /// This function invokes the registered handler function for a message. - /// Network connections used by the NetworkClient and NetworkServer use this function for handling network messages. - /// - /// The message type to unregister. - /// The message object to process. - /// Returns true if the handler was successfully invoked - public bool InvokeHandler(T msg, int channelId) where T : NetworkMessage - { - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - // if it is a value type, just use typeof(T) to avoid boxing - // this works because value types cannot be derived - // if it is a reference type (for example NetworkMessage), - // ask the message for the real type - int msgType = MessagePacker.GetId(default(T) != null ? typeof(T) : msg.GetType()); - - MessagePacker.Pack(msg, writer); - ArraySegment segment = writer.ToArraySegment(); - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(segment)) - return InvokeHandler(msgType, networkReader, channelId); - } - } - - // note: original HLAPI HandleBytes function handled >1 message in a while loop, but this wasn't necessary - // anymore because NetworkServer/NetworkClient Update both use while loops to handle >1 data events per - // frame already. - // -> in other words, we always receive 1 message per Receive call, never two. - // -> can be tested easily with a 1000ms send delay and then logging amount received in while loops here - // and in NetworkServer/Client Update. HandleBytes already takes exactly one. - /// - /// This function allows custom network connection classes to process data from the network before it is passed to the application. - /// - /// The data received. - internal void TransportReceive(ArraySegment buffer, int channelId) - { - if (buffer.Count == 0) - { - logger.LogError($"ConnectionRecv {this} Message was empty"); - return; - } - - // unpack message - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(buffer)) - { - if (MessagePacker.UnpackMessage(networkReader, out int msgType)) - { - // logging - if (logger.LogEnabled()) logger.Log("ConnectionRecv " + this + " msgType:" + msgType + " content:" + BitConverter.ToString(buffer.Array, buffer.Offset, buffer.Count)); - - // try to invoke the handler for that message - if (InvokeHandler(msgType, networkReader, channelId)) - { - lastMessageTime = Time.time; - } - } - else - { - logger.LogError("Closed connection: " + this + ". Invalid message header."); - Disconnect(); - } - } - } - - /// - /// Checks if cliet has sent a message within timeout - /// - /// Some transports are unreliable at sending disconnect message to the server - /// so this acts as a failsafe to make sure clients are kicked - /// - /// - /// Client should send ping message to server every 2 seconds to keep this alive - /// - /// - /// True if server has recently recieved a message - internal virtual bool IsAlive(float timeout) => Time.time - lastMessageTime < timeout; - - internal void AddOwnedObject(NetworkIdentity obj) - { - clientOwnedObjects.Add(obj); - } - - internal void RemoveOwnedObject(NetworkIdentity obj) - { - clientOwnedObjects.Remove(obj); - } - - internal void DestroyOwnedObjects() - { - // create a copy because the list might be modified when destroying - HashSet tmp = new HashSet(clientOwnedObjects); - foreach (NetworkIdentity netIdentity in tmp) - { - if (netIdentity != null) - { - NetworkServer.Destroy(netIdentity.gameObject); - } - } - - // clear the hashset because we destroyed them all - clientOwnedObjects.Clear(); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkConnection.cs.meta b/Assets/Mirror/Runtime/NetworkConnection.cs.meta deleted file mode 100644 index 3688d9c..0000000 --- a/Assets/Mirror/Runtime/NetworkConnection.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 11ea41db366624109af1f0834bcdde2f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs b/Assets/Mirror/Runtime/NetworkConnectionToClient.cs deleted file mode 100644 index 30e8077..0000000 --- a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - public class NetworkConnectionToClient : NetworkConnection - { - static readonly ILogger logger = LogFactory.GetLogger(); - - public NetworkConnectionToClient(int networkConnectionId) : base(networkConnectionId) { } - - public override string address => Transport.activeTransport.ServerGetClientAddress(connectionId); - - internal override void Send(ArraySegment segment, int channelId = Channels.DefaultReliable) - { - if (logger.LogEnabled()) logger.Log("ConnectionSend " + this + " bytes:" + BitConverter.ToString(segment.Array, segment.Offset, segment.Count)); - - // validate packet size first. - if (ValidatePacketSize(segment, channelId)) - { - Transport.activeTransport.ServerSend(connectionId, channelId, segment); - } - } - - /// - /// Disconnects this connection. - /// - public override void Disconnect() - { - // set not ready and handle clientscene disconnect in any case - // (might be client or host mode here) - isReady = false; - Transport.activeTransport.ServerDisconnect(connectionId); - RemoveObservers(); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs.meta b/Assets/Mirror/Runtime/NetworkConnectionToClient.cs.meta deleted file mode 100644 index 75bb702..0000000 --- a/Assets/Mirror/Runtime/NetworkConnectionToClient.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bb2195f8b29d24f0680a57fde2e9fd09 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkConnectionToServer.cs b/Assets/Mirror/Runtime/NetworkConnectionToServer.cs deleted file mode 100644 index a7080e3..0000000 --- a/Assets/Mirror/Runtime/NetworkConnectionToServer.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - public class NetworkConnectionToServer : NetworkConnection - { - static readonly ILogger logger = LogFactory.GetLogger(); - - public override string address => ""; - - internal override void Send(ArraySegment segment, int channelId = Channels.DefaultReliable) - { - if (logger.LogEnabled()) logger.Log("ConnectionSend " + this + " bytes:" + BitConverter.ToString(segment.Array, segment.Offset, segment.Count)); - - // validate packet size first. - if (ValidatePacketSize(segment, channelId)) - { - Transport.activeTransport.ClientSend(channelId, segment); - } - } - - /// - /// Disconnects this connection. - /// - public override void Disconnect() - { - // set not ready and handle clientscene disconnect in any case - // (might be client or host mode here) - isReady = false; - ClientScene.HandleClientDisconnect(this); - Transport.activeTransport.ClientDisconnect(); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkConnectionToServer.cs.meta b/Assets/Mirror/Runtime/NetworkConnectionToServer.cs.meta deleted file mode 100644 index 7e4a710..0000000 --- a/Assets/Mirror/Runtime/NetworkConnectionToServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 761977cbf38a34ded9dd89de45445675 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkDiagnostics.cs b/Assets/Mirror/Runtime/NetworkDiagnostics.cs deleted file mode 100644 index 70743d2..0000000 --- a/Assets/Mirror/Runtime/NetworkDiagnostics.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; - -namespace Mirror -{ - /// - /// Provides profiling information from mirror - /// A profiler can subscribe to these events and - /// present the data in a friendly way to the user - /// - public static class NetworkDiagnostics - { - /// - /// Describes an outgoing message - /// - public readonly struct MessageInfo - { - /// - /// The message being sent - /// - public readonly NetworkMessage message; - /// - /// channel through which the message was sent - /// - public readonly int channel; - /// - /// how big was the message (does not include transport headers) - /// - public readonly int bytes; - /// - /// How many connections was the message sent to - /// If an object has a lot of observers this count could be high - /// - public readonly int count; - - internal MessageInfo(NetworkMessage message, int channel, int bytes, int count) - { - this.message = message; - this.channel = channel; - this.bytes = bytes; - this.count = count; - } - } - - #region Out messages - /// - /// Event that gets raised when Mirror sends a message - /// Subscribe to this if you want to diagnose the network - /// - public static event Action OutMessageEvent; - - internal static void OnSend(T message, int channel, int bytes, int count) where T : NetworkMessage - { - if (count > 0 && OutMessageEvent != null) - { - MessageInfo outMessage = new MessageInfo(message, channel, bytes, count); - OutMessageEvent?.Invoke(outMessage); - } - } - #endregion - - #region In messages - - /// - /// Event that gets raised when Mirror receives a message - /// Subscribe to this if you want to profile the network - /// - public static event Action InMessageEvent; - - internal static void OnReceive(T message, int channel, int bytes) where T : NetworkMessage - { - if (InMessageEvent != null) - { - MessageInfo inMessage = new MessageInfo(message, channel, bytes, 1); - InMessageEvent?.Invoke(inMessage); - } - } - - #endregion - } -} diff --git a/Assets/Mirror/Runtime/NetworkDiagnostics.cs.meta b/Assets/Mirror/Runtime/NetworkDiagnostics.cs.meta deleted file mode 100644 index 6695d61..0000000 --- a/Assets/Mirror/Runtime/NetworkDiagnostics.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c3754b39e5f8740fd93f3337b2c4274e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkIdentity.cs b/Assets/Mirror/Runtime/NetworkIdentity.cs deleted file mode 100644 index 0117e97..0000000 --- a/Assets/Mirror/Runtime/NetworkIdentity.cs +++ /dev/null @@ -1,1518 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Security.Cryptography; -using Mirror.RemoteCalls; -using UnityEngine; -using UnityEngine.Serialization; - - -#if UNITY_EDITOR -using UnityEditor; -#if UNITY_2018_3_OR_NEWER -using UnityEditor.Experimental.SceneManagement; -#endif -#endif - -namespace Mirror -{ - /// - /// The NetworkIdentity identifies objects across the network, between server and clients. - /// Its primary data is a NetworkInstanceId which is allocated by the server and then set on clients. - /// This is used in network communications to be able to lookup game objects on different machines. - /// - /// - /// - /// The NetworkIdentity is used to synchronize information in the object with the network. - /// Only the server should create instances of objects which have NetworkIdentity as otherwise - /// they will not be properly connected to the system. - /// - /// - /// For complex objects with a hierarchy of subcomponents, the NetworkIdentity must be on the root of the hierarchy. - /// It is not supported to have multiple NetworkIdentity components on subcomponents of a hierarchy. - /// - /// - /// NetworkBehaviour scripts require a NetworkIdentity on the game object to be able to function. - /// - /// - /// The NetworkIdentity manages the dirty state of the NetworkBehaviours of the object. - /// When it discovers that NetworkBehaviours are dirty, it causes an update packet to be created and sent to clients. - /// - /// - /// - /// - /// The flow for serialization updates managed by the NetworkIdentity is: - /// - /// - /// - /// Each NetworkBehaviour has a dirty mask. This mask is available inside OnSerialize as syncVarDirtyBits - /// - /// - /// Each SyncVar in a NetworkBehaviour script is assigned a bit in the dirty mask. - /// - /// - /// Changing the value of SyncVars causes the bit for that SyncVar to be set in the dirty mask - /// - /// - /// Alternatively, calling SetDirtyBit() writes directly to the dirty mask - /// - /// - /// NetworkIdentity objects are checked on the server as part of it's update loop - /// - /// - /// If any NetworkBehaviours on a NetworkIdentity are dirty, then an UpdateVars packet is created for that object - /// - /// - /// The UpdateVars packet is populated by calling OnSerialize on each NetworkBehaviour on the object - /// - /// - /// NetworkBehaviours that are NOT dirty write a zero to the packet for their dirty bits - /// - /// - /// NetworkBehaviours that are dirty write their dirty mask, then the values for the SyncVars that have changed - /// - /// - /// If OnSerialize returns true for a NetworkBehaviour, the dirty mask is reset for that NetworkBehaviour, - /// so it will not send again until its value changes. - /// - /// - /// The UpdateVars packet is sent to ready clients that are observing the object - /// - /// - /// - /// - /// - /// On the client: - /// - /// - /// an UpdateVars packet is received for an object - /// - /// - /// The OnDeserialize function is called for each NetworkBehaviour script on the object - /// - /// - /// Each NetworkBehaviour script on the object reads a dirty mask. - /// - /// - /// If the dirty mask for a NetworkBehaviour is zero, the OnDeserialize functions returns without reading any more - /// - /// - /// If the dirty mask is non-zero value, then the OnDeserialize function reads the values for the SyncVars that correspond to the dirty bits that are set - /// - /// - /// If there are SyncVar hook functions, those are invoked with the value read from the stream. - /// - /// - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkIdentity")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkIdentity.html")] - public sealed class NetworkIdentity : MonoBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(); - - NetworkBehaviour[] networkBehavioursCache; - - /// - /// Returns true if running as a client and this object was spawned by a server. - /// - /// - /// - /// IMPORTANT: checking NetworkClient.active means that isClient is false in OnDestroy: - /// - /// - /// public bool isClient => NetworkClient.active && netId != 0 && !serverOnly; - /// - /// - /// but we need it in OnDestroy, e.g. when saving skillbars on quit. this - /// works fine if we keep the UNET way of setting isClient manually. - /// - /// - /// => fixes - /// - /// - public bool isClient { get; internal set; } - - /// - /// Returns true if NetworkServer.active and server is not stopped. - /// - /// - /// - /// IMPORTANT: checking NetworkServer.active means that isServer is false in OnDestroy: - /// - /// - /// public bool isServer => NetworkServer.active && netId != 0; - /// - /// - /// but we need it in OnDestroy, e.g. when saving players on quit. this - /// works fine if we keep the UNET way of setting isServer manually. - /// - /// - /// => fixes - /// - /// - public bool isServer { get; internal set; } - - /// - /// This returns true if this object is the one that represents the player on the local machine. - /// This is set when the server has spawned an object for this particular client. - /// - public bool isLocalPlayer => ClientScene.localPlayer == this; - - /// - /// This returns true if this object is the authoritative player object on the client. - /// This value is determined at runtime. For most objects, authority is held by the server. - /// For objects that had their authority set by AssignClientAuthority on the server, this will be true on the client that owns the object. NOT on other clients. - /// - public bool hasAuthority { get; internal set; } - - /// - /// The set of network connections (players) that can see this object. - /// null until OnStartServer was called. this is necessary for SendTo* to work properly in server-only mode. - /// - public Dictionary observers; - - /// - /// Unique identifier for this particular object instance, used for tracking objects between networked clients and the server. - /// This is a unique identifier for this particular GameObject instance. Use it to track GameObjects between networked clients and the server. - /// - public uint netId { get; internal set; } - - /// - /// A unique identifier for NetworkIdentity objects within a scene. - /// This is used for spawning scene objects on clients. - /// - // persistent scene id (see AssignSceneID comments) - [FormerlySerializedAs("m_SceneId"), HideInInspector] - public ulong sceneId; - - /// - /// Flag to make this object only exist when the game is running as a server (or host). - /// - [FormerlySerializedAs("m_ServerOnly")] - public bool serverOnly; - - /// - /// Set to try before Destroy is called so that OnDestroy doesn't try to destroy the object again - /// - internal bool destroyCalled; - - /// - /// The NetworkConnection associated with this NetworkIdentity. This is only valid for player objects on a local client. - /// - public NetworkConnection connectionToServer { get; internal set; } - - NetworkConnectionToClient _connectionToClient; - - /// - /// The NetworkConnection associated with this NetworkIdentity. This is valid for player and other owned objects in the server. - /// Use it to return details such as the connection's identity, IP address and ready status. - /// - public NetworkConnectionToClient connectionToClient - { - get => _connectionToClient; - - internal set - { - _connectionToClient?.RemoveOwnedObject(this); - _connectionToClient = value; - _connectionToClient?.AddOwnedObject(this); - } - } - - /// - /// All spawned NetworkIdentities by netId. Available on server and client. - /// - public static readonly Dictionary spawned = new Dictionary(); - - public NetworkBehaviour[] NetworkBehaviours - { - get - { - if (networkBehavioursCache == null) - { - CreateNetworkBehavioursCache(); - } - return networkBehavioursCache; - } - } - - void CreateNetworkBehavioursCache() - { - networkBehavioursCache = GetComponents(); - if (networkBehavioursCache.Length > byte.MaxValue) - { - logger.LogError($"Only {byte.MaxValue} NetworkBehaviour components are allowed for NetworkIdentity: {name} because we send the index as byte.", this); - // Log error once then resize array so that NetworkIdentity does not throw exceptions later - Array.Resize(ref networkBehavioursCache, byte.MaxValue); - } - } - - - NetworkVisibility visibilityCache; - public NetworkVisibility visibility - { - get - { - if (visibilityCache == null) - { - visibilityCache = GetComponent(); - } - return visibilityCache; - } - } - - [SerializeField, HideInInspector] string m_AssetId; - - - /// - /// Unique identifier used to find the source assets when server spawns the on clients. - /// - /// - /// - /// - /// The AssetId trick: - /// - /// - /// Ideally we would have a serialized 'Guid m_AssetId' but Unity can't - /// serialize it because Guid's internal bytes are private - /// - /// - /// UNET used 'NetworkHash128' originally, with byte0, ..., byte16 - /// which works, but it just unnecessary extra code - /// - /// - /// Using just the Guid string would work, but it's 32 chars long and - /// would then be sent over the network as 64 instead of 16 bytes - /// - /// - /// The solution is to serialize the string internally here and then - /// use the real 'Guid' type for everything else via .assetId - /// - public Guid assetId - { - get - { -#if UNITY_EDITOR - // This is important because sometimes OnValidate does not run (like when adding view to prefab with no child links) - if (string.IsNullOrEmpty(m_AssetId)) - SetupIDs(); -#endif - // convert string to Guid and use .Empty to avoid exception if - // we would use 'new Guid("")' - return string.IsNullOrEmpty(m_AssetId) ? Guid.Empty : new Guid(m_AssetId); - } - internal set - { - string newAssetIdString = value == Guid.Empty ? string.Empty : value.ToString("N"); - string oldAssetIdSrting = m_AssetId; - - // they are the same, do nothing - if (oldAssetIdSrting == newAssetIdString) - { - return; - } - - // new is empty - if (string.IsNullOrEmpty(newAssetIdString)) - { - logger.LogError($"Can not set AssetId to empty guid on NetworkIdentity '{name}', old assetId '{oldAssetIdSrting}'"); - return; - } - - // old not empty - if (!string.IsNullOrEmpty(oldAssetIdSrting)) - { - logger.LogError($"Can not Set AssetId on NetworkIdentity '{name}' becasue it already had an assetId, current assetId '{oldAssetIdSrting}', attempted new assetId '{newAssetIdString}'"); - return; - } - - // old is empty - m_AssetId = newAssetIdString; - - if (logger.LogEnabled()) logger.Log($"Settings AssetId on NetworkIdentity '{name}', new assetId '{newAssetIdString}'"); - } - } - - /// - /// Keep track of all sceneIds to detect scene duplicates - /// - static readonly Dictionary sceneIds = new Dictionary(); - - /// - /// Gets the NetworkIdentity from the sceneIds dictionary with the corresponding id - /// - /// - /// NetworkIdentity from the sceneIds dictionary - public static NetworkIdentity GetSceneIdentity(ulong id) => sceneIds[id]; - - /// - /// used when adding players - /// - /// - internal void SetClientOwner(NetworkConnection conn) - { - // do nothing if it already has an owner - if (connectionToClient != null && conn != connectionToClient) - { - logger.LogError($"Object {this} netId={netId} already has an owner. Use RemoveClientAuthority() first", this); - return; - } - - // otherwise set the owner connection - connectionToClient = (NetworkConnectionToClient)conn; - } - - static uint nextNetworkId = 1; - internal static uint GetNextNetworkId() => nextNetworkId++; - - /// - /// Resets nextNetworkId = 1 - /// - public static void ResetNextNetworkId() => nextNetworkId = 1; - - /// - /// The delegate type for the clientAuthorityCallback. - /// - /// The network connection that is gaining or losing authority. - /// The object whose client authority status is being changed. - /// The new state of client authority of the object for the connection. - public delegate void ClientAuthorityCallback(NetworkConnection conn, NetworkIdentity identity, bool authorityState); - - /// - /// A callback that can be populated to be notified when the client-authority state of objects changes. - /// Whenever an object is spawned with client authority, or the client authority status of an object is changed with AssignClientAuthority or RemoveClientAuthority, then this callback will be invoked. - /// This callback is only invoked on the server. - /// - public static event ClientAuthorityCallback clientAuthorityCallback; - - /// - /// this is used when a connection is destroyed, since the "observers" property is read-only - /// - /// - internal void RemoveObserverInternal(NetworkConnection conn) - { - observers?.Remove(conn.connectionId); - } - - /// - /// hasSpawned should always be false before runtime - /// - [SerializeField, HideInInspector] bool hasSpawned; - public bool SpawnedFromInstantiate { get; private set; } - - void Awake() - { - if (hasSpawned) - { - logger.LogError($"{name} has already spawned. Don't call Instantiate for NetworkIdentities that were in the scene since the beginning (aka scene objects). Otherwise the client won't know which object to use for a SpawnSceneObject message."); - - SpawnedFromInstantiate = true; - Destroy(gameObject); - } - - hasSpawned = true; - } - - void OnValidate() - { - // OnValidate is not called when using Instantiate, so we can use - // it to make sure that hasSpawned is false - hasSpawned = false; - -#if UNITY_EDITOR - SetupIDs(); -#endif - } - -#if UNITY_EDITOR - void AssignAssetID(GameObject prefab) => AssignAssetID(AssetDatabase.GetAssetPath(prefab)); - void AssignAssetID(string path) => m_AssetId = AssetDatabase.AssetPathToGUID(path); - - bool ThisIsAPrefab() => PrefabUtility.IsPartOfPrefabAsset(gameObject); - - bool ThisIsASceneObjectWithPrefabParent(out GameObject prefab) - { - prefab = null; - - if (!PrefabUtility.IsPartOfPrefabInstance(gameObject)) - { - return false; - } - prefab = PrefabUtility.GetCorrespondingObjectFromSource(gameObject); - - if (prefab == null) - { - logger.LogError("Failed to find prefab parent for scene object [name:" + gameObject.name + "]"); - return false; - } - return true; - } - - static uint GetRandomUInt() - { - // use Crypto RNG to avoid having time based duplicates - using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) - { - byte[] bytes = new byte[4]; - rng.GetBytes(bytes); - return BitConverter.ToUInt32(bytes, 0); - } - } - - // persistent sceneId assignment - // (because scene objects have no persistent unique ID in Unity) - // - // original UNET used OnPostProcessScene to assign an index based on - // FindObjectOfType order. - // -> this didn't work because FindObjectOfType order isn't deterministic. - // -> one workaround is to sort them by sibling paths, but it can still - // get out of sync when we open scene2 in editor and we have - // DontDestroyOnLoad objects that messed with the sibling index. - // - // we absolutely need a persistent id. challenges: - // * it needs to be 0 for prefabs - // => we set it to 0 in SetupIDs() if prefab! - // * it needs to be only assigned in edit time, not at runtime because - // only the objects that were in the scene since beginning should have - // a scene id. - // => Application.isPlaying check solves that - // * it needs to detect duplicated sceneIds after duplicating scene - // objects - // => sceneIds dict takes care of that - // * duplicating the whole scene file shouldn't result in duplicate - // scene objects - // => buildIndex is shifted into sceneId for that. - // => if we have no scenes in build index then it doesn't matter - // because by definition a build can't switch to other scenes - // => if we do have scenes in build index then it will be != -1 - // note: the duplicated scene still needs to be opened once for it to - // be set properly - // * scene objects need the correct scene index byte even if the scene's - // build index was changed or a duplicated scene wasn't opened yet. - // => OnPostProcessScene is the only function that gets called for - // each scene before runtime, so this is where we set the scene - // byte. - // * disabled scenes in build settings should result in same scene index - // in editor and in build - // => .gameObject.scene.buildIndex filters out disabled scenes by - // default - // * generated sceneIds absolutely need to set scene dirty and force the - // user to resave. - // => Undo.RecordObject does that perfectly. - // * sceneIds should never be generated temporarily for unopened scenes - // when building, otherwise editor and build get out of sync - // => BuildPipeline.isBuildingPlayer check solves that - void AssignSceneID() - { - // we only ever assign sceneIds at edit time, never at runtime. - // by definition, only the original scene objects should get one. - // -> if we assign at runtime then server and client would generate - // different random numbers! - if (Application.isPlaying) - return; - - // no valid sceneId yet, or duplicate? - bool duplicate = sceneIds.TryGetValue(sceneId, out NetworkIdentity existing) && existing != null && existing != this; - if (sceneId == 0 || duplicate) - { - // clear in any case, because it might have been a duplicate - sceneId = 0; - - // if a scene was never opened and we are building it, then a - // sceneId would be assigned to build but not saved in editor, - // resulting in them getting out of sync. - // => don't ever assign temporary ids. they always need to be - // permanent - // => throw an exception to cancel the build and let the user - // know how to fix it! - if (BuildPipeline.isBuildingPlayer) - throw new InvalidOperationException("Scene " + gameObject.scene.path + " needs to be opened and resaved before building, because the scene object " + name + " has no valid sceneId yet."); - - // if we generate the sceneId then we MUST be sure to set dirty - // in order to save the scene object properly. otherwise it - // would be regenerated every time we reopen the scene, and - // upgrading would be very difficult. - // -> Undo.RecordObject is the new EditorUtility.SetDirty! - // -> we need to call it before changing. - Undo.RecordObject(this, "Generated SceneId"); - - // generate random sceneId part (0x00000000FFFFFFFF) - uint randomId = GetRandomUInt(); - - // only assign if not a duplicate of an existing scene id - // (small chance, but possible) - duplicate = sceneIds.TryGetValue(randomId, out existing) && existing != null && existing != this; - if (!duplicate) - { - sceneId = randomId; - //logger.Log(name + " in scene=" + gameObject.scene.name + " sceneId assigned to: " + m_SceneId.ToString("X")); - } - } - - // add to sceneIds dict no matter what - // -> even if we didn't generate anything new, because we still need - // existing sceneIds in there to check duplicates - sceneIds[sceneId] = this; - } - - // copy scene path hash into sceneId for scene objects. - // this is the only way for scene file duplication to not contain - // duplicate sceneIds as it seems. - // -> sceneId before: 0x00000000AABBCCDD - // -> then we clear the left 4 bytes, so that our 'OR' uses 0x00000000 - // -> then we OR the hash into the 0x00000000 part - // -> buildIndex is not enough, because Editor and Build have different - // build indices if there are disabled scenes in build settings, and - // if no scene is in build settings then Editor and Build have - // different indices too (Editor=0, Build=-1) - // => ONLY USE THIS FROM POSTPROCESSSCENE! - public void SetSceneIdSceneHashPartInternal() - { - // Use `ToLower` to that because BuildPipeline.BuildPlayer is case insensitive but hash is case sensitive - // If the scene in the project is `forest.unity` but `Forest.unity` is given to BuildPipeline then the - // BuildPipeline will use `Forest.unity` for the build and create a different hash than the editor will. - // Using ToLower will mean the hash will be the same for these 2 paths - // Assets/Scenes/Forest.unity - // Assets/Scenes/forest.unity - string scenePath = gameObject.scene.path.ToLower(); - - // get deterministic scene hash - uint pathHash = (uint)scenePath.GetStableHashCode(); - - // shift hash from 0x000000FFFFFFFF to 0xFFFFFFFF00000000 - ulong shiftedHash = (ulong)pathHash << 32; - - // OR into scene id - sceneId = (sceneId & 0xFFFFFFFF) | shiftedHash; - - // log it. this is incredibly useful to debug sceneId issues. - if (logger.LogEnabled()) logger.Log(name + " in scene=" + gameObject.scene.name + " scene index hash(" + pathHash.ToString("X") + ") copied into sceneId: " + sceneId.ToString("X")); - } - - void SetupIDs() - { - if (ThisIsAPrefab()) - { - // force 0 for prefabs - sceneId = 0; - AssignAssetID(gameObject); - } - // are we currently in prefab editing mode? aka prefab stage - // => check prefabstage BEFORE SceneObjectWithPrefabParent - // (fixes https://github.com/vis2k/Mirror/issues/976) - // => if we don't check GetCurrentPrefabStage and only check - // GetPrefabStage(gameObject), then the 'else' case where we - // 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) - { - // when modifying a prefab in prefab stage, Unity calls - // OnValidate for that prefab and for all scene objects based on - // that prefab. - // - // is this GameObject the prefab that we modify, and not just a - // scene object based on the prefab? - // * GetCurrentPrefabStage = 'are we editing ANY prefab?' - // * GetPrefabStage(go) = 'are we editing THIS prefab?' - if (PrefabStageUtility.GetPrefabStage(gameObject) != null) - { - // force 0 for prefabs - sceneId = 0; - //logger.Log(name + " @ scene: " + gameObject.scene.name + " sceneid reset to 0 because CurrentPrefabStage=" + PrefabStageUtility.GetCurrentPrefabStage() + " PrefabStage=" + PrefabStageUtility.GetPrefabStage(gameObject)); - // 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; -#else - string path = PrefabStageUtility.GetCurrentPrefabStage().prefabAssetPath; -#endif - - AssignAssetID(path); - } - } - else if (ThisIsASceneObjectWithPrefabParent(out GameObject prefab)) - { - AssignSceneID(); - AssignAssetID(prefab); - } - else - { - AssignSceneID(); - m_AssetId = ""; - } - } -#endif - - /// - /// Unity will Destroy all networked objects on Scene Change, so we have to handle that here silently. - /// That means we cannot have any warning or logging in this method. - /// - void OnDestroy() - { - // Objects spawned from Instantiate are not allowed so are destroyed right away - // we don't want to call NetworkServer.Destroy if this is the case - if (SpawnedFromInstantiate) - return; - - // If false the object has already been unspawned - // if it is still true, then we need to unspawn it - // if destroy is already called don't call it again - if (isServer && !destroyCalled) - { - // Do not add logging to this (see above) - NetworkServer.Destroy(gameObject); - } - - if (isLocalPlayer) - { - ClientScene.ClearLocalPlayer(); - } - } - - internal void OnStartServer() - { - // do nothing if already spawned - if (isServer) - return; - - // set isServer flag - isServer = true; - - // If the instance/net ID is invalid here then this is an object instantiated from a prefab and the server should assign a valid ID - // NOTE: this might not be necessary because the above m_IsServer - // check already checks netId. BUT this case here checks only - // netId, so it would still check cases where isServer=false - // but netId!=0. - if (netId != 0) - { - // This object has already been spawned, this method might be called again - // if we try to respawn all objects. This can happen when we add a scene - // in that case there is nothing else to do. - return; - } - - netId = GetNextNetworkId(); - observers = new Dictionary(); - - if (logger.LogEnabled()) logger.Log("OnStartServer " + this + " NetId:" + netId + " SceneId:" + sceneId.ToString("X")); - - // add to spawned (note: the original EnableIsServer isn't needed - // because we already set m_isServer=true above) - spawned[netId] = this; - - // in host mode we set isClient true before calling OnStartServer, - // otherwise isClient is false in OnStartServer. - if (NetworkClient.active) - { - isClient = true; - } - - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStartServer should be caught, so that one - // component's exception doesn't stop all other components from - // being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStartServer(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStartServer:" + e.Message + " " + e.StackTrace); - } - } - } - - internal void OnStopServer() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStartServer should be caught, so that one - // component's exception doesn't stop all other components from - // being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStopServer(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStopServer:" + e.Message + " " + e.StackTrace); - } - } - } - - bool clientStarted; - internal void OnStartClient() - { - if (clientStarted) - return; - clientStarted = true; - - isClient = true; - - if (logger.LogEnabled()) logger.Log("OnStartClient " + gameObject + " netId:" + netId); - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStartClient should be caught, so that one - // component's exception doesn't stop all other components from - // being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - // user implemented startup - comp.OnStartClient(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStartClient:" + e.Message + " " + e.StackTrace); - } - } - } - - static NetworkIdentity previousLocalPlayer = null; - internal void OnStartLocalPlayer() - { - if (previousLocalPlayer == this) - return; - previousLocalPlayer = this; - - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStartLocalPlayer should be caught, so that - // one component's exception doesn't stop all other components - // from being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStartLocalPlayer(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStartLocalPlayer:" + e.Message + " " + e.StackTrace); - } - } - } - - bool hadAuthority; - internal void NotifyAuthority() - { - if (!hadAuthority && hasAuthority) - OnStartAuthority(); - if (hadAuthority && !hasAuthority) - OnStopAuthority(); - hadAuthority = hasAuthority; - } - - internal void OnStartAuthority() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStartAuthority should be caught, so that one - // component's exception doesn't stop all other components from - // being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStartAuthority(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStartAuthority:" + e.Message + " " + e.StackTrace); - } - } - } - - internal void OnStopAuthority() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnStopAuthority should be caught, so that one - // component's exception doesn't stop all other components from - // being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStopAuthority(); - } - catch (Exception e) - { - logger.LogError("Exception in OnStopAuthority:" + e.Message + " " + e.StackTrace); - } - } - } - - internal void OnSetHostVisibility(bool visible) - { - if (visibility != null) - { - try - { - visibility.OnSetHostVisibility(visible); - } - catch (Exception e) - { - logger.LogError("Exception in OnSetLocalVisibility:" + e.Message + " " + e.StackTrace); - } - } - } - - /// - /// check if observer can be seen by connection. - /// - /// - /// true if we have no NetworkVisibility, default objects are visible - internal bool OnCheckObserver(NetworkConnection conn) - { - if (visibility != null) - { - try - { - return visibility.OnCheckObserver(conn); - } - catch (Exception e) - { - logger.LogError("Exception in OnCheckObserver:" + e.Message + " " + e.StackTrace); - } - } - return true; - } - - internal void OnStopClient() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - // an exception in OnNetworkDestroy should be caught, so that - // one component's exception doesn't stop all other components - // from being initialized - // => this is what Unity does for Start() etc. too. - // one exception doesn't stop all the other Start() calls! - try - { - comp.OnStopClient(); - } - catch (Exception e) - { - logger.LogError("Exception in OnNetworkDestroy:" + e.Message + " " + e.StackTrace); - } - isServer = false; - } - } - - // vis2k: readstring bug prevention: https://issuetracker.unity3d.com/issues/unet-networkwriter-dot-write-causing-readstring-slash-readbytes-out-of-range-errors-in-clients - // -> OnSerialize writes length,componentData,length,componentData,... - // -> OnDeserialize carefully extracts each data, then deserializes each component with separate readers - // -> it will be impossible to read too many or too few bytes in OnDeserialize - // -> we can properly track down errors - bool OnSerializeSafely(NetworkBehaviour comp, NetworkWriter writer, bool initialState) - { - // write placeholder length bytes - // (jumping back later is WAY faster than allocating a temporary - // writer for the payload, then writing payload.size, payload) - int headerPosition = writer.Position; - writer.WriteInt32(0); - int contentPosition = writer.Position; - - // write payload - bool result = false; - try - { - result = comp.OnSerialize(writer, initialState); - } - catch (Exception e) - { - // show a detailed error and let the user know what went wrong - logger.LogError("OnSerialize failed for: object=" + name + " component=" + comp.GetType() + " sceneId=" + sceneId.ToString("X") + "\n\n" + e); - } - int endPosition = writer.Position; - - // fill in length now - writer.Position = headerPosition; - writer.WriteInt32(endPosition - contentPosition); - writer.Position = endPosition; - - if (logger.LogEnabled()) logger.Log("OnSerializeSafely written for object=" + comp.name + " component=" + comp.GetType() + " sceneId=" + sceneId.ToString("X") + "header@" + headerPosition + " content@" + contentPosition + " end@" + endPosition + " contentSize=" + (endPosition - contentPosition)); - - return result; - } - - /// - /// serialize all components using dirtyComponentsMask - /// check ownerWritten/observersWritten to know if anything was written - /// We pass dirtyComponentsMask into this function so that we can check if any Components are dirty before creating writers - /// - /// - /// - /// - /// - /// - internal void OnSerializeAllSafely(bool initialState, NetworkWriter ownerWriter, out int ownerWritten, NetworkWriter observersWriter, out int observersWritten) - { - // clear 'written' variables - ownerWritten = observersWritten = 0; - - // check if components are in byte.MaxRange just to be 100% sure - // that we avoid overflows - NetworkBehaviour[] components = NetworkBehaviours; - if (components.Length > byte.MaxValue) - throw new IndexOutOfRangeException($"{name} has more than {byte.MaxValue} components. This is not supported."); - - // serialize all components - for (int i = 0; i < components.Length; ++i) - { - // is this component dirty? - // -> always serialize if initialState so all components are included in spawn packet - // -> note: IsDirty() is false if the component isn't dirty or sendInterval isn't elapsed yet - NetworkBehaviour comp = components[i]; - if (initialState || comp.IsDirty()) - { - if (logger.LogEnabled()) logger.Log("OnSerializeAllSafely: " + name + " -> " + comp.GetType() + " initial=" + initialState); - - // remember start position in case we need to copy it into - // observers writer too - int startPosition = ownerWriter.Position; - - // write index as byte [0..255] - ownerWriter.WriteByte((byte)i); - - // serialize into ownerWriter first - // (owner always gets everything!) - OnSerializeSafely(comp, ownerWriter, initialState); - ++ownerWritten; - - // copy into observersWriter too if SyncMode.Observers - // -> we copy instead of calling OnSerialize again because - // we don't know what magic the user does in OnSerialize. - // -> it's not guaranteed that calling it twice gets the - // same result - // -> it's not guaranteed that calling it twice doesn't mess - // with the user's OnSerialize timing code etc. - // => so we just copy the result without touching - // OnSerialize again - if (comp.syncMode == SyncMode.Observers) - { - ArraySegment segment = ownerWriter.ToArraySegment(); - int length = ownerWriter.Position - startPosition; - observersWriter.WriteBytes(segment.Array, startPosition, length); - ++observersWritten; - } - } - } - } - - - void OnDeserializeSafely(NetworkBehaviour comp, NetworkReader reader, bool initialState) - { - // read header as 4 bytes and calculate this chunk's start+end - int contentSize = reader.ReadInt32(); - int chunkStart = reader.Position; - int chunkEnd = reader.Position + contentSize; - - // call OnDeserialize and wrap it in a try-catch block so there's no - // way to mess up another component's deserialization - try - { - if (logger.LogEnabled()) logger.Log("OnDeserializeSafely: " + comp.name + " component=" + comp.GetType() + " sceneId=" + sceneId.ToString("X") + " length=" + contentSize); - comp.OnDeserialize(reader, initialState); - } - catch (Exception e) - { - // show a detailed error and let the user know what went wrong - logger.LogError($"OnDeserialize failed for: object={name} component={comp.GetType()} sceneId={sceneId:X} length={contentSize}. Possible Reasons:\n" + - $" * Do {comp.GetType()}'s OnSerialize and OnDeserialize calls write the same amount of data({contentSize} bytes)? \n" + - $" * Was there an exception in {comp.GetType()}'s OnSerialize/OnDeserialize code?\n" + - $" * Are the server and client the exact same project?\n" + - $" * Maybe this OnDeserialize call was meant for another GameObject? The sceneIds can easily get out of sync if the Hierarchy was modified only in the client OR the server. Try rebuilding both.\n\n" + - $"Exception {e}"); - } - - // now the reader should be EXACTLY at 'before + size'. - // otherwise the component read too much / too less data. - if (reader.Position != chunkEnd) - { - // warn the user - int bytesRead = reader.Position - chunkStart; - logger.LogWarning("OnDeserialize was expected to read " + contentSize + " instead of " + bytesRead + " bytes for object:" + name + " component=" + comp.GetType() + " sceneId=" + sceneId.ToString("X") + ". Make sure that OnSerialize and OnDeserialize write/read the same amount of data in all cases."); - - // fix the position, so the following components don't all fail - reader.Position = chunkEnd; - } - } - - internal void OnDeserializeAllSafely(NetworkReader reader, bool initialState) - { - // deserialize all components that were received - NetworkBehaviour[] components = NetworkBehaviours; - while (reader.Position < reader.Length) - { - // read & check index [0..255] - byte index = reader.ReadByte(); - if (index < components.Length) - { - // deserialize this component - OnDeserializeSafely(components[index], reader, initialState); - } - } - } - - /// - /// Helper function to handle Command/Rpc - /// - /// - /// - /// - /// - /// - internal void HandleRemoteCall(int componentIndex, int functionHash, MirrorInvokeType invokeType, NetworkReader reader, NetworkConnectionToClient senderConnection = null) - { - // check if unity object has been destroyed - if (this == null) - { - logger.LogWarning($"{invokeType} [{functionHash}] received for deleted object [netId={netId}]"); - return; - } - - // find the right component to invoke the function on - if (componentIndex < 0 || componentIndex >= NetworkBehaviours.Length) - { - logger.LogWarning($"Component [{componentIndex}] not found for [netId={netId}]"); - return; - } - - - NetworkBehaviour invokeComponent = NetworkBehaviours[componentIndex]; - - if (!RemoteCallHelper.InvokeHandlerDelegate(functionHash, invokeType, reader, invokeComponent, senderConnection)) - { - logger.LogError($"Found no receiver for incoming {invokeType} [{functionHash}] on {gameObject.name}, the server and client should have the same NetworkBehaviour instances [netId={netId}]."); - } - } - - /// - /// Runs on server - /// - /// - /// - /// - internal CommandInfo GetCommandInfo(int componentIndex, int cmdHash) - { - // check if unity object has been destroyed - if (this == null) - { - // error can be logged later - return default; - } - - // find the right component to invoke the function on - if (0 <= componentIndex && componentIndex < NetworkBehaviours.Length) - { - NetworkBehaviour invokeComponent = NetworkBehaviours[componentIndex]; - return RemoteCallHelper.GetCommandInfo(cmdHash, invokeComponent); - } - else - { - // error can be logged later - return default; - } - } - - /// - /// Called when NetworkIdentity is destroyed - /// - internal void ClearObservers() - { - if (observers != null) - { - foreach (NetworkConnection conn in observers.Values) - { - conn.RemoveFromVisList(this, true); - } - observers.Clear(); - } - } - - internal void AddObserver(NetworkConnection conn) - { - if (observers == null) - { - logger.LogError("AddObserver for " + gameObject + " observer list is null"); - return; - } - - if (observers.ContainsKey(conn.connectionId)) - { - // if we try to add a connectionId that was already added, then - // we may have generated one that was already in use. - return; - } - - if (logger.LogEnabled()) logger.Log("Added observer " + conn.address + " added for " + gameObject); - - observers[conn.connectionId] = conn; - conn.AddToVisList(this); - } - - /// - /// Helper function to call OnRebuildObservers in all components - /// HashSet is passed in so we can cache it! - /// Returns true if we have a NetworkVisibility, false otherwise - /// Initialize is true on first rebuild, false on consecutive rebuilds - /// - /// - /// - /// - internal bool GetNewObservers(HashSet observersSet, bool initialize) - { - observersSet.Clear(); - - if (visibility != null) - { - visibility.OnRebuildObservers(observersSet, initialize); - return true; - } - - // we have no NetworkVisibility. return false to indicate that we - // should use the default implementation. - return false; - } - - /// - /// Helper function to add all server connections as observers. - /// This is used if none of the components provides their own - /// OnRebuildObservers function. - /// - internal void AddAllReadyServerConnectionsToObservers() - { - // add all server connections - foreach (NetworkConnection conn in NetworkServer.connections.Values) - { - if (conn.isReady) - AddObserver(conn); - } - - // add local host connection (if any) - if (NetworkServer.localConnection != null && NetworkServer.localConnection.isReady) - { - AddObserver(NetworkServer.localConnection); - } - } - - static readonly HashSet newObservers = new HashSet(); - - /// - /// This causes the set of players that can see this object to be rebuild. - /// The OnRebuildObservers callback function will be invoked on each NetworkBehaviour. - /// - /// True if this is the first time. - public void RebuildObservers(bool initialize) - { - // observers are null until OnStartServer creates them - if (observers == null) - return; - - bool changed = false; - - // call OnRebuildObservers function - bool rebuildOverwritten = GetNewObservers(newObservers, initialize); - - // if player connection: ensure player always see himself no matter what. - // -> fixes https://github.com/vis2k/Mirror/issues/692 where a - // player might teleport out of the ProximityChecker's cast, - // losing the own connection as observer. - if (connectionToClient != null && connectionToClient.isReady) - { - newObservers.Add(connectionToClient); - } - - // if no NetworkVisibility component, then add all server connections. - if (!rebuildOverwritten) - { - // only add all connections when rebuilding the first time. - // second time we just keep them without rebuilding anything. - if (initialize) - { - AddAllReadyServerConnectionsToObservers(); - } - return; - } - - // add all newObservers that aren't in .observers yet - foreach (NetworkConnection conn in newObservers) - { - // only add ready connections. - // otherwise the player might not be in the world yet or anymore - if (conn != null && conn.isReady) - { - if (initialize || !observers.ContainsKey(conn.connectionId)) - { - // new observer - conn.AddToVisList(this); - if (logger.LogEnabled()) logger.Log("New Observer for " + gameObject + " " + conn); - changed = true; - } - } - } - - // remove all old .observers that aren't in newObservers anymore - foreach (NetworkConnection conn in observers.Values) - { - if (!newObservers.Contains(conn)) - { - // removed observer - conn.RemoveFromVisList(this, false); - if (logger.LogEnabled()) logger.Log("Removed Observer for " + gameObject + " " + conn); - changed = true; - } - } - - if (changed) - { - observers.Clear(); - foreach (NetworkConnection conn in newObservers) - { - if (conn != null && conn.isReady) - observers.Add(conn.connectionId, conn); - } - } - - // special case for host mode: we use SetHostVisibility to hide - // NetworkIdentities that aren't in observer range from host. - // this is what games like Dota/Counter-Strike do too, where a host - // does NOT see all players by default. they are in memory, but - // hidden to the host player. - // - // this code is from UNET, it's a bit strange but it works: - // * it hides newly connected identities in host mode - // => that part was the intended behaviour - // * it hides ALL NetworkIdentities in host mode when the host - // connects but hasn't selected a character yet - // => this only works because we have no .localConnection != null - // check. at this stage, localConnection is null because - // StartHost starts the server first, then calls this code, - // then starts the client and sets .localConnection. so we can - // NOT add a null check without breaking host visibility here. - // * it hides ALL NetworkIdentities in server-only mode because - // observers never contain the 'null' .localConnection - // => that was not intended, but let's keep it as it is so we - // don't break anything in host mode. it's way easier than - // iterating all identities in a special function in StartHost. - if (initialize) - { - if (!newObservers.Contains(NetworkServer.localConnection)) - { - OnSetHostVisibility(false); - } - } - } - - /// - /// Assign control of an object to a client via the client's NetworkConnection. - /// This causes hasAuthority to be set on the client that owns the object, and NetworkBehaviour.OnStartAuthority will be called on that client. This object then will be in the NetworkConnection.clientOwnedObjects list for the connection. - /// Authority can be removed with RemoveClientAuthority. Only one client can own an object at any time. This does not need to be called for player objects, as their authority is setup automatically. - /// - /// The connection of the client to assign authority to. - /// True if authority was assigned. - public bool AssignClientAuthority(NetworkConnection conn) - { - if (!isServer) - { - logger.LogError("AssignClientAuthority can only be called on the server for spawned objects."); - return false; - } - - if (conn == null) - { - logger.LogError("AssignClientAuthority for " + gameObject + " owner cannot be null. Use RemoveClientAuthority() instead."); - return false; - } - - if (connectionToClient != null && conn != connectionToClient) - { - logger.LogError("AssignClientAuthority for " + gameObject + " already has an owner. Use RemoveClientAuthority() first."); - return false; - } - - SetClientOwner(conn); - - // The client will match to the existing object - // update all variables and assign authority - NetworkServer.SendSpawnMessage(this, conn); - - clientAuthorityCallback?.Invoke(conn, this, true); - - return true; - } - - /// - /// Removes ownership for an object. - /// This applies to objects that had authority set by AssignClientAuthority, or NetworkServer.Spawn with a NetworkConnection parameter included. - /// Authority cannot be removed for player objects. - /// - public void RemoveClientAuthority() - { - if (!isServer) - { - logger.LogError("RemoveClientAuthority can only be called on the server for spawned objects."); - return; - } - - if (connectionToClient?.identity == this) - { - logger.LogError("RemoveClientAuthority cannot remove authority for a player object"); - return; - } - - if (connectionToClient != null) - { - clientAuthorityCallback?.Invoke(connectionToClient, this, false); - - NetworkConnectionToClient previousOwner = connectionToClient; - - connectionToClient = null; - - // we need to resynchronize the entire object - // so just spawn it again, - // the client will not create a new instance, it will simply - // reset all variables and remove authority - NetworkServer.SendSpawnMessage(this, previousOwner); - - connectionToClient = null; - } - } - - - /// - /// Marks the identity for future reset, this is because we cant reset the identity during destroy - /// as people might want to be able to read the members inside OnDestroy(), and we have no way - /// of invoking reset after OnDestroy is called. - /// - internal void Reset() - { - // make sure to call this before networkBehavioursCache is cleared below - ResetSyncObjects(); - - hasSpawned = false; - clientStarted = false; - isClient = false; - isServer = false; - - netId = 0; - connectionToServer = null; - connectionToClient = null; - networkBehavioursCache = null; - - ClearObservers(); - - if (isLocalPlayer) - { - ClientScene.ClearLocalPlayer(); - } - } - - /// - /// Invoked by NetworkServer.Update during LateUpdate - /// - internal void ServerUpdate() - { - if (observers != null && observers.Count > 0) - { - SendUpdateVarsMessage(); - } - else - { - // clear all component's dirty bits. - // it would be spawned on new observers anyway. - ClearAllComponentsDirtyBits(); - } - } - - void SendUpdateVarsMessage() - { - // one writer for owner, one for observers - using (PooledNetworkWriter ownerWriter = NetworkWriterPool.GetWriter(), observersWriter = NetworkWriterPool.GetWriter()) - { - // serialize all the dirty components and send - OnSerializeAllSafely(false, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten); - if (ownerWritten > 0 || observersWritten > 0) - { - UpdateVarsMessage varsMessage = new UpdateVarsMessage - { - netId = netId - }; - - // send ownerWriter to owner - // (only if we serialized anything for owner) - // (only if there is a connection (e.g. if not a monster), - // and if connection is ready because we use SendToReady - // below too) - if (ownerWritten > 0) - { - varsMessage.payload = ownerWriter.ToArraySegment(); - if (connectionToClient != null && connectionToClient.isReady) - NetworkServer.SendToClientOfPlayer(this, varsMessage); - } - - // send observersWriter to everyone but owner - // (only if we serialized anything for observers) - if (observersWritten > 0) - { - varsMessage.payload = observersWriter.ToArraySegment(); - NetworkServer.SendToReady(this, varsMessage, false); - } - - // clear dirty bits only for the components that we serialized - // DO NOT clean ALL component's dirty bits, because - // components can have different syncIntervals and we don't - // want to reset dirty bits for the ones that were not - // synced yet. - // (we serialized only the IsDirty() components, or all of - // them if initialState. clearing the dirty ones is enough.) - ClearDirtyComponentsDirtyBits(); - } - } - } - - - /// - /// clear all component's dirty bits no matter what - /// - internal void ClearAllComponentsDirtyBits() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - comp.ClearAllDirtyBits(); - } - } - - /// - /// Clear only dirty component's dirty bits. ignores components which - /// may be dirty but not ready to be synced yet (because of syncInterval) - /// - internal void ClearDirtyComponentsDirtyBits() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - if (comp.IsDirty()) - { - comp.ClearAllDirtyBits(); - } - } - } - - void ResetSyncObjects() - { - foreach (NetworkBehaviour comp in NetworkBehaviours) - { - comp.ResetSyncObjects(); - } - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkIdentity.cs.meta b/Assets/Mirror/Runtime/NetworkIdentity.cs.meta deleted file mode 100644 index 7b96521..0000000 --- a/Assets/Mirror/Runtime/NetworkIdentity.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9b91ecbcc199f4492b9a91e820070131 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkManager.cs b/Assets/Mirror/Runtime/NetworkManager.cs deleted file mode 100644 index 031db09..0000000 --- a/Assets/Mirror/Runtime/NetworkManager.cs +++ /dev/null @@ -1,1463 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.Serialization; -using kcp2k; - -namespace Mirror -{ - /// - /// Enumeration of methods of where to spawn player objects in multiplayer games. - /// - public enum PlayerSpawnMethod { Random, RoundRobin } - - /// - /// Enumeration of methods of current Network Manager state at runtime. - /// - public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host } - - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkManager")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkManager.html")] - public class NetworkManager : MonoBehaviour - { - static readonly ILogger logger = LogFactory.GetLogger(); - - /// - /// A flag to control whether the NetworkManager object is destroyed when the scene changes. - /// This should be set if your game has a single NetworkManager that exists for the lifetime of the process. If there is a NetworkManager in each scene, then this should not be set. - /// - [Header("Configuration")] - [FormerlySerializedAs("m_DontDestroyOnLoad")] - [Tooltip("Should the Network Manager object be persisted through scene changes?")] - public bool dontDestroyOnLoad = true; - - /// - /// Controls whether the program runs when it is in the background. - /// This is required when multiple instances of a program using networking are running on the same machine, such as when testing using localhost. But this is not recommended when deploying to mobile platforms. - /// - [FormerlySerializedAs("m_RunInBackground")] - [Tooltip("Should the server or client keep running in the background?")] - public bool runInBackground = true; - - /// - /// Automatically invoke StartServer() - /// If the application is a Server Build, StartServer is automatically invoked. - /// Server build is true when "Server build" is checked in build menu, or BuildOptions.EnableHeadlessMode flag is in BuildOptions - /// - [Tooltip("Should the server auto-start when 'Server Build' is checked in build settings")] - [FormerlySerializedAs("startOnHeadless")] - public bool autoStartServerBuild = true; - - /// - /// Enables verbose debug messages in the console - /// - [FormerlySerializedAs("m_ShowDebugMessages")] - [Tooltip("This will enable verbose debug messages in the Unity Editor console")] - public bool showDebugMessages; - - /// - /// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. - /// - [Tooltip("Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")] - public int serverTickRate = 30; - - /// - /// The scene to switch to when offline. - /// Setting this makes the NetworkManager do scene management. This scene will be switched to when a network session is completed - such as a client disconnect, or a server shutdown. - /// - [Header("Scene Management")] - [Scene] - [FormerlySerializedAs("m_OfflineScene")] - [Tooltip("Scene that Mirror will switch to when the client or server is stopped")] - public string offlineScene = ""; - - /// - /// The scene to switch to when online. - /// Setting this makes the NetworkManager do scene management. This scene will be switched to when a network session is started - such as a client connect, or a server listen. - /// - [Scene] - [FormerlySerializedAs("m_OnlineScene")] - [Tooltip("Scene that Mirror will switch to when the server is started. Clients will recieve a Scene Message to load the server's current scene when they connect.")] - public string onlineScene = ""; - - // transport layer - [Header("Network Info")] - [Tooltip("Transport component attached to this object that server and client will use to connect")] - [SerializeField] - protected Transport transport; - - /// - /// The network address currently in use. - /// For clients, this is the address of the server that is connected to. For servers, this is the local address. - /// - [FormerlySerializedAs("m_NetworkAddress")] - [Tooltip("Network Address where the client should connect to the server. Server does not use this for anything.")] - public string networkAddress = "localhost"; - - /// - /// The maximum number of concurrent network connections to support. - /// This effects the memory usage of the network layer. - /// - [FormerlySerializedAs("m_MaxConnections")] - [Tooltip("Maximum number of concurrent connections.")] - public int maxConnections = 4; - - // This value is passed to NetworkServer in SetupServer - /// - /// Should the server disconnect remote connections that have gone silent for more than Server Idle Timeout? - /// - [Tooltip("Server Only - Disconnects remote connections that have been silent for more than Server Idle Timeout")] - public bool disconnectInactiveConnections; - - // This value is passed to NetworkServer in SetupServer - /// - /// Timeout in seconds since last message from a client after which server will auto-disconnect. - /// By default, clients send at least a Ping message every 2 seconds. - /// The Host client is immune from idle timeout disconnection. - /// Default value is 60 seconds. - /// - [Tooltip("Timeout in seconds since last message from a client after which server will auto-disconnect if Disconnect Inactive Connections is enabled.")] - public float disconnectInactiveTimeout = 60f; - - [Header("Authentication")] - [Tooltip("Authentication component attached to this object")] - public NetworkAuthenticator authenticator; - - /// - /// The default prefab to be used to create player objects on the server. - /// Player objects are created in the default handler for AddPlayer() on the server. Implementing OnServerAddPlayer overrides this behaviour. - /// - [Header("Player Object")] - [FormerlySerializedAs("m_PlayerPrefab")] - [Tooltip("Prefab of the player object. Prefab must have a Network Identity component. May be an empty game object or a full avatar.")] - public GameObject playerPrefab; - - /// - /// A flag to control whether or not player objects are automatically created on connect, and on scene change. - /// - [FormerlySerializedAs("m_AutoCreatePlayer")] - [Tooltip("Should Mirror automatically spawn the player after scene change?")] - public bool autoCreatePlayer = true; - - /// - /// The current method of spawning players used by the NetworkManager. - /// - [FormerlySerializedAs("m_PlayerSpawnMethod")] - [Tooltip("Round Robin or Random order of Start Position selection")] - public PlayerSpawnMethod playerSpawnMethod; - - /// - /// List of prefabs that will be registered with the spawning system. - /// For each of these prefabs, ClientScene.RegisterPrefab() will be automatically invoked. - /// - [FormerlySerializedAs("m_SpawnPrefabs"), HideInInspector] - public List spawnPrefabs = new List(); - - /// - /// NetworkManager singleton - /// - public static NetworkManager singleton { get; private set; } - - /// - /// Number of active player objects across all connections on the server. - /// This is only valid on the host / server. - /// - public int numPlayers => NetworkServer.connections.Count(kv => kv.Value.identity != null); - - /// - /// True if the server or client is started and running - /// This is set True in StartServer / StartClient, and set False in StopServer / StopClient - /// - [NonSerialized] - public bool isNetworkActive; - - static NetworkConnection clientReadyConnection; - - /// - /// This is true if the client loaded a new scene when connecting to the server. - /// This is set before OnClientConnect is called, so it can be checked there to perform different logic if a scene load occurred. - /// - [NonSerialized] - public bool clientLoadedScene; - - // helper enum to know if we started the networkmanager as server/client/host. - // -> this is necessary because when StartHost changes server scene to - // online scene, FinishLoadScene is called and the host client isn't - // connected yet (no need to connect it before server was fully set up). - // in other words, we need this to know which mode we are running in - // during FinishLoadScene. - public NetworkManagerMode mode { get; private set; } - - #region Unity Callbacks - - /// - /// virtual so that inheriting classes' OnValidate() can call base.OnValidate() too - /// - public virtual void OnValidate() - { - // add transport if there is none yet. makes upgrading easier. - if (transport == null) - { - // was a transport added yet? if not, add one - transport = GetComponent(); - if (transport == null) - { - transport = gameObject.AddComponent(); - logger.Log("NetworkManager: added default Transport because there was none yet."); - } -#if UNITY_EDITOR - UnityEditor.Undo.RecordObject(gameObject, "Added default Transport"); -#endif - } - - // always >= 0 - maxConnections = Mathf.Max(maxConnections, 0); - - if (playerPrefab != null && playerPrefab.GetComponent() == null) - { - logger.LogError("NetworkManager - playerPrefab must have a NetworkIdentity."); - playerPrefab = null; - } - } - - /// - /// virtual so that inheriting classes' Awake() can call base.Awake() too - /// - public virtual void Awake() - { - // Don't allow collision-destroyed second instance to continue. - if (!InitializeSingleton()) return; - - logger.Log("Thank you for using Mirror! https://mirror-networking.com"); - - // Set the networkSceneName to prevent a scene reload - // if client connection to server fails. - networkSceneName = offlineScene; - - // setup OnSceneLoaded callback - SceneManager.sceneLoaded += OnSceneLoaded; - } - - /// - /// virtual so that inheriting classes' Start() can call base.Start() too - /// - public virtual void Start() - { - // headless mode? then start the server - // can't do this in Awake because Awake is for initialization. - // some transports might not be ready until Start. - // - // (tick rate is applied in StartServer!) -#if UNITY_SERVER - if (autoStartServerBuild) - { - StartServer(); - } -#endif - } - - // NetworkIdentity.UNetStaticUpdate is called from UnityEngine while LLAPI network is active. - // If we want TCP then we need to call it manually. Probably best from NetworkManager, although this means that we can't use NetworkServer/NetworkClient without a NetworkManager invoking Update anymore. - /// - /// virtual so that inheriting classes' LateUpdate() can call base.LateUpdate() too - /// - public virtual void LateUpdate() - { - // call it while the NetworkManager exists. - // -> we don't only call while Client/Server.Connected, because then we would stop if disconnected and the - // NetworkClient wouldn't receive the last Disconnect event, result in all kinds of issues - NetworkServer.Update(); - NetworkClient.Update(); - UpdateScene(); - } - - #endregion - - #region Start & Stop - - // keep the online scene change check in a separate function - bool IsServerOnlineSceneChangeNeeded() - { - // Only change scene if the requested online scene is not blank, and is not already loaded - return !string.IsNullOrEmpty(onlineScene) && !IsSceneActive(onlineScene) && onlineScene != offlineScene; - } - - public static bool IsSceneActive(string scene) - { - Scene activeScene = SceneManager.GetActiveScene(); - return activeScene.path == scene || activeScene.name == scene; - } - - // full server setup code, without spawning objects yet - void SetupServer() - { - if (logger.LogEnabled()) logger.Log("NetworkManager SetupServer"); - InitializeSingleton(); - - if (runInBackground) - Application.runInBackground = true; - - if (authenticator != null) - { - authenticator.OnStartServer(); - authenticator.OnServerAuthenticated.AddListener(OnServerAuthenticated); - } - - ConfigureServerFrameRate(); - - // Copy auto-disconnect settings to NetworkServer - NetworkServer.disconnectInactiveTimeout = disconnectInactiveTimeout; - NetworkServer.disconnectInactiveConnections = disconnectInactiveConnections; - - // start listening to network connections - NetworkServer.Listen(maxConnections); - - // call OnStartServer AFTER Listen, so that NetworkServer.active is - // true and we can call NetworkServer.Spawn in OnStartServer - // overrides. - // (useful for loading & spawning stuff from database etc.) - // - // note: there is no risk of someone connecting after Listen() and - // before OnStartServer() because this all runs in one thread - // and we don't start processing connects until Update. - OnStartServer(); - - // this must be after Listen(), since that registers the default message handlers - RegisterServerMessages(); - - isNetworkActive = true; - } - - /// - /// This starts a new server. - /// - public void StartServer() - { - mode = NetworkManagerMode.ServerOnly; - - // StartServer is inherently ASYNCHRONOUS (=doesn't finish immediately) - // - // Here is what it does: - // Listen - // if onlineScene: - // LoadSceneAsync - // ... - // FinishLoadSceneServerOnly - // SpawnObjects - // else: - // SpawnObjects - // - // there is NO WAY to make it synchronous because both LoadSceneAsync - // and LoadScene do not finish loading immediately. as long as we - // have the onlineScene feature, it will be asynchronous! - - SetupServer(); - - // scene change needed? then change scene and spawn afterwards. - if (IsServerOnlineSceneChangeNeeded()) - { - ServerChangeScene(onlineScene); - } - // otherwise spawn directly - else - { - NetworkServer.SpawnObjects(); - } - } - - /// - /// This starts a network client. It uses the networkAddress property as the address to connect to. - /// This makes the newly created client connect to the server immediately. - /// - public void StartClient() - { - mode = NetworkManagerMode.ClientOnly; - - InitializeSingleton(); - - if (authenticator != null) - { - authenticator.OnStartClient(); - authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated); - } - - if (runInBackground) - Application.runInBackground = true; - - isNetworkActive = true; - - RegisterClientMessages(); - - if (string.IsNullOrEmpty(networkAddress)) - { - logger.LogError("Must set the Network Address field in the manager"); - return; - } - if (logger.LogEnabled()) logger.Log("NetworkManager StartClient address:" + networkAddress); - - NetworkClient.Connect(networkAddress); - - OnStartClient(); - } - - /// - /// This starts a network client. It uses the Uri parameter as the address to connect to. - /// This makes the newly created client connect to the server immediately. - /// - /// location of the server to connect to - public void StartClient(Uri uri) - { - mode = NetworkManagerMode.ClientOnly; - - InitializeSingleton(); - - if (authenticator != null) - { - authenticator.OnStartClient(); - authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated); - } - - if (runInBackground) - { - Application.runInBackground = true; - } - - isNetworkActive = true; - - RegisterClientMessages(); - - if (logger.LogEnabled()) logger.Log("NetworkManager StartClient address:" + uri); - networkAddress = uri.Host; - - NetworkClient.Connect(uri); - - OnStartClient(); - } - - /// - /// This starts a network "host" - a server and client in the same application. - /// The client returned from StartHost() is a special "local" client that communicates to the in-process server using a message queue instead of the real network. But in almost all other cases, it can be treated as a normal client. - /// - public void StartHost() - { - mode = NetworkManagerMode.Host; - - // StartHost is inherently ASYNCHRONOUS (=doesn't finish immediately) - // - // Here is what it does: - // Listen - // ConnectHost - // if onlineScene: - // LoadSceneAsync - // ... - // FinishLoadSceneHost - // FinishStartHost - // SpawnObjects - // StartHostClient <= not guaranteed to happen after SpawnObjects if onlineScene is set! - // ClientAuth - // success: server sends changescene msg to client - // else: - // FinishStartHost - // - // there is NO WAY to make it synchronous because both LoadSceneAsync - // and LoadScene do not finish loading immediately. as long as we - // have the onlineScene feature, it will be asynchronous! - - // setup server first - SetupServer(); - - // call OnStartHost AFTER SetupServer. this way we can use - // NetworkServer.Spawn etc. in there too. just like OnStartServer - // is called after the server is actually properly started. - OnStartHost(); - - // scene change needed? then change scene and spawn afterwards. - // => BEFORE host client connects. if client auth succeeds then the - // server tells it to load 'onlineScene'. we can't do that if - // server is still in 'offlineScene'. so load on server first. - if (IsServerOnlineSceneChangeNeeded()) - { - // call FinishStartHost after changing scene. - finishStartHostPending = true; - ServerChangeScene(onlineScene); - } - // otherwise call FinishStartHost directly - else - { - FinishStartHost(); - } - } - - // This may be set true in StartHost and is evaluated in FinishStartHost - bool finishStartHostPending; - - // FinishStartHost is guaranteed to be called after the host server was - // fully started and all the asynchronous StartHost magic is finished - // (= scene loading), or immediately if there was no asynchronous magic. - // - // note: we don't really need FinishStartClient/FinishStartServer. the - // host version is enough. - void FinishStartHost() - { - // ConnectHost needs to be called BEFORE SpawnObjects: - // https://github.com/vis2k/Mirror/pull/1249/ - // -> this sets NetworkServer.localConnection. - // -> localConnection needs to be set before SpawnObjects because: - // -> SpawnObjects calls OnStartServer in all NetworkBehaviours - // -> OnStartServer might spawn an object and set [SyncVar(hook="OnColorChanged")] object.color = green; - // -> this calls SyncVar.set (generated by Weaver), which has - // a custom case for host mode (because host mode doesn't - // get OnDeserialize calls, where SyncVar hooks are usually - // called): - // - // if (!SyncVarEqual(value, ref color)) - // { - // if (NetworkServer.localClientActive && !getSyncVarHookGuard(1uL)) - // { - // setSyncVarHookGuard(1uL, value: true); - // OnColorChangedHook(value); - // setSyncVarHookGuard(1uL, value: false); - // } - // SetSyncVar(value, ref color, 1uL); - // } - // - // -> localClientActive needs to be true, otherwise the hook - // isn't called in host mode! - // - // TODO call this after spawnobjects and worry about the syncvar hook fix later? - NetworkClient.ConnectHost(); - - // server scene was loaded. now spawn all the objects - NetworkServer.SpawnObjects(); - - // connect client and call OnStartClient AFTER server scene was - // loaded and all objects were spawned. - // DO NOT do this earlier. it would cause race conditions where a - // client will do things before the server is even fully started. - logger.Log("StartHostClient called"); - StartHostClient(); - } - - void StartHostClient() - { - logger.Log("NetworkManager ConnectLocalClient"); - - if (authenticator != null) - { - authenticator.OnStartClient(); - authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated); - } - - networkAddress = "localhost"; - NetworkServer.ActivateHostScene(); - RegisterClientMessages(); - - // ConnectLocalServer needs to be called AFTER RegisterClientMessages - // (https://github.com/vis2k/Mirror/pull/1249/) - NetworkClient.ConnectLocalServer(); - - OnStartClient(); - } - - /// - /// This stops both the client and the server that the manager is using. - /// - public void StopHost() - { - OnStopHost(); - - // TODO try to move DisconnectLocalServer into StopClient(), and - // then call StopClient() before StopServer(). needs testing!. - - // DisconnectLocalServer needs to be called so that the host client - // receives a DisconnectMessage too. - // fixes: https://github.com/vis2k/Mirror/issues/1515 - NetworkClient.DisconnectLocalServer(); - - StopClient(); - StopServer(); - } - - /// - /// Stops the server that the manager is using. - /// - public void StopServer() - { - if (!NetworkServer.active) - return; - - if (authenticator != null) - authenticator.OnServerAuthenticated.RemoveListener(OnServerAuthenticated); - - OnStopServer(); - - logger.Log("NetworkManager StopServer"); - isNetworkActive = false; - NetworkServer.Shutdown(); - - // set offline mode BEFORE changing scene so that FinishStartScene - // doesn't think we need initialize anything. - mode = NetworkManagerMode.Offline; - - if (!string.IsNullOrEmpty(offlineScene)) - { - ServerChangeScene(offlineScene); - } - - startPositionIndex = 0; - - networkSceneName = ""; - } - - /// - /// Stops the client that the manager is using. - /// - public void StopClient() - { - if (authenticator != null) - authenticator.OnClientAuthenticated.RemoveListener(OnClientAuthenticated); - - OnStopClient(); - - logger.Log("NetworkManager StopClient"); - isNetworkActive = false; - - // shutdown client - NetworkClient.Disconnect(); - NetworkClient.Shutdown(); - - // set offline mode BEFORE changing scene so that FinishStartScene - // doesn't think we need initialize anything. - mode = NetworkManagerMode.Offline; - - // If this is the host player, StopServer will already be changing scenes. - // Check loadingSceneAsync to ensure we don't double-invoke the scene change. - // Check if NetworkServer.active because we can get here via Disconnect before server has started to change scenes. - if (!string.IsNullOrEmpty(offlineScene) && !IsSceneActive(offlineScene) && loadingSceneAsync == null && !NetworkServer.active) - { - ClientChangeScene(offlineScene, SceneOperation.Normal); - } - - networkSceneName = ""; - } - - /// - /// called when quitting the application by closing the window / pressing stop in the editor - /// virtual so that inheriting classes' OnApplicationQuit() can call base.OnApplicationQuit() too - /// - public virtual void OnApplicationQuit() - { - // stop client first - // (we want to send the quit packet to the server instead of waiting - // for a timeout) - if (NetworkClient.isConnected) - { - StopClient(); - print("OnApplicationQuit: stopped client"); - } - - // stop server after stopping client (for proper host mode stopping) - if (NetworkServer.active) - { - StopServer(); - print("OnApplicationQuit: stopped server"); - } - } - - /// - /// Set the frame rate for a headless server. - /// Override if you wish to disable the behavior or set your own tick rate. - /// - public virtual void ConfigureServerFrameRate() - { - // only set framerate for server build -#if UNITY_SERVER - Application.targetFrameRate = serverTickRate; - if (logger.logEnabled) logger.Log("Server Tick Rate set to: " + Application.targetFrameRate + " Hz."); -#endif - } - - bool InitializeSingleton() - { - if (singleton != null && singleton == this) return true; - - // do this early - LogFilter.Debug = showDebugMessages; - if (LogFilter.Debug) - { - LogFactory.EnableDebugMode(); - } - - if (dontDestroyOnLoad) - { - if (singleton != null) - { - logger.LogWarning("Multiple NetworkManagers detected in the scene. Only one NetworkManager can exist at a time. The duplicate NetworkManager will be destroyed."); - Destroy(gameObject); - - // Return false to not allow collision-destroyed second instance to continue. - return false; - } - logger.Log("NetworkManager created singleton (DontDestroyOnLoad)"); - singleton = this; - if (Application.isPlaying) DontDestroyOnLoad(gameObject); - } - else - { - logger.Log("NetworkManager created singleton (ForScene)"); - singleton = this; - } - - // set active transport AFTER setting singleton. - // so only if we didn't destroy ourselves. - Transport.activeTransport = transport; - - return true; - } - - void RegisterServerMessages() - { - NetworkServer.RegisterHandler(OnServerConnectInternal, false); - NetworkServer.RegisterHandler(OnServerDisconnectInternal, false); - NetworkServer.RegisterHandler(OnServerAddPlayerInternal); - NetworkServer.RegisterHandler(OnServerErrorInternal, false); - - // Network Server initially registers its own handler for this, so we replace it here. - NetworkServer.ReplaceHandler(OnServerReadyMessageInternal); - } - - void RegisterClientMessages() - { - NetworkClient.RegisterHandler(OnClientConnectInternal, false); - NetworkClient.RegisterHandler(OnClientDisconnectInternal, false); - NetworkClient.RegisterHandler(OnClientNotReadyMessageInternal); - NetworkClient.RegisterHandler(OnClientErrorInternal, false); - NetworkClient.RegisterHandler(OnClientSceneInternal, false); - - if (playerPrefab != null) - { - ClientScene.RegisterPrefab(playerPrefab); - } - for (int i = 0; i < spawnPrefabs.Count; i++) - { - GameObject prefab = spawnPrefabs[i]; - if (prefab != null) - { - ClientScene.RegisterPrefab(prefab); - } - } - } - - /// - /// This is the only way to clear the singleton, so another instance can be created. - /// - public static void Shutdown() - { - if (singleton == null) - return; - - startPositions.Clear(); - startPositionIndex = 0; - clientReadyConnection = null; - - singleton.StopHost(); - singleton = null; - } - - /// - /// virtual so that inheriting classes' OnDestroy() can call base.OnDestroy() too - /// - public virtual void OnDestroy() - { - logger.Log("NetworkManager destroyed"); - } - - #endregion - - #region Scene Management - - /// - /// The name of the current network scene. - /// - /// - /// This is populated if the NetworkManager is doing scene management. Calls to ServerChangeScene() cause this to change. New clients that connect to a server will automatically load this scene. - /// This is used to make sure that all scene changes are initialized by Mirror. - /// Loading a scene manually wont set networkSceneName, so Mirror would still load it again on start. - /// - public static string networkSceneName { get; protected set; } = ""; - - public static UnityEngine.AsyncOperation loadingSceneAsync; - - /// - /// This causes the server to switch scenes and sets the networkSceneName. - /// Clients that connect to this server will automatically switch to this scene. This is called autmatically if onlineScene or offlineScene are set, but it can be called from user code to switch scenes again while the game is in progress. This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready() again to participate in the new scene. - /// - /// - public virtual void ServerChangeScene(string newSceneName) - { - if (string.IsNullOrEmpty(newSceneName)) - { - logger.LogError("ServerChangeScene empty scene name"); - return; - } - - if (logger.logEnabled) logger.Log("ServerChangeScene " + newSceneName); - NetworkServer.SetAllClientsNotReady(); - networkSceneName = newSceneName; - - // Let server prepare for scene change - OnServerChangeScene(newSceneName); - - // Suspend the server's transport while changing scenes - // It will be re-enabled in FinishScene. - Transport.activeTransport.enabled = false; - - loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName); - - // ServerChangeScene can be called when stopping the server - // when this happens the server is not active so does not need to tell clients about the change - if (NetworkServer.active) - { - // notify all clients about the new scene - NetworkServer.SendToAll(new SceneMessage { sceneName = newSceneName }); - } - - startPositionIndex = 0; - startPositions.Clear(); - } - - // This is only set in ClientChangeScene below...never on server. - // We need to check this in OnClientSceneChanged called from FinishLoadSceneClientOnly - // to prevent AddPlayer message after loading/unloading additive scenes - SceneOperation clientSceneOperation = SceneOperation.Normal; - - internal void ClientChangeScene(string newSceneName, SceneOperation sceneOperation = SceneOperation.Normal, bool customHandling = false) - { - if (string.IsNullOrEmpty(newSceneName)) - { - logger.LogError("ClientChangeScene empty scene name"); - return; - } - - if (logger.LogEnabled()) logger.Log("ClientChangeScene newSceneName:" + newSceneName + " networkSceneName:" + networkSceneName); - - // vis2k: pause message handling while loading scene. otherwise we will process messages and then lose all - // the state as soon as the load is finishing, causing all kinds of bugs because of missing state. - // (client may be null after StopClient etc.) - if (logger.LogEnabled()) logger.Log("ClientChangeScene: pausing handlers while scene is loading to avoid data loss after scene was loaded."); - Transport.activeTransport.enabled = false; - - // Let client prepare for scene change - OnClientChangeScene(newSceneName, sceneOperation, customHandling); - - // scene handling will happen in overrides of OnClientChangeScene and/or OnClientSceneChanged - if (customHandling) - { - FinishLoadScene(); - return; - } - - // cache sceneOperation so we know what was done in OnClientSceneChanged called from FinishLoadSceneClientOnly - clientSceneOperation = sceneOperation; - - switch (sceneOperation) - { - case SceneOperation.Normal: - loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName); - break; - case SceneOperation.LoadAdditive: - // Ensure additive scene is not already loaded on client by name or path - // since we don't know which was passed in the Scene message - if (!SceneManager.GetSceneByName(newSceneName).IsValid() && !SceneManager.GetSceneByPath(newSceneName).IsValid()) - loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName, LoadSceneMode.Additive); - else - { - logger.LogWarning($"Scene {newSceneName} is already loaded"); - - // Re-enable the transport that we disabled before entering this switch - Transport.activeTransport.enabled = true; - } - break; - case SceneOperation.UnloadAdditive: - // Ensure additive scene is actually loaded on client by name or path - // since we don't know which was passed in the Scene message - if (SceneManager.GetSceneByName(newSceneName).IsValid() || SceneManager.GetSceneByPath(newSceneName).IsValid()) - loadingSceneAsync = SceneManager.UnloadSceneAsync(newSceneName, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects); - else - { - logger.LogWarning($"Cannot unload {newSceneName} with UnloadAdditive operation"); - - // Re-enable the transport that we disabled before entering this switch - Transport.activeTransport.enabled = true; - } - break; - } - - // don't change the client's current networkSceneName when loading additive scene content - if (sceneOperation == SceneOperation.Normal) - networkSceneName = newSceneName; - } - - // support additive scene loads: - // NetworkScenePostProcess disables all scene objects on load, and - // * NetworkServer.SpawnObjects enables them again on the server when - // calling OnStartServer - // * ClientScene.PrepareToSpawnSceneObjects enables them again on the - // client after the server sends ObjectSpawnStartedMessage to client - // in SpawnObserversForConnection. this is only called when the - // client joins, so we need to rebuild scene objects manually again - // TODO merge this with FinishLoadScene()? - void OnSceneLoaded(Scene scene, LoadSceneMode mode) - { - if (mode == LoadSceneMode.Additive) - { - if (NetworkServer.active) - { - // TODO only respawn the server objects from that scene later! - NetworkServer.SpawnObjects(); - if (logger.LogEnabled()) logger.Log("Respawned Server objects after additive scene load: " + scene.name); - } - if (NetworkClient.active) - { - ClientScene.PrepareToSpawnSceneObjects(); - if (logger.LogEnabled()) logger.Log("Rebuild Client spawnableObjects after additive scene load: " + scene.name); - } - } - } - - static void UpdateScene() - { - if (singleton != null && loadingSceneAsync != null && loadingSceneAsync.isDone) - { - if (logger.LogEnabled()) logger.Log("ClientChangeScene done readyCon:" + clientReadyConnection); - singleton.FinishLoadScene(); - loadingSceneAsync.allowSceneActivation = true; - loadingSceneAsync = null; - } - } - - void FinishLoadScene() - { - // NOTE: this cannot use NetworkClient.allClients[0] - that client may be for a completely different purpose. - - // process queued messages that we received while loading the scene - logger.Log("FinishLoadScene: resuming handlers after scene was loading."); - Transport.activeTransport.enabled = true; - - // host mode? - if (mode == NetworkManagerMode.Host) - { - FinishLoadSceneHost(); - } - // server-only mode? - else if (mode == NetworkManagerMode.ServerOnly) - { - FinishLoadSceneServerOnly(); - } - // client-only mode? - else if (mode == NetworkManagerMode.ClientOnly) - { - FinishLoadSceneClientOnly(); - } - // otherwise we called it after stopping when loading offline scene. - // do nothing then. - } - - // finish load scene part for host mode. makes code easier and is - // necessary for FinishStartHost later. - // (the 3 things have to happen in that exact order) - void FinishLoadSceneHost() - { - // debug message is very important. if we ever break anything then - // it's very obvious to notice. - logger.Log("Finished loading scene in host mode."); - - if (clientReadyConnection != null) - { - OnClientConnect(clientReadyConnection); - clientLoadedScene = true; - clientReadyConnection = null; - } - - // do we need to finish a StartHost() call? - // then call FinishStartHost and let it take care of spawning etc. - if (finishStartHostPending) - { - finishStartHostPending = false; - FinishStartHost(); - - // call OnServerSceneChanged - OnServerSceneChanged(networkSceneName); - - // DO NOT call OnClientSceneChanged here. - // the scene change happened because StartHost loaded the - // server's online scene. it has nothing to do with the client. - // this was not meant as a client scene load, so don't call it. - // - // otherwise AddPlayer would be called twice: - // -> once for client OnConnected - // -> once in OnClientSceneChanged - } - // otherwise we just changed a scene in host mode - else - { - // spawn server objects - NetworkServer.SpawnObjects(); - - // call OnServerSceneChanged - OnServerSceneChanged(networkSceneName); - - if (NetworkClient.isConnected) - { - // let client know that we changed scene - OnClientSceneChanged(NetworkClient.connection); - } - } - } - - // finish load scene part for server-only. . makes code easier and is - // necessary for FinishStartServer later. - void FinishLoadSceneServerOnly() - { - // debug message is very important. if we ever break anything then - // it's very obvious to notice. - logger.Log("Finished loading scene in server-only mode."); - - NetworkServer.SpawnObjects(); - OnServerSceneChanged(networkSceneName); - } - - // finish load scene part for client-only. makes code easier and is - // necessary for FinishStartClient later. - void FinishLoadSceneClientOnly() - { - // debug message is very important. if we ever break anything then - // it's very obvious to notice. - logger.Log("Finished loading scene in client-only mode."); - - if (clientReadyConnection != null) - { - OnClientConnect(clientReadyConnection); - clientLoadedScene = true; - clientReadyConnection = null; - } - - if (NetworkClient.isConnected) - { - OnClientSceneChanged(NetworkClient.connection); - } - } - - #endregion - - #region Start Positions - - public static int startPositionIndex; - - /// - /// List of transforms populted by NetworkStartPosition components found in the scene. - /// - public static List startPositions = new List(); - - /// - /// Registers the transform of a game object as a player spawn location. - /// This is done automatically by NetworkStartPosition components, but can be done manually from user script code. - /// - /// Transform to register. - public static void RegisterStartPosition(Transform start) - { - if (logger.LogEnabled()) logger.Log("RegisterStartPosition: (" + start.gameObject.name + ") " + start.position); - startPositions.Add(start); - - // reorder the list so that round-robin spawning uses the start positions - // in hierarchy order. This assumes all objects with NetworkStartPosition - // component are siblings, either in the scene root or together as children - // under a single parent in the scene. - startPositions = startPositions.OrderBy(transform => transform.GetSiblingIndex()).ToList(); - } - - /// - /// Unregisters the transform of a game object as a player spawn location. - /// This is done automatically by the NetworkStartPosition component, but can be done manually from user code. - /// - /// Transform to unregister. - public static void UnRegisterStartPosition(Transform start) - { - if (logger.LogEnabled()) logger.Log("UnRegisterStartPosition: (" + start.gameObject.name + ") " + start.position); - startPositions.Remove(start); - } - - /// - /// This finds a spawn position based on NetworkStartPosition objects in the scene. - /// This is used by the default implementation of OnServerAddPlayer. - /// - /// Returns the transform to spawn a player at, or null. - public Transform GetStartPosition() - { - // first remove any dead transforms - startPositions.RemoveAll(t => t == null); - - if (startPositions.Count == 0) - return null; - - if (playerSpawnMethod == PlayerSpawnMethod.Random) - { - return startPositions[UnityEngine.Random.Range(0, startPositions.Count)]; - } - else - { - Transform startPosition = startPositions[startPositionIndex]; - startPositionIndex = (startPositionIndex + 1) % startPositions.Count; - return startPosition; - } - } - - #endregion - - #region Server Internal Message Handlers - - void OnServerConnectInternal(NetworkConnection conn, ConnectMessage connectMsg) - { - logger.Log("NetworkManager.OnServerConnectInternal"); - - if (authenticator != null) - { - // we have an authenticator - let it handle authentication - authenticator.OnServerAuthenticate(conn); - } - else - { - // authenticate immediately - OnServerAuthenticated(conn); - } - } - - // called after successful authentication - void OnServerAuthenticated(NetworkConnection conn) - { - logger.Log("NetworkManager.OnServerAuthenticated"); - - // set connection to authenticated - conn.isAuthenticated = true; - - // proceed with the login handshake by calling OnServerConnect - if (networkSceneName != "" && networkSceneName != offlineScene) - { - SceneMessage msg = new SceneMessage() { sceneName = networkSceneName }; - conn.Send(msg); - } - - OnServerConnect(conn); - } - - void OnServerDisconnectInternal(NetworkConnection conn, DisconnectMessage msg) - { - logger.Log("NetworkManager.OnServerDisconnectInternal"); - OnServerDisconnect(conn); - } - - void OnServerReadyMessageInternal(NetworkConnection conn, ReadyMessage msg) - { - logger.Log("NetworkManager.OnServerReadyMessageInternal"); - OnServerReady(conn); - } - - void OnServerAddPlayerInternal(NetworkConnection conn, AddPlayerMessage msg) - { - logger.Log("NetworkManager.OnServerAddPlayer"); - - if (autoCreatePlayer && playerPrefab == null) - { - logger.LogError("The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object."); - return; - } - - if (autoCreatePlayer && playerPrefab.GetComponent() == null) - { - logger.LogError("The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab."); - return; - } - - if (conn.identity != null) - { - logger.LogError("There is already a player for this connection."); - return; - } - - OnServerAddPlayer(conn); - } - - void OnServerErrorInternal(NetworkConnection conn, ErrorMessage msg) - { - logger.Log("NetworkManager.OnServerErrorInternal"); - OnServerError(conn, msg.value); - } - - #endregion - - #region Client Internal Message Handlers - - void OnClientConnectInternal(NetworkConnection conn, ConnectMessage message) - { - logger.Log("NetworkManager.OnClientConnectInternal"); - - if (authenticator != null) - { - // we have an authenticator - let it handle authentication - authenticator.OnClientAuthenticate(conn); - } - else - { - // authenticate immediately - OnClientAuthenticated(conn); - } - } - - // called after successful authentication - void OnClientAuthenticated(NetworkConnection conn) - { - logger.Log("NetworkManager.OnClientAuthenticated"); - - // set connection to authenticated - conn.isAuthenticated = true; - - // proceed with the login handshake by calling OnClientConnect - if (string.IsNullOrEmpty(onlineScene) || onlineScene == offlineScene || IsSceneActive(onlineScene)) - { - clientLoadedScene = false; - OnClientConnect(conn); - } - else - { - // will wait for scene id to come from the server. - clientLoadedScene = true; - clientReadyConnection = conn; - } - } - - void OnClientDisconnectInternal(NetworkConnection conn, DisconnectMessage msg) - { - logger.Log("NetworkManager.OnClientDisconnectInternal"); - OnClientDisconnect(conn); - } - - void OnClientNotReadyMessageInternal(NetworkConnection conn, NotReadyMessage msg) - { - logger.Log("NetworkManager.OnClientNotReadyMessageInternal"); - - ClientScene.ready = false; - OnClientNotReady(conn); - - // NOTE: clientReadyConnection is not set here! don't want OnClientConnect to be invoked again after scene changes. - } - - void OnClientErrorInternal(NetworkConnection conn, ErrorMessage msg) - { - logger.Log("NetworkManager:OnClientErrorInternal"); - OnClientError(conn, msg.value); - } - - void OnClientSceneInternal(NetworkConnection conn, SceneMessage msg) - { - logger.Log("NetworkManager.OnClientSceneInternal"); - - if (NetworkClient.isConnected && !NetworkServer.active) - { - ClientChangeScene(msg.sceneName, msg.sceneOperation, msg.customHandling); - } - } - - #endregion - - #region Server System Callbacks - - /// - /// Called on the server when a new client connects. - /// Unity calls this on the Server when a Client connects to the Server. Use an override to tell the NetworkManager what to do when a client connects to the server. - /// - /// Connection from client. - public virtual void OnServerConnect(NetworkConnection conn) { } - - /// - /// Called on the server when a client disconnects. - /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. - /// - /// Connection from client. - public virtual void OnServerDisconnect(NetworkConnection conn) - { - NetworkServer.DestroyPlayerForConnection(conn); - logger.Log("OnServerDisconnect: Client disconnected."); - } - - /// - /// Called on the server when a client is ready. - /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. - /// - /// Connection from client. - public virtual void OnServerReady(NetworkConnection conn) - { - if (conn.identity == null) - { - // this is now allowed (was not for a while) - logger.Log("Ready with no player object"); - } - NetworkServer.SetClientReady(conn); - } - - /// - /// Called on the server when a client adds a new player with ClientScene.AddPlayer. - /// The default implementation for this function creates a new player object from the playerPrefab. - /// - /// Connection from client. - public virtual void OnServerAddPlayer(NetworkConnection conn) - { - Transform startPos = GetStartPosition(); - GameObject player = startPos != null - ? Instantiate(playerPrefab, startPos.position, startPos.rotation) - : Instantiate(playerPrefab); - - NetworkServer.AddPlayerForConnection(conn, player); - } - - /// - /// Called on the server when a network error occurs for a client connection. - /// - /// Connection from client. - /// Error code. - public virtual void OnServerError(NetworkConnection conn, int errorCode) { } - - /// - /// Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed - /// This allows server to do work / cleanup / prep before the scene changes. - /// - /// Name of the scene that's about to be loaded - public virtual void OnServerChangeScene(string newSceneName) { } - - /// - /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). - /// - /// The name of the new scene. - public virtual void OnServerSceneChanged(string sceneName) { } - - #endregion - - #region Client System Callbacks - - /// - /// Called on the client when connected to a server. - /// The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects. - /// - /// Connection to the server. - public virtual void OnClientConnect(NetworkConnection conn) - { - // OnClientConnect by default calls AddPlayer but it should not do - // that when we have online/offline scenes. so we need the - // clientLoadedScene flag to prevent it. - if (!clientLoadedScene) - { - // Ready/AddPlayer is usually triggered by a scene load completing. if no scene was loaded, then Ready/AddPlayer it here instead. - if (!ClientScene.ready) ClientScene.Ready(conn); - if (autoCreatePlayer) - { - ClientScene.AddPlayer(conn); - } - } - } - - /// - /// Called on clients when disconnected from a server. - /// This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects. - /// - /// Connection to the server. - public virtual void OnClientDisconnect(NetworkConnection conn) - { - StopClient(); - } - - /// - /// Called on clients when a network error occurs. - /// - /// Connection to a server. - /// Error code. - public virtual void OnClientError(NetworkConnection conn, int errorCode) { } - - /// - /// Called on clients when a servers tells the client it is no longer ready. - /// This is commonly used when switching scenes. - /// - /// Connection to the server. - public virtual void OnClientNotReady(NetworkConnection conn) { } - - /// - /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed - /// This allows client to do work / cleanup / prep before the scene changes. - /// - /// Name of the scene that's about to be loaded - /// Scene operation that's about to happen - /// true to indicate that scene loading will be handled through overrides - public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) { } - - /// - /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. - /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. - /// - /// The network connection that the scene change message arrived on. - public virtual void OnClientSceneChanged(NetworkConnection conn) - { - // always become ready. - if (!ClientScene.ready) ClientScene.Ready(conn); - - // Only call AddPlayer for normal scene changes, not additive load/unload - if (clientSceneOperation == SceneOperation.Normal && autoCreatePlayer && ClientScene.localPlayer == null) - { - // add player if existing one is null - ClientScene.AddPlayer(conn); - } - } - - #endregion - - #region Start & Stop callbacks - - // Since there are multiple versions of StartServer, StartClient and StartHost, to reliably customize - // their functionality, users would need override all the versions. Instead these callbacks are invoked - // from all versions, so users only need to implement this one case. - - /// - /// This is invoked when a host is started. - /// StartHost has multiple signatures, but they all cause this hook to be called. - /// - public virtual void OnStartHost() { } - - /// - /// This is invoked when a server is started - including when a host is started. - /// StartServer has multiple signatures, but they all cause this hook to be called. - /// - public virtual void OnStartServer() { } - - /// - /// This is invoked when the client is started. - /// - public virtual void OnStartClient() { } - - /// - /// This is called when a server is stopped - including when a host is stopped. - /// - public virtual void OnStopServer() { } - - /// - /// This is called when a client is stopped. - /// - public virtual void OnStopClient() { } - - /// - /// This is called when a host is stopped. - /// - public virtual void OnStopHost() { } - - #endregion - } -} diff --git a/Assets/Mirror/Runtime/NetworkManager.cs.meta b/Assets/Mirror/Runtime/NetworkManager.cs.meta deleted file mode 100644 index 0a7564a..0000000 --- a/Assets/Mirror/Runtime/NetworkManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkManagerHUD.cs b/Assets/Mirror/Runtime/NetworkManagerHUD.cs deleted file mode 100644 index 7b5b534..0000000 --- a/Assets/Mirror/Runtime/NetworkManagerHUD.cs +++ /dev/null @@ -1,158 +0,0 @@ -// vis2k: GUILayout instead of spacey += ...; removed Update hotkeys to avoid -// confusion if someone accidentally presses one. -using UnityEngine; - -namespace Mirror -{ - /// - /// An extension for the NetworkManager that displays a default HUD for controlling the network state of the game. - /// This component also shows useful internal state for the networking system in the inspector window of the editor. It allows users to view connections, networked objects, message handlers, and packet statistics. This information can be helpful when debugging networked games. - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkManagerHUD")] - [RequireComponent(typeof(NetworkManager))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkManagerHUD.html")] - public class NetworkManagerHUD : MonoBehaviour - { - NetworkManager manager; - - /// - /// Whether to show the default control HUD at runtime. - /// - public bool showGUI = true; - - /// - /// The horizontal offset in pixels to draw the HUD runtime GUI at. - /// - public int offsetX; - - /// - /// The vertical offset in pixels to draw the HUD runtime GUI at. - /// - public int offsetY; - - void Awake() - { - manager = GetComponent(); - } - - void OnGUI() - { - if (!showGUI) - return; - - GUILayout.BeginArea(new Rect(10 + offsetX, 40 + offsetY, 215, 9999)); - if (!NetworkClient.isConnected && !NetworkServer.active) - { - StartButtons(); - } - else - { - StatusLabels(); - } - - // client ready - if (NetworkClient.isConnected && !ClientScene.ready) - { - if (GUILayout.Button("Client Ready")) - { - ClientScene.Ready(NetworkClient.connection); - - if (ClientScene.localPlayer == null) - { - ClientScene.AddPlayer(NetworkClient.connection); - } - } - } - - StopButtons(); - - GUILayout.EndArea(); - } - - void StartButtons() - { - if (!NetworkClient.active) - { - // Server + Client - if (Application.platform != RuntimePlatform.WebGLPlayer) - { - if (GUILayout.Button("Host (Server + Client)")) - { - manager.StartHost(); - } - } - - // Client + IP - GUILayout.BeginHorizontal(); - if (GUILayout.Button("Client")) - { - manager.StartClient(); - } - manager.networkAddress = GUILayout.TextField(manager.networkAddress); - GUILayout.EndHorizontal(); - - // Server Only - if (Application.platform == RuntimePlatform.WebGLPlayer) - { - // cant be a server in webgl build - GUILayout.Box("( WebGL cannot be server )"); - } - else - { - if (GUILayout.Button("Server Only")) manager.StartServer(); - } - } - else - { - // Connecting - GUILayout.Label("Connecting to " + manager.networkAddress + ".."); - if (GUILayout.Button("Cancel Connection Attempt")) - { - manager.StopClient(); - } - } - } - - void StatusLabels() - { - // server / client status message - if (NetworkServer.active) - { - GUILayout.Label("Server: active. Transport: " + Transport.activeTransport); - } - if (NetworkClient.isConnected) - { - GUILayout.Label("Client: address=" + manager.networkAddress); - } - } - - void StopButtons() - { - // stop host if host mode - if (NetworkServer.active && NetworkClient.isConnected) - { - if (GUILayout.Button("Stop Host")) - { - manager.StopHost(); - } - } - // stop client if client-only - else if (NetworkClient.isConnected) - { - if (GUILayout.Button("Stop Client")) - { - manager.StopClient(); - } - } - // stop server if server-only - else if (NetworkServer.active) - { - if (GUILayout.Button("Stop Server")) - { - manager.StopServer(); - } - } - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkManagerHUD.cs.meta b/Assets/Mirror/Runtime/NetworkManagerHUD.cs.meta deleted file mode 100644 index a720b9c..0000000 --- a/Assets/Mirror/Runtime/NetworkManagerHUD.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6442dc8070ceb41f094e44de0bf87274 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkMessage.cs b/Assets/Mirror/Runtime/NetworkMessage.cs deleted file mode 100644 index 300b10e..0000000 --- a/Assets/Mirror/Runtime/NetworkMessage.cs +++ /dev/null @@ -1 +0,0 @@ -// file removed 03/17/2020 diff --git a/Assets/Mirror/Runtime/NetworkMessage.cs.meta b/Assets/Mirror/Runtime/NetworkMessage.cs.meta deleted file mode 100644 index 370b0a6..0000000 --- a/Assets/Mirror/Runtime/NetworkMessage.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: eb04e4848a2e4452aa2dbd7adb801c51 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkReader.cs b/Assets/Mirror/Runtime/NetworkReader.cs deleted file mode 100644 index 09f2d5c..0000000 --- a/Assets/Mirror/Runtime/NetworkReader.cs +++ /dev/null @@ -1,426 +0,0 @@ -// Custom NetworkReader that doesn't use C#'s built in MemoryStream in order to -// avoid allocations. -// -// Benchmark: 100kb byte[] passed to NetworkReader constructor 1000x -// before with MemoryStream -// 0.8% CPU time, 250KB memory, 3.82ms -// now: -// 0.0% CPU time, 32KB memory, 0.02ms -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using UnityEngine; - -namespace Mirror -{ - /// - /// a class that holds readers for the different types - /// Note that c# creates a different static variable for each - /// type - /// This will be populated by the weaver - /// - /// - public static class Reader - { - public static Func read; - } - - // Note: This class is intended to be extremely pedantic, and - // throw exceptions whenever stuff is going slightly wrong. - // The exceptions will be handled in NetworkServer/NetworkClient. - /// - /// Binary stream Reader. Supports simple types, buffers, arrays, structs, and nested types - /// Use NetworkReaderPool.GetReader to reduce memory allocation - /// - public class NetworkReader - { - // internal buffer - // byte[] pointer would work, but we use ArraySegment to also support - // the ArraySegment constructor - internal ArraySegment buffer; - - // 'int' is the best type for .Position. 'short' is too small if we send >32kb which would result in negative .Position - // -> converting long to int is fine until 2GB of data (MAX_INT), so we don't have to worry about overflows here - public int Position; - public int Length => buffer.Count; - - public NetworkReader(byte[] bytes) - { - buffer = new ArraySegment(bytes); - } - - public NetworkReader(ArraySegment segment) - { - buffer = segment; - } - - public byte ReadByte() - { - if (Position + 1 > buffer.Count) - { - throw new EndOfStreamException("ReadByte out of range:" + ToString()); - } - return buffer.Array[buffer.Offset + Position++]; - } - public int ReadInt32() => (int)ReadUInt32(); - public uint ReadUInt32() - { - uint value = 0; - value |= ReadByte(); - value |= (uint)(ReadByte() << 8); - value |= (uint)(ReadByte() << 16); - value |= (uint)(ReadByte() << 24); - return value; - } - public long ReadInt64() => (long)ReadUInt64(); - public ulong ReadUInt64() - { - ulong value = 0; - value |= ReadByte(); - value |= ((ulong)ReadByte()) << 8; - value |= ((ulong)ReadByte()) << 16; - value |= ((ulong)ReadByte()) << 24; - value |= ((ulong)ReadByte()) << 32; - value |= ((ulong)ReadByte()) << 40; - value |= ((ulong)ReadByte()) << 48; - value |= ((ulong)ReadByte()) << 56; - return value; - } - - // read bytes into the passed buffer - public byte[] ReadBytes(byte[] bytes, int count) - { - // check if passed byte array is big enough - if (count > bytes.Length) - { - throw new EndOfStreamException("ReadBytes can't read " + count + " + bytes because the passed byte[] only has length " + bytes.Length); - } - - ArraySegment data = ReadBytesSegment(count); - Array.Copy(data.Array, data.Offset, bytes, 0, count); - return bytes; - } - - // useful to parse payloads etc. without allocating - public ArraySegment ReadBytesSegment(int count) - { - // check if within buffer limits - if (Position + count > buffer.Count) - { - throw new EndOfStreamException("ReadBytesSegment can't read " + count + " bytes because it would read past the end of the stream. " + ToString()); - } - - // return the segment - ArraySegment result = new ArraySegment(buffer.Array, buffer.Offset + Position, count); - Position += count; - return result; - } - - public override string ToString() - { - return "NetworkReader pos=" + Position + " len=" + Length + " buffer=" + BitConverter.ToString(buffer.Array, buffer.Offset, buffer.Count); - } - - /// - /// Reads any data type that mirror supports - /// - /// - /// - public T Read() - { - return Reader.read(this); - } - } - - // Mirror's Weaver automatically detects all NetworkReader function types, - // but they do all need to be extensions. - public static class NetworkReaderExtensions - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkReaderExtensions)); - - // cache encoding instead of creating it each time - // 1000 readers before: 1MB GC, 30ms - // 1000 readers after: 0.8MB GC, 18ms - static readonly UTF8Encoding encoding = new UTF8Encoding(false, true); - - public static byte ReadByte(this NetworkReader reader) => reader.ReadByte(); - public static sbyte ReadSByte(this NetworkReader reader) => (sbyte)reader.ReadByte(); - public static char ReadChar(this NetworkReader reader) => (char)reader.ReadUInt16(); - public static bool ReadBoolean(this NetworkReader reader) => reader.ReadByte() != 0; - public static short ReadInt16(this NetworkReader reader) => (short)reader.ReadUInt16(); - public static ushort ReadUInt16(this NetworkReader reader) - { - ushort value = 0; - value |= reader.ReadByte(); - value |= (ushort)(reader.ReadByte() << 8); - return value; - } - public static int ReadInt32(this NetworkReader reader) => (int)reader.ReadUInt32(); - public static uint ReadUInt32(this NetworkReader reader) - { - uint value = 0; - value |= reader.ReadByte(); - value |= (uint)(reader.ReadByte() << 8); - value |= (uint)(reader.ReadByte() << 16); - value |= (uint)(reader.ReadByte() << 24); - return value; - } - public static long ReadInt64(this NetworkReader reader) => (long)reader.ReadUInt64(); - public static ulong ReadUInt64(this NetworkReader reader) - { - ulong value = 0; - value |= reader.ReadByte(); - value |= ((ulong)reader.ReadByte()) << 8; - value |= ((ulong)reader.ReadByte()) << 16; - value |= ((ulong)reader.ReadByte()) << 24; - value |= ((ulong)reader.ReadByte()) << 32; - value |= ((ulong)reader.ReadByte()) << 40; - value |= ((ulong)reader.ReadByte()) << 48; - value |= ((ulong)reader.ReadByte()) << 56; - return value; - } - public static float ReadSingle(this NetworkReader reader) - { - UIntFloat converter = new UIntFloat(); - converter.intValue = reader.ReadUInt32(); - return converter.floatValue; - } - public static double ReadDouble(this NetworkReader reader) - { - UIntDouble converter = new UIntDouble(); - converter.longValue = reader.ReadUInt64(); - return converter.doubleValue; - } - public static decimal ReadDecimal(this NetworkReader reader) - { - UIntDecimal converter = new UIntDecimal(); - converter.longValue1 = reader.ReadUInt64(); - converter.longValue2 = reader.ReadUInt64(); - return converter.decimalValue; - } - - // note: this will throw an ArgumentException if an invalid utf8 string is sent - // null support, see NetworkWriter - public static string ReadString(this NetworkReader reader) - { - // read number of bytes - ushort size = reader.ReadUInt16(); - - if (size == 0) - return null; - - int realSize = size - 1; - - // make sure it's within limits to avoid allocation attacks etc. - if (realSize >= NetworkWriter.MaxStringLength) - { - throw new EndOfStreamException("ReadString too long: " + realSize + ". Limit is: " + NetworkWriter.MaxStringLength); - } - - ArraySegment data = reader.ReadBytesSegment(realSize); - - // convert directly from buffer to string via encoding - return encoding.GetString(data.Array, data.Offset, data.Count); - } - - // Use checked() to force it to throw OverflowException if data is invalid - // null support, see NetworkWriter - public static byte[] ReadBytesAndSize(this NetworkReader reader) - { - // count = 0 means the array was null - // otherwise count -1 is the length of the array - uint count = reader.ReadPackedUInt32(); - return count == 0 ? null : reader.ReadBytes(checked((int)(count - 1u))); - } - - public static ArraySegment ReadBytesAndSizeSegment(this NetworkReader reader) - { - // count = 0 means the array was null - // otherwise count - 1 is the length of the array - uint count = reader.ReadPackedUInt32(); - return count == 0 ? default : reader.ReadBytesSegment(checked((int)(count - 1u))); - } - - // zigzag decoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba - public static int ReadPackedInt32(this NetworkReader reader) - { - uint data = reader.ReadPackedUInt32(); - return (int)((data >> 1) ^ -(data & 1)); - } - - // http://sqlite.org/src4/doc/trunk/www/varint.wiki - // NOTE: big endian. - // Use checked() to force it to throw OverflowException if data is invalid - public static uint ReadPackedUInt32(this NetworkReader reader) => checked((uint)reader.ReadPackedUInt64()); - - // zigzag decoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba - public static long ReadPackedInt64(this NetworkReader reader) - { - ulong data = reader.ReadPackedUInt64(); - return ((long)(data >> 1)) ^ -((long)data & 1); - } - - public static ulong ReadPackedUInt64(this NetworkReader reader) - { - byte a0 = reader.ReadByte(); - if (a0 < 241) - { - return a0; - } - - byte a1 = reader.ReadByte(); - if (a0 >= 241 && a0 <= 248) - { - return 240 + ((a0 - (ulong)241) << 8) + a1; - } - - byte a2 = reader.ReadByte(); - if (a0 == 249) - { - return 2288 + ((ulong)a1 << 8) + a2; - } - - byte a3 = reader.ReadByte(); - if (a0 == 250) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16); - } - - byte a4 = reader.ReadByte(); - if (a0 == 251) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24); - } - - byte a5 = reader.ReadByte(); - if (a0 == 252) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32); - } - - byte a6 = reader.ReadByte(); - if (a0 == 253) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40); - } - - byte a7 = reader.ReadByte(); - if (a0 == 254) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48); - } - - byte a8 = reader.ReadByte(); - if (a0 == 255) - { - return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48) + (((ulong)a8) << 56); - } - - throw new IndexOutOfRangeException("ReadPackedUInt64() failure: " + a0); - } - - public static Vector2 ReadVector2(this NetworkReader reader) => new Vector2(reader.ReadSingle(), reader.ReadSingle()); - public static Vector3 ReadVector3(this NetworkReader reader) => new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - public static Vector4 ReadVector4(this NetworkReader reader) => new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - public static Vector2Int ReadVector2Int(this NetworkReader reader) => new Vector2Int(reader.ReadPackedInt32(), reader.ReadPackedInt32()); - public static Vector3Int ReadVector3Int(this NetworkReader reader) => new Vector3Int(reader.ReadPackedInt32(), reader.ReadPackedInt32(), reader.ReadPackedInt32()); - public static Color ReadColor(this NetworkReader reader) => new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - public static Color32 ReadColor32(this NetworkReader reader) => new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); - public static Quaternion ReadQuaternion(this NetworkReader reader) => new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - public static Rect ReadRect(this NetworkReader reader) => new Rect(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - public static Plane ReadPlane(this NetworkReader reader) => new Plane(reader.ReadVector3(), reader.ReadSingle()); - public static Ray ReadRay(this NetworkReader reader) => new Ray(reader.ReadVector3(), reader.ReadVector3()); - - public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) - { - return new Matrix4x4 - { - m00 = reader.ReadSingle(), - m01 = reader.ReadSingle(), - m02 = reader.ReadSingle(), - m03 = reader.ReadSingle(), - m10 = reader.ReadSingle(), - m11 = reader.ReadSingle(), - m12 = reader.ReadSingle(), - m13 = reader.ReadSingle(), - m20 = reader.ReadSingle(), - m21 = reader.ReadSingle(), - m22 = reader.ReadSingle(), - m23 = reader.ReadSingle(), - m30 = reader.ReadSingle(), - m31 = reader.ReadSingle(), - m32 = reader.ReadSingle(), - m33 = reader.ReadSingle() - }; - } - - public static byte[] ReadBytes(this NetworkReader reader, int count) - { - byte[] bytes = new byte[count]; - reader.ReadBytes(bytes, count); - return bytes; - } - - public static Guid ReadGuid(this NetworkReader reader) => new Guid(reader.ReadBytes(16)); - public static Transform ReadTransform(this NetworkReader reader) - { - // Dont use null propagation here as it could lead to MissingReferenceException - NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); - return networkIdentity != null ? networkIdentity.transform : null; - } - - public static GameObject ReadGameObject(this NetworkReader reader) - { - // Dont use null propagation here as it could lead to MissingReferenceException - NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); - return networkIdentity != null ? networkIdentity.gameObject : null; - } - - public static NetworkIdentity ReadNetworkIdentity(this NetworkReader reader) - { - uint netId = reader.ReadPackedUInt32(); - if (netId == 0) - return null; - - if (NetworkIdentity.spawned.TryGetValue(netId, out NetworkIdentity identity)) - { - return identity; - } - - if (logger.WarnEnabled()) logger.LogFormat(LogType.Warning, "ReadNetworkIdentity netId:{0} not found in spawned", netId); - return null; - } - - public static List ReadList(this NetworkReader reader) - { - int length = reader.ReadPackedInt32(); - if (length < 0) - return null; - List result = new List(length); - for (int i = 0; i < length; i++) - { - result.Add(reader.Read()); - } - return result; - } - - public static T[] ReadArray(this NetworkReader reader) - { - int length = reader.ReadPackedInt32(); - if (length < 0) - return null; - T[] result = new T[length]; - for (int i = 0; i < length; i++) - { - result[i] = reader.Read(); - } - return result; - } - - public static Uri ReadUri(this NetworkReader reader) - { - return new Uri(reader.ReadString()); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkReader.cs.meta b/Assets/Mirror/Runtime/NetworkReader.cs.meta deleted file mode 100644 index f5b0c1e..0000000 --- a/Assets/Mirror/Runtime/NetworkReader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1610f05ec5bd14d6882e689f7372596a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkReaderPool.cs b/Assets/Mirror/Runtime/NetworkReaderPool.cs deleted file mode 100644 index 4c80a6a..0000000 --- a/Assets/Mirror/Runtime/NetworkReaderPool.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// NetworkReader to be used with NetworkReaderPool - /// - public class PooledNetworkReader : NetworkReader, IDisposable - { - internal PooledNetworkReader(byte[] bytes) : base(bytes) { } - - internal PooledNetworkReader(ArraySegment segment) : base(segment) { } - - public void Dispose() - { - NetworkReaderPool.Recycle(this); - } - } - - /// - /// Pool of NetworkReaders - /// Use this pool instead of NetworkReader to reduce memory allocation - /// Use Capacity to change size of pool - /// - public static class NetworkReaderPool - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkReaderPool), LogType.Error); - - /// - /// Size of the pool - /// If pool is too small getting readers will causes memory allocation - /// Default value: 100 - /// - public static int Capacity - { - get => pool.Length; - set - { - // resize the array - Array.Resize(ref pool, value); - - // if capacity is smaller than before, then we need to adjust - // 'next' so it doesn't point to an index out of range - // -> if we set '0' then next = min(_, 0-1) => -1 - // -> if we set '2' then next = min(_, 2-1) => 1 - next = Mathf.Min(next, pool.Length - 1); - } - } - - /// - /// Mirror usually only uses up to 4 readers in nested usings, - /// 100 is a good margin for edge cases when users need a lot readers at - /// the same time. - /// - /// keep in mind, most entries of the pool will be null in most cases - /// - /// - /// Note: we use an Array instead of a Stack because it's significantly - /// faster: https://github.com/vis2k/Mirror/issues/1614 - static PooledNetworkReader[] pool = new PooledNetworkReader[100]; - - static int next = -1; - - /// - /// Get the next reader in the pool - /// If pool is empty, creates a new Reader - /// - public static PooledNetworkReader GetReader(byte[] bytes) - { - if (next == -1) - { - return new PooledNetworkReader(bytes); - } - - PooledNetworkReader reader = pool[next]; - pool[next] = null; - next--; - - // reset buffer - SetBuffer(reader, bytes); - return reader; - } - - /// - /// Get the next reader in the pool - /// If pool is empty, creates a new Reader - /// - public static PooledNetworkReader GetReader(ArraySegment segment) - { - if (next == -1) - { - return new PooledNetworkReader(segment); - } - - PooledNetworkReader reader = pool[next]; - pool[next] = null; - next--; - - // reset buffer - SetBuffer(reader, segment); - return reader; - } - - /// - /// Puts reader back into pool - /// When pool is full, the extra reader is left for the GC - /// - public static void Recycle(PooledNetworkReader reader) - { - if (next < pool.Length - 1) - { - next++; - pool[next] = reader; - } - else - { - logger.LogWarning("NetworkReaderPool.Recycle, Pool was full leaving extra reader for GC"); - } - } - - // SetBuffer methods mirror constructor for ReaderPool - static void SetBuffer(NetworkReader reader, byte[] bytes) - { - reader.buffer = new ArraySegment(bytes); - reader.Position = 0; - } - - static void SetBuffer(NetworkReader reader, ArraySegment segment) - { - reader.buffer = segment; - reader.Position = 0; - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta b/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta deleted file mode 100644 index a1ef25e..0000000 --- a/Assets/Mirror/Runtime/NetworkReaderPool.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2bacff63613ad634a98f9e4d15d29dbf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkServer.cs b/Assets/Mirror/Runtime/NetworkServer.cs deleted file mode 100644 index 498db68..0000000 --- a/Assets/Mirror/Runtime/NetworkServer.cs +++ /dev/null @@ -1,1306 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Mirror.RemoteCalls; -using UnityEngine; - -namespace Mirror -{ - /// - /// The NetworkServer. - /// - /// - /// NetworkServer handles remote connections from remote clients via a NetworkServerSimple instance, and also has a local connection for a local client. - /// The NetworkServer is a singleton. It has static convenience functions such as NetworkServer.SendToAll() and NetworkServer.Spawn() which automatically use the singleton instance. - /// The NetworkManager uses the NetworkServer, but it can be used without the NetworkManager. - /// The set of networked objects that have been spawned is managed by NetworkServer. Objects are spawned with NetworkServer.Spawn() which adds them to this set, and makes them be created on clients. Spawned objects are removed automatically when they are destroyed, or than they can be removed from the spawned set by calling NetworkServer.UnSpawn() - this does not destroy the object. - /// There are a number of internal messages used by NetworkServer, these are setup when NetworkServer.Listen() is called. - /// - public static class NetworkServer - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkServer)); - - static bool initialized; - static int maxConnections; - - /// - /// The connection to the host mode client (if any). - /// - public static NetworkConnectionToClient localConnection { get; private set; } - - /// - /// True is a local client is currently active on the server. - /// This will be true for "Hosts" on hosted server games. - /// - public static bool localClientActive => localConnection != null; - - /// - /// A list of local connections on the server. - /// - public static Dictionary connections = new Dictionary(); - - /// - /// Dictionary of the message handlers registered with the server. - /// The key to the dictionary is the message Id. - /// - static Dictionary handlers = new Dictionary(); - - /// - /// If you enable this, the server will not listen for incoming connections on the regular network port. - /// This can be used if the game is running in host mode and does not want external players to be able to connect - making it like a single-player game. Also this can be useful when using AddExternalConnection(). - /// - public static bool dontListen; - - /// - /// Checks if the server has been started. - /// This will be true after NetworkServer.Listen() has been called. - /// - public static bool active { get; internal set; } - - /// - /// Should the server disconnect remote connections that have gone silent for more than Server Idle Timeout? - /// This value is initially set from NetworkManager in SetupServer and can be changed at runtime - /// - public static bool disconnectInactiveConnections; - - /// - /// Timeout in seconds since last message from a client after which server will auto-disconnect. - /// This value is initially set from NetworkManager in SetupServer and can be changed at runtime - /// By default, clients send at least a Ping message every 2 seconds. - /// The Host client is immune from idle timeout disconnection. - /// Default value is 60 seconds. - /// - public static float disconnectInactiveTimeout = 60f; - - /// - /// This shuts down the server and disconnects all clients. - /// - public static void Shutdown() - { - if (initialized) - { - DisconnectAll(); - - if (!dontListen) - { - // stop the server. - // we do NOT call Transport.Shutdown, because someone only - // called NetworkServer.Shutdown. we can't assume that the - // client is supposed to be shut down too! - Transport.activeTransport.ServerStop(); - } - - Transport.activeTransport.OnServerDisconnected.RemoveListener(OnDisconnected); - Transport.activeTransport.OnServerConnected.RemoveListener(OnConnected); - Transport.activeTransport.OnServerDataReceived.RemoveListener(OnDataReceived); - Transport.activeTransport.OnServerError.RemoveListener(OnError); - - initialized = false; - } - dontListen = false; - active = false; - handlers.Clear(); - - CleanupNetworkIdentities(); - NetworkIdentity.ResetNextNetworkId(); - } - - static void CleanupNetworkIdentities() - { - foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values) - { - if (identity != null) - { - if (identity.sceneId != 0) - { - identity.Reset(); - identity.gameObject.SetActive(false); - } - else - { - GameObject.Destroy(identity.gameObject); - } - } - } - - NetworkIdentity.spawned.Clear(); - } - - static void Initialize() - { - if (initialized) - return; - - initialized = true; - if (logger.LogEnabled()) logger.Log("NetworkServer Created version " + Version.Current); - - //Make sure connections are cleared in case any old connections references exist from previous sessions - connections.Clear(); - - logger.Assert(Transport.activeTransport != null, "There was no active transport when calling NetworkServer.Listen, If you are calling Listen manually then make sure to set 'Transport.activeTransport' first"); - Transport.activeTransport.OnServerDisconnected.AddListener(OnDisconnected); - Transport.activeTransport.OnServerConnected.AddListener(OnConnected); - Transport.activeTransport.OnServerDataReceived.AddListener(OnDataReceived); - Transport.activeTransport.OnServerError.AddListener(OnError); - } - - internal static void RegisterMessageHandlers() - { - RegisterHandler(OnClientReadyMessage); - RegisterHandler(OnCommandMessage); - RegisterHandler(NetworkTime.OnServerPing, false); - } - - /// - /// Start the server, setting the maximum number of connections. - /// - /// Maximum number of allowed connections - public static void Listen(int maxConns) - { - Initialize(); - maxConnections = maxConns; - - // only start server if we want to listen - if (!dontListen) - { - Transport.activeTransport.ServerStart(); - logger.Log("Server started listening"); - } - - active = true; - RegisterMessageHandlers(); - } - - /// - /// This accepts a network connection and adds it to the server. - /// This connection will use the callbacks registered with the server. - /// - /// Network connection to add. - /// True if added. - public static bool AddConnection(NetworkConnectionToClient conn) - { - if (!connections.ContainsKey(conn.connectionId)) - { - // connection cannot be null here or conn.connectionId - // would throw NRE - connections[conn.connectionId] = conn; - conn.SetHandlers(handlers); - return true; - } - // already a connection with this id - return false; - } - - /// - /// This removes an external connection added with AddExternalConnection(). - /// - /// The id of the connection to remove. - /// True if the removal succeeded - public static bool RemoveConnection(int connectionId) - { - return connections.Remove(connectionId); - } - - /// - /// called by LocalClient to add itself. dont call directly. - /// - /// - internal static void SetLocalConnection(ULocalConnectionToClient conn) - { - if (localConnection != null) - { - logger.LogError("Local Connection already exists"); - return; - } - - localConnection = conn; - } - - internal static void RemoveLocalConnection() - { - if (localConnection != null) - { - localConnection.Disconnect(); - localConnection = null; - } - RemoveConnection(0); - } - - public static void ActivateHostScene() - { - foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values) - { - if (!identity.isClient) - { - if (logger.LogEnabled()) logger.Log("ActivateHostScene " + identity.netId + " " + identity); - - identity.OnStartClient(); - } - } - } - - - /// - /// this is like SendToReady - but it doesn't check the ready flag on the connection. - /// this is used for ObjectDestroy messages. - /// - /// - /// - /// - /// - static void SendToObservers(NetworkIdentity identity, T msg, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - if (logger.LogEnabled()) logger.Log("Server.SendToObservers id:" + typeof(T)); - - if (identity == null || identity.observers == null || identity.observers.Count == 0) - return; - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - // pack message into byte[] once - MessagePacker.Pack(msg, writer); - ArraySegment segment = writer.ToArraySegment(); - - foreach (NetworkConnection conn in identity.observers.Values) - { - // use local connection directly because it doesn't send via transport - if (conn is ULocalConnectionToClient) - conn.Send(segment); - // send to regular connection - else - conn.Send(segment, channelId); - } - - NetworkDiagnostics.OnSend(msg, channelId, segment.Count, identity.observers.Count); - } - } - - /// - /// Send a message to all connected clients, both ready and not-ready. - /// See NetworkConnection.isReady - /// - /// Message type - /// Message - /// Transport channel to use - /// Indicates if only ready clients should receive the message - public static void SendToAll(T msg, int channelId = Channels.DefaultReliable, bool sendToReadyOnly = false) where T : NetworkMessage - { - if (!active) - { - logger.LogWarning("Can not send using NetworkServer.SendToAll(T msg) because NetworkServer is not active"); - return; - } - - if (logger.LogEnabled()) logger.Log("Server.SendToAll id:" + typeof(T)); - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - // pack message only once - MessagePacker.Pack(msg, writer); - ArraySegment segment = writer.ToArraySegment(); - - // filter and then send to all internet connections at once - // -> makes code more complicated, but is HIGHLY worth it to - // avoid allocations, allow for multicast, etc. - int count = 0; - foreach (NetworkConnectionToClient conn in connections.Values) - { - if (sendToReadyOnly && !conn.isReady) - continue; - - count++; - - // use local connection directly because it doesn't send via transport - if (conn is ULocalConnectionToClient) - conn.Send(segment); - // send to regular connection - else - conn.Send(segment, channelId); - } - - NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count); - } - } - - /// - /// Send a message to only clients which are ready. - /// See NetworkConnection.isReady - /// - /// Message type. - /// Message - /// Transport channel to use - public static void SendToReady(T msg, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - if (!active) - { - logger.LogWarning("Can not send using NetworkServer.SendToReady(T msg) because NetworkServer is not active"); - return; - } - - SendToAll(msg, channelId, true); - } - - /// - /// Send a message to only clients which are ready with option to include the owner of the object identity. - /// See NetworkConnection.isReady - /// - /// Message type. - /// Identity of the owner - /// Message - /// Should the owner of the object be included - /// Transport channel to use - public static void SendToReady(NetworkIdentity identity, T msg, bool includeOwner = true, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - if (logger.LogEnabled()) logger.Log("Server.SendToReady msgType:" + typeof(T)); - - if (identity == null || identity.observers == null || identity.observers.Count == 0) - return; - - using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) - { - // pack message only once - MessagePacker.Pack(msg, writer); - ArraySegment segment = writer.ToArraySegment(); - - int count = 0; - foreach (NetworkConnection conn in identity.observers.Values) - { - bool isOwner = conn == identity.connectionToClient; - if ((!isOwner || includeOwner) && conn.isReady) - { - count++; - - // use local connection directly because it doesn't send via transport - if (conn is ULocalConnectionToClient) - conn.Send(segment); - // send to connection - else - conn.Send(segment, channelId); - } - } - - NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count); - } - } - - /// - /// Send a message to only clients which are ready including the owner of the object identity. - /// See NetworkConnection.isReady - /// - /// Message type - /// identity of the object - /// Message - /// Transport channel to use - public static void SendToReady(NetworkIdentity identity, T msg, int channelId) where T : NetworkMessage - { - SendToReady(identity, msg, true, channelId); - } - - /// - /// Disconnect all currently connected clients, including the local connection. - /// This can only be called on the server. Clients will receive the Disconnect message. - /// - public static void DisconnectAll() - { - DisconnectAllConnections(); - localConnection = null; - - active = false; - } - - /// - /// Disconnect all currently connected clients except the local connection. - /// This can only be called on the server. Clients will receive the Disconnect message. - /// - public static void DisconnectAllConnections() - { - // disconnect and remove all connections. - // we can not use foreach here because if - // conn.Disconnect -> Transport.ServerDisconnect calls - // OnDisconnect -> NetworkServer.OnDisconnect(connectionId) - // immediately then OnDisconnect would remove the connection while - // we are iterating here. - // see also: https://github.com/vis2k/Mirror/issues/2357 - // this whole process should be simplified some day. - // until then, let's copy .Values to avoid InvalidOperatinException. - // note that this is only called when stopping the server, so the - // copy is no performance problem. - foreach (NetworkConnection conn in connections.Values.ToList()) - { - conn.Disconnect(); - // call OnDisconnected unless local player in host mode - if (conn.connectionId != NetworkConnection.LocalConnectionId) - OnDisconnected(conn); - } - connections.Clear(); - } - - /// - /// If connections is empty or if only has host - /// - /// - public static bool NoConnections() - { - return connections.Count == 0 || (connections.Count == 1 && localConnection != null); - } - - /// - /// Called from NetworkManager in LateUpdate - /// The user should never need to pump the update loop manually - /// - public static void Update() - { - // dont need to update server if not active - if (!active) - return; - - // Check for dead clients but exclude the host client because it - // doesn't ping itself and therefore may appear inactive. - CheckForInavtiveConnections(); - - // update all server objects - foreach (KeyValuePair kvp in NetworkIdentity.spawned) - { - NetworkIdentity identity = kvp.Value; - if (identity != null) - { - identity.ServerUpdate(); - } - else - { - // spawned list should have no null entries because we - // always call Remove in OnObjectDestroy everywhere. - logger.LogWarning("Found 'null' entry in spawned list for netId=" + kvp.Key + ". Please call NetworkServer.Destroy to destroy networked objects. Don't use GameObject.Destroy."); - } - } - } - - static void CheckForInavtiveConnections() - { - if (!disconnectInactiveConnections) - return; - - foreach (NetworkConnectionToClient conn in connections.Values) - { - if (!conn.IsAlive(disconnectInactiveTimeout)) - { - logger.LogWarning($"Disconnecting {conn} for inactivity!"); - conn.Disconnect(); - } - } - } - - static void OnConnected(int connectionId) - { - if (logger.LogEnabled()) logger.Log("Server accepted client:" + connectionId); - - // connectionId needs to be > 0 because 0 is reserved for local player - if (connectionId <= 0) - { - logger.LogError("Server.HandleConnect: invalid connectionId: " + connectionId + " . Needs to be >0, because 0 is reserved for local player."); - Transport.activeTransport.ServerDisconnect(connectionId); - return; - } - - // connectionId not in use yet? - if (connections.ContainsKey(connectionId)) - { - Transport.activeTransport.ServerDisconnect(connectionId); - if (logger.LogEnabled()) logger.Log("Server connectionId " + connectionId + " already in use. kicked client:" + connectionId); - return; - } - - // are more connections allowed? if not, kick - // (it's easier to handle this in Mirror, so Transports can have - // less code and third party transport might not do that anyway) - // (this way we could also send a custom 'tooFull' message later, - // Transport can't do that) - if (connections.Count < maxConnections) - { - // add connection - NetworkConnectionToClient conn = new NetworkConnectionToClient(connectionId); - OnConnected(conn); - } - else - { - // kick - Transport.activeTransport.ServerDisconnect(connectionId); - if (logger.LogEnabled()) logger.Log("Server full, kicked client:" + connectionId); - } - } - - internal static void OnConnected(NetworkConnectionToClient conn) - { - if (logger.LogEnabled()) logger.Log("Server accepted client:" + conn); - - // add connection and invoke connected event - AddConnection(conn); - conn.InvokeHandler(new ConnectMessage(), -1); - } - - internal static void OnDisconnected(int connectionId) - { - if (logger.LogEnabled()) logger.Log("Server disconnect client:" + connectionId); - - if (connections.TryGetValue(connectionId, out NetworkConnectionToClient conn)) - { - conn.Disconnect(); - RemoveConnection(connectionId); - if (logger.LogEnabled()) logger.Log("Server lost client:" + connectionId); - - OnDisconnected(conn); - } - } - - static void OnDisconnected(NetworkConnection conn) - { - conn.InvokeHandler(new DisconnectMessage(), -1); - if (logger.LogEnabled()) logger.Log("Server lost client:" + conn); - } - - static void OnDataReceived(int connectionId, ArraySegment data, int channelId) - { - if (connections.TryGetValue(connectionId, out NetworkConnectionToClient conn)) - { - conn.TransportReceive(data, channelId); - } - else - { - logger.LogError("HandleData Unknown connectionId:" + connectionId); - } - } - - static void OnError(int connectionId, Exception exception) - { - // TODO Let's discuss how we will handle errors - logger.LogException(exception); - } - - /// - /// Register a handler for a particular message type. - /// There are several system message types which you can add handlers for. You can also add your own message types. - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - int msgType = MessagePacker.GetId(); - if (handlers.ContainsKey(msgType)) - { - logger.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); - } - handlers[msgType] = MessagePacker.MessageHandler(handler, requireAuthentication); - } - - /// - /// Register a handler for a particular message type. - /// There are several system message types which you can add handlers for. You can also add your own message types. - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void RegisterHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - RegisterHandler((_, value) => { handler(value); }, requireAuthentication); - } - - /// - /// Replaces a handler for a particular message type. - /// See also RegisterHandler(T)(Action(NetworkConnection, T), bool) - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - int msgType = MessagePacker.GetId(); - handlers[msgType] = MessagePacker.MessageHandler(handler, requireAuthentication); - } - - /// - /// Replaces a handler for a particular message type. - /// See also RegisterHandler(T)(Action(NetworkConnection, T), bool) - /// - /// Message type - /// Function handler which will be invoked when this message type is received. - /// True if the message requires an authenticated connection - public static void ReplaceHandler(Action handler, bool requireAuthentication = true) where T : NetworkMessage - { - ReplaceHandler((_, value) => { handler(value); }, requireAuthentication); - } - - /// - /// Unregisters a handler for a particular message type. - /// - /// Message type - public static void UnregisterHandler() where T : NetworkMessage - { - int msgType = MessagePacker.GetId(); - handlers.Remove(msgType); - } - - /// - /// Clear all registered callback handlers. - /// - public static void ClearHandlers() - { - handlers.Clear(); - } - - /// - /// send this message to the player only - /// - /// Message type - /// - /// - public static void SendToClientOfPlayer(NetworkIdentity identity, T msg, int channelId = Channels.DefaultReliable) where T : NetworkMessage - { - if (identity != null) - { - identity.connectionToClient.Send(msg, channelId); - } - else - { - logger.LogError("SendToClientOfPlayer: player has no NetworkIdentity: " + identity); - } - } - - /// - /// This replaces the player object for a connection with a different player object. The old player object is not destroyed. - /// If a connection already has a player object, this can be used to replace that object with a different player object. This does NOT change the ready state of the connection, so it can safely be used while changing scenes. - /// - /// Connection which is adding the player. - /// Player object spawned for the player. - /// - /// Does the previous player remain attached to this connection? - /// True if connection was successfully replaced for player. - public static bool ReplacePlayerForConnection(NetworkConnection conn, GameObject player, Guid assetId, bool keepAuthority = false) - { - if (GetNetworkIdentity(player, out NetworkIdentity identity)) - { - identity.assetId = assetId; - } - return InternalReplacePlayerForConnection(conn, player, keepAuthority); - } - - /// - /// This replaces the player object for a connection with a different player object. The old player object is not destroyed. - /// If a connection already has a player object, this can be used to replace that object with a different player object. This does NOT change the ready state of the connection, so it can safely be used while changing scenes. - /// - /// Connection which is adding the player. - /// Player object spawned for the player. - /// Does the previous player remain attached to this connection? - /// True if connection was successfully replaced for player. - public static bool ReplacePlayerForConnection(NetworkConnection conn, GameObject player, bool keepAuthority = false) - { - return InternalReplacePlayerForConnection(conn, player, keepAuthority); - } - - /// - /// When an AddPlayer message handler has received a request from a player, the server calls this to associate the player object with the connection. - /// When a player is added for a connection, the client for that connection is made ready automatically. The player object is automatically spawned, so you do not need to call NetworkServer.Spawn for that object. This function is used for "adding" a player, not for "replacing" the player on a connection. If there is already a player on this playerControllerId for this connection, this will fail. - /// - /// Connection which is adding the player. - /// Player object spawned for the player. - /// - /// True if connection was sucessfully added for a connection. - public static bool AddPlayerForConnection(NetworkConnection conn, GameObject player, Guid assetId) - { - if (GetNetworkIdentity(player, out NetworkIdentity identity)) - { - identity.assetId = assetId; - } - return AddPlayerForConnection(conn, player); - } - - static void SpawnObserversForConnection(NetworkConnection conn) - { - if (logger.LogEnabled()) logger.Log("Spawning " + NetworkIdentity.spawned.Count + " objects for conn " + conn); - - if (!conn.isReady) - { - // client needs to finish initializing before we can spawn objects - // otherwise it would not find them. - return; - } - - // let connection know that we are about to start spawning... - conn.Send(new ObjectSpawnStartedMessage()); - - // add connection to each nearby NetworkIdentity's observers, which - // internally sends a spawn message for each one to the connection. - foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values) - { - // try with far away ones in ummorpg! - if (identity.gameObject.activeSelf) //TODO this is different - { - if (logger.LogEnabled()) logger.Log("Sending spawn message for current server objects name='" + identity.name + "' netId=" + identity.netId + " sceneId=" + identity.sceneId.ToString("X")); - - bool visible = identity.OnCheckObserver(conn); - if (visible) - { - identity.AddObserver(conn); - } - } - } - - // let connection know that we finished spawning, so it can call - // OnStartClient on each one (only after all were spawned, which - // is how Unity's Start() function works too) - conn.Send(new ObjectSpawnFinishedMessage()); - } - - /// - /// When an AddPlayer message handler has received a request from a player, the server calls this to associate the player object with the connection. - /// When a player is added for a connection, the client for that connection is made ready automatically. The player object is automatically spawned, so you do not need to call NetworkServer.Spawn for that object. This function is used for "adding" a player, not for "replacing" the player on a connection. If there is already a player on this playerControllerId for this connection, this will fail. - /// - /// Connection which is adding the player. - /// Player object spawned for the player. - /// True if connection was successfully added for a connection. - public static bool AddPlayerForConnection(NetworkConnection conn, GameObject player) - { - NetworkIdentity identity = player.GetComponent(); - if (identity == null) - { - logger.LogWarning("AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to " + player); - return false; - } - - // cannot have a player object in "Add" version - if (conn.identity != null) - { - logger.Log("AddPlayer: player object already exists"); - return false; - } - - // make sure we have a controller before we call SetClientReady - // because the observers will be rebuilt only if we have a controller - conn.identity = identity; - - // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients) - identity.SetClientOwner(conn); - - // special case, we are in host mode, set hasAuthority to true so that all overrides see it - if (conn is ULocalConnectionToClient) - { - identity.hasAuthority = true; - ClientScene.InternalAddPlayer(identity); - } - - // set ready if not set yet - SetClientReady(conn); - - if (logger.LogEnabled()) logger.Log("Adding new playerGameObject object netId: " + identity.netId + " asset ID " + identity.assetId); - - Respawn(identity); - return true; - } - - static void Respawn(NetworkIdentity identity) - { - if (identity.netId == 0) - { - // If the object has not been spawned, then do a full spawn and update observers - Spawn(identity.gameObject, identity.connectionToClient); - } - else - { - // otherwise just replace his data - SendSpawnMessage(identity, identity.connectionToClient); - } - } - - internal static bool InternalReplacePlayerForConnection(NetworkConnection conn, GameObject player, bool keepAuthority) - { - NetworkIdentity identity = player.GetComponent(); - if (identity == null) - { - logger.LogError("ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to " + player); - return false; - } - - if (identity.connectionToClient != null && identity.connectionToClient != conn) - { - logger.LogError("Cannot replace player for connection. New player is already owned by a different connection" + player); - return false; - } - - //NOTE: there can be an existing player - logger.Log("NetworkServer ReplacePlayer"); - - NetworkIdentity previousPlayer = conn.identity; - - conn.identity = identity; - - // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients) - identity.SetClientOwner(conn); - - // special case, we are in host mode, set hasAuthority to true so that all overrides see it - if (conn is ULocalConnectionToClient) - { - identity.hasAuthority = true; - ClientScene.InternalAddPlayer(identity); - } - - // add connection to observers AFTER the playerController was set. - // by definition, there is nothing to observe if there is no player - // controller. - // - // IMPORTANT: do this in AddPlayerForConnection & ReplacePlayerForConnection! - SpawnObserversForConnection(conn); - - if (logger.LogEnabled()) logger.Log("Replacing playerGameObject object netId: " + player.GetComponent().netId + " asset ID " + player.GetComponent().assetId); - - Respawn(identity); - - if (!keepAuthority) - previousPlayer.RemoveClientAuthority(); - - return true; - } - - internal static bool GetNetworkIdentity(GameObject go, out NetworkIdentity identity) - { - identity = go.GetComponent(); - if (identity == null) - { - logger.LogError($"GameObject {go.name} doesn't have NetworkIdentity."); - return false; - } - return true; - } - - /// - /// Sets the client to be ready. - /// When a client has signaled that it is ready, this method tells the server that the client is ready to receive spawned objects and state synchronization updates. This is usually called in a handler for the SYSTEM_READY message. If there is not specific action a game needs to take for this message, relying on the default ready handler function is probably fine, so this call wont be needed. - /// - /// The connection of the client to make ready. - public static void SetClientReady(NetworkConnection conn) - { - if (logger.LogEnabled()) logger.Log("SetClientReadyInternal for conn:" + conn); - - // set ready - conn.isReady = true; - - // client is ready to start spawning objects - if (conn.identity != null) - SpawnObserversForConnection(conn); - } - - internal static void ShowForConnection(NetworkIdentity identity, NetworkConnection conn) - { - if (conn.isReady) - SendSpawnMessage(identity, conn); - } - - internal static void HideForConnection(NetworkIdentity identity, NetworkConnection conn) - { - ObjectHideMessage msg = new ObjectHideMessage - { - netId = identity.netId - }; - conn.Send(msg); - } - - /// - /// Marks all connected clients as no longer ready. - /// All clients will no longer be sent state synchronization updates. The player's clients can call ClientManager.Ready() again to re-enter the ready state. This is useful when switching scenes. - /// - public static void SetAllClientsNotReady() - { - foreach (NetworkConnection conn in connections.Values) - { - SetClientNotReady(conn); - } - } - - /// - /// Sets the client of the connection to be not-ready. - /// Clients that are not ready do not receive spawned objects or state synchronization updates. They client can be made ready again by calling SetClientReady(). - /// - /// The connection of the client to make not ready. - public static void SetClientNotReady(NetworkConnection conn) - { - if (conn.isReady) - { - if (logger.LogEnabled()) logger.Log("PlayerNotReady " + conn); - conn.isReady = false; - conn.RemoveObservers(); - - conn.Send(new NotReadyMessage()); - } - } - - /// - /// default ready handler. - /// - /// - /// - static void OnClientReadyMessage(NetworkConnection conn, ReadyMessage msg) - { - if (logger.LogEnabled()) logger.Log("Default handler for ready message from " + conn); - SetClientReady(conn); - } - - /// - /// Removes the player object from the connection - /// - /// The connection of the client to remove from - /// Indicates whether the server object should be destroyed - public static void RemovePlayerForConnection(NetworkConnection conn, bool destroyServerObject) - { - if (conn.identity != null) - { - if (destroyServerObject) - Destroy(conn.identity.gameObject); - else - UnSpawn(conn.identity.gameObject); - - conn.identity = null; - } - else - { - if (logger.LogEnabled()) logger.Log($"Connection {conn} has no identity"); - } - } - - /// - /// Handle command from specific player, this could be one of multiple players on a single client - /// - /// - /// - static void OnCommandMessage(NetworkConnection conn, CommandMessage msg) - { - if (!NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) - { - logger.LogWarning("Spawned object not found when handling Command message [netId=" + msg.netId + "]"); - return; - } - - CommandInfo commandInfo = identity.GetCommandInfo(msg.componentIndex, msg.functionHash); - - // Commands can be for player objects, OR other objects with client-authority - // -> so if this connection's controller has a different netId then - // only allow the command if clientAuthorityOwner - bool needAuthority = !commandInfo.ignoreAuthority; - if (needAuthority && identity.connectionToClient != conn) - { - logger.LogWarning("Command for object without authority [netId=" + msg.netId + "]"); - return; - } - - if (logger.LogEnabled()) logger.Log("OnCommandMessage for netId=" + msg.netId + " conn=" + conn); - - using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload)) - identity.HandleRemoteCall(msg.componentIndex, msg.functionHash, MirrorInvokeType.Command, networkReader, conn as NetworkConnectionToClient); - } - - internal static void SpawnObject(GameObject obj, NetworkConnection ownerConnection) - { - if (!active) - { - logger.LogError("SpawnObject for " + obj + ", NetworkServer is not active. Cannot spawn objects without an active server."); - return; - } - - NetworkIdentity identity = obj.GetComponent(); - if (identity == null) - { - logger.LogError("SpawnObject " + obj + " has no NetworkIdentity. Please add a NetworkIdentity to " + obj); - return; - } - - if (identity.SpawnedFromInstantiate) - { - // Using Instantiate on SceneObject is not allowed, so stop spawning here - // NetworkIdentity.Awake already logs error, no need to log a second error here - return; - } - - identity.connectionToClient = (NetworkConnectionToClient)ownerConnection; - - // special case to make sure hasAuthority is set - // on start server in host mode - if (ownerConnection is ULocalConnectionToClient) - identity.hasAuthority = true; - - identity.OnStartServer(); - - if (logger.LogEnabled()) logger.Log("SpawnObject instance ID " + identity.netId + " asset ID " + identity.assetId); - - identity.RebuildObservers(true); - } - - internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnection conn) - { - if (identity.serverOnly) - return; - - // for easier debugging - if (logger.LogEnabled()) logger.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.netId); - - // one writer for owner, one for observers - using (PooledNetworkWriter ownerWriter = NetworkWriterPool.GetWriter(), observersWriter = NetworkWriterPool.GetWriter()) - { - bool isOwner = identity.connectionToClient == conn; - - ArraySegment payload = CreateSpawnMessagePayload(isOwner, identity, ownerWriter, observersWriter); - - SpawnMessage msg = new SpawnMessage - { - netId = identity.netId, - isLocalPlayer = conn.identity == identity, - isOwner = isOwner, - sceneId = identity.sceneId, - assetId = identity.assetId, - // use local values for VR support - position = identity.transform.localPosition, - rotation = identity.transform.localRotation, - scale = identity.transform.localScale, - - payload = payload, - }; - - conn.Send(msg); - } - } - - static ArraySegment CreateSpawnMessagePayload(bool isOwner, NetworkIdentity identity, PooledNetworkWriter ownerWriter, PooledNetworkWriter observersWriter) - { - // Only call OnSerializeAllSafely if there are NetworkBehaviours - if (identity.NetworkBehaviours.Length == 0) - { - return default; - } - - // serialize all components with initialState = true - // (can be null if has none) - identity.OnSerializeAllSafely(true, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten); - - // convert to ArraySegment to avoid reader allocations - // (need to handle null case too) - ArraySegment ownerSegment = ownerWritten > 0 ? ownerWriter.ToArraySegment() : default; - ArraySegment observersSegment = observersWritten > 0 ? observersWriter.ToArraySegment() : default; - - // use owner segment if 'conn' owns this identity, otherwise - // use observers segment - ArraySegment payload = isOwner ? ownerSegment : observersSegment; - - return payload; - } - - /// - /// This destroys all the player objects associated with a NetworkConnections on a server. - /// This is used when a client disconnects, to remove the players for that client. This also destroys non-player objects that have client authority set for this connection. - /// - /// The connections object to clean up for. - public static void DestroyPlayerForConnection(NetworkConnection conn) - { - // destroy all objects owned by this connection, including the player object - conn.DestroyOwnedObjects(); - conn.identity = null; - } - - /// - /// Spawn the given game object on all clients which are ready. - /// This will cause a new object to be instantiated from the registered prefab, or from a custom spawn function. - /// - /// Game object with NetworkIdentity to spawn. - /// The connection that has authority over the object - public static void Spawn(GameObject obj, NetworkConnection ownerConnection = null) - { - if (VerifyCanSpawn(obj)) - { - SpawnObject(obj, ownerConnection); - } - } - - /// - /// This spawns an object like NetworkServer.Spawn() but also assigns Client Authority to the specified client. - /// This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object. - /// - /// The object to spawn. - /// The player object to set Client Authority to. - public static void Spawn(GameObject obj, GameObject ownerPlayer) - { - NetworkIdentity identity = ownerPlayer.GetComponent(); - if (identity == null) - { - logger.LogError("Player object has no NetworkIdentity"); - return; - } - - if (identity.connectionToClient == null) - { - logger.LogError("Player object is not a player."); - return; - } - - Spawn(obj, identity.connectionToClient); - } - - /// - /// This spawns an object like NetworkServer.Spawn() but also assigns Client Authority to the specified client. - /// This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object. - /// - /// The object to spawn. - /// The assetId of the object to spawn. Used for custom spawn handlers. - /// The connection that has authority over the object - public static void Spawn(GameObject obj, Guid assetId, NetworkConnection ownerConnection = null) - { - if (VerifyCanSpawn(obj)) - { - if (GetNetworkIdentity(obj, out NetworkIdentity identity)) - { - identity.assetId = assetId; - } - SpawnObject(obj, ownerConnection); - } - } - - static bool CheckForPrefab(GameObject obj) - { -#if UNITY_EDITOR -#if UNITY_2018_3_OR_NEWER - return UnityEditor.PrefabUtility.IsPartOfPrefabAsset(obj); -#elif UNITY_2018_2_OR_NEWER - return (UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj) == null) && (UnityEditor.PrefabUtility.GetPrefabObject(obj) != null); -#else - return (UnityEditor.PrefabUtility.GetPrefabParent(obj) == null) && (UnityEditor.PrefabUtility.GetPrefabObject(obj) != null); -#endif -#else - return false; -#endif - } - - static bool VerifyCanSpawn(GameObject obj) - { - if (CheckForPrefab(obj)) - { - logger.LogFormat(LogType.Error, "GameObject {0} is a prefab, it can't be spawned. This will cause errors in builds.", obj.name); - return false; - } - - return true; - } - - static void DestroyObject(NetworkIdentity identity, bool destroyServerObject) - { - if (logger.LogEnabled()) logger.Log("DestroyObject instance:" + identity.netId); - NetworkIdentity.spawned.Remove(identity.netId); - - identity.connectionToClient?.RemoveOwnedObject(identity); - - ObjectDestroyMessage msg = new ObjectDestroyMessage - { - netId = identity.netId - }; - SendToObservers(identity, msg); - - identity.ClearObservers(); - if (NetworkClient.active && localClientActive) - { - identity.OnStopClient(); - } - - identity.OnStopServer(); - - // when unspawning, dont destroy the server's object - if (destroyServerObject) - { - identity.destroyCalled = true; - UnityEngine.Object.Destroy(identity.gameObject); - } - // if we are destroying the server object we don't need to reset the identity - // reseting it will cause isClient/isServer to be false in the OnDestroy call - else - { - identity.Reset(); - } - } - - /// - /// Destroys this object and corresponding objects on all clients. - /// In some cases it is useful to remove an object but not delete it on the server. For that, use NetworkServer.UnSpawn() instead of NetworkServer.Destroy(). - /// - /// Game object to destroy. - public static void Destroy(GameObject obj) - { - if (obj == null) - { - logger.Log("NetworkServer DestroyObject is null"); - return; - } - - if (GetNetworkIdentity(obj, out NetworkIdentity identity)) - { - DestroyObject(identity, true); - } - } - - /// - /// This takes an object that has been spawned and un-spawns it. - /// The object will be removed from clients that it was spawned on, or the custom spawn handler function on the client will be called for the object. - /// Unlike when calling NetworkServer.Destroy(), on the server the object will NOT be destroyed. This allows the server to re-use the object, even spawn it again later. - /// - /// The spawned object to be unspawned. - public static void UnSpawn(GameObject obj) - { - if (obj == null) - { - logger.Log("NetworkServer UnspawnObject is null"); - return; - } - - if (GetNetworkIdentity(obj, out NetworkIdentity identity)) - { - DestroyObject(identity, false); - } - } - - internal static bool ValidateSceneObject(NetworkIdentity identity) - { - if (identity.gameObject.hideFlags == HideFlags.NotEditable || - identity.gameObject.hideFlags == HideFlags.HideAndDontSave) - return false; - -#if UNITY_EDITOR - if (UnityEditor.EditorUtility.IsPersistent(identity.gameObject)) - return false; -#endif - - // If not a scene object - return identity.sceneId != 0; - } - - /// - /// This causes NetworkIdentity objects in a scene to be spawned on a server. - /// NetworkIdentity objects in a scene are disabled by default. Calling SpawnObjects() causes these scene objects to be enabled and spawned. It is like calling NetworkServer.Spawn() for each of them. - /// - /// Success if objects where spawned. - public static bool SpawnObjects() - { - // only if server active - if (!active) - return false; - - NetworkIdentity[] identities = Resources.FindObjectsOfTypeAll(); - foreach (NetworkIdentity identity in identities) - { - if (ValidateSceneObject(identity)) - { - if (logger.LogEnabled()) logger.Log("SpawnObjects sceneId:" + identity.sceneId.ToString("X") + " name:" + identity.gameObject.name); - identity.gameObject.SetActive(true); - } - } - - foreach (NetworkIdentity identity in identities) - { - if (ValidateSceneObject(identity)) - Spawn(identity.gameObject); - } - return true; - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkServer.cs.meta b/Assets/Mirror/Runtime/NetworkServer.cs.meta deleted file mode 100644 index 4d44a26..0000000 --- a/Assets/Mirror/Runtime/NetworkServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a5f5ec068f5604c32b160bc49ee97b75 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkStartPosition.cs b/Assets/Mirror/Runtime/NetworkStartPosition.cs deleted file mode 100644 index cca2694..0000000 --- a/Assets/Mirror/Runtime/NetworkStartPosition.cs +++ /dev/null @@ -1,24 +0,0 @@ -using UnityEngine; - -namespace Mirror -{ - /// - /// This component is used to make a gameObject a starting position for spawning player objects in multiplayer games. - /// This object's transform will be automatically registered and unregistered with the NetworkManager as a starting position. - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkStartPosition")] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkStartPosition.html")] - public class NetworkStartPosition : MonoBehaviour - { - public void Awake() - { - NetworkManager.RegisterStartPosition(transform); - } - - public void OnDestroy() - { - NetworkManager.UnRegisterStartPosition(transform); - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkStartPosition.cs.meta b/Assets/Mirror/Runtime/NetworkStartPosition.cs.meta deleted file mode 100644 index ae9ab89..0000000 --- a/Assets/Mirror/Runtime/NetworkStartPosition.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 41f84591ce72545258ea98cb7518d8b9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkTime.cs b/Assets/Mirror/Runtime/NetworkTime.cs deleted file mode 100644 index 415739b..0000000 --- a/Assets/Mirror/Runtime/NetworkTime.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using UnityEngine; -using Stopwatch = System.Diagnostics.Stopwatch; - -namespace Mirror -{ - /// - /// Synchronize time between the server and the clients - /// - public static class NetworkTime - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkTime)); - - /// - /// how often are we sending ping messages - /// used to calculate network time and RTT - /// - public static float PingFrequency = 2.0f; - - /// - /// average out the last few results from Ping - /// - public static int PingWindowSize = 10; - - static double lastPingTime; - - // Date and time when the application started - static readonly Stopwatch stopwatch = new Stopwatch(); - - static NetworkTime() - { - stopwatch.Start(); - } - - static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(10); - static ExponentialMovingAverage _offset = new ExponentialMovingAverage(10); - - // the true offset guaranteed to be in this range - static double offsetMin = double.MinValue; - static double offsetMax = double.MaxValue; - - // returns the clock time _in this system_ - static double LocalTime() - { - return stopwatch.Elapsed.TotalSeconds; - } - - public static void Reset() - { - _rtt = new ExponentialMovingAverage(PingWindowSize); - _offset = new ExponentialMovingAverage(PingWindowSize); - offsetMin = double.MinValue; - offsetMax = double.MaxValue; - } - - internal static void UpdateClient() - { - if (Time.time - lastPingTime >= PingFrequency) - { - NetworkPingMessage pingMessage = new NetworkPingMessage(LocalTime()); - NetworkClient.Send(pingMessage); - lastPingTime = Time.time; - } - } - - // executed at the server when we receive a ping message - // reply with a pong containing the time from the client - // and time from the server - internal static void OnServerPing(NetworkConnection conn, NetworkPingMessage msg) - { - if (logger.LogEnabled()) logger.Log("OnPingServerMessage conn=" + conn); - - NetworkPongMessage pongMsg = new NetworkPongMessage - { - clientTime = msg.clientTime, - serverTime = LocalTime() - }; - - conn.Send(pongMsg); - } - - // Executed at the client when we receive a Pong message - // find out how long it took since we sent the Ping - // and update time offset - internal static void OnClientPong(NetworkPongMessage msg) - { - double now = LocalTime(); - - // how long did this message take to come back - double newRtt = now - msg.clientTime; - _rtt.Add(newRtt); - - // the difference in time between the client and the server - // but subtract half of the rtt to compensate for latency - // half of rtt is the best approximation we have - double newOffset = now - newRtt * 0.5f - msg.serverTime; - - double newOffsetMin = now - newRtt - msg.serverTime; - double newOffsetMax = now - msg.serverTime; - offsetMin = Math.Max(offsetMin, newOffsetMin); - offsetMax = Math.Min(offsetMax, newOffsetMax); - - if (_offset.Value < offsetMin || _offset.Value > offsetMax) - { - // the old offset was offrange, throw it away and use new one - _offset = new ExponentialMovingAverage(PingWindowSize); - _offset.Add(newOffset); - } - else if (newOffset >= offsetMin || newOffset <= offsetMax) - { - // new offset looks reasonable, add to the average - _offset.Add(newOffset); - } - } - - /// - /// The time in seconds since the server started. - /// - // - // I measured the accuracy of float and I got this: - // for the same day, accuracy is better than 1 ms - // after 1 day, accuracy goes down to 7 ms - // after 10 days, accuracy is 61 ms - // after 30 days , accuracy is 238 ms - // after 60 days, accuracy is 454 ms - // in other words, if the server is running for 2 months, - // and you cast down to float, then the time will jump in 0.4s intervals. - public static double time => LocalTime() - _offset.Value; - - /// - /// Measurement of the variance of time. - /// The higher the variance, the less accurate the time is - /// - public static double timeVar => _offset.Var; - - /// - /// standard deviation of time. - /// The higher the variance, the less accurate the time is - /// - public static double timeSd => Math.Sqrt(timeVar); - - /// - /// Clock difference in seconds between the client and the server - /// - /// - /// Note this value is always 0 at the server - /// - public static double offset => _offset.Value; - - /// - /// how long in seconds does it take for a message to go - /// to the server and come back - /// - public static double rtt => _rtt.Value; - - /// - /// measure variance of rtt - /// the higher the number, the less accurate rtt is - /// - public static double rttVar => _rtt.Var; - - /// - /// Measure the standard deviation of rtt - /// the higher the number, the less accurate rtt is - /// - public static double rttSd => Math.Sqrt(rttVar); - } -} diff --git a/Assets/Mirror/Runtime/NetworkTime.cs.meta b/Assets/Mirror/Runtime/NetworkTime.cs.meta deleted file mode 100644 index f5c2b6c..0000000 --- a/Assets/Mirror/Runtime/NetworkTime.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 09a0c241fc4a5496dbf4a0ab6e9a312c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkVisibility.cs b/Assets/Mirror/Runtime/NetworkVisibility.cs deleted file mode 100644 index 6f30ae6..0000000 --- a/Assets/Mirror/Runtime/NetworkVisibility.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror -{ - // the name NetworkProximityCheck implies that it's only about objects in - // proximity to the player. But we might have room based, guild based, - // instanced based checks too, so NetworkVisibility is more fitting. - // - // note: we inherit from NetworkBehaviour so we can reuse .netIdentity, etc. - // note: unlike UNET, we only allow 1 proximity checker per NetworkIdentity. - [DisallowMultipleComponent] - public abstract class NetworkVisibility : NetworkBehaviour - { - /// - /// Callback used by the visibility system to determine if an observer (player) can see this object. - /// If this function returns true, the network connection will be added as an observer. - /// - /// Network connection of a player. - /// True if the player can see this object. - public abstract bool OnCheckObserver(NetworkConnection conn); - - /// - /// Callback used by the visibility system to (re)construct the set of observers that can see this object. - /// Implementations of this callback should add network connections of players that can see this object to the observers set. - /// - /// The new set of observers for this object. - /// True if the set of observers is being built for the first time. - public abstract void OnRebuildObservers(HashSet observers, bool initialize); - - /// - /// Callback used by the visibility system for objects on a host. - /// Objects on a host (with a local client) cannot be disabled or destroyed when they are not visible to the local client. So this function is called to allow custom code to hide these objects. A typical implementation will disable renderer components on the object. This is only called on local clients on a host. - /// - /// New visibility state. - public virtual void OnSetHostVisibility(bool visible) - { - foreach (Renderer rend in GetComponentsInChildren()) - rend.enabled = visible; - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkVisibility.cs.meta b/Assets/Mirror/Runtime/NetworkVisibility.cs.meta deleted file mode 100644 index 1e66658..0000000 --- a/Assets/Mirror/Runtime/NetworkVisibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c08f1a030234d49d391d7223a8592f15 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkWriter.cs b/Assets/Mirror/Runtime/NetworkWriter.cs deleted file mode 100644 index 7442bf1..0000000 --- a/Assets/Mirror/Runtime/NetworkWriter.cs +++ /dev/null @@ -1,596 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; -using UnityEngine; - -namespace Mirror -{ - /// - /// a class that holds writers for the different types - /// Note that c# creates a different static variable for each - /// type - /// This will be populated by the weaver - /// - /// - public static class Writer - { - public static Action write; - } - - /// - /// Binary stream Writer. Supports simple types, buffers, arrays, structs, and nested types - /// Use NetworkWriter.GetWriter to reduce memory allocation - /// - public class NetworkWriter - { - public const int MaxStringLength = 1024 * 32; - - // create writer immediately with it's own buffer so no one can mess with it and so that we can resize it. - // note: BinaryWriter allocates too much, so we only use a MemoryStream - // => 1500 bytes by default because on average, most packets will be <= MTU - byte[] buffer = new byte[1500]; - - // 'int' is the best type for .Position. 'short' is too small if we send >32kb which would result in negative .Position - // -> converting long to int is fine until 2GB of data (MAX_INT), so we don't have to worry about overflows here - int position; - int length; - - public int Length => length; - - public int Position - { - get => position; - set - { - position = value; - EnsureLength(value); - } - } - - /// - /// Reset both the position and length of the stream - /// - /// - /// Leaves the capacity the same so that we can reuse this writer without extra allocations - /// - public void Reset() - { - position = 0; - length = 0; - } - - /// - /// Sets length, moves position if it is greater than new length - /// - /// - /// - /// Zeros out any extra length created by setlength - /// - public void SetLength(int newLength) - { - int oldLength = length; - - // ensure length & capacity - EnsureLength(newLength); - - // zero out new length - if (oldLength < newLength) - { - Array.Clear(buffer, oldLength, newLength - oldLength); - } - - length = newLength; - position = Mathf.Min(position, length); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void EnsureLength(int value) - { - if (length < value) - { - length = value; - EnsureCapacity(value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void EnsureCapacity(int value) - { - if (buffer.Length < value) - { - int capacity = Math.Max(value, buffer.Length * 2); - Array.Resize(ref buffer, capacity); - } - } - - // MemoryStream has 3 values: Position, Length and Capacity. - // Position is used to indicate where we are writing - // Length is how much data we have written - // capacity is how much memory we have allocated - // ToArray returns all the data we have written, regardless of the current position - public byte[] ToArray() - { - byte[] data = new byte[length]; - Array.ConstrainedCopy(buffer, 0, data, 0, length); - return data; - } - - // Gets the serialized data in an ArraySegment - // this is similar to ToArray(), but it gets the data in O(1) - // and without allocations. - // Do not write anything else or modify the NetworkWriter - // while you are using the ArraySegment - public ArraySegment ToArraySegment() - { - return new ArraySegment(buffer, 0, length); - } - - public void WriteByte(byte value) - { - EnsureLength(position + 1); - buffer[position++] = value; - } - - - // for byte arrays with consistent size, where the reader knows how many to read - // (like a packet opcode that's always the same) - public void WriteBytes(byte[] buffer, int offset, int count) - { - EnsureLength(position + count); - Array.ConstrainedCopy(buffer, offset, this.buffer, position, count); - position += count; - } - - public void WriteUInt32(uint value) - { - EnsureLength(position + 4); - buffer[position++] = (byte)value; - buffer[position++] = (byte)(value >> 8); - buffer[position++] = (byte)(value >> 16); - buffer[position++] = (byte)(value >> 24); - } - - public void WriteInt32(int value) => WriteUInt32((uint)value); - - public void WriteUInt64(ulong value) - { - EnsureLength(position + 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); - } - - public void WriteInt64(long value) => WriteUInt64((ulong)value); - - /// - /// Writes any type that mirror supports - /// - /// - /// - public void Write(T value) - { - Writer.write(this, value); - } - } - - - // Mirror's Weaver automatically detects all NetworkWriter function types, - // but they do all need to be extensions. - public static class NetworkWriterExtensions - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkWriterExtensions)); - - // cache encoding instead of creating it with BinaryWriter each time - // 1000 readers before: 1MB GC, 30ms - // 1000 readers after: 0.8MB GC, 18ms - static readonly UTF8Encoding encoding = new UTF8Encoding(false, true); - static readonly byte[] stringBuffer = new byte[NetworkWriter.MaxStringLength]; - - public static void WriteByte(this NetworkWriter writer, byte value) => writer.WriteByte(value); - - public static void WriteSByte(this NetworkWriter writer, sbyte value) => writer.WriteByte((byte)value); - - public static void WriteChar(this NetworkWriter writer, char value) => writer.WriteUInt16(value); - - public static void WriteBoolean(this NetworkWriter writer, bool value) => writer.WriteByte((byte)(value ? 1 : 0)); - - public static void WriteUInt16(this NetworkWriter writer, ushort value) - { - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - } - - public static void WriteInt16(this NetworkWriter writer, short value) => writer.WriteUInt16((ushort)value); - - public static void WriteSingle(this NetworkWriter writer, float value) - { - UIntFloat converter = new UIntFloat - { - floatValue = value - }; - writer.WriteUInt32(converter.intValue); - } - - public static void WriteDouble(this NetworkWriter writer, double value) - { - UIntDouble converter = new UIntDouble - { - doubleValue = value - }; - writer.WriteUInt64(converter.longValue); - } - - public static void WriteDecimal(this NetworkWriter writer, decimal value) - { - // the only way to read it without allocations is to both read and - // write it with the FloatConverter (which is not binary compatible - // to writer.Write(decimal), hence why we use it here too) - UIntDecimal converter = new UIntDecimal - { - decimalValue = value - }; - writer.WriteUInt64(converter.longValue1); - writer.WriteUInt64(converter.longValue2); - } - - public static void WriteString(this NetworkWriter writer, string value) - { - // write 0 for null support, increment real size by 1 - // (note: original HLAPI would write "" for null strings, but if a - // string is null on the server then it should also be null - // on the client) - if (value == null) - { - writer.WriteUInt16(0); - return; - } - - // write string with same method as NetworkReader - // convert to byte[] - int size = encoding.GetBytes(value, 0, value.Length, stringBuffer, 0); - - // check if within max size - if (size >= NetworkWriter.MaxStringLength) - { - throw new IndexOutOfRangeException("NetworkWriter.Write(string) too long: " + size + ". Limit: " + NetworkWriter.MaxStringLength); - } - - // write size and bytes - writer.WriteUInt16(checked((ushort)(size + 1))); - writer.WriteBytes(stringBuffer, 0, size); - } - - // for byte arrays with dynamic size, where the reader doesn't know how many will come - // (like an inventory with different items etc.) - public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, int offset, int count) - { - // null is supported because [SyncVar]s might be structs with null byte[] arrays - // write 0 for null array, increment normal size by 1 to save bandwith - // (using size=-1 for null would limit max size to 32kb instead of 64kb) - if (buffer == null) - { - writer.WritePackedUInt32(0u); - return; - } - writer.WritePackedUInt32(checked((uint)count) + 1u); - writer.WriteBytes(buffer, offset, count); - } - - // Weaver needs a write function with just one byte[] parameter - // (we don't name it .Write(byte[]) because it's really a WriteBytesAndSize since we write size / null info too) - public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) - { - // buffer might be null, so we can't use .Length in that case - writer.WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0); - } - - public static void WriteBytesAndSizeSegment(this NetworkWriter writer, ArraySegment buffer) - { - writer.WriteBytesAndSize(buffer.Array, buffer.Offset, buffer.Count); - } - - // zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba - public static void WritePackedInt32(this NetworkWriter writer, int i) - { - uint zigzagged = (uint)((i >> 31) ^ (i << 1)); - writer.WritePackedUInt32(zigzagged); - } - - // http://sqlite.org/src4/doc/trunk/www/varint.wiki - public static void WritePackedUInt32(this NetworkWriter writer, uint value) - { - // for 32 bit values WritePackedUInt64 writes the - // same exact thing bit by bit - writer.WritePackedUInt64(value); - } - - // zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba - public static void WritePackedInt64(this NetworkWriter writer, long i) - { - ulong zigzagged = (ulong)((i >> 63) ^ (i << 1)); - writer.WritePackedUInt64(zigzagged); - } - - public static void WritePackedUInt64(this NetworkWriter writer, ulong value) - { - if (value <= 240) - { - writer.WriteByte((byte)value); - return; - } - if (value <= 2287) - { - writer.WriteByte((byte)(((value - 240) >> 8) + 241)); - writer.WriteByte((byte)(value - 240)); - return; - } - if (value <= 67823) - { - writer.WriteByte(249); - writer.WriteByte((byte)((value - 2288) >> 8)); - writer.WriteByte((byte)(value - 2288)); - return; - } - if (value <= 16777215) - { - writer.WriteByte(250); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - return; - } - if (value <= 4294967295) - { - writer.WriteByte(251); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - writer.WriteByte((byte)(value >> 24)); - return; - } - if (value <= 1099511627775) - { - writer.WriteByte(252); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - writer.WriteByte((byte)(value >> 24)); - writer.WriteByte((byte)(value >> 32)); - return; - } - if (value <= 281474976710655) - { - writer.WriteByte(253); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - writer.WriteByte((byte)(value >> 24)); - writer.WriteByte((byte)(value >> 32)); - writer.WriteByte((byte)(value >> 40)); - return; - } - if (value <= 72057594037927935) - { - writer.WriteByte(254); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - writer.WriteByte((byte)(value >> 24)); - writer.WriteByte((byte)(value >> 32)); - writer.WriteByte((byte)(value >> 40)); - writer.WriteByte((byte)(value >> 48)); - return; - } - - // all others - { - writer.WriteByte(255); - writer.WriteByte((byte)value); - writer.WriteByte((byte)(value >> 8)); - writer.WriteByte((byte)(value >> 16)); - writer.WriteByte((byte)(value >> 24)); - writer.WriteByte((byte)(value >> 32)); - writer.WriteByte((byte)(value >> 40)); - writer.WriteByte((byte)(value >> 48)); - writer.WriteByte((byte)(value >> 56)); - } - } - - public static void WriteVector2(this NetworkWriter writer, Vector2 value) - { - writer.WriteSingle(value.x); - writer.WriteSingle(value.y); - } - - public static void WriteVector3(this NetworkWriter writer, Vector3 value) - { - writer.WriteSingle(value.x); - writer.WriteSingle(value.y); - writer.WriteSingle(value.z); - } - - public static void WriteVector4(this NetworkWriter writer, Vector4 value) - { - writer.WriteSingle(value.x); - writer.WriteSingle(value.y); - writer.WriteSingle(value.z); - writer.WriteSingle(value.w); - } - - public static void WriteVector2Int(this NetworkWriter writer, Vector2Int value) - { - writer.WritePackedInt32(value.x); - writer.WritePackedInt32(value.y); - } - - public static void WriteVector3Int(this NetworkWriter writer, Vector3Int value) - { - writer.WritePackedInt32(value.x); - writer.WritePackedInt32(value.y); - writer.WritePackedInt32(value.z); - } - - public static void WriteColor(this NetworkWriter writer, Color value) - { - writer.WriteSingle(value.r); - writer.WriteSingle(value.g); - writer.WriteSingle(value.b); - writer.WriteSingle(value.a); - } - - public static void WriteColor32(this NetworkWriter writer, Color32 value) - { - writer.WriteByte(value.r); - writer.WriteByte(value.g); - writer.WriteByte(value.b); - writer.WriteByte(value.a); - } - - public static void WriteQuaternion(this NetworkWriter writer, Quaternion value) - { - writer.WriteSingle(value.x); - writer.WriteSingle(value.y); - writer.WriteSingle(value.z); - writer.WriteSingle(value.w); - } - - public static void WriteRect(this NetworkWriter writer, Rect value) - { - writer.WriteSingle(value.xMin); - writer.WriteSingle(value.yMin); - writer.WriteSingle(value.width); - writer.WriteSingle(value.height); - } - - public static void WritePlane(this NetworkWriter writer, Plane value) - { - writer.WriteVector3(value.normal); - writer.WriteSingle(value.distance); - } - - public static void WriteRay(this NetworkWriter writer, Ray value) - { - writer.WriteVector3(value.origin); - writer.WriteVector3(value.direction); - } - - public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) - { - writer.WriteSingle(value.m00); - writer.WriteSingle(value.m01); - writer.WriteSingle(value.m02); - writer.WriteSingle(value.m03); - writer.WriteSingle(value.m10); - writer.WriteSingle(value.m11); - writer.WriteSingle(value.m12); - writer.WriteSingle(value.m13); - writer.WriteSingle(value.m20); - writer.WriteSingle(value.m21); - writer.WriteSingle(value.m22); - writer.WriteSingle(value.m23); - writer.WriteSingle(value.m30); - writer.WriteSingle(value.m31); - writer.WriteSingle(value.m32); - writer.WriteSingle(value.m33); - } - - public static void WriteGuid(this NetworkWriter writer, Guid value) - { - byte[] data = value.ToByteArray(); - writer.WriteBytes(data, 0, data.Length); - } - - public static void WriteNetworkIdentity(this NetworkWriter writer, NetworkIdentity value) - { - if (value == null) - { - writer.WritePackedUInt32(0); - return; - } - writer.WritePackedUInt32(value.netId); - } - - public static void WriteTransform(this NetworkWriter writer, Transform value) - { - if (value == null) - { - writer.WritePackedUInt32(0); - return; - } - NetworkIdentity identity = value.GetComponent(); - if (identity != null) - { - writer.WritePackedUInt32(identity.netId); - } - else - { - logger.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); - writer.WritePackedUInt32(0); - } - } - - public static void WriteGameObject(this NetworkWriter writer, GameObject value) - { - if (value == null) - { - writer.WritePackedUInt32(0); - return; - } - NetworkIdentity identity = value.GetComponent(); - if (identity != null) - { - writer.WritePackedUInt32(identity.netId); - } - else - { - logger.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); - writer.WritePackedUInt32(0); - } - } - - public static void WriteUri(this NetworkWriter writer, Uri uri) - { - writer.WriteString(uri.ToString()); - } - - public static void WriteList(this NetworkWriter writer, List list) - { - if (list is null) - { - writer.WritePackedInt32(-1); - return; - } - writer.WritePackedInt32(list.Count); - for (int i = 0; i < list.Count; i++) - writer.Write(list[i]); - } - - public static void WriteArray(this NetworkWriter writer, T[] array) - { - if (array is null) - { - writer.WritePackedInt32(-1); - return; - } - writer.WritePackedInt32(array.Length); - for (int i = 0; i < array.Length; i++) - writer.Write(array[i]); - } - - public static void WriteArraySegment(this NetworkWriter writer, ArraySegment segment) - { - int length = segment.Count; - writer.WritePackedInt32(length); - for (int i = 0; i < length; i++) - { - writer.Write(segment.Array[segment.Offset + i]); - } - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkWriter.cs.meta b/Assets/Mirror/Runtime/NetworkWriter.cs.meta deleted file mode 100644 index 240f74a..0000000 --- a/Assets/Mirror/Runtime/NetworkWriter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 48d2207bcef1f4477b624725f075f9bd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/NetworkWriterPool.cs b/Assets/Mirror/Runtime/NetworkWriterPool.cs deleted file mode 100644 index 79a6ab1..0000000 --- a/Assets/Mirror/Runtime/NetworkWriterPool.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using UnityEngine; - -namespace Mirror -{ - /// - /// NetworkWriter to be used with NetworkWriterPool - /// - public class PooledNetworkWriter : NetworkWriter, IDisposable - { - public void Dispose() - { - NetworkWriterPool.Recycle(this); - } - } - - /// - /// Pool of NetworkWriters - /// Use this pool instead of NetworkWriter to reduce memory allocation - /// Use Capacity to change size of pool - /// - public static class NetworkWriterPool - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkWriterPool), LogType.Error); - - /// - /// Size of the pool - /// If pool is too small getting writers will causes memory allocation - /// Default value: 100 - /// - public static int Capacity - { - get => pool.Length; - set - { - // resize the array - Array.Resize(ref pool, value); - - // if capacity is smaller than before, then we need to adjust - // 'next' so it doesn't point to an index out of range - // -> if we set '0' then next = min(_, 0-1) => -1 - // -> if we set '2' then next = min(_, 2-1) => 1 - next = Mathf.Min(next, pool.Length - 1); - } - } - - /// - /// Mirror usually only uses up to 4 writes in nested usings, - /// 100 is a good margin for edge cases when users need a lot writers at - /// the same time. - /// - /// keep in mind, most entries of the pool will be null in most cases - /// - /// - /// Note: we use an Array instead of a Stack because it's significantly - /// faster: https://github.com/vis2k/Mirror/issues/1614 - static PooledNetworkWriter[] pool = new PooledNetworkWriter[100]; - - static int next = -1; - - /// - /// Get the next writer in the pool - /// If pool is empty, creates a new Writer - /// - public static PooledNetworkWriter GetWriter() - { - if (next == -1) - { - return new PooledNetworkWriter(); - } - - PooledNetworkWriter writer = pool[next]; - pool[next] = null; - next--; - - // reset cached writer length and position - writer.Reset(); - return writer; - } - - /// - /// Puts writer back into pool - /// When pool is full, the extra writer is left for the GC - /// - public static void Recycle(PooledNetworkWriter writer) - { - if (next < pool.Length - 1) - { - next++; - pool[next] = writer; - } - else - { - logger.LogWarning("NetworkWriterPool.Recycle, Pool was full leaving extra writer for GC"); - } - } - } -} diff --git a/Assets/Mirror/Runtime/NetworkWriterPool.cs.meta b/Assets/Mirror/Runtime/NetworkWriterPool.cs.meta deleted file mode 100644 index d383901..0000000 --- a/Assets/Mirror/Runtime/NetworkWriterPool.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3f34b53bea38e4f259eb8dc211e4fdb6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/RemoteCallHelper.cs b/Assets/Mirror/Runtime/RemoteCallHelper.cs deleted file mode 100644 index 99566f3..0000000 --- a/Assets/Mirror/Runtime/RemoteCallHelper.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.RemoteCalls -{ - /// - /// Delegate for Command functions. - /// - /// - /// - public delegate void CmdDelegate(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection); - - class Invoker - { - public Type invokeClass; - public MirrorInvokeType invokeType; - public CmdDelegate invokeFunction; - public bool cmdIgnoreAuthority; - - public bool AreEqual(Type invokeClass, MirrorInvokeType invokeType, CmdDelegate invokeFunction) - { - return (this.invokeClass == invokeClass && - this.invokeType == invokeType && - this.invokeFunction == invokeFunction); - } - } - - public struct CommandInfo - { - public bool ignoreAuthority; - } - - /// - /// Used to help manage remote calls for NetworkBehaviours - /// - public static class RemoteCallHelper - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(RemoteCallHelper)); - - static readonly Dictionary cmdHandlerDelegates = new Dictionary(); - - /// - /// Creates hash from Type and method name - /// - /// - /// - /// - internal static int GetMethodHash(Type invokeClass, string methodName) - { - // (invokeClass + ":" + cmdName).GetStableHashCode() would cause allocations. - // so hash1 + hash2 is better. - unchecked - { - int hash = invokeClass.FullName.GetStableHashCode(); - return hash * 503 + methodName.GetStableHashCode(); - } - } - - - /// - /// helper function register a Command/Rpc delegate - /// - /// - /// - /// - /// - /// - /// remote function hash - internal static int RegisterDelegate(Type invokeClass, string cmdName, MirrorInvokeType invokerType, CmdDelegate func, bool cmdIgnoreAuthority = false) - { - // type+func so Inventory.RpcUse != Equipment.RpcUse - int cmdHash = GetMethodHash(invokeClass, cmdName); - - if (CheckIfDeligateExists(invokeClass, invokerType, func, cmdHash)) - return cmdHash; - - Invoker invoker = new Invoker - { - invokeType = invokerType, - invokeClass = invokeClass, - invokeFunction = func, - cmdIgnoreAuthority = cmdIgnoreAuthority, - }; - - cmdHandlerDelegates[cmdHash] = invoker; - - if (logger.LogEnabled()) - { - string ingoreAuthorityMessage = invokerType == MirrorInvokeType.Command ? $" IgnoreAuthority:{cmdIgnoreAuthority}" : ""; - logger.Log($"RegisterDelegate hash: {cmdHash} invokerType: {invokerType} method: {func.GetMethodName()}{ingoreAuthorityMessage}"); - } - - return cmdHash; - } - - static bool CheckIfDeligateExists(Type invokeClass, MirrorInvokeType invokerType, CmdDelegate func, int cmdHash) - { - if (cmdHandlerDelegates.ContainsKey(cmdHash)) - { - // something already registered this hash - Invoker oldInvoker = cmdHandlerDelegates[cmdHash]; - if (oldInvoker.AreEqual(invokeClass, invokerType, func)) - { - // it's all right, it was the same function - return true; - } - - logger.LogError($"Function {oldInvoker.invokeClass}.{oldInvoker.invokeFunction.GetMethodName()} and {invokeClass}.{func.GetMethodName()} have the same hash. Please rename one of them"); - } - - return false; - } - - public static void RegisterCommandDelegate(Type invokeClass, string cmdName, CmdDelegate func, bool ignoreAuthority) - { - RegisterDelegate(invokeClass, cmdName, MirrorInvokeType.Command, func, ignoreAuthority); - } - - public static void RegisterRpcDelegate(Type invokeClass, string rpcName, CmdDelegate func) - { - RegisterDelegate(invokeClass, rpcName, MirrorInvokeType.ClientRpc, func); - } - - /// - /// We need this in order to clean up tests - /// - internal static void RemoveDelegate(int hash) - { - cmdHandlerDelegates.Remove(hash); - } - - static bool GetInvokerForHash(int cmdHash, MirrorInvokeType invokeType, out Invoker invoker) - { - if (cmdHandlerDelegates.TryGetValue(cmdHash, out invoker) && invoker != null && invoker.invokeType == invokeType) - { - return true; - } - - // debug message if not found, or null, or mismatched type - // (no need to throw an error, an attacker might just be trying to - // call an cmd with an rpc's hash) - if (logger.LogEnabled()) logger.Log("GetInvokerForHash hash:" + cmdHash + " not found"); - - return false; - } - - // InvokeCmd/Rpc Delegate can all use the same function here - internal static bool InvokeHandlerDelegate(int cmdHash, MirrorInvokeType invokeType, NetworkReader reader, NetworkBehaviour invokingType, NetworkConnectionToClient senderConnection = null) - { - if (GetInvokerForHash(cmdHash, invokeType, out Invoker invoker) && invoker.invokeClass.IsInstanceOfType(invokingType)) - { - invoker.invokeFunction(invokingType, reader, senderConnection); - - return true; - } - return false; - } - - internal static CommandInfo GetCommandInfo(int cmdHash, NetworkBehaviour invokingType) - { - if (GetInvokerForHash(cmdHash, MirrorInvokeType.Command, out Invoker invoker) && invoker.invokeClass.IsInstanceOfType(invokingType)) - { - return new CommandInfo - { - ignoreAuthority = invoker.cmdIgnoreAuthority - }; - } - return default; - } - - /// - /// Gets the handler function for a given hash - /// Can be used by profilers and debuggers - /// - /// rpc function hash - /// The function delegate that will handle the command - public static CmdDelegate GetDelegate(int cmdHash) - { - if (cmdHandlerDelegates.TryGetValue(cmdHash, out Invoker invoker)) - { - return invoker.invokeFunction; - } - return null; - } - } -} - diff --git a/Assets/Mirror/Runtime/RemoteCallHelper.cs.meta b/Assets/Mirror/Runtime/RemoteCallHelper.cs.meta deleted file mode 100644 index 862d6e4..0000000 --- a/Assets/Mirror/Runtime/RemoteCallHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d2cdbcbd1e377d6408a91acbec31ba16 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/StringHash.cs b/Assets/Mirror/Runtime/StringHash.cs deleted file mode 100644 index 95e9b07..0000000 --- a/Assets/Mirror/Runtime/StringHash.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Mirror -{ - public static class StringHash - { - // string.GetHashCode is not guaranteed to be the same on all machines, but - // we need one that is the same on all machines. simple and stupid: - public static int GetStableHashCode(this string text) - { - unchecked - { - int hash = 23; - foreach (char c in text) - hash = hash * 31 + c; - return hash; - } - } - } -} diff --git a/Assets/Mirror/Runtime/StringHash.cs.meta b/Assets/Mirror/Runtime/StringHash.cs.meta deleted file mode 100644 index 6198581..0000000 --- a/Assets/Mirror/Runtime/StringHash.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 733f020f9b76d453da841089579fd7a7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/SyncDictionary.cs b/Assets/Mirror/Runtime/SyncDictionary.cs deleted file mode 100644 index a5d30a5..0000000 --- a/Assets/Mirror/Runtime/SyncDictionary.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using JetBrains.Annotations; - -namespace Mirror -{ - public class SyncIDictionary : IDictionary, SyncObject, IReadOnlyDictionary - { - public delegate void SyncDictionaryChanged(Operation op, TKey key, TValue item); - - protected readonly IDictionary objects; - - public int Count => objects.Count; - public bool IsReadOnly { get; private set; } - public event SyncDictionaryChanged Callback; - - public enum Operation : byte - { - OP_ADD, - OP_CLEAR, - OP_REMOVE, - OP_SET - } - - struct Change - { - internal Operation operation; - internal TKey key; - internal TValue item; - } - - readonly List changes = new List(); - // how many changes we need to ignore - // this is needed because when we initialize the list, - // we might later receive changes that have already been applied - // so we need to skip them - int changesAhead; - - public void Reset() - { - IsReadOnly = false; - changes.Clear(); - changesAhead = 0; - objects.Clear(); - } - - public bool IsDirty => changes.Count > 0; - - public ICollection Keys => objects.Keys; - - public ICollection Values => objects.Values; - - IEnumerable IReadOnlyDictionary.Keys => objects.Keys; - - IEnumerable IReadOnlyDictionary.Values => objects.Values; - - // throw away all the changes - // this should be called after a successfull sync - public void Flush() => changes.Clear(); - - public SyncIDictionary(IDictionary objects) - { - this.objects = objects; - } - - void AddOperation(Operation op, TKey key, TValue item) - { - if (IsReadOnly) - { - throw new System.InvalidOperationException("SyncDictionaries can only be modified by the server"); - } - - Change change = new Change - { - operation = op, - key = key, - item = item - }; - - changes.Add(change); - - Callback?.Invoke(op, key, item); - } - - public void OnSerializeAll(NetworkWriter writer) - { - // if init, write the full list content - writer.WritePackedUInt32((uint)objects.Count); - - foreach (KeyValuePair syncItem in objects) - { - writer.Write(syncItem.Key); - writer.Write(syncItem.Value); - } - - // all changes have been applied already - // thus the client will need to skip all the pending changes - // or they would be applied again. - // So we write how many changes are pending - writer.WritePackedUInt32((uint)changes.Count); - } - - public void OnSerializeDelta(NetworkWriter writer) - { - // write all the queued up changes - writer.WritePackedUInt32((uint)changes.Count); - - for (int i = 0; i < changes.Count; i++) - { - Change change = changes[i]; - writer.WriteByte((byte)change.operation); - - switch (change.operation) - { - case Operation.OP_ADD: - case Operation.OP_REMOVE: - case Operation.OP_SET: - writer.Write(change.key); - writer.Write(change.item); - break; - case Operation.OP_CLEAR: - break; - } - } - } - - public void OnDeserializeAll(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - // if init, write the full list content - int count = (int)reader.ReadPackedUInt32(); - - objects.Clear(); - changes.Clear(); - - for (int i = 0; i < count; i++) - { - TKey key = reader.Read(); - TValue obj = reader.Read(); - objects.Add(key, obj); - } - - // We will need to skip all these changes - // the next time the list is synchronized - // because they have already been applied - changesAhead = (int)reader.ReadPackedUInt32(); - } - - public void OnDeserializeDelta(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - int changesCount = (int)reader.ReadPackedUInt32(); - - for (int i = 0; i < changesCount; i++) - { - Operation operation = (Operation)reader.ReadByte(); - - // apply the operation only if it is a new change - // that we have not applied yet - bool apply = changesAhead == 0; - TKey key = default; - TValue item = default; - - switch (operation) - { - case Operation.OP_ADD: - case Operation.OP_SET: - key = reader.Read(); - item = reader.Read(); - if (apply) - { - objects[key] = item; - } - break; - - case Operation.OP_CLEAR: - if (apply) - { - objects.Clear(); - } - break; - - case Operation.OP_REMOVE: - key = reader.Read(); - item = reader.Read(); - if (apply) - { - objects.Remove(key); - } - break; - } - - if (apply) - { - Callback?.Invoke(operation, key, item); - } - // we just skipped this change - else - { - changesAhead--; - } - } - } - - public void Clear() - { - objects.Clear(); - AddOperation(Operation.OP_CLEAR, default, default); - } - - public bool ContainsKey(TKey key) => objects.ContainsKey(key); - - public bool Remove(TKey key) - { - if (objects.TryGetValue(key, out TValue item) && objects.Remove(key)) - { - AddOperation(Operation.OP_REMOVE, key, item); - return true; - } - return false; - } - - public TValue this[TKey i] - { - get => objects[i]; - set - { - if (ContainsKey(i)) - { - objects[i] = value; - AddOperation(Operation.OP_SET, i, value); - } - else - { - objects[i] = value; - AddOperation(Operation.OP_ADD, i, value); - } - } - } - - public bool TryGetValue(TKey key, out TValue value) => objects.TryGetValue(key, out value); - - public void Add(TKey key, TValue value) - { - objects.Add(key, value); - AddOperation(Operation.OP_ADD, key, value); - } - - public void Add(KeyValuePair item) => Add(item.Key, item.Value); - - public bool Contains(KeyValuePair item) - { - return TryGetValue(item.Key, out TValue val) && EqualityComparer.Default.Equals(val, item.Value); - } - - public void CopyTo([NotNull] KeyValuePair[] array, int arrayIndex) - { - if (arrayIndex < 0 || arrayIndex > array.Length) - { - throw new System.ArgumentOutOfRangeException(nameof(arrayIndex), "Array Index Out of Range"); - } - if (array.Length - arrayIndex < Count) - { - throw new System.ArgumentException("The number of items in the SyncDictionary is greater than the available space from arrayIndex to the end of the destination array"); - } - - int i = arrayIndex; - foreach (KeyValuePair item in objects) - { - array[i] = item; - i++; - } - } - - public bool Remove(KeyValuePair item) - { - bool result = objects.Remove(item.Key); - if (result) - { - AddOperation(Operation.OP_REMOVE, item.Key, item.Value); - } - return result; - } - - public IEnumerator> GetEnumerator() => objects.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => objects.GetEnumerator(); - } - - public class SyncDictionary : SyncIDictionary - { - public SyncDictionary() : base(new Dictionary()) - { - } - - public SyncDictionary(IEqualityComparer eq) : base(new Dictionary(eq)) - { - } - - public new Dictionary.ValueCollection Values => ((Dictionary)objects).Values; - - public new Dictionary.KeyCollection Keys => ((Dictionary)objects).Keys; - - public new Dictionary.Enumerator GetEnumerator() => ((Dictionary)objects).GetEnumerator(); - - } -} diff --git a/Assets/Mirror/Runtime/SyncDictionary.cs.meta b/Assets/Mirror/Runtime/SyncDictionary.cs.meta deleted file mode 100644 index 9b4ff53..0000000 --- a/Assets/Mirror/Runtime/SyncDictionary.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4b346c49cfdb668488a364c3023590e2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/SyncList.cs b/Assets/Mirror/Runtime/SyncList.cs deleted file mode 100644 index 3185db4..0000000 --- a/Assets/Mirror/Runtime/SyncList.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Mirror -{ - // Deprecated 10/02/2020 - [Obsolete("Use SyncList instead")] - public class SyncListString : SyncList - { - } - - // Deprecated 10/02/2020 - [Obsolete("Use SyncList instead")] - public class SyncListFloat : SyncList - { - } - - // Deprecated 10/02/2020 - [Obsolete("Use SyncList instead")] - public class SyncListInt : SyncList - { - } - - // Deprecated 10/02/2020 - [Obsolete("Use SyncList instead")] - public class SyncListUInt : SyncList - { - } - - // Deprecated 10/02/2020 - [Obsolete("Use SyncList instead")] - public class SyncListBool : SyncList - { - } - - public class SyncList : IList, IReadOnlyList, SyncObject - { - public delegate void SyncListChanged(Operation op, int itemIndex, T oldItem, T newItem); - - readonly IList objects; - readonly IEqualityComparer comparer; - - public int Count => objects.Count; - public bool IsReadOnly { get; private set; } - public event SyncListChanged Callback; - - public enum Operation : byte - { - OP_ADD, - OP_CLEAR, - OP_INSERT, - OP_REMOVEAT, - OP_SET - } - - struct Change - { - internal Operation operation; - internal int index; - internal T item; - } - - readonly List changes = new List(); - // how many changes we need to ignore - // this is needed because when we initialize the list, - // we might later receive changes that have already been applied - // so we need to skip them - int changesAhead; - - public SyncList() : this(EqualityComparer.Default) - { - } - - public SyncList(IEqualityComparer comparer) - { - this.comparer = comparer ?? EqualityComparer.Default; - objects = new List(); - } - - public SyncList(IList objects, IEqualityComparer comparer = null) - { - this.comparer = comparer ?? EqualityComparer.Default; - this.objects = objects; - } - - public bool IsDirty => changes.Count > 0; - - // throw away all the changes - // this should be called after a successfull sync - public void Flush() => changes.Clear(); - - public void Reset() - { - IsReadOnly = false; - changes.Clear(); - changesAhead = 0; - objects.Clear(); - } - - void AddOperation(Operation op, int itemIndex, T oldItem, T newItem) - { - if (IsReadOnly) - { - throw new InvalidOperationException("Synclists can only be modified at the server"); - } - - Change change = new Change - { - operation = op, - index = itemIndex, - item = newItem - }; - - changes.Add(change); - - Callback?.Invoke(op, itemIndex, oldItem, newItem); - } - - public void OnSerializeAll(NetworkWriter writer) - { - // if init, write the full list content - writer.WritePackedUInt32((uint)objects.Count); - - for (int i = 0; i < objects.Count; i++) - { - T obj = objects[i]; - writer.Write(obj); - } - - // all changes have been applied already - // thus the client will need to skip all the pending changes - // or they would be applied again. - // So we write how many changes are pending - writer.WritePackedUInt32((uint)changes.Count); - } - - public void OnSerializeDelta(NetworkWriter writer) - { - // write all the queued up changes - writer.WritePackedUInt32((uint)changes.Count); - - for (int i = 0; i < changes.Count; i++) - { - Change change = changes[i]; - writer.WriteByte((byte)change.operation); - - switch (change.operation) - { - case Operation.OP_ADD: - writer.Write(change.item); - break; - - case Operation.OP_CLEAR: - break; - - case Operation.OP_REMOVEAT: - writer.WritePackedUInt32((uint)change.index); - break; - - case Operation.OP_INSERT: - case Operation.OP_SET: - writer.WritePackedUInt32((uint)change.index); - writer.Write(change.item); - break; - } - } - } - - public void OnDeserializeAll(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - // if init, write the full list content - int count = (int)reader.ReadPackedUInt32(); - - objects.Clear(); - changes.Clear(); - - for (int i = 0; i < count; i++) - { - T obj = reader.Read(); - objects.Add(obj); - } - - // We will need to skip all these changes - // the next time the list is synchronized - // because they have already been applied - changesAhead = (int)reader.ReadPackedUInt32(); - } - - public void OnDeserializeDelta(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - int changesCount = (int)reader.ReadPackedUInt32(); - - for (int i = 0; i < changesCount; i++) - { - Operation operation = (Operation)reader.ReadByte(); - - // apply the operation only if it is a new change - // that we have not applied yet - bool apply = changesAhead == 0; - int index = 0; - T oldItem = default; - T newItem = default; - - switch (operation) - { - case Operation.OP_ADD: - newItem = reader.Read(); - if (apply) - { - index = objects.Count; - objects.Add(newItem); - } - break; - - case Operation.OP_CLEAR: - if (apply) - { - objects.Clear(); - } - break; - - case Operation.OP_INSERT: - index = (int)reader.ReadPackedUInt32(); - newItem = reader.Read(); - if (apply) - { - objects.Insert(index, newItem); - } - break; - - case Operation.OP_REMOVEAT: - index = (int)reader.ReadPackedUInt32(); - if (apply) - { - oldItem = objects[index]; - objects.RemoveAt(index); - } - break; - - case Operation.OP_SET: - index = (int)reader.ReadPackedUInt32(); - newItem = reader.Read(); - if (apply) - { - oldItem = objects[index]; - objects[index] = newItem; - } - break; - } - - if (apply) - { - Callback?.Invoke(operation, index, oldItem, newItem); - } - // we just skipped this change - else - { - changesAhead--; - } - } - } - - public void Add(T item) - { - objects.Add(item); - AddOperation(Operation.OP_ADD, objects.Count - 1, default, item); - } - - public void AddRange(IEnumerable range) - { - foreach (T entry in range) - { - Add(entry); - } - } - - public void Clear() - { - objects.Clear(); - AddOperation(Operation.OP_CLEAR, 0, default, default); - } - - public bool Contains(T item) => IndexOf(item) >= 0; - - public void CopyTo(T[] array, int index) => objects.CopyTo(array, index); - - public int IndexOf(T item) - { - for (int i = 0; i < objects.Count; ++i) - if (comparer.Equals(item, objects[i])) - return i; - return -1; - } - - public int FindIndex(Predicate match) - { - for (int i = 0; i < objects.Count; ++i) - if (match(objects[i])) - return i; - return -1; - } - - public T Find(Predicate match) - { - int i = FindIndex(match); - return (i != -1) ? objects[i] : default; - } - - public List FindAll(Predicate match) - { - List results = new List(); - for (int i = 0; i < objects.Count; ++i) - if (match(objects[i])) - results.Add(objects[i]); - return results; - } - - public void Insert(int index, T item) - { - objects.Insert(index, item); - AddOperation(Operation.OP_INSERT, index, default, item); - } - - public void InsertRange(int index, IEnumerable range) - { - foreach (T entry in range) - { - Insert(index, entry); - index++; - } - } - - public bool Remove(T item) - { - int index = IndexOf(item); - bool result = index >= 0; - if (result) - { - RemoveAt(index); - } - return result; - } - - public void RemoveAt(int index) - { - T oldItem = objects[index]; - objects.RemoveAt(index); - AddOperation(Operation.OP_REMOVEAT, index, oldItem, default); - } - - public int RemoveAll(Predicate match) - { - List toRemove = new List(); - for (int i = 0; i < objects.Count; ++i) - if (match(objects[i])) - toRemove.Add(objects[i]); - - foreach (T entry in toRemove) - { - Remove(entry); - } - - return toRemove.Count; - } - - public T this[int i] - { - get => objects[i]; - set - { - if (!comparer.Equals(objects[i], value)) - { - T oldItem = objects[i]; - objects[i] = value; - AddOperation(Operation.OP_SET, i, oldItem, value); - } - } - } - - public Enumerator GetEnumerator() => new Enumerator(this); - - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); - - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); - - // default Enumerator allocates. we need a custom struct Enumerator to - // not allocate on the heap. - // (System.Collections.Generic.List source code does the same) - // - // benchmark: - // uMMORPG with 800 monsters, Skills.GetHealthBonus() which runs a - // foreach on skills SyncList: - // before: 81.2KB GC per frame - // after: 0KB GC per frame - // => this is extremely important for MMO scale networking - public struct Enumerator : IEnumerator - { - readonly SyncList list; - int index; - public T Current { get; private set; } - - public Enumerator(SyncList list) - { - this.list = list; - index = -1; - Current = default; - } - - public bool MoveNext() - { - if (++index >= list.Count) - { - return false; - } - Current = list[index]; - return true; - } - - public void Reset() => index = -1; - object IEnumerator.Current => Current; - public void Dispose() { } - } - } -} diff --git a/Assets/Mirror/Runtime/SyncList.cs.meta b/Assets/Mirror/Runtime/SyncList.cs.meta deleted file mode 100644 index 9b9387d..0000000 --- a/Assets/Mirror/Runtime/SyncList.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 744fc71f748fe40d5940e04bf42b29f3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/SyncObject.cs b/Assets/Mirror/Runtime/SyncObject.cs deleted file mode 100644 index c7bf105..0000000 --- a/Assets/Mirror/Runtime/SyncObject.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace Mirror -{ - /// - /// A sync object is an object that can synchronize it's state - /// between server and client, such as a SyncList - /// - public interface SyncObject - { - /// - /// true if there are changes since the last flush - /// - bool IsDirty { get; } - - /// - /// Discard all the queued changes - /// Consider the object fully synchronized with clients - /// - void Flush(); - - /// - /// Write a full copy of the object - /// - /// - void OnSerializeAll(NetworkWriter writer); - - /// - /// Write the changes made to the object since last sync - /// - /// - void OnSerializeDelta(NetworkWriter writer); - - /// - /// Reads a full copy of the object - /// - /// - void OnDeserializeAll(NetworkReader reader); - - /// - /// Reads the changes made to the object since last sync - /// - /// - void OnDeserializeDelta(NetworkReader reader); - - /// - /// Resets the SyncObject so that it can be re-used - /// - void Reset(); - } -} diff --git a/Assets/Mirror/Runtime/SyncObject.cs.meta b/Assets/Mirror/Runtime/SyncObject.cs.meta deleted file mode 100644 index a67485d..0000000 --- a/Assets/Mirror/Runtime/SyncObject.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ae226d17a0c844041aa24cc2c023dd49 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/SyncSet.cs b/Assets/Mirror/Runtime/SyncSet.cs deleted file mode 100644 index 9ea4b91..0000000 --- a/Assets/Mirror/Runtime/SyncSet.cs +++ /dev/null @@ -1,340 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Mirror -{ - public class SyncSet : ISet, SyncObject - { - public delegate void SyncSetChanged(Operation op, T item); - - protected readonly ISet objects; - - public int Count => objects.Count; - public bool IsReadOnly { get; private set; } - public event SyncSetChanged Callback; - - public enum Operation : byte - { - OP_ADD, - OP_CLEAR, - OP_REMOVE - } - - struct Change - { - internal Operation operation; - internal T item; - } - - readonly List changes = new List(); - // how many changes we need to ignore - // this is needed because when we initialize the list, - // we might later receive changes that have already been applied - // so we need to skip them - int changesAhead; - - public SyncSet(ISet objects) - { - this.objects = objects; - } - - public void Reset() - { - IsReadOnly = false; - changes.Clear(); - changesAhead = 0; - objects.Clear(); - } - - public bool IsDirty => changes.Count > 0; - - // throw away all the changes - // this should be called after a successfull sync - public void Flush() => changes.Clear(); - - void AddOperation(Operation op, T item) - { - if (IsReadOnly) - { - throw new InvalidOperationException("SyncSets can only be modified at the server"); - } - - Change change = new Change - { - operation = op, - item = item - }; - - changes.Add(change); - - Callback?.Invoke(op, item); - } - - void AddOperation(Operation op) => AddOperation(op, default); - - public void OnSerializeAll(NetworkWriter writer) - { - // if init, write the full list content - writer.WritePackedUInt32((uint)objects.Count); - - foreach (T obj in objects) - { - writer.Write(obj); - } - - // all changes have been applied already - // thus the client will need to skip all the pending changes - // or they would be applied again. - // So we write how many changes are pending - writer.WritePackedUInt32((uint)changes.Count); - } - - public void OnSerializeDelta(NetworkWriter writer) - { - // write all the queued up changes - writer.WritePackedUInt32((uint)changes.Count); - - for (int i = 0; i < changes.Count; i++) - { - Change change = changes[i]; - writer.WriteByte((byte)change.operation); - - switch (change.operation) - { - case Operation.OP_ADD: - writer.Write(change.item); - break; - - case Operation.OP_CLEAR: - break; - - case Operation.OP_REMOVE: - writer.Write(change.item); - break; - } - } - } - - public void OnDeserializeAll(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - // if init, write the full list content - int count = (int)reader.ReadPackedUInt32(); - - objects.Clear(); - changes.Clear(); - - for (int i = 0; i < count; i++) - { - T obj = reader.Read(); - objects.Add(obj); - } - - // We will need to skip all these changes - // the next time the list is synchronized - // because they have already been applied - changesAhead = (int)reader.ReadPackedUInt32(); - } - - public void OnDeserializeDelta(NetworkReader reader) - { - // This list can now only be modified by synchronization - IsReadOnly = true; - - int changesCount = (int)reader.ReadPackedUInt32(); - - for (int i = 0; i < changesCount; i++) - { - Operation operation = (Operation)reader.ReadByte(); - - // apply the operation only if it is a new change - // that we have not applied yet - bool apply = changesAhead == 0; - T item = default; - - switch (operation) - { - case Operation.OP_ADD: - item = reader.Read(); - if (apply) - { - objects.Add(item); - } - break; - - case Operation.OP_CLEAR: - if (apply) - { - objects.Clear(); - } - break; - - case Operation.OP_REMOVE: - item = reader.Read(); - if (apply) - { - objects.Remove(item); - } - break; - } - - if (apply) - { - Callback?.Invoke(operation, item); - } - // we just skipped this change - else - { - changesAhead--; - } - } - } - - public bool Add(T item) - { - if (objects.Add(item)) - { - AddOperation(Operation.OP_ADD, item); - return true; - } - return false; - } - - void ICollection.Add(T item) - { - if (objects.Add(item)) - { - AddOperation(Operation.OP_ADD, item); - } - } - - public void Clear() - { - objects.Clear(); - AddOperation(Operation.OP_CLEAR); - } - - public bool Contains(T item) => objects.Contains(item); - - public void CopyTo(T[] array, int index) => objects.CopyTo(array, index); - - public bool Remove(T item) - { - if (objects.Remove(item)) - { - AddOperation(Operation.OP_REMOVE, item); - return true; - } - return false; - } - - public IEnumerator GetEnumerator() => objects.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public void ExceptWith(IEnumerable other) - { - if (other == this) - { - Clear(); - return; - } - - // remove every element in other from this - foreach (T element in other) - { - Remove(element); - } - } - - public void IntersectWith(IEnumerable other) - { - if (other is ISet otherSet) - { - IntersectWithSet(otherSet); - } - else - { - HashSet otherAsSet = new HashSet(other); - IntersectWithSet(otherAsSet); - } - } - - void IntersectWithSet(ISet otherSet) - { - List elements = new List(objects); - - foreach (T element in elements) - { - if (!otherSet.Contains(element)) - { - Remove(element); - } - } - } - - public bool IsProperSubsetOf(IEnumerable other) => objects.IsProperSubsetOf(other); - - public bool IsProperSupersetOf(IEnumerable other) => objects.IsProperSupersetOf(other); - - public bool IsSubsetOf(IEnumerable other) => objects.IsSubsetOf(other); - - public bool IsSupersetOf(IEnumerable other) => objects.IsSupersetOf(other); - - public bool Overlaps(IEnumerable other) => objects.Overlaps(other); - - public bool SetEquals(IEnumerable other) => objects.SetEquals(other); - - public void SymmetricExceptWith(IEnumerable other) - { - if (other == this) - { - Clear(); - } - else - { - foreach (T element in other) - { - if (!Remove(element)) - { - Add(element); - } - } - } - } - - public void UnionWith(IEnumerable other) - { - if (other != this) - { - foreach (T element in other) - { - Add(element); - } - } - } - } - - public class SyncHashSet : SyncSet - { - public SyncHashSet() : this(EqualityComparer.Default) { } - - public SyncHashSet(IEqualityComparer comparer) : base(new HashSet(comparer ?? EqualityComparer.Default)) { } - - // allocation free enumerator - public new HashSet.Enumerator GetEnumerator() => ((HashSet)objects).GetEnumerator(); - } - - public class SyncSortedSet : SyncSet - { - public SyncSortedSet() : this(Comparer.Default) { } - - public SyncSortedSet(IComparer comparer) : base(new SortedSet(comparer ?? Comparer.Default)) { } - - // allocation free enumerator - public new SortedSet.Enumerator GetEnumerator() => ((SortedSet)objects).GetEnumerator(); - } -} diff --git a/Assets/Mirror/Runtime/SyncSet.cs.meta b/Assets/Mirror/Runtime/SyncSet.cs.meta deleted file mode 100644 index 173523c..0000000 --- a/Assets/Mirror/Runtime/SyncSet.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8a31599d9f9dd4ef9999f7b9707c832c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport.meta b/Assets/Mirror/Runtime/Transport.meta deleted file mode 100644 index fc29442..0000000 --- a/Assets/Mirror/Runtime/Transport.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7825d46cd73fe47938869eb5427b40fa -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/FallbackTransport.cs b/Assets/Mirror/Runtime/Transport/FallbackTransport.cs deleted file mode 100644 index fbb4ced..0000000 --- a/Assets/Mirror/Runtime/Transport/FallbackTransport.cs +++ /dev/null @@ -1,189 +0,0 @@ -// uses the first available transport for server and client. -// example: to use Apathy if on Windows/Mac/Linux and fall back to Telepathy -// otherwise. -using System; -using UnityEngine; - -namespace Mirror -{ - [HelpURL("https://mirror-networking.com/docs/Transports/Fallback.html")] - public class FallbackTransport : Transport - { - public Transport[] transports; - - // the first transport that is available on this platform - Transport available; - - public void Awake() - { - if (transports == null || transports.Length == 0) - { - throw new Exception("FallbackTransport requires at least 1 underlying transport"); - } - InitClient(); - InitServer(); - available = GetAvailableTransport(); - Debug.Log("FallbackTransport available: " + available.GetType()); - } - - void OnEnable() - { - available.enabled = true; - } - - void OnDisable() - { - available.enabled = false; - } - - // The client just uses the first transport available - Transport GetAvailableTransport() - { - foreach (Transport transport in transports) - { - if (transport.Available()) - { - return transport; - } - } - throw new Exception("No transport suitable for this platform"); - } - - public override bool Available() - { - return available.Available(); - } - - // clients always pick the first transport - void InitClient() - { - // wire all the base transports to our events - foreach (Transport transport in transports) - { - transport.OnClientConnected.AddListener(OnClientConnected.Invoke); - transport.OnClientDataReceived.AddListener(OnClientDataReceived.Invoke); - transport.OnClientError.AddListener(OnClientError.Invoke); - transport.OnClientDisconnected.AddListener(OnClientDisconnected.Invoke); - } - } - - public override void ClientConnect(string address) - { - available.ClientConnect(address); - } - - public override void ClientConnect(Uri uri) - { - foreach (Transport transport in transports) - { - if (transport.Available()) - { - try - { - transport.ClientConnect(uri); - available = transport; - } - catch (ArgumentException) - { - // transport does not support the schema, just move on to the next one - } - } - } - throw new Exception("No transport suitable for this platform"); - } - - public override bool ClientConnected() - { - return available.ClientConnected(); - } - - public override void ClientDisconnect() - { - available.ClientDisconnect(); - } - - public override void ClientSend(int channelId, ArraySegment segment) - { - available.ClientSend(channelId, segment); - } - - void InitServer() - { - // wire all the base transports to our events - foreach (Transport transport in transports) - { - transport.OnServerConnected.AddListener(OnServerConnected.Invoke); - transport.OnServerDataReceived.AddListener(OnServerDataReceived.Invoke); - transport.OnServerError.AddListener(OnServerError.Invoke); - transport.OnServerDisconnected.AddListener(OnServerDisconnected.Invoke); - } - } - - // right now this just returns the first available uri, - // should we return the list of all available uri? - public override Uri ServerUri() => available.ServerUri(); - - public override bool ServerActive() - { - return available.ServerActive(); - } - - public override string ServerGetClientAddress(int connectionId) - { - return available.ServerGetClientAddress(connectionId); - } - - public override bool ServerDisconnect(int connectionId) - { - return available.ServerDisconnect(connectionId); - } - - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - available.ServerSend(connectionId, channelId, segment); - } - - public override void ServerStart() - { - available.ServerStart(); - } - - public override void ServerStop() - { - available.ServerStop(); - } - - public override void Shutdown() - { - available.Shutdown(); - } - - public override int GetMaxPacketSize(int channelId = 0) - { - // finding the max packet size in a fallback environment has to be - // done very carefully: - // * servers and clients might run different transports depending on - // which platform they are on. - // * there should only ever be ONE true max packet size for everyone, - // otherwise a spawn message might be sent to all tcp sockets, but - // be too big for some udp sockets. that would be a debugging - // nightmare and allow for possible exploits and players on - // different platforms seeing a different game state. - // => the safest solution is to use the smallest max size for all - // transports. that will never fail. - int mininumAllowedSize = int.MaxValue; - foreach (Transport transport in transports) - { - int size = transport.GetMaxPacketSize(channelId); - mininumAllowedSize = Mathf.Min(size, mininumAllowedSize); - } - return mininumAllowedSize; - } - - public override string ToString() - { - return available.ToString(); - } - - } -} diff --git a/Assets/Mirror/Runtime/Transport/FallbackTransport.cs.meta b/Assets/Mirror/Runtime/Transport/FallbackTransport.cs.meta deleted file mode 100644 index 509a58f..0000000 --- a/Assets/Mirror/Runtime/Transport/FallbackTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 330c9aab13d2d42069c6ebbe582b73ca -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP.meta b/Assets/Mirror/Runtime/Transport/KCP.meta deleted file mode 100644 index ba9d190..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 953bb5ec5ab2346a092f58061e01ba65 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport.meta b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport.meta deleted file mode 100644 index dedea2f..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7bdb797750d0a490684410110bf48192 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs deleted file mode 100644 index 63066c4..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs +++ /dev/null @@ -1,172 +0,0 @@ -//#if MIRROR <- commented out because MIRROR isn't defined on first import yet -using System; -using System.Linq; -using System.Net; -using Mirror; -using UnityEngine; - -namespace kcp2k -{ - public class KcpTransport : Transport - { - // scheme used by this transport - public const string Scheme = "kcp"; - - // common - [Header("Transport Configuration")] - public ushort Port = 7777; - [Tooltip("NoDelay is recommended to reduce latency. This also scales better without buffers getting full.")] - public bool NoDelay = true; - [Tooltip("KCP internal update interval. 100ms is KCP default, but a lower interval is recommended to minimize latency and to scale to more networked entities.")] - public uint Interval = 10; - [Header("Advanced")] - [Tooltip("KCP fastresend parameter. Faster resend for the cost of higher bandwidth.")] - public int FastResend = 0; - [Tooltip("KCP congestion window can be disabled. This is necessary to Mirror 10k Benchmark. Disable this for high scale games if connections get chocked regularly.")] - public bool CongestionWindow = true; // KCP 'NoCongestionWindow' is false by default. here we negate it for ease of use. - [Tooltip("KCP window size can be modified to support higher loads. For example, Mirror Benchmark requires 128 for 4k monsters, 256 for 10k monsters (if CongestionWindow is disabled.)")] - public uint SendWindowSize = 128; //Kcp.WND_SND; 32 by default. 128 is better for 4k Benchmark etc. - [Tooltip("KCP window size can be modified to support higher loads. For example, Mirror Benchmark requires 128 for 4k monsters, 256 for 10k monsters (if CongestionWindow is disabled.)")] - public uint ReceiveWindowSize = Kcp.WND_RCV; - - // server & client - KcpServer server; - KcpClient client; - - // debugging - [Header("Debug")] - public bool debugGUI; - - void Awake() - { - // TODO simplify after converting Mirror Transport events to Action - client = new KcpClient( - () => OnClientConnected.Invoke(), - (message) => OnClientDataReceived.Invoke(message, Channels.DefaultReliable), - () => OnClientDisconnected.Invoke() - ); - // TODO simplify after converting Mirror Transport events to Action - server = new KcpServer( - (connectionId) => OnServerConnected.Invoke(connectionId), - (connectionId, message) => OnServerDataReceived.Invoke(connectionId, message, Channels.DefaultReliable), - (connectionId) => OnServerDisconnected.Invoke(connectionId), - NoDelay, - Interval, - FastResend, - CongestionWindow, - SendWindowSize, - ReceiveWindowSize - ); - Debug.Log("KcpTransport initialized!"); - } - - // all except WebGL - public override bool Available() => - Application.platform != RuntimePlatform.WebGLPlayer; - - // client - public override bool ClientConnected() => client.connected; - public override void ClientConnect(string address) - { - client.Connect(address, Port, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize); - } - public override void ClientSend(int channelId, ArraySegment segment) - { - client.Send(segment); - } - public override void ClientDisconnect() => client.Disconnect(); - - // IMPORTANT: set script execution order to >1000 to call Transport's - // LateUpdate after all others. Fixes race condition where - // e.g. in uSurvival Transport would apply Cmds before - // ShoulderRotation.LateUpdate, resulting in projectile - // spawns at the point before shoulder rotation. - public void LateUpdate() - { - // note: we need to check enabled in case we set it to false - // when LateUpdate already started. - // (https://github.com/vis2k/Mirror/pull/379) - if (!enabled) - return; - - server.Tick(); - client.Tick(); - } - - // server - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder(); - builder.Scheme = Scheme; - builder.Host = Dns.GetHostName(); - builder.Port = Port; - return builder.Uri; - } - public override bool ServerActive() => server.IsActive(); - public override void ServerStart() => server.Start(Port); - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - server.Send(connectionId, segment); - } - public override bool ServerDisconnect(int connectionId) - { - server.Disconnect(connectionId); - return true; - } - public override string ServerGetClientAddress(int connectionId) => server.GetClientAddress(connectionId); - public override void ServerStop() => server.Stop(); - - // common - public override void Shutdown() {} - - // MTU - public override int GetMaxPacketSize(int channelId = Channels.DefaultReliable) => Kcp.MTU_DEF; - - public override string ToString() - { - return "KCP"; - } - - int GetTotalSendQueue() => - server.connections.Values.Sum(conn => conn.SendQueueCount); - int GetTotalReceiveQueue() => - server.connections.Values.Sum(conn => conn.ReceiveQueueCount); - int GetTotalSendBuffer() => - server.connections.Values.Sum(conn => conn.SendBufferCount); - int GetTotalReceiveBuffer() => - server.connections.Values.Sum(conn => conn.ReceiveBufferCount); - - void OnGUI() - { - if (!debugGUI) return; - - GUILayout.BeginArea(new Rect(5, 100, 300, 300)); - - if (ServerActive()) - { - GUILayout.BeginVertical("Box"); - GUILayout.Label("SERVER"); - GUILayout.Label(" connections: " + server.connections.Count); - GUILayout.Label(" SendQueue: " + GetTotalSendQueue()); - GUILayout.Label(" ReceiveQueue: " + GetTotalReceiveQueue()); - GUILayout.Label(" SendBuffer: " + GetTotalSendBuffer()); - GUILayout.Label(" ReceiveBuffer: " + GetTotalReceiveBuffer()); - GUILayout.EndVertical(); - } - - if (ClientConnected()) - { - GUILayout.BeginVertical("Box"); - GUILayout.Label("CLIENT"); - GUILayout.Label(" SendQueue: " + client.connection.SendQueueCount); - GUILayout.Label(" ReceiveQueue: " + client.connection.ReceiveQueueCount); - GUILayout.Label(" SendBuffer: " + client.connection.SendBufferCount); - GUILayout.Label(" ReceiveBuffer: " + client.connection.ReceiveBufferCount); - GUILayout.EndVertical(); - } - - GUILayout.EndArea(); - } - } -} -//#endif MIRROR <- commented out because MIRROR isn't defined on first import yet diff --git a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs.meta deleted file mode 100644 index f7280c8..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6b0fecffa3f624585964b0d0eb21b18e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k.meta deleted file mode 100644 index 1dceadf..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 71a1c8e8c022d4731a481c1808f37e5d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE deleted file mode 100644 index c77582e..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -MIT License - -Copyright (c) 2016 limpo1989 -Copyright (c) 2020 Paul Pacheco -Copyright (c) 2020 Lymdun -Copyright (c) 2020 vis2k - -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. \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE.meta deleted file mode 100644 index 49dc767..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/LICENSE.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 9a3e8369060cf4e94ac117603de47aa6 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION deleted file mode 100644 index 40ab2cb..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION +++ /dev/null @@ -1,9 +0,0 @@ -V1.1 -- high level cleanup, fixes, improvements - -V1.0 -- Kcp.cs now mirrors original Kcp.c behaviour - (this fixes dozens of bugs) - -V0.1 -- initial kcp-csharp based version \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION.meta deleted file mode 100644 index 2a07daa..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: ed3f2cf1bbf1b4d53a6f2c103d311f71 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel.meta deleted file mode 100644 index 1c11c3d..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5a54d18b954cb4407a28b633fc32ea6d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs deleted file mode 100644 index cdff96c..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs +++ /dev/null @@ -1,95 +0,0 @@ -// kcp client logic abstracted into a class. -// for use in Mirror, DOTSNET, testing, etc. -using System; -using UnityEngine; - -namespace kcp2k -{ - public class KcpClient - { - // events - public Action OnConnected; - public Action> OnData; - public Action OnDisconnected; - - // state - public KcpClientConnection connection; - public bool connected; - - public KcpClient(Action OnConnected, Action> OnData, Action OnDisconnected) - { - this.OnConnected = OnConnected; - this.OnData = OnData; - this.OnDisconnected = OnDisconnected; - } - - public void Connect(string address, ushort port, bool noDelay, uint interval, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) - { - if (connected) - { - Debug.LogWarning("KCP: client already connected!"); - return; - } - - connection = new KcpClientConnection(); - - // setup events - connection.OnAuthenticated = () => - { - Debug.Log($"KCP: OnClientConnected"); - connected = true; - OnConnected.Invoke(); - }; - connection.OnData = (message) => - { - //Debug.Log($"KCP: OnClientData({BitConverter.ToString(message.Array, message.Offset, message.Count)})"); - OnData.Invoke(message); - }; - connection.OnDisconnected = () => - { - Debug.Log($"KCP: OnClientDisconnected"); - connected = false; - connection = null; - OnDisconnected.Invoke(); - }; - - // connect - connection.Connect(address, port, noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize); - } - - public void Send(ArraySegment segment) - { - if (connected) - { - connection.Send(segment); - } - else Debug.LogWarning("KCP: can't send because client not connected!"); - } - - public void Disconnect() - { - // only if connected - // otherwise we end up in a deadlock because of an open Mirror bug: - // https://github.com/vis2k/Mirror/issues/2353 - if (connected) - { - // call Disconnect and let the connection handle it. - // DO NOT set it to null yet. it needs to be updated a few more - // times first. let the connection handle it! - connection?.Disconnect(); - } - } - - public void Tick() - { - // tick client connection - if (connection != null) - { - // recv on socket first - connection.RawReceive(); - // then update - connection.Tick(); - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs.meta deleted file mode 100644 index e55306b..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 6aa069a28ed24fedb533c102d9742b36 -timeCreated: 1603786960 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs deleted file mode 100644 index 5be1315..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs +++ /dev/null @@ -1,59 +0,0 @@ -using UnityEngine; -using System.Net; -using System.Net.Sockets; - -namespace kcp2k -{ - public class KcpClientConnection : KcpConnection - { - readonly byte[] buffer = new byte[1500]; - - public void Connect(string host, ushort port, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) - { - Debug.Log($"KcpClient: connect to {host}:{port}"); - IPAddress[] ipAddress = Dns.GetHostAddresses(host); - if (ipAddress.Length < 1) - throw new SocketException((int)SocketError.HostNotFound); - - remoteEndpoint = new IPEndPoint(ipAddress[0], port); - socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - socket.Connect(remoteEndpoint); - SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize); - - // client should send handshake to server as very first message - SendHandshake(); - - RawReceive(); - } - - // call from transport update - public void RawReceive() - { - try - { - if (socket != null) - { - while (socket.Poll(0, SelectMode.SelectRead)) - { - int msgLength = socket.ReceiveFrom(buffer, ref remoteEndpoint); - //Debug.Log($"KCP: client raw recv {msgLength} bytes = {BitConverter.ToString(buffer, 0, msgLength)}"); - RawInput(buffer, msgLength); - } - } - } - // this is fine, the socket might have been closed in the other end - catch (SocketException) {} - } - - protected override void Dispose() - { - socket.Close(); - socket = null; - } - - protected override void RawSend(byte[] data, int length) - { - socket.Send(data, length, SocketFlags.None); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs.meta deleted file mode 100644 index 3369918..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 96512e74aa8214a6faa8a412a7a07877 -timeCreated: 1602601237 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs deleted file mode 100644 index 12ea4ab..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs +++ /dev/null @@ -1,366 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using Debug = UnityEngine.Debug; - -namespace kcp2k -{ - enum KcpState { Connected, Authenticated, Disconnected } - - public abstract class KcpConnection - { - protected Socket socket; - protected EndPoint remoteEndpoint; - internal Kcp kcp; - - // kcp can have several different states, let's use a state machine - KcpState state = KcpState.Disconnected; - - public Action OnAuthenticated; - public Action> OnData; - public Action OnDisconnected; - - // If we don't receive anything these many milliseconds - // then consider us disconnected - public const int TIMEOUT = 10000; - uint lastReceiveTime; - - // internal time. - // StopWatch offers ElapsedMilliSeconds and should be more precise than - // Unity's time.deltaTime over long periods. - readonly Stopwatch refTime = new Stopwatch(); - - // recv buffer to avoid allocations - byte[] buffer = new byte[Kcp.MTU_DEF]; - - internal static readonly ArraySegment Hello = new ArraySegment(new byte[] { 0 }); - static readonly ArraySegment Goodbye = new ArraySegment(new byte[] { 1 }); - static readonly ArraySegment Ping = new ArraySegment(new byte[] { 2 }); - - // send a ping occasionally so we don't time out on the other end. - // for example, creating a character in an MMO could easily take a - // minute of no data being sent. which doesn't mean we want to time out. - // same goes for slow paced card games etc. - public const int PING_INTERVAL = 1000; - uint lastPingTime; - - // if we send more than kcp can handle, we will get ever growing - // send/recv buffers and queues and minutes of latency. - // => if a connection can't keep up, it should be disconnected instead - // to protect the server under heavy load, and because there is no - // point in growing to gigabytes of memory or minutes of latency! - // => 2k isn't enough. we reach 2k when spawning 4k monsters at once - // easily, but it does recover over time. - // => 10k seems safe. - // - // note: we have a ChokeConnectionAutoDisconnects test for this too! - internal const int QueueDisconnectThreshold = 10000; - - // getters for queue and buffer counts, used for debug info - public int SendQueueCount => kcp.snd_queue.Count; - public int ReceiveQueueCount => kcp.rcv_queue.Count; - public int SendBufferCount => kcp.snd_buf.Count; - public int ReceiveBufferCount => kcp.rcv_buf.Count; - - // NoDelay, interval, window size are the most important configurations. - // let's force require the parameters so we don't forget it anywhere. - protected void SetupKcp(bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) - { - kcp = new Kcp(0, RawSend); - // set nodelay. - // note that kcp uses 'nocwnd' internally so we negate the parameter - kcp.SetNoDelay(noDelay ? 1u : 0u, interval, fastResend, !congestionWindow); - kcp.SetWindowSize(sendWindowSize, receiveWindowSize); - refTime.Start(); - state = KcpState.Connected; - - Tick(); - } - - void HandleTimeout(uint time) - { - // note: we are also sending a ping regularly, so timeout should - // only ever happen if the connection is truly gone. - if (time >= lastReceiveTime + TIMEOUT) - { - Debug.LogWarning($"KCP: Connection timed out after {TIMEOUT}ms. Disconnecting."); - Disconnect(); - } - } - - void HandleDeadLink() - { - // kcp has 'dead_link' detection. might as well use it. - if (kcp.state == -1) - { - Debug.LogWarning("KCP Connection dead_link detected. Disconnecting."); - Disconnect(); - } - } - - // send a ping occasionally in order to not time out on the other end. - void HandlePing(uint time) - { - // enough time elapsed since last ping? - if (time >= lastPingTime + PING_INTERVAL) - { - // ping again and reset time - //Debug.Log("KCP: sending ping..."); - Send(Ping); - lastPingTime = time; - } - } - - void HandleChoked() - { - // disconnect connections that can't process the load. - // see QueueSizeDisconnect comments. - int total = kcp.rcv_queue.Count + kcp.snd_queue.Count + - kcp.rcv_buf.Count + kcp.snd_buf.Count; - if (total >= QueueDisconnectThreshold) - { - Debug.LogWarning($"KCP: disconnecting connection because it can't process data fast enough.\n" + - $"Queue total {total}>{QueueDisconnectThreshold}. rcv_queue={kcp.rcv_queue.Count} snd_queue={kcp.snd_queue.Count} rcv_buf={kcp.rcv_buf.Count} snd_buf={kcp.snd_buf.Count}\n" + - $"* Try to Enable NoDelay, decrease INTERVAL, disable Congestion Window (= enable NOCWND!), increase SEND/RECV WINDOW or compress data.\n" + - $"* Or perhaps the network is simply too slow on our end, or on the other end.\n"); - - // let's clear all pending sends before disconnting with 'Bye'. - // otherwise a single Flush in Disconnect() won't be enough to - // flush thousands of messages to finally deliver 'Bye'. - // this is just faster and more robust. - kcp.snd_queue.Clear(); - - Disconnect(); - } - } - - // reads the next message from connection. - bool ReceiveNext(out ArraySegment message) - { - // read only one message - int msgSize = kcp.PeekSize(); - if (msgSize > 0) - { - // only allow receiving up to MaxMessageSize sized messages. - // otherwise we would get BlockCopy ArgumentException anyway. - if (msgSize <= Kcp.MTU_DEF) - { - int received = kcp.Receive(buffer, msgSize); - if (received >= 0) - { - message = new ArraySegment(buffer, 0, msgSize); - lastReceiveTime = (uint)refTime.ElapsedMilliseconds; - - // return false if it was a ping message. true otherwise. - if (Utils.SegmentsEqual(message, Ping)) - { - //Debug.Log("KCP: received ping."); - return false; - } - return true; - } - else - { - // if receive failed, close everything - Debug.LogWarning($"Receive failed with error={received}. closing connection."); - Disconnect(); - } - } - // we don't allow sending messages > Max, so this must be an - // attacker. let's disconnect to avoid allocation attacks etc. - else - { - Debug.LogWarning($"KCP: possible allocation attack for msgSize {msgSize} > max {Kcp.MTU_DEF}. Disconnecting the connection."); - Disconnect(); - } - } - return false; - } - - void TickConnected(uint time) - { - // detect common events & ping - HandleTimeout(time); - HandleDeadLink(); - HandlePing(time); - HandleChoked(); - - kcp.Update(time); - - // any message received? - if (ReceiveNext(out ArraySegment message)) - { - // handshake message? - if (Utils.SegmentsEqual(message, Hello)) - { - Debug.Log("KCP: received handshake"); - state = KcpState.Authenticated; - OnAuthenticated?.Invoke(); - } - // otherwise it's random data from the internet, not - // from a legitimate player. disconnect. - else - { - Debug.LogWarning("KCP: received random data before handshake. Disconnecting the connection."); - Disconnect(); - } - } - } - - void TickAuthenticated(uint time) - { - // detect common events & ping - HandleTimeout(time); - HandleDeadLink(); - HandlePing(time); - HandleChoked(); - - kcp.Update(time); - - // process all received messages - while (ReceiveNext(out ArraySegment message)) - { - // disconnect message? - if (Utils.SegmentsEqual(message, Goodbye)) - { - Debug.Log("KCP: received disconnect message"); - Disconnect(); - break; - } - // otherwise regular message - else - { - // only accept regular messages - //Debug.LogWarning($"Kcp recv msg: {BitConverter.ToString(buffer, 0, msgSize)}"); - OnData?.Invoke(message); - } - } - } - - public void Tick() - { - uint time = (uint)refTime.ElapsedMilliseconds; - - try - { - switch (state) - { - case KcpState.Connected: - { - TickConnected(time); - break; - } - case KcpState.Authenticated: - { - TickAuthenticated(time); - break; - } - case KcpState.Disconnected: - { - // do nothing while disconnected - break; - } - } - } - catch (SocketException exception) - { - // this is ok, the connection was closed - Debug.Log($"KCP Connection: Disconnecting because {exception}. This is fine."); - Disconnect(); - } - catch (ObjectDisposedException exception) - { - // fine, socket was closed - Debug.Log($"KCP Connection: Disconnecting because {exception}. This is fine."); - Disconnect(); - } - catch (Exception ex) - { - // unexpected - Debug.LogException(ex); - Disconnect(); - } - } - - public void RawInput(byte[] buffer, int msgLength) - { - int input = kcp.Input(buffer, msgLength); - if (input != 0) - { - Debug.LogWarning($"Input failed with error={input} for buffer with length={msgLength}"); - } - } - - protected abstract void RawSend(byte[] data, int length); - - public void Send(ArraySegment data) - { - // only allow sending up to MaxMessageSize sized messages. - // other end won't process bigger messages anyway. - if (data.Count <= Kcp.MTU_DEF) - { - int sent = kcp.Send(data.Array, data.Offset, data.Count); - if (sent < 0) - { - Debug.LogWarning($"Send failed with error={sent} for segment with length={data.Count}"); - } - } - else Debug.LogError($"Failed to send message of size {data.Count} because it's larger than MaxMessageSize={Kcp.MTU_DEF}"); - } - - // server & client need to send handshake at different times, so we need - // to expose the function. - // * client should send it immediately. - // * server should send it as reply to client's handshake, not before - // (server should not reply to random internet messages with handshake) - public void SendHandshake() - { - Debug.Log("KcpConnection: sending Handshake to other end!"); - Send(Hello); - } - - protected virtual void Dispose() - { - } - - // disconnect this connection - public void Disconnect() - { - // only if not disconnected yet - if (state == KcpState.Disconnected) - return; - - // send a disconnect message - if (socket.Connected) - { - try - { - Send(Goodbye); - kcp.Flush(); - } - catch (SocketException) - { - // this is ok, the connection was already closed - } - catch (ObjectDisposedException) - { - // this is normal when we stop the server - // the socket is stopped so we can't send anything anymore - // to the clients - - // the clients will eventually timeout and realize they - // were disconnected - } - } - - // set as Disconnected, call event - Debug.Log("KCP Connection: Disconnected."); - state = KcpState.Disconnected; - OnDisconnected?.Invoke(); - } - - // get remote endpoint - public EndPoint GetRemoteEndPoint() => remoteEndpoint; - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs.meta deleted file mode 100644 index fa5dcff..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 3915c7c62b72d4dc2a9e4e76c94fc484 -timeCreated: 1602600432 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs deleted file mode 100644 index a6caf0a..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs +++ /dev/null @@ -1,229 +0,0 @@ -// kcp server logic abstracted into a class. -// for use in Mirror, DOTSNET, testing, etc. -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using UnityEngine; - -namespace kcp2k -{ - public class KcpServer - { - // events - public Action OnConnected; - public Action> OnData; - public Action OnDisconnected; - - // configuration - // NoDelay is recommended to reduce latency. This also scales better - // without buffers getting full. - public bool NoDelay; - // KCP internal update interval. 100ms is KCP default, but a lower - // interval is recommended to minimize latency and to scale to more - // networked entities. - public uint Interval; - // KCP fastresend parameter. Faster resend for the cost of higher - // bandwidth. - public int FastResend; - // KCP 'NoCongestionWindow' is false by default. here we negate it for - // ease of use. This can be disabled for high scale games if connections - // choke regularly. - public bool CongestionWindow; - // KCP window size can be modified to support higher loads. - // for example, Mirror Benchmark requires: - // 128, 128 for 4k monsters - // 512, 512 for 10k monsters - // 8192, 8192 for 20k monsters - public uint SendWindowSize; - public uint ReceiveWindowSize; - - // state - Socket socket; - EndPoint newClientEP = new IPEndPoint(IPAddress.IPv6Any, 0); - readonly byte[] buffer = new byte[Kcp.MTU_DEF]; - - // connections where connectionId is EndPoint.GetHashCode - public Dictionary connections = new Dictionary(); - - public KcpServer(Action OnConnected, - Action> OnData, - Action OnDisconnected, - bool NoDelay, - uint Interval, - int FastResend = 0, - bool CongestionWindow = true, - uint SendWindowSize = Kcp.WND_SND, - uint ReceiveWindowSize = Kcp.WND_RCV) - { - this.OnConnected = OnConnected; - this.OnData = OnData; - this.OnDisconnected = OnDisconnected; - this.NoDelay = NoDelay; - this.Interval = Interval; - this.FastResend = FastResend; - this.CongestionWindow = CongestionWindow; - this.SendWindowSize = SendWindowSize; - this.ReceiveWindowSize = ReceiveWindowSize; - } - - public bool IsActive() => socket != null; - - public void Start(ushort port) - { - // only start once - if (socket != null) - { - Debug.LogWarning("KCP: server already started!"); - } - - // listen - socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); - socket.DualMode = true; - socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port)); - } - - public void Send(int connectionId, ArraySegment segment) - { - if (connections.TryGetValue(connectionId, out KcpServerConnection connection)) - { - connection.Send(segment); - } - } - public void Disconnect(int connectionId) - { - if (connections.TryGetValue(connectionId, out KcpServerConnection connection)) - { - connection.Disconnect(); - } - } - - public string GetClientAddress(int connectionId) - { - if (connections.TryGetValue(connectionId, out KcpServerConnection connection)) - { - return (connection.GetRemoteEndPoint() as IPEndPoint).Address.ToString(); - } - return ""; - } - - HashSet connectionsToRemove = new HashSet(); - public void Tick() - { - while (socket != null && socket.Poll(0, SelectMode.SelectRead)) - { - int msgLength = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP); - //Debug.Log($"KCP: server raw recv {msgLength} bytes = {BitConverter.ToString(buffer, 0, msgLength)}"); - - // calculate connectionId from endpoint - int connectionId = newClientEP.GetHashCode(); - - // is this a new connection? - if (!connections.TryGetValue(connectionId, out KcpServerConnection connection)) - { - // create a new KcpConnection - connection = new KcpServerConnection(socket, newClientEP, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize); - - // DO NOT add to connections yet. only if the first message - // is actually the kcp handshake. otherwise it's either: - // * random data from the internet - // * or from a client connection that we just disconnected - // but that hasn't realized it yet, still sending data - // from last session that we should absolutely ignore. - // - // - // TODO this allocates a new KcpConnection for each new - // internet connection. not ideal, but C# UDP Receive - // already allocated anyway. - // - // expecting a MAGIC byte[] would work, but sending the raw - // UDP message without kcp's reliability will have low - // probability of being received. - // - // for now, this is fine. - - // setup authenticated event that also adds to connections - connection.OnAuthenticated = () => - { - // only send handshake to client AFTER we received his - // handshake in OnAuthenticated. - // we don't want to reply to random internet messages - // with handshakes each time. - connection.SendHandshake(); - - // add to connections dict after being authenticated. - connections.Add(connectionId, connection); - Debug.Log($"KCP: server added connection({connectionId}): {newClientEP}"); - - // setup Data + Disconnected events only AFTER the - // handshake. we don't want to fire OnServerDisconnected - // every time we receive invalid random data from the - // internet. - - // setup data event - connection.OnData = (message) => - { - // call mirror event - //Debug.Log($"KCP: OnServerDataReceived({connectionId}, {BitConverter.ToString(message.Array, message.Offset, message.Count)})"); - OnData.Invoke(connectionId, message); - }; - - // setup disconnected event - connection.OnDisconnected = () => - { - // flag for removal - // (can't remove directly because connection is updated - // and event is called while iterating all connections) - connectionsToRemove.Add(connectionId); - - // call mirror event - Debug.Log($"KCP: OnServerDisconnected({connectionId})"); - OnDisconnected.Invoke(connectionId); - }; - - // finally, call mirror OnConnected event - Debug.Log($"KCP: OnServerConnected({connectionId})"); - OnConnected.Invoke(connectionId); - }; - - // now input the message & tick - // connected event was set up. - // tick will process the first message and adds the - // connection if it was the handshake. - connection.RawInput(buffer, msgLength); - connection.Tick(); - - // again, do not add to connections. - // if the first message wasn't the kcp handshake then - // connection will simply be garbage collected. - } - // existing connection: simply input the message into kcp - else - { - connection.RawInput(buffer, msgLength); - } - } - - // tick all server connections - foreach (KcpServerConnection connection in connections.Values) - { - connection.Tick(); - } - - // remove disconnected connections - // (can't do it in connection.OnDisconnected because Tick is called - // while iterating connections) - foreach (int connectionId in connectionsToRemove) - { - connections.Remove(connectionId); - } - connectionsToRemove.Clear(); - } - - public void Stop() - { - socket?.Close(); - socket = null; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs.meta deleted file mode 100644 index ef720d4..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 9759159c6589494a9037f5e130a867ed -timeCreated: 1603787747 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs deleted file mode 100644 index bd2358e..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Net; -using System.Net.Sockets; - -namespace kcp2k -{ - public class KcpServerConnection : KcpConnection - { - public KcpServerConnection(Socket socket, EndPoint remoteEndpoint, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV) - { - this.socket = socket; - this.remoteEndpoint = remoteEndpoint; - SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize); - } - - protected override void RawSend(byte[] data, int length) - { - socket.SendTo(data, 0, length, SocketFlags.None, remoteEndpoint); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs.meta deleted file mode 100644 index 10d9803..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServerConnection.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 80a9b1ce9a6f14abeb32bfa9921d097b -timeCreated: 1602601483 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs deleted file mode 100644 index b67268e..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Unity.Collections.LowLevel.Unsafe; - -namespace kcp2k -{ - public static partial class Utils - { - // ArraySegment content comparison without Linq - public static unsafe bool SegmentsEqual(ArraySegment a, ArraySegment b) - { - if (a.Count == b.Count) - { - fixed (byte* aPtr = &a.Array[a.Offset], - bPtr = &b.Array[b.Offset]) - { - return UnsafeUtility.MemCmp(aPtr, bPtr, a.Count) == 0; - } - } - return false; - } - - } -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs.meta deleted file mode 100644 index 7b71362..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/Utils.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f3a2f1efc7864cb2b01af9d99470613a -timeCreated: 1603833478 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp.meta deleted file mode 100644 index a7d6e11..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5cafb8851a0084f3e94a580c207b3923 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs deleted file mode 100644 index 5fe5547..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("kcp2k.Tests")] \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs.meta deleted file mode 100644 index 6b442a9..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/AssemblyInfo.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: aec6a15ac7bd43129317ea1f01f19782 -timeCreated: 1602665988 \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs deleted file mode 100644 index 199926f..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs +++ /dev/null @@ -1,1025 +0,0 @@ -// Kcp based on https://github.com/skywind3000/kcp -// Kept as close to original as possible. -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace kcp2k -{ - public class Kcp - { - // original Kcp has a define option, which is not defined by default: - // #define FASTACK_CONSERVE - - public const int RTO_NDL = 30; // no delay min rto - public const int RTO_MIN = 100; // normal min rto - public const int RTO_DEF = 200; // default RTO - public const int RTO_MAX = 60000; // maximum RTO - public const int CMD_PUSH = 81; // cmd: push data - public const int CMD_ACK = 82; // cmd: ack - public const int CMD_WASK = 83; // cmd: window probe (ask) - public const int CMD_WINS = 84; // cmd: window size (tell) - public const int ASK_SEND = 1; // need to send CMD_WASK - public const int ASK_TELL = 2; // need to send CMD_WINS - public const int WND_SND = 32; // default send window - public const int WND_RCV = 128; // default receive window. must be >= max fragment size - public const int MTU_DEF = 1200; // default MTU (reduced to 1200 to fit all cases: https://en.wikipedia.org/wiki/Maximum_transmission_unit ; steam uses 1200 too!) - public const int ACK_FAST = 3; - public const int INTERVAL = 100; - public const int OVERHEAD = 24; - public const int DEADLINK = 20; - public const int THRESH_INIT = 2; - public const int THRESH_MIN = 2; - public const int PROBE_INIT = 7000; // 7 secs to probe window size - public const int PROBE_LIMIT = 120000; // up to 120 secs to probe window - public const int FASTACK_LIMIT = 5; // max times to trigger fastack - - internal struct AckItem - { - internal uint serialNumber; - internal uint timestamp; - } - - // kcp members. - internal int state; - readonly uint conv; // conversation - internal uint mtu; - internal uint mss; // maximum segment size - internal uint snd_una; // unacknowledged - internal uint snd_nxt; - internal uint rcv_nxt; - internal uint ssthresh; // slow start threshold - internal int rx_rttval; - internal int rx_srtt; // smoothed round trip time - internal int rx_rto; - internal int rx_minrto; - internal uint snd_wnd; // send window - internal uint rcv_wnd; // receive window - internal uint rmt_wnd; // remote window - internal uint cwnd; // congestion window - internal uint probe; - internal uint interval; - internal uint ts_flush; - internal uint xmit; - internal uint nodelay; // not a bool. original Kcp has '<2 else' check. - internal bool updated; - internal uint ts_probe; // timestamp probe - internal uint probe_wait; - internal uint dead_link; - internal uint incr; - internal uint current; // current time (milliseconds). set by Update. - - internal int fastresend; - internal int fastlimit; - internal bool nocwnd; // no congestion window - internal readonly Queue snd_queue = new Queue(16); // send queue - internal readonly Queue rcv_queue = new Queue(16); // receive queue - // snd_buffer needs index removals. - // C# LinkedList allocates for each entry, so let's keep List for now. - internal readonly List snd_buf = new List(16); // send buffer - // rcv_buffer needs index insertions and backwards iteration. - // C# LinkedList allocates for each entry, so let's keep List for now. - internal readonly List rcv_buf = new List(16); // receive buffer - internal readonly List acklist = new List(16); - - internal byte[] buffer; - readonly Action output; // buffer, size - - // get how many packet is waiting to be sent - public int WaitSnd => snd_buf.Count + snd_queue.Count; - - // ikcp_create - // create a new kcp control object, 'conv' must equal in two endpoint - // from the same connection. - public Kcp(uint conv, Action output) - { - this.conv = conv; - this.output = output; - snd_wnd = WND_SND; - rcv_wnd = WND_RCV; - rmt_wnd = WND_RCV; - mtu = MTU_DEF; - mss = mtu - OVERHEAD; - rx_rto = RTO_DEF; - rx_minrto = RTO_MIN; - interval = INTERVAL; - ts_flush = INTERVAL; - ssthresh = THRESH_INIT; - fastlimit = FASTACK_LIMIT; - dead_link = DEADLINK; - buffer = new byte[(mtu + OVERHEAD) * 3]; - } - - // ikcp_segment_new - // we keep the original function and add our pooling to it. - // this way we'll never miss it anywhere. - static Segment SegmentNew() - { - return Segment.Take(); - } - - // ikcp_segment_delete - // we keep the original function and add our pooling to it. - // this way we'll never miss it anywhere. - static void SegmentDelete(Segment seg) - { - Segment.Return(seg); - } - - // ikcp_recv - // receive data from kcp state machine - // returns number of bytes read. - // returns negative on error. - // note: pass negative length to peek. - public int Receive(byte[] buffer, int len) - { - // kcp's ispeek feature is not supported. - // this makes 'merge fragment' code significantly easier because - // we can iterate while queue.Count > 0 and dequeue each time. - // if we had to consider ispeek then count would always be > 0 and - // we would have to remove only after the loop. - // - //bool ispeek = len < 0; - if (len < 0) - throw new NotSupportedException("Receive ispeek for negative len is not supported!"); - - if (rcv_queue.Count == 0) - return -1; - - if (len < 0) len = -len; - - int peeksize = PeekSize(); - - if (peeksize < 0) - return -2; - - if (peeksize > len) - return -3; - - bool recover = rcv_queue.Count >= rcv_wnd; - - // merge fragment. - int offset = 0; - len = 0; - // original KCP iterates rcv_queue and deletes if !ispeek. - // removing from a c# queue while iterating is not possible, but - // we can change to 'while Count > 0' and remove every time. - // (we can remove every time because we removed ispeek support!) - while (rcv_queue.Count > 0) - { - // unlike original kcp, we dequeue instead of just getting the - // entry. this is fine because we remove it in ANY case. - Segment seg = rcv_queue.Dequeue(); - - Buffer.BlockCopy(seg.data.GetBuffer(), 0, buffer, offset, (int)seg.data.Position); - offset += (int)seg.data.Position; - - len += (int)seg.data.Position; - uint fragment = seg.frg; - - // note: ispeek is not supported in order to simplify this loop - - // unlike original kcp, we don't need to remove seg from queue - // because we already dequeued it. - // simply delete it - SegmentDelete(seg); - - if (fragment == 0) - break; - } - - // move available data from rcv_buf -> rcv_queue - int removed = 0; - foreach (Segment seg in rcv_buf) - { - if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd) - { - // can't remove while iterating. remember how many to remove - // and do it after the loop. - // note: don't return segment. we only add it to rcv_queue - ++removed; - // add - rcv_queue.Enqueue(seg); - rcv_nxt++; - } - else - { - break; - } - } - rcv_buf.RemoveRange(0, removed); - - // fast recover - if (rcv_queue.Count < rcv_wnd && recover) - { - // ready to send back CMD_WINS in flush - // tell remote my window size - probe |= ASK_TELL; - } - - return len; - } - - // ikcp_peeksize - // check the size of next message in the recv queue - public int PeekSize() - { - int length = 0; - - if (rcv_queue.Count == 0) return -1; - - Segment seq = rcv_queue.Peek(); - if (seq.frg == 0) return (int)seq.data.Position; - - if (rcv_queue.Count < seq.frg + 1) return -1; - - foreach (Segment seg in rcv_queue) - { - length += (int)seg.data.Position; - if (seg.frg == 0) break; - } - - return length; - } - - // ikcp_send - // sends byte[] to the other end. - public int Send(byte[] buffer, int offset, int len) - { - int count; - - if (len < 0) return -1; - - // streaming mode: removed. we never want to send 'hello' and - // receive 'he' 'll' 'o'. we want to always receive 'hello'. - - if (len <= mss) count = 1; - else count = (int)((len + mss - 1) / mss); - - // this might be a kcp bug. - // it's possible that we should check 'count >= rcv_wnd' instead of - // the constant here. - // see also: https://github.com/skywind3000/kcp/pull/291/files - if (count >= WND_RCV) return -2; - - if (count == 0) count = 1; - - // fragment - for (int i = 0; i < count; i++) - { - int size = len > (int)mss ? (int)mss : len; - Segment seg = SegmentNew(); - - if (len > 0) - { - seg.data.Write(buffer, offset, size); - } - // seg.len = size: WriteBytes sets segment.Position! - seg.frg = (byte)(count - i - 1); - snd_queue.Enqueue(seg); - offset += size; - len -= size; - } - - return 0; - } - - // ikcp_update_ack - void UpdateAck(int rtt) // round trip time - { - // https://tools.ietf.org/html/rfc6298 - if (rx_srtt == 0) - { - rx_srtt = rtt; - rx_rttval = rtt / 2; - } - else - { - int delta = rtt - rx_srtt; - if (delta < 0) delta = -delta; - rx_rttval = (3 * rx_rttval + delta) / 4; - rx_srtt = (7 * rx_srtt + rtt) / 8; - if (rx_srtt < 1) rx_srtt = 1; - } - int rto = rx_srtt + Math.Max((int)interval, 4 * rx_rttval); - rx_rto = Mathf.Clamp(rto, rx_minrto, RTO_MAX); - } - - // ikcp_shrink_buf - internal void ShrinkBuf() - { - if (snd_buf.Count > 0) - { - Segment seg = snd_buf[0]; - snd_una = seg.sn; - } - else - { - snd_una = snd_nxt; - } - } - - // ikcp_parse_ack - // removes the segment with 'sn' from send buffer - internal void ParseAck(uint sn) - { - if (Utils.TimeDiff(sn, snd_una) < 0 || Utils.TimeDiff(sn, snd_nxt) >= 0) - return; - - // for-int so we can erase while iterating - for (int i = 0; i < snd_buf.Count; ++i) - { - Segment seg = snd_buf[i]; - if (sn == seg.sn) - { - snd_buf.RemoveAt(i); - SegmentDelete(seg); - break; - } - if (Utils.TimeDiff(sn, seg.sn) < 0) - { - break; - } - } - } - - // ikcp_parse_una - void ParseUna(uint una) - { - int removed = 0; - foreach (Segment seg in snd_buf) - { - if (Utils.TimeDiff(una, seg.sn) > 0) - { - // can't remove while iterating. remember how many to remove - // and do it after the loop. - ++removed; - SegmentDelete(seg); - } - else - { - break; - } - } - snd_buf.RemoveRange(0, removed); - } - - // ikcp_parse_fastack - void ParseFastack(uint sn, uint ts) - { - if (Utils.TimeDiff(sn, snd_una) < 0 || Utils.TimeDiff(sn, snd_nxt) >= 0) - return; - - foreach (Segment seg in snd_buf) - { - if (Utils.TimeDiff(sn, seg.sn) < 0) - { - break; - } - else if (sn != seg.sn) - { -#if !FASTACK_CONSERVE - seg.fastack++; -#else - if (Utils.TimeDiff(ts, seg.ts) >= 0) - seg.fastack++; -#endif - } - } - } - - // ikcp_ack_push - // appends an ack. - void AckPush(uint sn, uint ts) - { - acklist.Add(new AckItem{ serialNumber = sn, timestamp = ts }); - } - - // ikcp_parse_data - void ParseData(Segment newseg) - { - uint sn = newseg.sn; - - if (Utils.TimeDiff(sn, rcv_nxt + rcv_wnd) >= 0 || - Utils.TimeDiff(sn, rcv_nxt) < 0) - { - SegmentDelete(newseg); - return; - } - - InsertSegmentInReceiveBuffer(newseg); - MoveReceiveBufferDataToReceiveQueue(); - } - - // inserts the segment into rcv_buf, ordered by seg.sn. - // drops the segment if one with the same seg.sn already exists. - // goes through receive buffer in reverse order for performance. - // - // note: see KcpTests.InsertSegmentInReceiveBuffer test! - // note: 'insert or delete' can be done in different ways, but let's - // keep consistency with original C kcp. - internal void InsertSegmentInReceiveBuffer(Segment newseg) - { - bool repeat = false; // 'duplicate' - - // original C iterates backwards, so we need to do that as well. - int i; - for (i = rcv_buf.Count - 1; i >= 0; i--) - { - Segment seg = rcv_buf[i]; - if (seg.sn == newseg.sn) - { - // duplicate segment found. nothing will be added. - repeat = true; - break; - } - if (Utils.TimeDiff(newseg.sn, seg.sn) > 0) - { - // this entry's sn is < newseg.sn, so let's stop - break; - } - } - - // no duplicate? then insert. - if (!repeat) - { - rcv_buf.Insert(i + 1, newseg); - } - // duplicate. just delete it. - else - { - SegmentDelete(newseg); - } - } - - // move available data from rcv_buf -> rcv_queue - void MoveReceiveBufferDataToReceiveQueue() - { - int removed = 0; - foreach (Segment seg in rcv_buf) - { - if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd) - { - // can't remove while iterating. remember how many to remove - // and do it after the loop. - ++removed; - rcv_queue.Enqueue(seg); - rcv_nxt++; - } - else - { - break; - } - } - rcv_buf.RemoveRange(0, removed); - } - - // ikcp_input - /// used when you receive a low level packet (eg. UDP packet) - public int Input(byte[] data, int size) - { - uint prev_una = snd_una; - uint maxack = 0; - uint latest_ts = 0; - int flag = 0; - - if (data == null || size < OVERHEAD) return -1; - - int offset = 0; - - while (true) - { - uint ts = 0; - uint sn = 0; - uint len = 0; - uint una = 0; - uint conv_ = 0; - ushort wnd = 0; - byte cmd = 0; - byte frg = 0; - - if (size < OVERHEAD) break; - - offset += Utils.Decode32U(data, offset, ref conv_); - if (conv_ != conv) return -1; - - offset += Utils.Decode8u(data, offset, ref cmd); - offset += Utils.Decode8u(data, offset, ref frg); - offset += Utils.Decode16U(data, offset, ref wnd); - offset += Utils.Decode32U(data, offset, ref ts); - offset += Utils.Decode32U(data, offset, ref sn); - offset += Utils.Decode32U(data, offset, ref una); - offset += Utils.Decode32U(data, offset, ref len); - - size -= OVERHEAD; - - if (size < len || len < 0) return -2; - - if (cmd != CMD_PUSH && cmd != CMD_ACK && - cmd != CMD_WASK && cmd != CMD_WINS) - return -3; - - rmt_wnd = wnd; - ParseUna(una); - ShrinkBuf(); - - if (cmd == CMD_ACK) - { - if (Utils.TimeDiff(current, ts) >= 0) - { - UpdateAck(Utils.TimeDiff(current, ts)); - } - ParseAck(sn); - ShrinkBuf(); - if (flag == 0) - { - flag = 1; - maxack = sn; - latest_ts = ts; - } - else - { - if (Utils.TimeDiff(sn, maxack) > 0) - { -#if !FASTACK_CONSERVE - maxack = sn; - latest_ts = ts; -#else - if (Utils.TimeDiff(ts, latest_ts) > 0) - { - maxack = sn; - latest_ts = ts; - } -#endif - } - } - } - else if (cmd == CMD_PUSH) - { - if (Utils.TimeDiff(sn, rcv_nxt + rcv_wnd) < 0) - { - AckPush(sn, ts); - if (Utils.TimeDiff(sn, rcv_nxt) >= 0) - { - Segment seg = SegmentNew(); - seg.conv = conv_; - seg.cmd = cmd; - seg.frg = frg; - seg.wnd = wnd; - seg.ts = ts; - seg.sn = sn; - seg.una = una; - if (len > 0) - { - seg.data.Write(data, offset, (int)len); - } - ParseData(seg); - } - } - } - else if (cmd == CMD_WASK) - { - // ready to send back CMD_WINS in flush - // tell remote my window size - probe |= ASK_TELL; - } - else if (cmd == CMD_WINS) - { - // do nothing - } - else - { - return -3; - } - - offset += (int)len; - size -= (int)len; - } - - if (flag != 0) - { - ParseFastack(maxack, latest_ts); - } - - // cwnd update when packet arrived - if (Utils.TimeDiff(snd_una, prev_una) > 0) - { - if (cwnd < rmt_wnd) - { - if (cwnd < ssthresh) - { - cwnd++; - incr += mss; - } - else - { - if (incr < mss) incr = mss; - incr += (mss * mss) / incr + (mss / 16); - if ((cwnd + 1) * mss <= incr) - { - cwnd = (incr + mss - 1) / ((mss > 0) ? mss : 1); - } - } - if (cwnd > rmt_wnd) - { - cwnd = rmt_wnd; - incr = rmt_wnd * mss; - } - } - } - - return 0; - } - - // ikcp_wnd_unused - uint WndUnused() - { - if (rcv_queue.Count < rcv_wnd) - return rcv_wnd - (uint)rcv_queue.Count; - return 0; - } - - // ikcp_flush - // flush remain ack segments - public void Flush() - { - int offset = 0; // buffer ptr in original C - bool lost = false; // lost segments - - // helper functions - void MakeSpace(int space) - { - if (offset + space > mtu) - { - output(buffer, offset); - offset = 0; - } - } - - void FlushBuffer() - { - if (offset > 0) - { - output(buffer, offset); - } - } - - // 'ikcp_update' haven't been called. - if (!updated) return; - - // kcp only stack allocs a segment here for performance, leaving - // its data buffer null because this segment's data buffer is never - // used. that's fine in C, but in C# our segment is class so we need - // to allocate and most importantly, not forget to deallocate it - // before returning. - Segment seg = SegmentNew(); - seg.conv = conv; - seg.cmd = CMD_ACK; - seg.wnd = WndUnused(); - seg.una = rcv_nxt; - - // flush acknowledges - foreach (AckItem ack in acklist) - { - MakeSpace(OVERHEAD); - // ikcp_ack_get assigns ack[i] to seg.sn, seg.ts - seg.sn = ack.serialNumber; - seg.ts = ack.timestamp; - offset += seg.Encode(buffer, offset); - } - - acklist.Clear(); - - // probe window size (if remote window size equals zero) - if (rmt_wnd == 0) - { - if (probe_wait == 0) - { - probe_wait = PROBE_INIT; - ts_probe = current + probe_wait; - } - else - { - if (Utils.TimeDiff(current, ts_probe) >= 0) - { - if (probe_wait < PROBE_INIT) - probe_wait = PROBE_INIT; - probe_wait += probe_wait / 2; - if (probe_wait > PROBE_LIMIT) - probe_wait = PROBE_LIMIT; - ts_probe = current + probe_wait; - probe |= ASK_SEND; - } - } - } - else - { - ts_probe = 0; - probe_wait = 0; - } - - // flush window probing commands - if ((probe & ASK_SEND) != 0) - { - seg.cmd = CMD_WASK; - MakeSpace(OVERHEAD); - offset += seg.Encode(buffer, offset); - } - - // flush window probing commands - if ((probe & ASK_TELL) != 0) - { - seg.cmd = CMD_WINS; - MakeSpace(OVERHEAD); - offset += seg.Encode(buffer, offset); - } - - probe = 0; - - // calculate window size - uint cwnd_ = Math.Min(snd_wnd, rmt_wnd); - if (!nocwnd) cwnd_ = Math.Min(cwnd, cwnd_); - - // move data from snd_queue to snd_buf - // sliding window, controlled by snd_nxt && sna_una+cwnd - while (Utils.TimeDiff(snd_nxt, snd_una + cwnd_) < 0) - { - if (snd_queue.Count == 0) break; - - Segment newseg = snd_queue.Dequeue(); - - newseg.conv = conv; - newseg.cmd = CMD_PUSH; - newseg.wnd = seg.wnd; - newseg.ts = current; - newseg.sn = snd_nxt++; - newseg.una = rcv_nxt; - newseg.resendts = current; - newseg.rto = rx_rto; - newseg.fastack = 0; - newseg.xmit = 0; - snd_buf.Add(newseg); - } - - // calculate resent - uint resent = fastresend > 0 ? (uint)fastresend : 0xffffffff; - uint rtomin = nodelay == 0 ? (uint)rx_rto >> 3 : 0; - - // flush data segments - int change = 0; - foreach (Segment segment in snd_buf) - { - bool needsend = false; - // initial transmit - if (segment.xmit == 0) - { - needsend = true; - segment.xmit++; - segment.rto = rx_rto; - segment.resendts = current + (uint)segment.rto + rtomin; - } - // RTO - else if (Utils.TimeDiff(current, segment.resendts) >= 0) - { - needsend = true; - segment.xmit++; - xmit++; - if (nodelay == 0) - { - segment.rto += Math.Max(segment.rto, rx_rto); - } - else - { - int step = (nodelay < 2) ? segment.rto : rx_rto; - segment.rto += step / 2; - } - segment.resendts = current + (uint)segment.rto; - lost = true; - } - // fast retransmit - else if (segment.fastack >= resent) - { - if (segment.xmit <= fastlimit || fastlimit <= 0) - { - needsend = true; - segment.xmit++; - segment.fastack = 0; - segment.resendts = current + (uint)segment.rto; - change++; - } - } - - if (needsend) - { - segment.ts = current; - segment.wnd = seg.wnd; - segment.una = rcv_nxt; - - int need = OVERHEAD + (int)segment.data.Position; - MakeSpace(need); - - offset += segment.Encode(buffer, offset); - - if (segment.data.Position > 0) - { - Buffer.BlockCopy(segment.data.GetBuffer(), 0, buffer, offset, (int)segment.data.Position); - offset += (int)segment.data.Position; - } - - if (segment.xmit >= dead_link) - { - state = -1; - } - } - } - - // kcp stackallocs 'seg'. our C# segment is a class though, so we - // need to properly delete and return it to the pool now that we are - // done with it. - SegmentDelete(seg); - - // flash remain segments - FlushBuffer(); - - // update ssthresh - // rate halving, https://tools.ietf.org/html/rfc6937 - if (change > 0) - { - uint inflight = snd_nxt - snd_una; - ssthresh = inflight / 2; - if (ssthresh < THRESH_MIN) - ssthresh = THRESH_MIN; - cwnd = ssthresh + resent; - incr = cwnd * mss; - } - - // congestion control, https://tools.ietf.org/html/rfc5681 - if (lost) - { - // original C uses 'cwnd', not kcp->cwnd! - ssthresh = cwnd_ / 2; - if (ssthresh < THRESH_MIN) - ssthresh = THRESH_MIN; - cwnd = 1; - incr = mss; - } - - if (cwnd < 1) - { - cwnd = 1; - incr = mss; - } - } - - // ikcp_update - // update state (call it repeatedly, every 10ms-100ms), or you can ask - // Check() when to call it again (without Input/Send calling). - // - // 'current' - current timestamp in millisec. pass it to Kcp so that - // Kcp doesn't have to do any stopwatch/deltaTime/etc. code - public void Update(uint currentTimeMilliSeconds) - { - current = currentTimeMilliSeconds; - - if (!updated) - { - updated = true; - ts_flush = current; - } - - int slap = Utils.TimeDiff(current, ts_flush); - - if (slap >= 10000 || slap < -10000) - { - ts_flush = current; - slap = 0; - } - - if (slap >= 0) - { - ts_flush += interval; - if (Utils.TimeDiff(current, ts_flush) >= 0) - { - ts_flush = current + interval; - } - Flush(); - } - } - - // ikcp_check - // Determine when should you invoke update - // Returns when you should invoke update in millisec, if there is no - // input/send calling. you can call update in that time, instead of - // call update repeatly. - // - // Important to reduce unnecessary update invoking. use it to schedule - // update (eg. implementing an epoll-like mechanism, or optimize update - // when handling massive kcp connections). - public uint Check(uint current_) - { - uint ts_flush_ = ts_flush; - int tm_flush = 0x7fffffff; - int tm_packet = 0x7fffffff; - - if (!updated) - { - return current_; - } - - if (Utils.TimeDiff(current_, ts_flush_) >= 10000 || - Utils.TimeDiff(current_, ts_flush_) < -10000) - { - ts_flush_ = current_; - } - - if (Utils.TimeDiff(current_, ts_flush_) >= 0) - { - return current_; - } - - tm_flush = Utils.TimeDiff(ts_flush_, current_); - - foreach (Segment seg in snd_buf) - { - int diff = Utils.TimeDiff(seg.resendts, current_); - if (diff <= 0) - { - return current_; - } - if (diff < tm_packet) tm_packet = diff; - } - - uint minimal = (uint)(tm_packet < tm_flush ? tm_packet : tm_flush); - if (minimal >= interval) minimal = interval; - - return current_ + minimal; - } - - // ikcp_setmtu - // Change MTU (Maximum Transmission Unit) size. - public void SetMtu(uint mtu) - { - if (mtu < 50 || mtu < OVERHEAD) - throw new ArgumentException("MTU must be higher than 50 and higher than OVERHEAD"); - - buffer = new byte[(mtu + OVERHEAD) * 3]; - this.mtu = mtu; - mss = mtu - OVERHEAD; - } - - // ikcp_interval - public void SetInterval(uint interval) - { - if (interval > 5000) interval = 5000; - else if (interval < 10) interval = 10; - this.interval = interval; - } - - // ikcp_nodelay - // Normal: false, 40, 0, 0 - // Fast: false, 30, 2, 1 - // Fast2: true, 20, 2, 1 - // Fast3: true, 10, 2, 1 - public void SetNoDelay(uint nodelay, uint interval = INTERVAL, int resend = 0, bool nocwnd = false) - { - this.nodelay = nodelay; - if (nodelay != 0) - { - rx_minrto = RTO_NDL; - } - else - { - rx_minrto = RTO_MIN; - } - - if (interval >= 0) - { - if (interval > 5000) interval = 5000; - else if (interval < 10) interval = 10; - this.interval = interval; - } - - if (resend >= 0) - { - fastresend = resend; - } - - this.nocwnd = nocwnd; - } - - // ikcp_wndsize - public void SetWindowSize(uint sendWindow, uint receiveWindow) - { - if (sendWindow > 0) - { - snd_wnd = sendWindow; - } - - if (receiveWindow > 0) - { - // must >= max fragment size - rcv_wnd = Math.Max(receiveWindow, WND_RCV); - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs.meta deleted file mode 100644 index 935b423..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a59b1cae10a334faf807432ab472f212 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs deleted file mode 100644 index ddea4c6..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace kcp2k -{ - // KCP Segment Definition - internal class Segment - { - internal uint conv; // conversation - internal uint cmd; // command, e.g. Kcp.CMD_ACK etc. - internal uint frg; // fragment - internal uint wnd; // window - internal uint ts; // timestamp - internal uint sn; // serial number - internal uint una; - internal uint resendts; // resend timestamp - internal int rto; - internal uint fastack; - internal uint xmit; - // we need a auto scaling byte[] with a WriteBytes function. - // MemoryStream does that perfectly, no need to reinvent the wheel. - // note: no need to pool it, because Segment is already pooled. - internal MemoryStream data = new MemoryStream(); - - // pool //////////////////////////////////////////////////////////////// - internal static readonly Stack Pool = new Stack(32); - - public static Segment Take() - { - if (Pool.Count > 0) - { - Segment seg = Pool.Pop(); - return seg; - } - return new Segment(); - } - - public static void Return(Segment seg) - { - seg.Reset(); - Pool.Push(seg); - } - //////////////////////////////////////////////////////////////////////// - - // ikcp_encode_seg - // encode a segment into buffer - internal int Encode(byte[] ptr, int offset) - { - int offset_ = offset; - offset += Utils.Encode32U(ptr, offset, conv); - offset += Utils.Encode8u(ptr, offset, (byte)cmd); - offset += Utils.Encode8u(ptr, offset, (byte)frg); - offset += Utils.Encode16U(ptr, offset, (ushort)wnd); - offset += Utils.Encode32U(ptr, offset, ts); - offset += Utils.Encode32U(ptr, offset, sn); - offset += Utils.Encode32U(ptr, offset, una); - offset += Utils.Encode32U(ptr, offset, (uint)data.Position); - - return offset - offset_; - } - - // reset to return a fresh segment to the pool - internal void Reset() - { - conv = 0; - cmd = 0; - frg = 0; - wnd = 0; - ts = 0; - sn = 0; - una = 0; - rto = 0; - xmit = 0; - resendts = 0; - fastack = 0; - - // keep buffer for next pool usage, but reset length (= bytes written) - data.SetLength(0); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs.meta deleted file mode 100644 index d14dc1a..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Segment.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fc58706a05dd3442c8fde858d5266855 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs deleted file mode 100644 index 8d23395..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace kcp2k -{ - public static partial class Utils - { - // encode 8 bits unsigned int - public static int Encode8u(byte[] p, int offset, byte c) - { - p[0 + offset] = c; - return 1; - } - - // decode 8 bits unsigned int - public static int Decode8u(byte[] p, int offset, ref byte c) - { - c = p[0 + offset]; - return 1; - } - - // encode 16 bits unsigned int (lsb) - public static int Encode16U(byte[] p, int offset, ushort w) - { - p[0 + offset] = (byte)(w >> 0); - p[1 + offset] = (byte)(w >> 8); - return 2; - } - - // decode 16 bits unsigned int (lsb) - public static int Decode16U(byte[] p, int offset, ref ushort c) - { - ushort result = 0; - result |= p[0 + offset]; - result |= (ushort)(p[1 + offset] << 8); - c = result; - return 2; - } - - // encode 32 bits unsigned int (lsb) - public static int Encode32U(byte[] p, int offset, uint l) - { - p[0 + offset] = (byte)(l >> 0); - p[1 + offset] = (byte)(l >> 8); - p[2 + offset] = (byte)(l >> 16); - p[3 + offset] = (byte)(l >> 24); - return 4; - } - - // decode 32 bits unsigned int (lsb) - public static int Decode32U(byte[] p, int offset, ref uint c) - { - uint result = 0; - result |= p[0 + offset]; - result |= (uint)(p[1 + offset] << 8); - result |= (uint)(p[2 + offset] << 16); - result |= (uint)(p[3 + offset] << 24); - c = result; - return 4; - } - - // timediff was a macro in original Kcp. let's inline it if possible. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int TimeDiff(uint later, uint earlier) - { - return (int)(later - earlier); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs.meta deleted file mode 100644 index 86118bc..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Utils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ef959eb716205bd48b050f010a9a35ae -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef deleted file mode 100644 index 296fc06..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "kcp2k", - "references": [], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef.meta b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef.meta deleted file mode 100644 index 1d70e80..0000000 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp2k.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6806a62c384838046a3c66c44f06d75f -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/LLAPITransport.cs b/Assets/Mirror/Runtime/Transport/LLAPITransport.cs deleted file mode 100644 index a10304c..0000000 --- a/Assets/Mirror/Runtime/Transport/LLAPITransport.cs +++ /dev/null @@ -1,384 +0,0 @@ -// Coburn: LLAPI is not available on UWP. There are a lot of compile directives here that we're checking against. -// Checking all of them may be overkill, but it's better to cover all the possible UWP directives. Sourced from -// https://docs.unity3d.com/Manual/PlatformDependentCompilation.html -// TODO: Check if LLAPI is supported on Xbox One? - -// LLAPITransport wraps UNET's LLAPI for use as a HLAPI TransportLayer, only if you're not on a UWP platform. -#if !(UNITY_WSA || UNITY_WSA_10_0 || UNITY_WINRT || UNITY_WINRT_10_0 || NETFX_CORE) - -using System; -using System.Net; -using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.Networking.Types; - -namespace Mirror -{ - [Obsolete("LLAPI is obsolete and will be removed from future versions of Unity")] - public class LLAPITransport : Transport - { - public const string Scheme = "unet"; - - public ushort port = 7777; - - [Tooltip("Enable for WebGL games. Can only do either WebSockets or regular Sockets, not both (yet).")] - public bool useWebsockets; - - // settings copied from uMMORPG configuration for best results - public ConnectionConfig connectionConfig = new ConnectionConfig - { - PacketSize = 1500, - FragmentSize = 500, - ResendTimeout = 1200, - DisconnectTimeout = 6000, - ConnectTimeout = 6000, - MinUpdateTimeout = 1, - PingTimeout = 2000, - ReducedPingTimeout = 100, - AllCostTimeout = 20, - NetworkDropThreshold = 80, - OverflowDropThreshold = 80, - MaxConnectionAttempt = 10, - AckDelay = 33, - SendDelay = 10, - MaxCombinedReliableMessageSize = 100, - MaxCombinedReliableMessageCount = 10, - MaxSentMessageQueueSize = 512, - AcksType = ConnectionAcksType.Acks128, - InitialBandwidth = 0, - BandwidthPeakFactor = 2, - WebSocketReceiveBufferMaxSize = 0, - UdpSocketReceiveBufferMaxSize = 0 - }; - - // settings copied from uMMORPG configuration for best results - public GlobalConfig globalConfig = new GlobalConfig - { - ReactorModel = ReactorModel.SelectReactor, - ThreadAwakeTimeout = 1, - ReactorMaximumSentMessages = 4096, - ReactorMaximumReceivedMessages = 4096, - MaxPacketSize = 2000, - MaxHosts = 16, - ThreadPoolSize = 3, - MinTimerTimeout = 1, - MaxTimerTimeout = 12000 - }; - - // always use first channel - readonly int channelId; - byte error; - - int clientId = -1; - int clientConnectionId = -1; - readonly byte[] clientReceiveBuffer = new byte[4096]; - byte[] clientSendBuffer; - - int serverHostId = -1; - readonly byte[] serverReceiveBuffer = new byte[4096]; - byte[] serverSendBuffer; - - void OnValidate() - { - // add connectionconfig channels if none - if (connectionConfig.Channels.Count == 0) - { - // channel 0 is reliable fragmented sequenced - connectionConfig.AddChannel(QosType.ReliableFragmentedSequenced); - // channel 1 is unreliable - connectionConfig.AddChannel(QosType.Unreliable); - } - } - - void Awake() - { - NetworkTransport.Init(globalConfig); - Debug.Log("LLAPITransport initialized!"); - - // initialize send buffers - clientSendBuffer = new byte[globalConfig.MaxPacketSize]; - serverSendBuffer = new byte[globalConfig.MaxPacketSize]; - } - - public override bool Available() - { - // LLAPI runs on all platforms, including webgl - return true; - } - - #region client - public override bool ClientConnected() - { - return clientConnectionId != -1; - } - - - - void ClientConnect(string address, int port) - { - // LLAPI can't handle 'localhost' - if (address.ToLower() == "localhost") address = "127.0.0.1"; - - HostTopology hostTopology = new HostTopology(connectionConfig, 1); - - // important: - // AddHost(topology) doesn't work in WebGL. - // AddHost(topology, port) works in standalone and webgl if port=0 - clientId = NetworkTransport.AddHost(hostTopology, 0); - - clientConnectionId = NetworkTransport.Connect(clientId, address, port, 0, out error); - NetworkError networkError = (NetworkError)error; - if (networkError != NetworkError.Ok) - { - Debug.LogWarning("NetworkTransport.Connect failed: clientId=" + clientId + " address= " + address + " port=" + port + " error=" + error); - clientConnectionId = -1; - } - } - - public override void ClientConnect(string address) - { - ClientConnect(address, port); - } - - public override void ClientConnect(Uri uri) - { - if (uri.Scheme != Scheme) - throw new ArgumentException($"Invalid url {uri}, use {Scheme}://host:port instead", nameof(uri)); - - int serverPort = uri.IsDefaultPort ? port : uri.Port; - - ClientConnect(uri.Host, serverPort); - } - - public override void ClientSend(int channelId, ArraySegment segment) - { - // Send buffer is copied internally, so we can get rid of segment - // immediately after returning and it still works. - // -> BUT segment has an offset, Send doesn't. we need to manually - // copy it into a 0-offset array - if (segment.Count <= clientSendBuffer.Length) - { - Array.Copy(segment.Array, segment.Offset, clientSendBuffer, 0, segment.Count); - NetworkTransport.Send(clientId, clientConnectionId, channelId, clientSendBuffer, segment.Count, out error); - } - else Debug.LogError("LLAPI.ClientSend: buffer( " + clientSendBuffer.Length + ") too small for: " + segment.Count); - } - - public bool ProcessClientMessage() - { - if (clientId == -1) - return false; - - NetworkEventType networkEvent = NetworkTransport.ReceiveFromHost(clientId, out int connectionId, out int channel, clientReceiveBuffer, clientReceiveBuffer.Length, out int receivedSize, out error); - - // note: 'error' is used for extra information, e.g. the reason for - // a disconnect. we don't necessarily have to throw an error if - // error != 0. but let's log it for easier debugging. - // - // DO NOT return after error != 0. otherwise Disconnect won't be - // registered. - NetworkError networkError = (NetworkError)error; - if (networkError != NetworkError.Ok) - { - string message = "NetworkTransport.Receive failed: hostid=" + clientId + " connId=" + connectionId + " channelId=" + channel + " error=" + networkError; - OnClientError.Invoke(new Exception(message)); - } - - // raise events - switch (networkEvent) - { - case NetworkEventType.ConnectEvent: - OnClientConnected.Invoke(); - break; - case NetworkEventType.DataEvent: - ArraySegment data = new ArraySegment(clientReceiveBuffer, 0, receivedSize); - OnClientDataReceived.Invoke(data, channel); - break; - case NetworkEventType.DisconnectEvent: - OnClientDisconnected.Invoke(); - break; - default: - return false; - } - - return true; - } - - public string ClientGetAddress() - { - NetworkTransport.GetConnectionInfo(serverHostId, clientId, out string address, out int port, out NetworkID networkId, out NodeID node, out error); - return address; - } - - public override void ClientDisconnect() - { - if (clientId != -1) - { - NetworkTransport.RemoveHost(clientId); - clientId = -1; - } - } - #endregion - - #region server - - // right now this just returns the first available uri, - // should we return the list of all available uri? - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder(); - builder.Scheme = Scheme; - builder.Host = Dns.GetHostName(); - builder.Port = port; - return builder.Uri; - } - - public override bool ServerActive() - { - return serverHostId != -1; - } - - public override void ServerStart() - { - if (useWebsockets) - { - HostTopology topology = new HostTopology(connectionConfig, ushort.MaxValue - 1); - serverHostId = NetworkTransport.AddWebsocketHost(topology, port); - //Debug.Log("LLAPITransport.ServerStartWebsockets port=" + port + " max=" + maxConnections + " hostid=" + serverHostId); - } - else - { - HostTopology topology = new HostTopology(connectionConfig, ushort.MaxValue - 1); - serverHostId = NetworkTransport.AddHost(topology, port); - //Debug.Log("LLAPITransport.ServerStart port=" + port + " max=" + maxConnections + " hostid=" + serverHostId); - } - } - - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - // Send buffer is copied internally, so we can get rid of segment - // immediately after returning and it still works. - // -> BUT segment has an offset, Send doesn't. we need to manually - // copy it into a 0-offset array - if (segment.Count <= serverSendBuffer.Length) - { - // copy to 0-offset - Array.Copy(segment.Array, segment.Offset, serverSendBuffer, 0, segment.Count); - - // send - NetworkTransport.Send(serverHostId, connectionId, channelId, serverSendBuffer, segment.Count, out error); - } - else Debug.LogError("LLAPI.ServerSend: buffer( " + serverSendBuffer.Length + ") too small for: " + segment.Count); - } - - public bool ProcessServerMessage() - { - if (serverHostId == -1) - return false; - - NetworkEventType networkEvent = NetworkTransport.ReceiveFromHost(serverHostId, out int connectionId, out int channel, serverReceiveBuffer, serverReceiveBuffer.Length, out int receivedSize, out error); - - // note: 'error' is used for extra information, e.g. the reason for - // a disconnect. we don't necessarily have to throw an error if - // error != 0. but let's log it for easier debugging. - // - // DO NOT return after error != 0. otherwise Disconnect won't be - // registered. - NetworkError networkError = (NetworkError)error; - if (networkError != NetworkError.Ok) - { - string message = "NetworkTransport.Receive failed: hostid=" + serverHostId + " connId=" + connectionId + " channelId=" + channel + " error=" + networkError; - - // TODO write a TransportException or better - OnServerError.Invoke(connectionId, new Exception(message)); - } - - // LLAPI client sends keep alive messages (75-6C-6C) on channel=110. - // ignore all messages that aren't for our selected channel. - /*if (channel != channelId) - { - return false; - }*/ - - switch (networkEvent) - { - case NetworkEventType.ConnectEvent: - OnServerConnected.Invoke(connectionId); - break; - case NetworkEventType.DataEvent: - ArraySegment data = new ArraySegment(serverReceiveBuffer, 0, receivedSize); - OnServerDataReceived.Invoke(connectionId, data, channel); - break; - case NetworkEventType.DisconnectEvent: - OnServerDisconnected.Invoke(connectionId); - break; - default: - // nothing or a message we don't recognize - return false; - } - - return true; - } - - public override bool ServerDisconnect(int connectionId) - { - return NetworkTransport.Disconnect(serverHostId, connectionId, out error); - } - - public override string ServerGetClientAddress(int connectionId) - { - NetworkTransport.GetConnectionInfo(serverHostId, connectionId, out string address, out int port, out NetworkID networkId, out NodeID node, out error); - return address; - } - - public override void ServerStop() - { - NetworkTransport.RemoveHost(serverHostId); - serverHostId = -1; - Debug.Log("LLAPITransport.ServerStop"); - } - #endregion - - #region common - // IMPORTANT: set script execution order to >1000 to call Transport's - // LateUpdate after all others. Fixes race condition where - // e.g. in uSurvival Transport would apply Cmds before - // ShoulderRotation.LateUpdate, resulting in projectile - // spawns at the point before shoulder rotation. - public void LateUpdate() - { - // process all messages - while (ProcessClientMessage()) { } - while (ProcessServerMessage()) { } - } - - public override void Shutdown() - { - NetworkTransport.Shutdown(); - serverHostId = -1; - clientConnectionId = -1; - Debug.Log("LLAPITransport.Shutdown"); - } - - public override int GetMaxPacketSize(int channelId) - { - return globalConfig.MaxPacketSize; - } - - public override string ToString() - { - if (ServerActive()) - { - return "LLAPI Server port: " + port; - } - else if (ClientConnected()) - { - string ip = ClientGetAddress(); - return "LLAPI Client ip: " + ip + " port: " + port; - } - return "LLAPI (inactive/disconnected)"; - } - #endregion - } -} -#endif diff --git a/Assets/Mirror/Runtime/Transport/LLAPITransport.cs.meta b/Assets/Mirror/Runtime/Transport/LLAPITransport.cs.meta deleted file mode 100644 index e2c4a04..0000000 --- a/Assets/Mirror/Runtime/Transport/LLAPITransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d333dcc8c7bd34f35896f5a9b4c9e759 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 1001 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs b/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs deleted file mode 100644 index 121755b..0000000 --- a/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace Mirror -{ - /// - /// Allows Middleware to override some of the transport methods or let the inner transport handle them. - /// - public abstract class MiddlewareTransport : Transport - { - /// - /// Transport to call to after middleware - /// - public Transport inner; - - public override bool Available() => inner.Available(); - public override int GetMaxPacketSize(int channelId = 0) => inner.GetMaxPacketSize(channelId); - public override void Shutdown() => inner.Shutdown(); - - #region Client - public override void ClientConnect(string address) => inner.ClientConnect(address); - public override bool ClientConnected() => inner.ClientConnected(); - public override void ClientDisconnect() => inner.ClientDisconnect(); - public override void ClientSend(int channelId, ArraySegment segment) => inner.ClientSend(channelId, segment); - #endregion - - #region Server - public override bool ServerActive() => inner.ServerActive(); - public override void ServerStart() => inner.ServerStart(); - public override void ServerStop() => inner.ServerStop(); - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) => inner.ServerSend(connectionId, channelId, segment); - public override bool ServerDisconnect(int connectionId) => inner.ServerDisconnect(connectionId); - public override string ServerGetClientAddress(int connectionId) => inner.ServerGetClientAddress(connectionId); - public override Uri ServerUri() => inner.ServerUri(); - #endregion - } -} diff --git a/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs.meta b/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs.meta deleted file mode 100644 index dfbaabb..0000000 --- a/Assets/Mirror/Runtime/Transport/MiddlewareTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 46f20ede74658e147a1af57172710de2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs b/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs deleted file mode 100644 index aa93769..0000000 --- a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs +++ /dev/null @@ -1,278 +0,0 @@ -using System; -using System.Text; -using UnityEngine; - -namespace Mirror -{ - // a transport that can listen to multiple underlying transport at the same time - public class MultiplexTransport : Transport - { - public Transport[] transports; - - Transport available; - - public void Awake() - { - if (transports == null || transports.Length == 0) - { - Debug.LogError("Multiplex transport requires at least 1 underlying transport"); - } - InitClient(); - InitServer(); - } - - void OnEnable() - { - foreach (Transport transport in transports) - { - transport.enabled = true; - } - } - - void OnDisable() - { - foreach (Transport transport in transports) - { - transport.enabled = false; - } - } - - public override bool Available() - { - // available if any of the transports is available - foreach (Transport transport in transports) - { - if (transport.Available()) - { - return true; - } - } - return false; - } - - #region Client - // clients always pick the first transport - void InitClient() - { - // wire all the base transports to my events - foreach (Transport transport in transports) - { - transport.OnClientConnected.AddListener(OnClientConnected.Invoke); - transport.OnClientDataReceived.AddListener(OnClientDataReceived.Invoke); - transport.OnClientError.AddListener(OnClientError.Invoke); - transport.OnClientDisconnected.AddListener(OnClientDisconnected.Invoke); - } - } - - public override void ClientConnect(string address) - { - foreach (Transport transport in transports) - { - if (transport.Available()) - { - available = transport; - transport.ClientConnect(address); - return; - } - } - throw new ArgumentException("No transport suitable for this platform"); - } - - public override void ClientConnect(Uri uri) - { - foreach (Transport transport in transports) - { - if (transport.Available()) - { - try - { - transport.ClientConnect(uri); - available = transport; - return; - } - catch (ArgumentException) - { - // transport does not support the schema, just move on to the next one - } - } - } - throw new ArgumentException("No transport suitable for this platform"); - } - - public override bool ClientConnected() - { - return (object)available != null && available.ClientConnected(); - } - - public override void ClientDisconnect() - { - if ((object)available != null) - available.ClientDisconnect(); - } - - public override void ClientSend(int channelId, ArraySegment segment) - { - available.ClientSend(channelId, segment); - } - - #endregion - - #region Server - // connection ids get mapped to base transports - // if we have 3 transports, then - // transport 0 will produce connection ids [0, 3, 6, 9, ...] - // transport 1 will produce connection ids [1, 4, 7, 10, ...] - // transport 2 will produce connection ids [2, 5, 8, 11, ...] - int FromBaseId(int transportId, int connectionId) - { - return connectionId * transports.Length + transportId; - } - - int ToBaseId(int connectionId) - { - return connectionId / transports.Length; - } - - int ToTransportId(int connectionId) - { - return connectionId % transports.Length; - } - - void InitServer() - { - // wire all the base transports to my events - for (int i = 0; i < transports.Length; i++) - { - // this is required for the handlers, if I use i directly - // then all the handlers will use the last i - int locali = i; - Transport transport = transports[i]; - - transport.OnServerConnected.AddListener(baseConnectionId => - { - OnServerConnected.Invoke(FromBaseId(locali, baseConnectionId)); - }); - - transport.OnServerDataReceived.AddListener((baseConnectionId, data, channel) => - { - OnServerDataReceived.Invoke(FromBaseId(locali, baseConnectionId), data, channel); - }); - - transport.OnServerError.AddListener((baseConnectionId, error) => - { - OnServerError.Invoke(FromBaseId(locali, baseConnectionId), error); - }); - transport.OnServerDisconnected.AddListener(baseConnectionId => - { - OnServerDisconnected.Invoke(FromBaseId(locali, baseConnectionId)); - }); - } - } - - // for now returns the first uri, - // should we return all available uris? - public override Uri ServerUri() - { - return transports[0].ServerUri(); - } - - - public override bool ServerActive() - { - // avoid Linq.All allocations - foreach (Transport transport in transports) - { - if (!transport.ServerActive()) - { - return false; - } - } - return true; - } - - public override string ServerGetClientAddress(int connectionId) - { - int baseConnectionId = ToBaseId(connectionId); - int transportId = ToTransportId(connectionId); - return transports[transportId].ServerGetClientAddress(baseConnectionId); - } - - public override bool ServerDisconnect(int connectionId) - { - int baseConnectionId = ToBaseId(connectionId); - int transportId = ToTransportId(connectionId); - return transports[transportId].ServerDisconnect(baseConnectionId); - } - - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - int baseConnectionId = ToBaseId(connectionId); - int transportId = ToTransportId(connectionId); - - for (int i = 0; i < transports.Length; ++i) - { - if (i == transportId) - { - transports[i].ServerSend(baseConnectionId, channelId, segment); - } - } - } - - public override void ServerStart() - { - foreach (Transport transport in transports) - { - transport.ServerStart(); - } - } - - public override void ServerStop() - { - foreach (Transport transport in transports) - { - transport.ServerStop(); - } - } - #endregion - - public override int GetMaxPacketSize(int channelId = 0) - { - // finding the max packet size in a multiplex environment has to be - // done very carefully: - // * servers run multiple transports at the same time - // * different clients run different transports - // * there should only ever be ONE true max packet size for everyone, - // otherwise a spawn message might be sent to all tcp sockets, but - // be too big for some udp sockets. that would be a debugging - // nightmare and allow for possible exploits and players on - // different platforms seeing a different game state. - // => the safest solution is to use the smallest max size for all - // transports. that will never fail. - int mininumAllowedSize = int.MaxValue; - foreach (Transport transport in transports) - { - int size = transport.GetMaxPacketSize(channelId); - mininumAllowedSize = Mathf.Min(size, mininumAllowedSize); - } - return mininumAllowedSize; - } - - public override void Shutdown() - { - foreach (Transport transport in transports) - { - transport.Shutdown(); - } - } - - public override string ToString() - { - StringBuilder builder = new StringBuilder(); - foreach (Transport transport in transports) - { - builder.AppendLine(transport.ToString()); - } - return builder.ToString().Trim(); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs.meta b/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs.meta deleted file mode 100644 index 6e97b28..0000000 --- a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 929e3234c7db540b899f00183fc2b1fe -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport.meta deleted file mode 100644 index 5baa80f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a3ba68af305d809418d6c6a804939290 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs deleted file mode 100644 index 25269e2..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("SimpleWebTransport.Tests.Runtime")] -[assembly: InternalsVisibleTo("SimpleWebTransport.Tests.Editor")] diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs.meta deleted file mode 100644 index 028a307..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/AssemblyInfo.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ee9e76201f7665244bd6ab8ea343a83f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client.meta deleted file mode 100644 index e6e2943..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5faa957b8d9fc314ab7596ccf14750d9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs deleted file mode 100644 index 419dc18..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Concurrent; -using UnityEngine; - -namespace Mirror.SimpleWeb -{ - public enum ClientState - { - NotConnected = 0, - Connecting = 1, - Connected = 2, - Disconnecting = 3, - } - /// - /// Client used to control websockets - /// Base class used by WebSocketClientWebGl and WebSocketClientStandAlone - /// - public abstract class SimpleWebClient - { - public static SimpleWebClient Create(int maxMessageSize, int maxMessagesPerTick, TcpConfig tcpConfig) - { -#if UNITY_WEBGL && !UNITY_EDITOR - return new WebSocketClientWebGl(maxMessageSize, maxMessagesPerTick); -#else - return new WebSocketClientStandAlone(maxMessageSize, maxMessagesPerTick, tcpConfig); -#endif - } - - readonly int maxMessagesPerTick; - protected readonly int maxMessageSize; - protected readonly ConcurrentQueue receiveQueue = new ConcurrentQueue(); - protected readonly BufferPool bufferPool; - - protected ClientState state; - - protected SimpleWebClient(int maxMessageSize, int maxMessagesPerTick) - { - this.maxMessageSize = maxMessageSize; - this.maxMessagesPerTick = maxMessagesPerTick; - bufferPool = new BufferPool(5, 20, maxMessageSize); - } - - public ClientState ConnectionState => state; - - public event Action onConnect; - public event Action onDisconnect; - public event Action> onData; - public event Action onError; - - public void ProcessMessageQueue(MonoBehaviour behaviour) - { - int processedCount = 0; - // check enabled every time incase behaviour was disabled after data - while ( - behaviour.enabled && - processedCount < maxMessagesPerTick && - // Dequeue last - receiveQueue.TryDequeue(out Message next) - ) - { - processedCount++; - - switch (next.type) - { - case EventType.Connected: - onConnect?.Invoke(); - break; - case EventType.Data: - onData?.Invoke(next.data.ToSegment()); - next.data.Release(); - break; - case EventType.Disconnected: - onDisconnect?.Invoke(); - break; - case EventType.Error: - onError?.Invoke(next.exception); - break; - } - } - } - - public abstract void Connect(Uri serverAddress); - public abstract void Disconnect(); - public abstract void Send(ArraySegment segment); - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs.meta deleted file mode 100644 index 90c361b..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/SimpleWebClient.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 13131761a0bf5a64dadeccd700fe26e5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone.meta deleted file mode 100644 index bf320c6..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a9c19d05220a87c4cbbe4d1e422da0aa -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs deleted file mode 100644 index 87f4ecd..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace Mirror.SimpleWeb -{ - /// - /// Handles Handshake to the server when it first connects - /// The client handshake does not need buffers to reduce allocations since it only happens once - /// - internal class ClientHandshake - { - public bool TryHandshake(Connection conn, Uri uri) - { - try - { - Stream stream = conn.stream; - - byte[] keyBuffer = new byte[16]; - using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) - { - rng.GetBytes(keyBuffer); - } - - string key = Convert.ToBase64String(keyBuffer); - string keySum = key + Constants.HandshakeGUID; - byte[] keySumBytes = Encoding.ASCII.GetBytes(keySum); - Log.Verbose($"Handshake Hashing {Encoding.ASCII.GetString(keySumBytes)}"); - - byte[] keySumHash = SHA1.Create().ComputeHash(keySumBytes); - - string expectedResponse = Convert.ToBase64String(keySumHash); - string handshake = - $"GET /chat HTTP/1.1\r\n" + - $"Host: {uri.Host}:{uri.Port}\r\n" + - $"Upgrade: websocket\r\n" + - $"Connection: Upgrade\r\n" + - $"Sec-WebSocket-Key: {key}\r\n" + - $"Sec-WebSocket-Version: 13\r\n" + - "\r\n"; - byte[] encoded = Encoding.ASCII.GetBytes(handshake); - stream.Write(encoded, 0, encoded.Length); - - byte[] responseBuffer = new byte[1000]; - - int? lengthOrNull = ReadHelper.SafeReadTillMatch(stream, responseBuffer, 0, responseBuffer.Length, Constants.endOfHandshake); - - if (!lengthOrNull.HasValue) - { - Log.Error("Connected closed before handshake"); - return false; - } - - string responseString = Encoding.ASCII.GetString(responseBuffer, 0, lengthOrNull.Value); - - string acceptHeader = "Sec-WebSocket-Accept: "; - int startIndex = responseString.IndexOf(acceptHeader) + acceptHeader.Length; - int endIndex = responseString.IndexOf("\r\n", startIndex); - string responseKey = responseString.Substring(startIndex, endIndex - startIndex); - - if (responseKey != expectedResponse) - { - Log.Error($"Response key incorrect, Response:{responseKey} Expected:{expectedResponse}"); - return false; - } - - return true; - } - catch (Exception e) - { - Log.Exception(e); - return false; - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs.meta deleted file mode 100644 index ad3d40d..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientHandshake.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3ffdcabc9e28f764a94fc4efc82d3e8b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs deleted file mode 100644 index be93f6c..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.IO; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; - -namespace Mirror.SimpleWeb -{ - internal class ClientSslHelper - { - internal bool TryCreateStream(Connection conn, Uri uri) - { - NetworkStream stream = conn.client.GetStream(); - if (uri.Scheme != "wss") - { - conn.stream = stream; - return true; - } - - try - { - conn.stream = CreateStream(stream, uri); - return true; - } - catch (Exception e) - { - Log.Error($"Create SSLStream Failed: {e}", false); - return false; - } - } - - Stream CreateStream(NetworkStream stream, Uri uri) - { - SslStream sslStream = new SslStream(stream, true, ValidateServerCertificate); - sslStream.AuthenticateAsClient(uri.Host); - return sslStream; - } - - static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - // Do not allow this client to communicate with unauthenticated servers. - - // only accept if no errors - return sslPolicyErrors == SslPolicyErrors.None; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs.meta deleted file mode 100644 index d6be2bb..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/ClientSslHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 46055a75559a79849a750f39a766db61 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs deleted file mode 100644 index 43737b0..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - public class WebSocketClientStandAlone : SimpleWebClient - { - readonly ClientSslHelper sslHelper; - readonly ClientHandshake handshake; - readonly TcpConfig tcpConfig; - Connection conn; - - - internal WebSocketClientStandAlone(int maxMessageSize, int maxMessagesPerTick, TcpConfig tcpConfig) : base(maxMessageSize, maxMessagesPerTick) - { -#if UNITY_WEBGL && !UNITY_EDITOR - throw new NotSupportedException(); -#else - sslHelper = new ClientSslHelper(); - handshake = new ClientHandshake(); - this.tcpConfig = tcpConfig; -#endif - } - - public override void Connect(Uri serverAddress) - { - state = ClientState.Connecting; - Thread receiveThread = new Thread(() => ConnectAndReceiveLoop(serverAddress)); - receiveThread.IsBackground = true; - receiveThread.Start(); - } - - void ConnectAndReceiveLoop(Uri serverAddress) - { - try - { - TcpClient client = new TcpClient(); - tcpConfig.ApplyTo(client); - - // create connection object here so dispose correctly disconnects on failed connect - conn = new Connection(client, AfterConnectionDisposed); - conn.receiveThread = Thread.CurrentThread; - - try - { - client.Connect(serverAddress.Host, serverAddress.Port); - } - catch (SocketException) - { - client.Dispose(); - throw; - } - - - bool success = sslHelper.TryCreateStream(conn, serverAddress); - if (!success) - { - Log.Warn("Failed to create Stream"); - conn.Dispose(); - return; - } - - success = handshake.TryHandshake(conn, serverAddress); - if (!success) - { - Log.Warn("Failed Handshake"); - conn.Dispose(); - return; - } - - Log.Info("HandShake Successful"); - - state = ClientState.Connected; - - receiveQueue.Enqueue(new Message(EventType.Connected)); - - Thread sendThread = new Thread(() => - { - SendLoop.Config sendConfig = new SendLoop.Config( - conn, - bufferSize: Constants.HeaderSize + Constants.MaskSize + maxMessageSize, - setMask: true); - - SendLoop.Loop(sendConfig); - }); - - conn.sendThread = sendThread; - sendThread.IsBackground = true; - sendThread.Start(); - - ReceiveLoop.Config config = new ReceiveLoop.Config(conn, - maxMessageSize, - false, - receiveQueue, - bufferPool); - ReceiveLoop.Loop(config); - } - catch (ThreadInterruptedException e) { Log.InfoException(e); } - catch (ThreadAbortException e) { Log.InfoException(e); } - catch (Exception e) { Log.Exception(e); } - finally - { - // close here incase connect fails - conn?.Dispose(); - } - } - - void AfterConnectionDisposed(Connection conn) - { - state = ClientState.NotConnected; - // make sure Disconnected event is only called once - receiveQueue.Enqueue(new Message(EventType.Disconnected)); - } - - public override void Disconnect() - { - state = ClientState.Disconnecting; - Log.Info("Disconnect Called"); - if (conn == null) - { - state = ClientState.NotConnected; - } - else - { - conn?.Dispose(); - } - } - - public override void Send(ArraySegment segment) - { - ArrayBuffer buffer = bufferPool.Take(segment.Count); - buffer.CopyFrom(segment); - - conn.sendQueue.Enqueue(buffer); - conn.sendPending.Set(); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs.meta deleted file mode 100644 index 37229d3..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/StandAlone/WebSocketClientStandAlone.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05a9c87dea309e241a9185e5aa0d72ab -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl.meta deleted file mode 100644 index 2d81f7f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7142349d566213c4abc763afaf4d91a1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs deleted file mode 100644 index 6af4671..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -#if UNITY_WEBGL -using System.Runtime.InteropServices; -#endif - -namespace Mirror.SimpleWeb -{ - internal static class SimpleWebJSLib - { -#if UNITY_WEBGL - [DllImport("__Internal")] - internal static extern bool IsConnected(int index); - -#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments - [DllImport("__Internal")] -#pragma warning restore CA2101 // Specify marshaling for P/Invoke string arguments - internal static extern int Connect(string address, Action openCallback, Action closeCallBack, Action messageCallback, Action errorCallback); - - [DllImport("__Internal")] - internal static extern void Disconnect(int index); - - [DllImport("__Internal")] - internal static extern bool Send(int index, byte[] array, int offset, int length); -#else - internal static bool IsConnected(int index) => throw new NotSupportedException(); - - internal static int Connect(string address, Action openCallback, Action closeCallBack, Action messageCallback, Action errorCallback) => throw new NotSupportedException(); - - internal static void Disconnect(int index) => throw new NotSupportedException(); - - internal static bool Send(int index, byte[] array, int offset, int length) => throw new NotSupportedException(); -#endif - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs.meta deleted file mode 100644 index 9dfa12e..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/SimpleWebJSLib.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 97b96a0b65c104443977473323c2ff35 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs deleted file mode 100644 index 0c953ef..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using AOT; - -namespace Mirror.SimpleWeb -{ - public class WebSocketClientWebGl : SimpleWebClient - { - static readonly Dictionary instances = new Dictionary(); - - /// - /// key for instances sent between c# and js - /// - int index; - - internal WebSocketClientWebGl(int maxMessageSize, int maxMessagesPerTick) : base(maxMessageSize, maxMessagesPerTick) - { -#if !UNITY_WEBGL || UNITY_EDITOR - throw new NotSupportedException(); -#endif - } - - public bool CheckJsConnected() => SimpleWebJSLib.IsConnected(index); - - public override void Connect(Uri serverAddress) - { - index = SimpleWebJSLib.Connect(serverAddress.ToString(), OpenCallback, CloseCallBack, MessageCallback, ErrorCallback); - instances.Add(index, this); - state = ClientState.Connecting; - } - - public override void Disconnect() - { - state = ClientState.Disconnecting; - // disconnect should cause closeCallback and OnDisconnect to be called - SimpleWebJSLib.Disconnect(index); - } - - public override void Send(ArraySegment segment) - { - if (segment.Count > maxMessageSize) - { - Log.Error($"Cant send message with length {segment.Count} because it is over the max size of {maxMessageSize}"); - return; - } - - SimpleWebJSLib.Send(index, segment.Array, 0, segment.Count); - } - - void onOpen() - { - receiveQueue.Enqueue(new Message(EventType.Connected)); - state = ClientState.Connected; - } - - void onClose() - { - // this code should be last in this class - - receiveQueue.Enqueue(new Message(EventType.Disconnected)); - state = ClientState.NotConnected; - instances.Remove(index); - } - - void onMessage(IntPtr bufferPtr, int count) - { - try - { - ArrayBuffer buffer = bufferPool.Take(count); - buffer.CopyFrom(bufferPtr, count); - - receiveQueue.Enqueue(new Message(buffer)); - } - catch (Exception e) - { - Log.Error($"onData {e.GetType()}: {e.Message}\n{e.StackTrace}"); - receiveQueue.Enqueue(new Message(e)); - } - } - - void onErr() - { - receiveQueue.Enqueue(new Message(new Exception("Javascript Websocket error"))); - Disconnect(); - } - - [MonoPInvokeCallback(typeof(Action))] - static void OpenCallback(int index) => instances[index].onOpen(); - - [MonoPInvokeCallback(typeof(Action))] - static void CloseCallBack(int index) => instances[index].onClose(); - - [MonoPInvokeCallback(typeof(Action))] - static void MessageCallback(int index, IntPtr bufferPtr, int count) => instances[index].onMessage(bufferPtr, count); - - [MonoPInvokeCallback(typeof(Action))] - static void ErrorCallback(int index) => instances[index].onErr(); - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs.meta deleted file mode 100644 index 3827d3a..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 015c5b1915fd1a64cbe36444d16b2f7d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin.meta deleted file mode 100644 index b516a8f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1999985791b91b9458059e88404885a7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib deleted file mode 100644 index 13da1b7..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib +++ /dev/null @@ -1,105 +0,0 @@ -// this will create a global object -const SimpleWeb = { - webSockets: [], - next: 1, - GetWebSocket: function (index) { - return SimpleWeb.webSockets[index] - }, - AddNextSocket: function (webSocket) { - var index = SimpleWeb.next; - SimpleWeb.next++; - SimpleWeb.webSockets[index] = webSocket; - return index; - }, - RemoveSocket: function (index) { - SimpleWeb.webSockets[index] = undefined; - }, -}; - -function IsConnected(index) { - var webSocket = SimpleWeb.GetWebSocket(index); - if (webSocket) { - return webSocket.readyState === webSocket.OPEN; - } - else { - return false; - } -} - -function Connect(addressPtr, openCallbackPtr, closeCallBackPtr, messageCallbackPtr, errorCallbackPtr) { - const address = Pointer_stringify(addressPtr); - console.log("Connecting to " + address); - // Create webSocket connection. - webSocket = new WebSocket(address); - webSocket.binaryType = 'arraybuffer'; - const index = SimpleWeb.AddNextSocket(webSocket); - - // Connection opened - webSocket.addEventListener('open', function (event) { - console.log("Connected to " + address); - Runtime.dynCall('vi', openCallbackPtr, [index]); - }); - webSocket.addEventListener('close', function (event) { - console.log("Disconnected from " + address); - Runtime.dynCall('vi', closeCallBackPtr, [index]); - }); - - // Listen for messages - webSocket.addEventListener('message', function (event) { - if (event.data instanceof ArrayBuffer) { - // TODO dont alloc each time - var array = new Uint8Array(event.data); - var arrayLength = array.length; - - var bufferPtr = _malloc(arrayLength); - var dataBuffer = new Uint8Array(HEAPU8.buffer, bufferPtr, arrayLength); - dataBuffer.set(array); - - Runtime.dynCall('viii', messageCallbackPtr, [index, bufferPtr, arrayLength]); - _free(bufferPtr); - } - else { - console.error("message type not supported") - } - }); - - webSocket.addEventListener('error', function (event) { - console.error('Socket Error', event); - - Runtime.dynCall('vi', errorCallbackPtr, [index]); - }); - - return index; -} - -function Disconnect(index) { - var webSocket = SimpleWeb.GetWebSocket(index); - if (webSocket) { - webSocket.close(1000, "Disconnect Called by Mirror"); - } - - SimpleWeb.RemoveSocket(index); -} - -function Send(index, arrayPtr, offset, length) { - var webSocket = SimpleWeb.GetWebSocket(index); - if (webSocket) { - const start = arrayPtr + offset; - const end = start + length; - const data = HEAPU8.buffer.slice(start, end); - webSocket.send(data); - return true; - } - return false; -} - - -const SimpleWebLib = { - $SimpleWeb: SimpleWeb, - IsConnected, - Connect, - Disconnect, - Send -}; -autoAddDeps(SimpleWebLib, '$SimpleWeb'); -mergeInto(LibraryManager.library, SimpleWebLib); \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib.meta deleted file mode 100644 index cc1319e..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Client/Webgl/plugin/SimpleWeb.jslib.meta +++ /dev/null @@ -1,37 +0,0 @@ -fileFormatVersion: 2 -guid: 54452a8c6d2ca9b49a8c79f81b50305c -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - Facebook: WebGL - second: - enabled: 1 - settings: {} - - first: - WebGL: WebGL - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common.meta deleted file mode 100644 index 078faaa..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 564d2cd3eee5b21419553c0528739d1b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs deleted file mode 100644 index 7c930b7..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - public interface IBufferOwner - { - void Return(ArrayBuffer buffer); - } - - public sealed class ArrayBuffer : IDisposable - { - readonly IBufferOwner owner; - - public readonly byte[] array; - - /// - /// number of bytes writen to buffer - /// - internal int count; - - /// - /// How many times release needs to be called before buffer is returned to pool - /// This allows the buffer to be used in multiple places at the same time - /// - public void SetReleasesRequired(int required) - { - releasesRequired = required; - } - - /// - /// How many times release needs to be called before buffer is returned to pool - /// This allows the buffer to be used in multiple places at the same time - /// - /// - /// This value is normally 0, but can be changed to require release to be called multiple times - /// - int releasesRequired; - - public ArrayBuffer(IBufferOwner owner, int size) - { - this.owner = owner; - array = new byte[size]; - } - - public void Release() - { - int newValue = Interlocked.Decrement(ref releasesRequired); - if (newValue <= 0) - { - count = 0; - owner.Return(this); - } - } - public void Dispose() - { - Release(); - } - - - public void CopyTo(byte[] target, int offset) - { - if (count > (target.Length + offset)) throw new ArgumentException($"{nameof(count)} was greater than {nameof(target)}.length", nameof(target)); - - Buffer.BlockCopy(array, 0, target, offset, count); - } - - public void CopyFrom(ArraySegment segment) - { - CopyFrom(segment.Array, segment.Offset, segment.Count); - } - - public void CopyFrom(byte[] source, int offset, int length) - { - if (length > array.Length) throw new ArgumentException($"{nameof(length)} was greater than {nameof(array)}.length", nameof(length)); - - count = length; - Buffer.BlockCopy(source, offset, array, 0, length); - } - - public void CopyFrom(IntPtr bufferPtr, int length) - { - if (length > array.Length) throw new ArgumentException($"{nameof(length)} was greater than {nameof(array)}.length", nameof(length)); - - count = length; - Marshal.Copy(bufferPtr, array, 0, length); - } - - public ArraySegment ToSegment() - { - return new ArraySegment(array, 0, count); - } - - [Conditional("UNITY_ASSERTIONS")] - internal void Validate(int arraySize) - { - if (array.Length != arraySize) - { - Log.Error("Buffer that was returned had an array of the wrong size"); - } - } - } - - internal class BufferBucket : IBufferOwner - { - public readonly int arraySize; - readonly ConcurrentQueue buffers; - - /// - /// keeps track of how many arrays are taken vs returned - /// - internal int _current = 0; - - public BufferBucket(int arraySize) - { - this.arraySize = arraySize; - buffers = new ConcurrentQueue(); - } - - public ArrayBuffer Take() - { - IncrementCreated(); - if (buffers.TryDequeue(out ArrayBuffer buffer)) - { - return buffer; - } - else - { - Log.Verbose($"BufferBucket({arraySize}) create new"); - return new ArrayBuffer(this, arraySize); - } - } - - public void Return(ArrayBuffer buffer) - { - DecrementCreated(); - buffer.Validate(arraySize); - buffers.Enqueue(buffer); - } - - [Conditional("DEBUG")] - void IncrementCreated() - { - int next = Interlocked.Increment(ref _current); - Log.Verbose($"BufferBucket({arraySize}) count:{next}"); - } - [Conditional("DEBUG")] - void DecrementCreated() - { - int next = Interlocked.Decrement(ref _current); - Log.Verbose($"BufferBucket({arraySize}) count:{next}"); - } - } - - /// - /// Collection of different sized buffers - /// - /// - /// - /// Problem:
- /// * Need to cached byte[] so that new ones arn't created each time
- /// * Arrays sent are multiple different sizes
- /// * Some message might be big so need buffers to cover that size
- /// * Most messages will be small compared to max message size
- ///
- ///
- /// - /// Solution:
- /// * Create multiple groups of buffers covering the range of allowed sizes
- /// * Split range exponentially (using math.log) so that there are more groups for small buffers
- ///
- ///
- public class BufferPool - { - internal readonly BufferBucket[] buckets; - readonly int bucketCount; - readonly int smallest; - readonly int largest; - - public BufferPool(int bucketCount, int smallest, int largest) - { - if (bucketCount < 2) throw new ArgumentException("Count must be atleast 2"); - if (smallest < 1) throw new ArgumentException("Smallest must be atleast 1"); - if (largest < smallest) throw new ArgumentException("Largest must be greater than smallest"); - - - this.bucketCount = bucketCount; - this.smallest = smallest; - this.largest = largest; - - - // split range over log scale (more buckets for smaller sizes) - - double minLog = Math.Log(this.smallest); - double maxLog = Math.Log(this.largest); - - double range = maxLog - minLog; - double each = range / (bucketCount - 1); - - buckets = new BufferBucket[bucketCount]; - - for (int i = 0; i < bucketCount; i++) - { - double size = smallest * Math.Pow(Math.E, each * i); - buckets[i] = new BufferBucket((int)Math.Ceiling(size)); - } - - - Validate(); - - // Example - // 5 count - // 20 smallest - // 16400 largest - - // 3.0 log 20 - // 9.7 log 16400 - - // 6.7 range 9.7 - 3 - // 1.675 each 6.7 / (5-1) - - // 20 e^ (3 + 1.675 * 0) - // 107 e^ (3 + 1.675 * 1) - // 572 e^ (3 + 1.675 * 2) - // 3056 e^ (3 + 1.675 * 3) - // 16,317 e^ (3 + 1.675 * 4) - - // perceision wont be lose when using doubles - } - - [Conditional("UNITY_ASSERTIONS")] - void Validate() - { - if (buckets[0].arraySize != smallest) - { - Log.Error($"BufferPool Failed to create bucket for smallest. bucket:{buckets[0].arraySize} smallest{smallest}"); - } - - int largestBucket = buckets[bucketCount - 1].arraySize; - // rounded using Ceiling, so allowed to be 1 more that largest - if (largestBucket != largest && largestBucket != largest + 1) - { - Log.Error($"BufferPool Failed to create bucket for largest. bucket:{largestBucket} smallest{largest}"); - } - } - - public ArrayBuffer Take(int size) - { - if (size > largest) { throw new ArgumentException($"Size ({size}) is greatest that largest ({largest})"); } - - for (int i = 0; i < bucketCount; i++) - { - if (size <= buckets[i].arraySize) - { - return buckets[i].Take(); - } - } - - throw new ArgumentException($"Size ({size}) is greatest that largest ({largest})"); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs.meta deleted file mode 100644 index 0b1070f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/BufferPool.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 94ae50f3ec35667469b861b12cd72f92 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs deleted file mode 100644 index 88451a5..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.IO; -using System.Net.Sockets; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - internal sealed class Connection : IDisposable - { - public const int IdNotSet = -1; - - readonly object disposedLock = new object(); - - public TcpClient client; - - public int connId = IdNotSet; - public Stream stream; - public Thread receiveThread; - public Thread sendThread; - - public ManualResetEventSlim sendPending = new ManualResetEventSlim(false); - public ConcurrentQueue sendQueue = new ConcurrentQueue(); - - public Action onDispose; - - volatile bool hasDisposed; - - public Connection(TcpClient client, Action onDispose) - { - this.client = client ?? throw new ArgumentNullException(nameof(client)); - this.onDispose = onDispose; - } - - - /// - /// disposes client and stops threads - /// - public void Dispose() - { - Log.Verbose($"Dispose {ToString()}"); - - // check hasDisposed first to stop ThreadInterruptedException on lock - if (hasDisposed) { return; } - - Log.Info($"Connection Close: {ToString()}"); - - - lock (disposedLock) - { - // check hasDisposed again inside lock to make sure no other object has called this - if (hasDisposed) { return; } - hasDisposed = true; - - // stop threads first so they dont try to use disposed objects - receiveThread.Interrupt(); - sendThread?.Interrupt(); - - try - { - // stream - stream?.Dispose(); - stream = null; - client.Dispose(); - client = null; - } - catch (Exception e) - { - Log.Exception(e); - } - - sendPending.Dispose(); - - // release all buffers in send queue - while (sendQueue.TryDequeue(out ArrayBuffer buffer)) - { - buffer.Release(); - } - - onDispose.Invoke(this); - } - } - - public override string ToString() - { - System.Net.EndPoint endpoint = client?.Client?.RemoteEndPoint; - return $"[Conn:{connId}, endPoint:{endpoint}]"; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs.meta deleted file mode 100644 index d48a835..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Connection.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a13073c2b49d39943888df45174851bd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs deleted file mode 100644 index cc94cf3..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Text; - -namespace Mirror.SimpleWeb -{ - /// - /// Constant values that should never change - /// - /// Some values are from https://tools.ietf.org/html/rfc6455 - /// - /// - internal static class Constants - { - /// - /// Header is at most 4 bytes - /// - /// If message is less than 125 then header is 2 bytes, else header is 4 bytes - /// - /// - public const int HeaderSize = 4; - - /// - /// Smallest size of header - /// - /// If message is less than 125 then header is 2 bytes, else header is 4 bytes - /// - /// - public const int HeaderMinSize = 2; - - /// - /// bytes for short length - /// - public const int ShortLength = 2; - - /// - /// Message mask is always 4 bytes - /// - public const int MaskSize = 4; - - /// - /// Max size of a message for length to be 1 byte long - /// - /// payload length between 0-125 - /// - /// - public const int BytePayloadLength = 125; - - /// - /// if payload length is 126 when next 2 bytes will be the length - /// - public const int UshortPayloadLength = 126; - - /// - /// if payload length is 127 when next 8 bytes will be the length - /// - public const int UlongPayloadLength = 127; - - - /// - /// Guid used for WebSocket Protocol - /// - public const string HandshakeGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - public static readonly int HandshakeGUIDLength = HandshakeGUID.Length; - - public static readonly byte[] HandshakeGUIDBytes = Encoding.ASCII.GetBytes(HandshakeGUID); - - /// - /// Handshake messages will end with \r\n\r\n - /// - public static readonly byte[] endOfHandshake = new byte[4] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs.meta deleted file mode 100644 index ece602e..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Constants.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 85d110a089d6ad348abf2d073ebce7cd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs deleted file mode 100644 index 3a9d185..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Mirror.SimpleWeb -{ - public enum EventType - { - Connected, - Data, - Disconnected, - Error - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs.meta deleted file mode 100644 index a91403a..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/EventType.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2d9cd7d2b5229ab42a12e82ae17d0347 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs deleted file mode 100644 index bb5179a..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using UnityEngine; -using Conditional = System.Diagnostics.ConditionalAttribute; - -namespace Mirror.SimpleWeb -{ - public static class Log - { - // used for Conditional - const string SIMPLEWEB_LOG_ENABLED = nameof(SIMPLEWEB_LOG_ENABLED); - const string DEBUG = nameof(DEBUG); - - public enum Levels - { - none = 0, - error = 1, - warn = 2, - info = 3, - verbose = 4, - } - - public static ILogger logger = Debug.unityLogger; - public static Levels level = Levels.none; - - public static string BufferToString(byte[] buffer, int offset = 0, int? length = null) - { - return BitConverter.ToString(buffer, offset, length ?? buffer.Length); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED)] - public static void DumpBuffer(string label, byte[] buffer, int offset, int length) - { - if (level < Levels.verbose) - return; - - logger.Log(LogType.Log, $"VERBOSE: {label}: {BufferToString(buffer, offset, length)}"); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED)] - public static void DumpBuffer(string label, ArrayBuffer arrayBuffer) - { - if (level < Levels.verbose) - return; - - logger.Log(LogType.Log, $"VERBOSE: {label}: {BufferToString(arrayBuffer.array, 0, arrayBuffer.count)}"); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED)] - public static void Verbose(string msg, bool showColor = true) - { - if (level < Levels.verbose) - return; - - if (showColor) - logger.Log(LogType.Log, $"VERBOSE: {msg}"); - else - logger.Log(LogType.Log, $"VERBOSE: {msg}"); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED)] - public static void Info(string msg, bool showColor = true) - { - if (level < Levels.info) - return; - - if (showColor) - logger.Log(LogType.Log, $"INFO: {msg}"); - else - logger.Log(LogType.Log, $"INFO: {msg}"); - } - - /// - /// An expected Exception was caught, useful for debugging but not important - /// - /// - /// - [Conditional(SIMPLEWEB_LOG_ENABLED)] - public static void InfoException(Exception e) - { - if (level < Levels.info) - return; - - logger.Log(LogType.Log, $"INFO_EXCEPTION: {e.GetType().Name} Message: {e.Message}"); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED), Conditional(DEBUG)] - public static void Warn(string msg, bool showColor = true) - { - if (level < Levels.warn) - return; - - if (showColor) - logger.Log(LogType.Warning, $"WARN: {msg}"); - else - logger.Log(LogType.Warning, $"WARN: {msg}"); - } - - [Conditional(SIMPLEWEB_LOG_ENABLED), Conditional(DEBUG)] - public static void Error(string msg, bool showColor = true) - { - if (level < Levels.error) - return; - - if (showColor) - logger.Log(LogType.Error, $"ERROR: {msg}"); - else - logger.Log(LogType.Error, $"ERROR: {msg}"); - } - - public static void Exception(Exception e) - { - // always log Exceptions - logger.Log(LogType.Error, $"EXCEPTION: {e.GetType().Name} Message: {e.Message}"); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs.meta deleted file mode 100644 index beb2883..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Log.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3cf1521098e04f74fbea0fe2aa0439f8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs deleted file mode 100644 index 29b4849..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace Mirror.SimpleWeb -{ - public struct Message - { - public readonly int connId; - public readonly EventType type; - public readonly ArrayBuffer data; - public readonly Exception exception; - - public Message(EventType type) : this() - { - this.type = type; - } - - public Message(ArrayBuffer data) : this() - { - type = EventType.Data; - this.data = data; - } - - public Message(Exception exception) : this() - { - type = EventType.Error; - this.exception = exception; - } - - public Message(int connId, EventType type) : this() - { - this.connId = connId; - this.type = type; - } - - public Message(int connId, ArrayBuffer data) : this() - { - this.connId = connId; - type = EventType.Data; - this.data = data; - } - - public Message(int connId, Exception exception) : this() - { - this.connId = connId; - type = EventType.Error; - this.exception = exception; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs.meta deleted file mode 100644 index 3286a2c..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Message.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f5d05d71b09d2714b96ffe80bc3d2a77 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs deleted file mode 100644 index 49e405f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.IO; -using System.Runtime.CompilerServices; - -namespace Mirror.SimpleWeb -{ - public static class MessageProcessor - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static byte FirstLengthByte(byte[] buffer) => (byte)(buffer[1] & 0b0111_1111); - - public static bool NeedToReadShortLength(byte[] buffer) - { - byte lenByte = FirstLengthByte(buffer); - - return lenByte >= Constants.UshortPayloadLength; - } - - public static int GetOpcode(byte[] buffer) - { - return buffer[0] & 0b0000_1111; - } - - public static int GetPayloadLength(byte[] buffer) - { - byte lenByte = FirstLengthByte(buffer); - return GetMessageLength(buffer, 0, lenByte); - } - - public static void ValidateHeader(byte[] buffer, int maxLength, bool expectMask) - { - bool finished = (buffer[0] & 0b1000_0000) != 0; // has full message been sent - bool hasMask = (buffer[1] & 0b1000_0000) != 0; // true from clients, false from server, "All messages from the client to the server have this bit set" - - int opcode = buffer[0] & 0b0000_1111; // expecting 1 - text message - byte lenByte = FirstLengthByte(buffer); - - ThrowIfNotFinished(finished); - ThrowIfMaskNotExpected(hasMask, expectMask); - ThrowIfBadOpCode(opcode); - - int msglen = GetMessageLength(buffer, 0, lenByte); - - ThrowIfLengthZero(msglen); - ThrowIfMsgLengthTooLong(msglen, maxLength); - } - - public static void ToggleMask(byte[] src, int sourceOffset, int messageLength, byte[] maskBuffer, int maskOffset) - { - ToggleMask(src, sourceOffset, src, sourceOffset, messageLength, maskBuffer, maskOffset); - } - - public static void ToggleMask(byte[] src, int sourceOffset, ArrayBuffer dst, int messageLength, byte[] maskBuffer, int maskOffset) - { - ToggleMask(src, sourceOffset, dst.array, 0, messageLength, maskBuffer, maskOffset); - dst.count = messageLength; - } - - public static void ToggleMask(byte[] src, int srcOffset, byte[] dst, int dstOffset, int messageLength, byte[] maskBuffer, int maskOffset) - { - for (int i = 0; i < messageLength; i++) - { - byte maskByte = maskBuffer[maskOffset + i % Constants.MaskSize]; - dst[dstOffset + i] = (byte)(src[srcOffset + i] ^ maskByte); - } - } - - /// - static int GetMessageLength(byte[] buffer, int offset, byte lenByte) - { - if (lenByte == Constants.UshortPayloadLength) - { - // header is 4 bytes long - ushort value = 0; - value |= (ushort)(buffer[offset + 2] << 8); - value |= buffer[offset + 3]; - - return value; - } - else if (lenByte == Constants.UlongPayloadLength) - { - throw new InvalidDataException("Max length is longer than allowed in a single message"); - } - else // is less than 126 - { - // header is 2 bytes long - return lenByte; - } - } - - /// - static void ThrowIfNotFinished(bool finished) - { - if (!finished) - { - throw new InvalidDataException("Full message should have been sent, if the full message wasn't sent it wasn't sent from this trasnport"); - } - } - - /// - static void ThrowIfMaskNotExpected(bool hasMask, bool expectMask) - { - if (hasMask != expectMask) - { - throw new InvalidDataException($"Message expected mask to be {expectMask} but was {hasMask}"); - } - } - - /// - static void ThrowIfBadOpCode(int opcode) - { - // 2 = binary - // 8 = close - if (opcode != 2 && opcode != 8) - { - throw new InvalidDataException("Expected opcode to be binary or close"); - } - } - - /// - static void ThrowIfLengthZero(int msglen) - { - if (msglen == 0) - { - throw new InvalidDataException("Message length was zero"); - } - } - - /// - /// need to check this so that data from previous buffer isnt used - /// - /// - static void ThrowIfMsgLengthTooLong(int msglen, int maxLength) - { - if (msglen > maxLength) - { - throw new InvalidDataException("Message length is greater than max length"); - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs.meta deleted file mode 100644 index 7e3a7c4..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/MessageProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4c1f218a2b16ca846aaf23260078e549 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs deleted file mode 100644 index 5bcb5d0..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.IO; -using System.Runtime.Serialization; - -namespace Mirror.SimpleWeb -{ - public static class ReadHelper - { - /// - /// Reads exactly length from stream - /// - /// outOffset + length - /// - public static int Read(Stream stream, byte[] outBuffer, int outOffset, int length) - { - int received = 0; - try - { - while (received < length) - { - int read = stream.Read(outBuffer, outOffset + received, length - received); - if (read == 0) - { - throw new ReadHelperException("returned 0"); - } - received += read; - } - } - catch (AggregateException ae) - { - // if interupt is called we dont care about Exceptions - Utils.CheckForInterupt(); - - // rethrow - ae.Handle(e => false); - } - - if (received != length) - { - throw new ReadHelperException("returned not equal to length"); - } - - return outOffset + received; - } - - /// - /// Reads and returns results. This should never throw an exception - /// - public static bool TryRead(Stream stream, byte[] outBuffer, int outOffset, int length) - { - try - { - Read(stream, outBuffer, outOffset, length); - return true; - } - catch (ReadHelperException) - { - return false; - } - catch (IOException) - { - return false; - } - catch (Exception e) - { - Log.Exception(e); - return false; - } - } - - public static int? SafeReadTillMatch(Stream stream, byte[] outBuffer, int outOffset, int maxLength, byte[] endOfHeader) - { - try - { - int read = 0; - int endIndex = 0; - int endLength = endOfHeader.Length; - while (true) - { - int next = stream.ReadByte(); - if (next == -1) // closed - return null; - - if (read >= maxLength) - { - Log.Error("SafeReadTillMatch exceeded maxLength"); - return null; - } - - outBuffer[outOffset + read] = (byte)next; - read++; - - // if n is match, check n+1 next - if (endOfHeader[endIndex] == next) - { - endIndex++; - // when all is match return with read length - if (endIndex >= endLength) - { - return read; - } - } - // if n not match reset to 0 - else - { - endIndex = 0; - } - } - } - catch (IOException e) - { - Log.InfoException(e); - return null; - } - catch (Exception e) - { - Log.Exception(e); - return null; - } - } - } - - [Serializable] - public class ReadHelperException : Exception - { - public ReadHelperException(string message) : base(message) { } - - protected ReadHelperException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs.meta deleted file mode 100644 index 77d09c1..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReadHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9f4fa5d324e708c46a55810a97de75bc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs deleted file mode 100644 index 2112186..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs +++ /dev/null @@ -1,195 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.IO; -using System.Net.Sockets; -using System.Text; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - internal static class ReceiveLoop - { - public struct Config - { - public readonly Connection conn; - public readonly int maxMessageSize; - public readonly bool expectMask; - public readonly ConcurrentQueue queue; - public readonly BufferPool bufferPool; - - public Config(Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue queue, BufferPool bufferPool) - { - this.conn = conn ?? throw new ArgumentNullException(nameof(conn)); - this.maxMessageSize = maxMessageSize; - this.expectMask = expectMask; - this.queue = queue ?? throw new ArgumentNullException(nameof(queue)); - this.bufferPool = bufferPool ?? throw new ArgumentNullException(nameof(bufferPool)); - } - - public void Deconstruct(out Connection conn, out int maxMessageSize, out bool expectMask, out ConcurrentQueue queue, out BufferPool bufferPool) - { - conn = this.conn; - maxMessageSize = this.maxMessageSize; - expectMask = this.expectMask; - queue = this.queue; - bufferPool = this.bufferPool; - } - } - - public static void Loop(Config config) - { - (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue queue, BufferPool _) = config; - - byte[] readBuffer = new byte[Constants.HeaderSize + (expectMask ? Constants.MaskSize : 0) + maxMessageSize]; - try - { - try - { - TcpClient client = conn.client; - - while (client.Connected) - { - ReadOneMessage(config, readBuffer); - } - - Log.Info($"{conn} Not Connected"); - } - catch (Exception) - { - // if interupted we dont care about other execptions - Utils.CheckForInterupt(); - throw; - } - } - catch (ThreadInterruptedException e) { Log.InfoException(e); } - catch (ThreadAbortException e) { Log.InfoException(e); } - catch (ObjectDisposedException e) { Log.InfoException(e); } - catch (ReadHelperException e) - { - // this could happen if client sends bad message - Log.InfoException(e); - queue.Enqueue(new Message(conn.connId, e)); - } - catch (SocketException e) - { - // this could happen if wss client closes stream - Log.Warn($"ReceiveLoop SocketException\n{e.Message}", false); - queue.Enqueue(new Message(conn.connId, e)); - } - catch (IOException e) - { - // this could happen if client disconnects - Log.Warn($"ReceiveLoop IOException\n{e.Message}", false); - queue.Enqueue(new Message(conn.connId, e)); - } - catch (InvalidDataException e) - { - Log.Error($"Invalid data from {conn}: {e.Message}"); - queue.Enqueue(new Message(conn.connId, e)); - } - catch (Exception e) - { - Log.Exception(e); - queue.Enqueue(new Message(conn.connId, e)); - } - finally - { - conn.Dispose(); - } - } - - static void ReadOneMessage(Config config, byte[] buffer) - { - (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue queue, BufferPool bufferPool) = config; - Stream stream = conn.stream; - - int offset = 0; - // read 2 - offset = ReadHelper.Read(stream, buffer, offset, Constants.HeaderMinSize); - // log after first blocking call - Log.Verbose($"Message From {conn}"); - - if (MessageProcessor.NeedToReadShortLength(buffer)) - { - offset = ReadHelper.Read(stream, buffer, offset, Constants.ShortLength); - } - - MessageProcessor.ValidateHeader(buffer, maxMessageSize, expectMask); - - if (expectMask) - { - offset = ReadHelper.Read(stream, buffer, offset, Constants.MaskSize); - } - - int opcode = MessageProcessor.GetOpcode(buffer); - int payloadLength = MessageProcessor.GetPayloadLength(buffer); - - Log.Verbose($"Header ln:{payloadLength} op:{opcode} mask:{expectMask}"); - Log.DumpBuffer($"Raw Header", buffer, 0, offset); - - int msgOffset = offset; - offset = ReadHelper.Read(stream, buffer, offset, payloadLength); - - switch (opcode) - { - case 2: - HandleArrayMessage(config, buffer, msgOffset, payloadLength); - break; - case 8: - HandleCloseMessage(config, buffer, msgOffset, payloadLength); - break; - } - } - - static void HandleArrayMessage(Config config, byte[] buffer, int msgOffset, int payloadLength) - { - (Connection conn, int _, bool expectMask, ConcurrentQueue queue, BufferPool bufferPool) = config; - - ArrayBuffer arrayBuffer = bufferPool.Take(payloadLength); - - if (expectMask) - { - int maskOffset = msgOffset - Constants.MaskSize; - // write the result of toggle directly into arrayBuffer to avoid 2nd copy call - MessageProcessor.ToggleMask(buffer, msgOffset, arrayBuffer, payloadLength, buffer, maskOffset); - } - else - { - arrayBuffer.CopyFrom(buffer, msgOffset, payloadLength); - } - - // dump after mask off - Log.DumpBuffer($"Message", arrayBuffer); - - queue.Enqueue(new Message(conn.connId, arrayBuffer)); - } - - static void HandleCloseMessage(Config config, byte[] buffer, int msgOffset, int payloadLength) - { - (Connection conn, int _, bool expectMask, ConcurrentQueue _, BufferPool _) = config; - - if (expectMask) - { - int maskOffset = msgOffset - Constants.MaskSize; - MessageProcessor.ToggleMask(buffer, msgOffset, payloadLength, buffer, maskOffset); - } - - // dump after mask off - Log.DumpBuffer($"Message", buffer, msgOffset, payloadLength); - - Log.Info($"Close: {GetCloseCode(buffer, msgOffset)} message:{GetCloseMessage(buffer, msgOffset, payloadLength)}"); - - conn.Dispose(); - } - - static string GetCloseMessage(byte[] buffer, int msgOffset, int payloadLength) - { - return Encoding.UTF8.GetString(buffer, msgOffset + 2, payloadLength - 2); - } - - static int GetCloseCode(byte[] buffer, int msgOffset) - { - return buffer[msgOffset + 0] << 8 | buffer[msgOffset + 1]; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs.meta deleted file mode 100644 index 47c6ff5..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/ReceiveLoop.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a26c2815f58431c4a98c158c8b655ffd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs deleted file mode 100644 index 05c2f4f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.IO; -using System.Net.Sockets; -using System.Security.Cryptography; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - internal static class SendLoop - { - public struct Config - { - public readonly Connection conn; - public readonly int bufferSize; - public readonly bool setMask; - - public Config(Connection conn, int bufferSize, bool setMask) - { - this.conn = conn ?? throw new ArgumentNullException(nameof(conn)); - this.bufferSize = bufferSize; - this.setMask = setMask; - } - - public void Deconstruct(out Connection conn, out int bufferSize, out bool setMask) - { - conn = this.conn; - bufferSize = this.bufferSize; - setMask = this.setMask; - } - } - - - public static void Loop(Config config) - { - (Connection conn, int bufferSize, bool setMask) = config; - - // create write buffer for this thread - byte[] writeBuffer = new byte[bufferSize]; - MaskHelper maskHelper = setMask ? new MaskHelper() : null; - try - { - TcpClient client = conn.client; - Stream stream = conn.stream; - - // null check incase disconnect while send thread is starting - if (client == null) - return; - - while (client.Connected) - { - // wait for message - conn.sendPending.Wait(); - conn.sendPending.Reset(); - - while (conn.sendQueue.TryDequeue(out ArrayBuffer msg)) - { - // check if connected before sending message - if (!client.Connected) { Log.Info($"SendLoop {conn} not connected"); return; } - - SendMessage(stream, writeBuffer, msg, setMask, maskHelper); - msg.Release(); - } - } - - Log.Info($"{conn} Not Connected"); - } - catch (ThreadInterruptedException e) { Log.InfoException(e); } - catch (ThreadAbortException e) { Log.InfoException(e); } - catch (Exception e) - { - Log.Exception(e); - } - finally - { - conn.Dispose(); - maskHelper?.Dispose(); - } - } - - static void SendMessage(Stream stream, byte[] buffer, ArrayBuffer msg, bool setMask, MaskHelper maskHelper) - { - int msgLength = msg.count; - int sendLength = WriteHeader(buffer, msgLength, setMask); - - if (setMask) - { - sendLength = maskHelper.WriteMask(buffer, sendLength); - } - - msg.CopyTo(buffer, sendLength); - sendLength += msgLength; - - // dump before mask on - Log.DumpBuffer("Send", buffer, 0, sendLength); - - if (setMask) - { - int messageOffset = sendLength - msgLength; - MessageProcessor.ToggleMask(buffer, messageOffset, msgLength, buffer, messageOffset - Constants.MaskSize); - } - - stream.Write(buffer, 0, sendLength); - } - - static int WriteHeader(byte[] buffer, int msgLength, bool setMask) - { - int sendLength = 0; - const byte finished = 128; - const byte byteOpCode = 2; - - buffer[0] = finished | byteOpCode; - sendLength++; - - if (msgLength <= Constants.BytePayloadLength) - { - buffer[1] = (byte)msgLength; - sendLength++; - } - else if (msgLength <= ushort.MaxValue) - { - buffer[1] = 126; - buffer[2] = (byte)(msgLength >> 8); - buffer[3] = (byte)msgLength; - sendLength += 3; - } - else - { - throw new InvalidDataException($"Trying to send a message larger than {ushort.MaxValue} bytes"); - } - - if (setMask) - { - buffer[1] |= 0b1000_0000; - } - - return sendLength; - } - - sealed class MaskHelper : IDisposable - { - readonly byte[] maskBuffer; - readonly RNGCryptoServiceProvider random; - - public MaskHelper() - { - maskBuffer = new byte[4]; - random = new RNGCryptoServiceProvider(); - } - public void Dispose() - { - random.Dispose(); - } - - public int WriteMask(byte[] buffer, int offset) - { - random.GetBytes(maskBuffer); - Buffer.BlockCopy(maskBuffer, 0, buffer, offset, 4); - - return offset + 4; - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs.meta deleted file mode 100644 index 09dfd1e..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/SendLoop.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f87dd81736d9c824db67f808ac71841d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs deleted file mode 100644 index 8cb4779..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Net.Sockets; - -namespace Mirror.SimpleWeb -{ - public struct TcpConfig - { - public readonly bool noDelay; - public readonly int sendTimeout; - public readonly int receiveTimeout; - - public TcpConfig(bool noDelay, int sendTimeout, int receiveTimeout) - { - this.noDelay = noDelay; - this.sendTimeout = sendTimeout; - this.receiveTimeout = receiveTimeout; - } - - public void ApplyTo(TcpClient client) - { - client.SendTimeout = sendTimeout; - client.ReceiveTimeout = receiveTimeout; - client.NoDelay = noDelay; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs.meta deleted file mode 100644 index 62ba232..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/TcpConfig.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 81ac8d35f28fab14b9edda5cd9d4fc86 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs deleted file mode 100644 index b8a860c..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading; - -namespace Mirror.SimpleWeb -{ - internal static class Utils - { - public static void CheckForInterupt() - { - // sleep in order to check for ThreadInterruptedException - Thread.Sleep(1); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs.meta deleted file mode 100644 index 79a1583..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Common/Utils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4643ffb4cb0562847b1ae925d07e15b6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt deleted file mode 100644 index 992424c..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt +++ /dev/null @@ -1,22 +0,0 @@ -SimpleWebTransport is a Transport that implements websocket for Webgl builds of -mirror. This transport can also work on standalone builds and has support for -encryption with websocket secure. - -How to use: - Replace your existing Transport with SimpleWebTransport on your NetworkManager - -Requirements: - Unity 2018.4 LTS - Mirror v18.0.0 - -Documentation: - https://mirror-networking.com/docs/ - https://github.com/MirrorNetworking/SimpleWebTransport/blob/master/README.md - -Support: - Discord: https://discordapp.com/invite/N9QVxbM - Bug Reports: https://github.com/MirrorNetworking/SimpleWebTransport/issues - - -**To get most recent updates and fixes download from github** -https://github.com/MirrorNetworking/SimpleWebTransport/releases diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt.meta deleted file mode 100644 index b63fe39..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/README.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0e3971d5783109f4d9ce93c7a689d701 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server.meta deleted file mode 100644 index 31f317f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0e599e92544d43344a9a9060052add28 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs deleted file mode 100644 index e54addd..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace Mirror.SimpleWeb -{ - /// - /// Handles Handshakes from new clients on the server - /// The server handshake has buffers to reduce allocations when clients connect - /// - internal class ServerHandshake - { - const int GetSize = 3; - const int ResponseLength = 129; - const int KeyLength = 24; - const int MergedKeyLength = 60; - const string KeyHeaderString = "Sec-WebSocket-Key: "; - // this isnt an offical max, just a reasonable size for a websocket handshake - readonly int maxHttpHeaderSize = 3000; - - readonly SHA1 sha1 = SHA1.Create(); - readonly BufferPool bufferPool; - - public ServerHandshake(BufferPool bufferPool, int handshakeMaxSize) - { - this.bufferPool = bufferPool; - this.maxHttpHeaderSize = handshakeMaxSize; - } - - ~ServerHandshake() - { - sha1.Dispose(); - } - - public bool TryHandshake(Connection conn) - { - Stream stream = conn.stream; - - using (ArrayBuffer getHeader = bufferPool.Take(GetSize)) - { - if (!ReadHelper.TryRead(stream, getHeader.array, 0, GetSize)) - return false; - getHeader.count = GetSize; - - - if (!IsGet(getHeader.array)) - { - Log.Warn($"First bytes from client was not 'GET' for handshake, instead was {Log.BufferToString(getHeader.array, 0, GetSize)}"); - return false; - } - } - - - string msg = ReadToEndForHandshake(stream); - - if (string.IsNullOrEmpty(msg)) - return false; - - try - { - AcceptHandshake(stream, msg); - return true; - } - catch (ArgumentException e) - { - Log.InfoException(e); - return false; - } - } - - string ReadToEndForHandshake(Stream stream) - { - using (ArrayBuffer readBuffer = bufferPool.Take(maxHttpHeaderSize)) - { - int? readCountOrFail = ReadHelper.SafeReadTillMatch(stream, readBuffer.array, 0, maxHttpHeaderSize, Constants.endOfHandshake); - if (!readCountOrFail.HasValue) - return null; - - int readCount = readCountOrFail.Value; - - string msg = Encoding.ASCII.GetString(readBuffer.array, 0, readCount); - Log.Verbose(msg); - - return msg; - } - } - - static bool IsGet(byte[] getHeader) - { - // just check bytes here instead of using Encoding.ASCII - return getHeader[0] == 71 && // G - getHeader[1] == 69 && // E - getHeader[2] == 84; // T - } - - void AcceptHandshake(Stream stream, string msg) - { - using ( - ArrayBuffer keyBuffer = bufferPool.Take(KeyLength), - responseBuffer = bufferPool.Take(ResponseLength)) - { - GetKey(msg, keyBuffer.array); - AppendGuid(keyBuffer.array); - byte[] keyHash = CreateHash(keyBuffer.array); - CreateResponse(keyHash, responseBuffer.array); - - stream.Write(responseBuffer.array, 0, ResponseLength); - } - } - - - static void GetKey(string msg, byte[] keyBuffer) - { - int start = msg.IndexOf(KeyHeaderString) + KeyHeaderString.Length; - - Log.Verbose($"Handshake Key: {msg.Substring(start, KeyLength)}"); - Encoding.ASCII.GetBytes(msg, start, KeyLength, keyBuffer, 0); - } - - static void AppendGuid(byte[] keyBuffer) - { - Buffer.BlockCopy(Constants.HandshakeGUIDBytes, 0, keyBuffer, KeyLength, Constants.HandshakeGUID.Length); - } - - byte[] CreateHash(byte[] keyBuffer) - { - Log.Verbose($"Handshake Hashing {Encoding.ASCII.GetString(keyBuffer, 0, MergedKeyLength)}"); - - return sha1.ComputeHash(keyBuffer, 0, MergedKeyLength); - } - - static void CreateResponse(byte[] keyHash, byte[] responseBuffer) - { - string keyHashString = Convert.ToBase64String(keyHash); - - // compiler should merge these strings into 1 string before format - string message = string.Format( - "HTTP/1.1 101 Switching Protocols\r\n" + - "Connection: Upgrade\r\n" + - "Upgrade: websocket\r\n" + - "Sec-WebSocket-Accept: {0}\r\n\r\n", - keyHashString); - - Log.Verbose($"Handshake Response length {message.Length}, IsExpected {message.Length == ResponseLength}"); - Encoding.ASCII.GetBytes(message, 0, ResponseLength, responseBuffer, 0); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs.meta deleted file mode 100644 index 6fa74da..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerHandshake.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6268509ac4fb48141b9944c03295da11 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs deleted file mode 100644 index de6c022..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.IO; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; - -namespace Mirror.SimpleWeb -{ - public struct SslConfig - { - public readonly bool enabled; - public readonly string certPath; - public readonly string certPassword; - public readonly SslProtocols sslProtocols; - - public SslConfig(bool enabled, string certPath, string certPassword, SslProtocols sslProtocols) - { - this.enabled = enabled; - this.certPath = certPath; - this.certPassword = certPassword; - this.sslProtocols = sslProtocols; - } - } - internal class ServerSslHelper - { - readonly SslConfig config; - readonly X509Certificate2 certificate; - - public ServerSslHelper(SslConfig sslConfig) - { - config = sslConfig; - if (config.enabled) - certificate = new X509Certificate2(config.certPath, config.certPassword); - } - - internal bool TryCreateStream(Connection conn) - { - NetworkStream stream = conn.client.GetStream(); - if (config.enabled) - { - try - { - conn.stream = CreateStream(stream); - return true; - } - catch (Exception e) - { - Log.Error($"Create SSLStream Failed: {e}", false); - return false; - } - } - else - { - conn.stream = stream; - return true; - } - } - - Stream CreateStream(NetworkStream stream) - { - SslStream sslStream = new SslStream(stream, true, acceptClient); - sslStream.AuthenticateAsServer(certificate, false, config.sslProtocols, false); - - return sslStream; - } - - bool acceptClient(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - // always accept client - return true; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs.meta deleted file mode 100644 index e0d133c..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/ServerSslHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 11061fee528ebdd43817a275b1e4a317 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs deleted file mode 100644 index 7b68a57..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirror.SimpleWeb -{ - public class SimpleWebServer - { - readonly int maxMessagesPerTick; - - readonly WebSocketServer server; - readonly BufferPool bufferPool; - - public SimpleWebServer(int maxMessagesPerTick, TcpConfig tcpConfig, int maxMessageSize, int handshakeMaxSize, SslConfig sslConfig) - { - this.maxMessagesPerTick = maxMessagesPerTick; - // use max because bufferpool is used for both messages and handshake - int max = Math.Max(maxMessageSize, handshakeMaxSize); - bufferPool = new BufferPool(5, 20, max); - - server = new WebSocketServer(tcpConfig, maxMessageSize, handshakeMaxSize, sslConfig, bufferPool); - } - - public bool Active { get; private set; } - - public event Action onConnect; - public event Action onDisconnect; - public event Action> onData; - public event Action onError; - - public void Start(ushort port) - { - server.Listen(port); - Active = true; - } - - public void Stop() - { - server.Stop(); - Active = false; - } - - public void SendAll(List connectionIds, ArraySegment source) - { - ArrayBuffer buffer = bufferPool.Take(source.Count); - buffer.CopyFrom(source); - buffer.SetReleasesRequired(connectionIds.Count); - - // make copy of array before for each, data sent to each client is the same - foreach (int id in connectionIds) - { - server.Send(id, buffer); - } - } - public void SendOne(int connectionId, ArraySegment source) - { - ArrayBuffer buffer = bufferPool.Take(source.Count); - buffer.CopyFrom(source); - - server.Send(connectionId, buffer); - } - - public bool KickClient(int connectionId) - { - return server.CloseConnection(connectionId); - } - - public string GetClientAddress(int connectionId) - { - return server.GetClientAddress(connectionId); - } - - public void ProcessMessageQueue(MonoBehaviour behaviour) - { - int processedCount = 0; - // check enabled every time incase behaviour was disabled after data - while ( - behaviour.enabled && - processedCount < maxMessagesPerTick && - // Dequeue last - server.receiveQueue.TryDequeue(out Message next) - ) - { - processedCount++; - - switch (next.type) - { - case EventType.Connected: - onConnect?.Invoke(next.connId); - break; - case EventType.Data: - onData?.Invoke(next.connId, next.data.ToSegment()); - next.data.Release(); - break; - case EventType.Disconnected: - onDisconnect?.Invoke(next.connId); - break; - case EventType.Error: - onError?.Invoke(next.connId, next.exception); - break; - } - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs.meta deleted file mode 100644 index c8c6f5a..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/SimpleWebServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bd51d7896f55a5e48b41a4b526562b0e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs deleted file mode 100644 index 1238af1..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs +++ /dev/null @@ -1,230 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Net.Sockets; -using System.Threading; - -namespace Mirror.SimpleWeb -{ - public class WebSocketServer - { - public readonly ConcurrentQueue receiveQueue = new ConcurrentQueue(); - - readonly TcpConfig tcpConfig; - readonly int maxMessageSize; - - TcpListener listener; - Thread acceptThread; - bool serverStopped; - readonly ServerHandshake handShake; - readonly ServerSslHelper sslHelper; - readonly BufferPool bufferPool; - readonly ConcurrentDictionary connections = new ConcurrentDictionary(); - - - int _idCounter = 0; - - public WebSocketServer(TcpConfig tcpConfig, int maxMessageSize, int handshakeMaxSize, SslConfig sslConfig, BufferPool bufferPool) - { - this.tcpConfig = tcpConfig; - this.maxMessageSize = maxMessageSize; - sslHelper = new ServerSslHelper(sslConfig); - this.bufferPool = bufferPool; - handShake = new ServerHandshake(this.bufferPool, handshakeMaxSize); - } - - public void Listen(int port) - { - listener = TcpListener.Create(port); - listener.Start(); - - Log.Info($"Server has started on port {port}"); - - acceptThread = new Thread(acceptLoop); - acceptThread.IsBackground = true; - acceptThread.Start(); - } - - public void Stop() - { - serverStopped = true; - - // Interrupt then stop so that Exception is handled correctly - acceptThread?.Interrupt(); - listener?.Stop(); - acceptThread = null; - - - Log.Info("Server stoped, Closing all connections..."); - // make copy so that foreach doesn't break if values are removed - Connection[] connectionsCopy = connections.Values.ToArray(); - foreach (Connection conn in connectionsCopy) - { - conn.Dispose(); - } - - connections.Clear(); - } - - void acceptLoop() - { - try - { - try - { - while (true) - { - TcpClient client = listener.AcceptTcpClient(); - tcpConfig.ApplyTo(client); - - - // TODO keep track of connections before they are in connections dictionary - // this might not be a problem as HandshakeAndReceiveLoop checks for stop - // and returns/disposes before sending message to queue - Connection conn = new Connection(client, AfterConnectionDisposed); - Log.Info($"A client connected {conn}"); - - // handshake needs its own thread as it needs to wait for message from client - Thread receiveThread = new Thread(() => HandshakeAndReceiveLoop(conn)); - - conn.receiveThread = receiveThread; - - receiveThread.IsBackground = true; - receiveThread.Start(); - } - } - catch (SocketException) - { - // check for Interrupted/Abort - Utils.CheckForInterupt(); - throw; - } - } - catch (ThreadInterruptedException e) { Log.InfoException(e); } - catch (ThreadAbortException e) { Log.InfoException(e); } - catch (Exception e) { Log.Exception(e); } - } - - void HandshakeAndReceiveLoop(Connection conn) - { - try - { - bool success = sslHelper.TryCreateStream(conn); - if (!success) - { - Log.Error($"Failed to create SSL Stream {conn}"); - conn.Dispose(); - return; - } - - success = handShake.TryHandshake(conn); - - if (success) - { - Log.Info($"Sent Handshake {conn}"); - } - else - { - Log.Error($"Handshake Failed {conn}"); - conn.Dispose(); - return; - } - - // check if Stop has been called since accepting this client - if (serverStopped) - { - Log.Info("Server stops after successful handshake"); - return; - } - - conn.connId = Interlocked.Increment(ref _idCounter); - connections.TryAdd(conn.connId, conn); - - receiveQueue.Enqueue(new Message(conn.connId, EventType.Connected)); - - Thread sendThread = new Thread(() => - { - SendLoop.Config sendConfig = new SendLoop.Config( - conn, - bufferSize: Constants.HeaderSize + maxMessageSize, - setMask: false); - - SendLoop.Loop(sendConfig); - }); - - conn.sendThread = sendThread; - sendThread.IsBackground = true; - sendThread.Name = $"SendLoop {conn.connId}"; - sendThread.Start(); - - ReceiveLoop.Config receiveConfig = new ReceiveLoop.Config( - conn, - maxMessageSize, - expectMask: true, - receiveQueue, - bufferPool); - - ReceiveLoop.Loop(receiveConfig); - } - catch (ThreadInterruptedException e) { Log.InfoException(e); } - catch (ThreadAbortException e) { Log.InfoException(e); } - catch (Exception e) { Log.Exception(e); } - finally - { - // close here incase connect fails - conn.Dispose(); - } - } - - void AfterConnectionDisposed(Connection conn) - { - if (conn.connId != Connection.IdNotSet) - { - receiveQueue.Enqueue(new Message(conn.connId, EventType.Disconnected)); - connections.TryRemove(conn.connId, out Connection _); - } - } - - public void Send(int id, ArrayBuffer buffer) - { - if (connections.TryGetValue(id, out Connection conn)) - { - conn.sendQueue.Enqueue(buffer); - conn.sendPending.Set(); - } - else - { - Log.Warn($"Cant send message to {id} because connection was not found in dictionary. Maybe it disconnected."); - } - } - - public bool CloseConnection(int id) - { - if (connections.TryGetValue(id, out Connection conn)) - { - Log.Info($"Kicking connection {id}"); - conn.Dispose(); - return true; - } - else - { - Log.Warn($"Failed to kick {id} because id not found"); - - return false; - } - } - - public string GetClientAddress(int id) - { - if (connections.TryGetValue(id, out Connection conn)) - { - return conn.client.Client.RemoteEndPoint.ToString(); - } - else - { - Log.Error($"Cant close connection to {id} because connection was not found in dictionary"); - return null; - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs.meta deleted file mode 100644 index 0a76a9f..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/Server/WebSocketServer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5c434db044777d2439bae5a57d4e8ee7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef deleted file mode 100644 index 3687c5d..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "SimpleWebTransport", - "references": [ - "Mirror" - ], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef.meta deleted file mode 100644 index 99755b6..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3b5390adca4e2bb4791cb930316d6f3e -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs deleted file mode 100644 index c111c55..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs +++ /dev/null @@ -1,280 +0,0 @@ -using System; -using System.Net; -using System.Security.Authentication; -using UnityEngine; -using UnityEngine.Serialization; - -namespace Mirror.SimpleWeb -{ - public class SimpleWebTransport : Transport - { - public const string NormalScheme = "ws"; - public const string SecureScheme = "wss"; - - [Tooltip("Port to use for server and client")] - public ushort port = 7778; - - - [Tooltip("Protect against allocation attacks by keeping the max message size small. Otherwise an attacker might send multiple fake packets with 2GB headers, causing the server to run out of memory after allocating multiple large packets.")] - public int maxMessageSize = 16 * 1024; - - [Tooltip("Max size for http header send as handshake for websockets")] - public int handshakeMaxSize = 3000; - - [Tooltip("disables nagle algorithm. lowers CPU% and latency but increases bandwidth")] - public bool noDelay = true; - - [Tooltip("Send would stall forever if the network is cut off during a send, so we need a timeout (in milliseconds)")] - public int sendTimeout = 5000; - - [Tooltip("How long without a message before disconnecting (in milliseconds)")] - public int receiveTimeout = 20000; - - [Tooltip("Caps the number of messages the server will process per tick. Allows LateUpdate to finish to let the reset of unity contiue incase more messages arrive before they are processed")] - public int serverMaxMessagesPerTick = 10000; - - [Tooltip("Caps the number of messages the client will process per tick. Allows LateUpdate to finish to let the reset of unity contiue incase more messages arrive before they are processed")] - public int clientMaxMessagesPerTick = 1000; - - [Header("Ssl Settings")] - public bool sslEnabled; - [Tooltip("Path to json file that contains path to cert and its password\n\nUse Json file so that cert password is not included in client builds\n\nSee cert.example.Json")] - public string sslCertJson = "./cert.json"; - public SslProtocols sslProtocols = SslProtocols.Tls12; - - [Header("Debug")] - [Tooltip("Log functions uses ConditionalAttribute which will effect which log methods are allowed. DEBUG allows warn/error, SIMPLEWEB_LOG_ENABLED allows all")] - [FormerlySerializedAs("logLevels")] - [SerializeField] Log.Levels _logLevels = Log.Levels.none; - - /// - /// Gets _logLevels field - /// Sets _logLevels and Log.level fields - /// - public Log.Levels LogLevels - { - get => _logLevels; - set - { - _logLevels = value; - Log.level = _logLevels; - } - } - - void OnValidate() - { - if (maxMessageSize > ushort.MaxValue) - { - Debug.LogWarning($"max supported value for maxMessageSize is {ushort.MaxValue}"); - maxMessageSize = ushort.MaxValue; - } - - Log.level = _logLevels; - } - - SimpleWebClient client; - SimpleWebServer server; - - TcpConfig TcpConfig => new TcpConfig(noDelay, sendTimeout, receiveTimeout); - - public override bool Available() - { - return true; - } - public override int GetMaxPacketSize(int channelId = 0) - { - return maxMessageSize; - } - - void Awake() - { - Log.level = _logLevels; - } - public override void Shutdown() - { - client?.Disconnect(); - client = null; - server?.Stop(); - server = null; - } - - void LateUpdate() - { - ProcessMessages(); - } - - /// - /// Processes message in server and client queues - /// Invokes OnData events allowing mirror to handle messages (Cmd/SyncVar/etc) - /// Called within LateUpdate, Can be called by user to process message before important logic - /// - public void ProcessMessages() - { - server?.ProcessMessageQueue(this); - client?.ProcessMessageQueue(this); - } - - #region Client - string GetScheme() => sslEnabled ? SecureScheme : NormalScheme; - public override bool ClientConnected() - { - // not null and not NotConnected (we want to return true if connecting or disconnecting) - return client != null && client.ConnectionState != ClientState.NotConnected; - } - - public override void ClientConnect(string hostname) - { - // connecting or connected - if (ClientConnected()) - { - Debug.LogError("Already Connected"); - return; - } - - UriBuilder builder = new UriBuilder - { - Scheme = GetScheme(), - Host = hostname, - Port = port - }; - - - client = SimpleWebClient.Create(maxMessageSize, clientMaxMessagesPerTick, TcpConfig); - if (client == null) { return; } - - client.onConnect += OnClientConnected.Invoke; - client.onDisconnect += () => - { - OnClientDisconnected.Invoke(); - // clear client here after disconnect event has been sent - // there should be no more messages after disconnect - client = null; - }; - client.onData += (ArraySegment data) => OnClientDataReceived.Invoke(data, Channels.DefaultReliable); - client.onError += (Exception e) => - { - ClientDisconnect(); - OnClientError.Invoke(e); - }; - - client.Connect(builder.Uri); - } - - public override void ClientDisconnect() - { - // dont set client null here of messages wont be processed - client?.Disconnect(); - } - - public override void ClientSend(int channelId, ArraySegment segment) - { - if (!ClientConnected()) - { - Debug.LogError("Not Connected"); - return; - } - - if (segment.Count > maxMessageSize) - { - Log.Error("Message greater than max size"); - return; - } - - if (segment.Count == 0) - { - Log.Error("Message count was zero"); - return; - } - - client.Send(segment); - } - #endregion - - #region Server - public override bool ServerActive() - { - return server != null && server.Active; - } - - public override void ServerStart() - { - if (ServerActive()) - { - Debug.LogError("SimpleWebServer Already Started"); - } - - SslConfig config = SslConfigLoader.Load(this); - server = new SimpleWebServer(serverMaxMessagesPerTick, TcpConfig, maxMessageSize, handshakeMaxSize, config); - - server.onConnect += OnServerConnected.Invoke; - server.onDisconnect += OnServerDisconnected.Invoke; - server.onData += (int connId, ArraySegment data) => OnServerDataReceived.Invoke(connId, data, Channels.DefaultReliable); - server.onError += OnServerError.Invoke; - - server.Start(port); - } - - public override void ServerStop() - { - if (!ServerActive()) - { - Debug.LogError("SimpleWebServer Not Active"); - } - - server.Stop(); - server = null; - } - - public override bool ServerDisconnect(int connectionId) - { - if (!ServerActive()) - { - Debug.LogError("SimpleWebServer Not Active"); - return false; - } - - return server.KickClient(connectionId); - } - - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - if (!ServerActive()) - { - Debug.LogError("SimpleWebServer Not Active"); - return; - } - - if (segment.Count > maxMessageSize) - { - Log.Error("Message greater than max size"); - return; - } - - if (segment.Count == 0) - { - Log.Error("Message count was zero"); - return; - } - - server.SendOne(connectionId, segment); - return; - } - - public override string ServerGetClientAddress(int connectionId) - { - return server.GetClientAddress(connectionId); - } - - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder - { - Scheme = GetScheme(), - Host = Dns.GetHostName(), - Port = port - }; - return builder.Uri; - } - #endregion - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs.meta deleted file mode 100644 index 381a5c7..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SimpleWebTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0110f245bfcfc7d459681f7bd9ebc590 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs deleted file mode 100644 index 8431ac7..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.IO; -using UnityEngine; - -namespace Mirror.SimpleWeb -{ - internal class SslConfigLoader - { - internal struct Cert - { - public string path; - public string password; - } - internal static SslConfig Load(SimpleWebTransport transport) - { - // dont need to load anything if ssl is not enabled - if (!transport.sslEnabled) - return default; - - string certJsonPath = transport.sslCertJson; - - Cert cert = LoadCertJson(certJsonPath); - - return new SslConfig( - enabled: transport.sslEnabled, - sslProtocols: transport.sslProtocols, - certPath: cert.path, - certPassword: cert.password - ); - } - - internal static Cert LoadCertJson(string certJsonPath) - { - string json = File.ReadAllText(certJsonPath); - Cert cert = JsonUtility.FromJson(json); - - if (string.IsNullOrEmpty(cert.path)) - { - throw new InvalidDataException("Cert Json didnt not contain \"path\""); - } - if (string.IsNullOrEmpty(cert.password)) - { - // password can be empty - cert.password = string.Empty; - } - - return cert; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs.meta b/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs.meta deleted file mode 100644 index e653532..0000000 --- a/Assets/Mirror/Runtime/Transport/SimpleWebTransport/SslConfigLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dfdb6b97a48a48b498e563e857342da1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy.meta b/Assets/Mirror/Runtime/Transport/Telepathy.meta deleted file mode 100644 index ede2d0e..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 552b3d8382916438d81fe7f39e18db72 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs deleted file mode 100644 index 08e7db4..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs +++ /dev/null @@ -1,213 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Net.Sockets; -using System.Threading; - -namespace Telepathy -{ - public class Client : Common - { - public TcpClient client; - Thread receiveThread; - Thread sendThread; - - // TcpClient.Connected doesn't check if socket != null, which - // results in NullReferenceExceptions if connection was closed. - // -> let's check it manually instead - public bool Connected => client != null && - client.Client != null && - client.Client.Connected; - - // TcpClient has no 'connecting' state to check. We need to keep track - // of it manually. - // -> checking 'thread.IsAlive && !Connected' is not enough because the - // thread is alive and connected is false for a short moment after - // disconnecting, so this would cause race conditions. - // -> we use a threadsafe bool wrapper so that ThreadFunction can remain - // static (it needs a common lock) - // => Connecting is true from first Connect() call in here, through the - // thread start, until TcpClient.Connect() returns. Simple and clear. - // => bools are atomic according to - // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables - // made volatile so the compiler does not reorder access to it - volatile bool _Connecting; - public bool Connecting => _Connecting; - - // send queue - // => SafeQueue is twice as fast as ConcurrentQueue, see SafeQueue.cs! - SafeQueue sendQueue = new SafeQueue(); - - // ManualResetEvent to wake up the send thread. better than Thread.Sleep - // -> call Set() if everything was sent - // -> call Reset() if there is something to send again - // -> call WaitOne() to block until Reset was called - ManualResetEvent sendPending = new ManualResetEvent(false); - - // the thread function - void ReceiveThreadFunction(string ip, int port) - { - // absolutely must wrap with try/catch, otherwise thread - // exceptions are silent - try - { - // connect (blocking) - client.Connect(ip, port); - _Connecting = false; - - // set socket options after the socket was created in Connect() - // (not after the constructor because we clear the socket there) - client.NoDelay = NoDelay; - client.SendTimeout = SendTimeout; - - // start send thread only after connected - sendThread = new Thread(() => { SendLoop(0, client, sendQueue, sendPending); }); - sendThread.IsBackground = true; - sendThread.Start(); - - // run the receive loop - ReceiveLoop(0, client, receiveQueue, MaxMessageSize); - } - catch (SocketException exception) - { - // this happens if (for example) the ip address is correct - // but there is no server running on that ip/port - Logger.LogError($"Client Recv: failed to connect to ip={ip} port={port} reason={exception}"); - - // add 'Disconnected' event to message queue so that the caller - // knows that the Connect failed. otherwise they will never know - receiveQueue.Enqueue(new Message(0, EventType.Disconnected, null)); - } - catch (ThreadInterruptedException) - { - // expected if Disconnect() aborts it - } - catch (ThreadAbortException) - { - // expected if Disconnect() aborts it - } - catch (Exception exception) - { - // something went wrong. probably important. - Logger.LogError($"Client Recv Exception: {exception}"); - } - - // sendthread might be waiting on ManualResetEvent, - // so let's make sure to end it if the connection - // closed. - // otherwise the send thread would only end if it's - // actually sending data while the connection is - // closed. - sendThread?.Interrupt(); - - // Connect might have failed. thread might have been closed. - // let's reset connecting state no matter what. - _Connecting = false; - - // if we got here then we are done. ReceiveLoop cleans up already, - // but we may never get there if connect fails. so let's clean up - // here too. - client?.Close(); - } - - public void Connect(string ip, int port) - { - // not if already started - if (Connecting || Connected) - { - Logger.LogWarning("Telepathy Client can not create connection because an existing connection is connecting or connected"); - return; - } - - // We are connecting from now until Connect succeeds or fails - _Connecting = true; - - // create a TcpClient with perfect IPv4, IPv6 and hostname resolving - // support. - // - // * TcpClient(hostname, port): works but would connect (and block) - // already - // * TcpClient(AddressFamily.InterNetworkV6): takes Ipv4 and IPv6 - // addresses but only connects to IPv6 servers (e.g. Telepathy). - // does NOT connect to IPv4 servers (e.g. Mirror Booster), even - // with DualMode enabled. - // * TcpClient(): creates IPv4 socket internally, which would force - // Connect() to only use IPv4 sockets. - // - // => the trick is to clear the internal IPv4 socket so that Connect - // resolves the hostname and creates either an IPv4 or an IPv6 - // socket as needed (see TcpClient source) - // creates IPv4 socket - client = new TcpClient(); - // clear internal IPv4 socket until Connect() - client.Client = null; - - // clear old messages in queue, just to be sure that the caller - // doesn't receive data from last time and gets out of sync. - // -> calling this in Disconnect isn't smart because the caller may - // still want to process all the latest messages afterwards - receiveQueue = new ConcurrentQueue(); - sendQueue.Clear(); - - // client.Connect(ip, port) is blocking. let's call it in the thread - // and return immediately. - // -> this way the application doesn't hang for 30s if connect takes - // too long, which is especially good in games - // -> this way we don't async client.BeginConnect, which seems to - // fail sometimes if we connect too many clients too fast - receiveThread = new Thread(() => { ReceiveThreadFunction(ip, port); }); - receiveThread.IsBackground = true; - receiveThread.Start(); - } - - public void Disconnect() - { - // only if started - if (Connecting || Connected) - { - // close client - client.Close(); - - // wait until thread finished. this is the only way to guarantee - // that we can call Connect() again immediately after Disconnect - // -> calling .Join would sometimes wait forever, e.g. when - // calling Disconnect while trying to connect to a dead end - receiveThread?.Interrupt(); - - // we interrupted the receive Thread, so we can't guarantee that - // connecting was reset. let's do it manually. - _Connecting = false; - - // clear send queues. no need to hold on to them. - // (unlike receiveQueue, which is still needed to process the - // latest Disconnected message, etc.) - sendQueue.Clear(); - - // let go of this one completely. the thread ended, no one uses - // it anymore and this way Connected is false again immediately. - client = null; - } - } - - public bool Send(byte[] data) - { - if (Connected) - { - // respect max message size to avoid allocation attacks. - if (data.Length <= MaxMessageSize) - { - // add to send queue and return immediately. - // calling Send here would be blocking (sometimes for long times - // if other side lags or wire was disconnected) - sendQueue.Enqueue(data); - // interrupt SendThread WaitOne() - sendPending.Set(); - return true; - } - Logger.LogError($"Client.Send: message too big: {data.Length}. Limit: {MaxMessageSize}"); - return false; - } - Logger.LogWarning("Client.Send: not connected!"); - return false; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs.meta deleted file mode 100644 index 1b6d222..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Client.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a5b95294cc4ec4b15aacba57531c7985 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs deleted file mode 100644 index e41a4c8..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs +++ /dev/null @@ -1,296 +0,0 @@ -// common code used by server and client -using System; -using System.Collections.Concurrent; -using System.Net.Sockets; -using System.Threading; - -namespace Telepathy -{ - public abstract class Common - { - ///////////////////////////////////////////////////////// - // common code - // incoming message queue of - // (not a HashSet because one connection can have multiple new messages) - protected ConcurrentQueue receiveQueue = new ConcurrentQueue(); - - // queue count, useful for debugging / benchmarks - public int ReceiveQueueCount => receiveQueue.Count; - - // warning if message queue gets too big - // if the average message is about 20 bytes then: - // - 1k messages are 20KB - // - 10k messages are 200KB - // - 100k messages are 1.95MB - // 2MB are not that much, but it is a bad sign if the caller process - // can't call GetNextMessage faster than the incoming messages. - public static int messageQueueSizeWarning = 100000; - - // removes and returns the oldest message from the message queue. - // (might want to call this until it doesn't return anything anymore) - // -> Connected, Data, Disconnected events are all added here - // -> bool return makes while (GetMessage(out Message)) easier! - // -> no 'is client connected' check because we still want to read the - // Disconnected message after a disconnect - public bool GetNextMessage(out Message message) - { - return receiveQueue.TryDequeue(out message); - } - - // NoDelay disables nagle algorithm. lowers CPU% and latency but - // increases bandwidth - public bool NoDelay = true; - - // Prevent allocation attacks. Each packet is prefixed with a length - // header, so an attacker could send a fake packet with length=2GB, - // causing the server to allocate 2GB and run out of memory quickly. - // -> simply increase max packet size if you want to send around bigger - // files! - // -> 16KB per message should be more than enough. - public int MaxMessageSize = 16 * 1024; - - // Send would stall forever if the network is cut off during a send, so - // we need a timeout (in milliseconds) - public int SendTimeout = 5000; - - // avoid header[4] allocations but don't use one buffer for all threads - [ThreadStatic] static byte[] header; - - // avoid payload[packetSize] allocations but don't use one buffer for - // all threads - [ThreadStatic] static byte[] payload; - - ///////////////////////////////////////////// - // static helper functions - // send message (via stream) with the message structure - // this function is blocking sometimes! - // (e.g. if someone has high latency or wire was cut off) - protected static bool SendMessagesBlocking(NetworkStream stream, byte[][] messages) - { - // stream.Write throws exceptions if client sends with high - // frequency and the server stops - try - { - // we might have multiple pending messages. merge into one - // packet to avoid TCP overheads and improve performance. - int packetSize = 0; - for (int i = 0; i < messages.Length; ++i) - // header + content - packetSize += sizeof(int) + messages[i].Length; - - // create payload buffer if not created yet or previous one is - // too small - // IMPORTANT: payload.Length might be > packetSize! don't use it! - if (payload == null || payload.Length < packetSize) - payload = new byte[packetSize]; - - // create the packet - int position = 0; - for (int i = 0; i < messages.Length; ++i) - { - // create header buffer if not created yet - if (header == null) - header = new byte[4]; - - // construct header (size) - Utils.IntToBytesBigEndianNonAlloc(messages[i].Length, header); - - // copy header + message into buffer - Array.Copy(header, 0, payload, position, header.Length); - Array.Copy(messages[i], 0, payload, position + header.Length, messages[i].Length); - position += header.Length + messages[i].Length; - } - - // write the whole thing - stream.Write(payload, 0, packetSize); - - return true; - } - catch (Exception exception) - { - // log as regular message because servers do shut down sometimes - Logger.Log("Send: stream.Write exception: " + exception); - return false; - } - } - - // read message (via stream) with the message structure - protected static bool ReadMessageBlocking(NetworkStream stream, int MaxMessageSize, out byte[] content) - { - content = null; - - // create header buffer if not created yet - if (header == null) - header = new byte[4]; - - // read exactly 4 bytes for header (blocking) - if (!stream.ReadExactly(header, 4)) - return false; - - // convert to int - int size = Utils.BytesToIntBigEndian(header); - - // protect against allocation attacks. an attacker might send - // multiple fake '2GB header' packets in a row, causing the server - // to allocate multiple 2GB byte arrays and run out of memory. - if (size <= MaxMessageSize) - { - // read exactly 'size' bytes for content (blocking) - content = new byte[size]; - return stream.ReadExactly(content, size); - } - Logger.LogWarning("ReadMessageBlocking: possible allocation attack with a header of: " + size + " bytes."); - return false; - } - - // thread receive function is the same for client and server's clients - // (static to reduce state for maximum reliability) - protected static void ReceiveLoop(int connectionId, TcpClient client, ConcurrentQueue receiveQueue, int MaxMessageSize) - { - // get NetworkStream from client - NetworkStream stream = client.GetStream(); - - // keep track of last message queue warning - DateTime messageQueueLastWarning = DateTime.Now; - - // absolutely must wrap with try/catch, otherwise thread exceptions - // are silent - try - { - // add connected event to queue with ip address as data in case - // it's needed - receiveQueue.Enqueue(new Message(connectionId, EventType.Connected, null)); - - // let's talk about reading data. - // -> normally we would read as much as possible and then - // extract as many , messages - // as we received this time. this is really complicated - // and expensive to do though - // -> instead we use a trick: - // Read(2) -> size - // Read(size) -> content - // repeat - // Read is blocking, but it doesn't matter since the - // best thing to do until the full message arrives, - // is to wait. - // => this is the most elegant AND fast solution. - // + no resizing - // + no extra allocations, just one for the content - // + no crazy extraction logic - while (true) - { - // read the next message (blocking) or stop if stream closed - byte[] content; - if (!ReadMessageBlocking(stream, MaxMessageSize, out content)) - // break instead of return so stream close still happens! - break; - - // queue it - receiveQueue.Enqueue(new Message(connectionId, EventType.Data, content)); - - // and show a warning if the queue gets too big - // -> we don't want to show a warning every single time, - // because then a lot of processing power gets wasted on - // logging, which will make the queue pile up even more. - // -> instead we show it every 10s, so that the system can - // use most it's processing power to hopefully process it. - if (receiveQueue.Count > messageQueueSizeWarning) - { - TimeSpan elapsed = DateTime.Now - messageQueueLastWarning; - if (elapsed.TotalSeconds > 10) - { - Logger.LogWarning("ReceiveLoop: messageQueue is getting big(" + receiveQueue.Count + "), try calling GetNextMessage more often. You can call it more than once per frame!"); - messageQueueLastWarning = DateTime.Now; - } - } - } - } - catch (Exception exception) - { - // something went wrong. the thread was interrupted or the - // connection closed or we closed our own connection or ... - // -> either way we should stop gracefully - Logger.Log("ReceiveLoop: finished receive function for connectionId=" + connectionId + " reason: " + exception); - } - finally - { - // clean up no matter what - stream.Close(); - client.Close(); - - // add 'Disconnected' message after disconnecting properly. - // -> always AFTER closing the streams to avoid a race condition - // where Disconnected -> Reconnect wouldn't work because - // Connected is still true for a short moment before the stream - // would be closed. - receiveQueue.Enqueue(new Message(connectionId, EventType.Disconnected, null)); - } - } - - // thread send function - // note: we really do need one per connection, so that if one connection - // blocks, the rest will still continue to get sends - protected static void SendLoop(int connectionId, TcpClient client, SafeQueue sendQueue, ManualResetEvent sendPending) - { - // get NetworkStream from client - NetworkStream stream = client.GetStream(); - - try - { - // try this. client will get closed eventually. - while (client.Connected) - { - // reset ManualResetEvent before we do anything else. this - // way there is no race condition. if Send() is called again - // while in here then it will be properly detected next time - // -> otherwise Send might be called right after dequeue but - // before .Reset, which would completely ignore it until - // the next Send call. - // WaitOne() blocks until .Set() again - sendPending.Reset(); - - // dequeue all - // SafeQueue.TryDequeueAll is twice as fast as - // ConcurrentQueue, see SafeQueue.cs! - byte[][] messages; - if (sendQueue.TryDequeueAll(out messages)) - { - // send message (blocking) or stop if stream is closed - if (!SendMessagesBlocking(stream, messages)) - // break instead of return so stream close still happens! - break; - } - - // don't choke up the CPU: wait until queue not empty anymore - sendPending.WaitOne(); - } - } - catch (ThreadAbortException) - { - // happens on stop. don't log anything. - } - catch (ThreadInterruptedException) - { - // happens if receive thread interrupts send thread. - } - catch (Exception exception) - { - // something went wrong. the thread was interrupted or the - // connection closed or we closed our own connection or ... - // -> either way we should stop gracefully - Logger.Log("SendLoop Exception: connectionId=" + connectionId + " reason: " + exception); - } - finally - { - // clean up no matter what - // we might get SocketExceptions when sending if the 'host has - // failed to respond' - in which case we should close the connection - // which causes the ReceiveLoop to end and fire the Disconnected - // message. otherwise the connection would stay alive forever even - // though we can't send anymore. - stream.Close(); - client.Close(); - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs.meta deleted file mode 100644 index 5d8ab5b..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Common.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c4d56322cf0e248a89103c002a505dab -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs b/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs deleted file mode 100644 index 66bc3b4..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Telepathy -{ - public enum EventType - { - Connected, - Data, - Disconnected - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs.meta deleted file mode 100644 index ac88c1b..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/EventType.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 49f1a330755814803be5f27f493e1910 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE b/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE deleted file mode 100644 index 680deef..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018, vis2k - -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/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE.meta b/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE.meta deleted file mode 100644 index 4d7664e..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/LICENSE.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0ba11103b95fd4721bffbb08440d5b8e -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs deleted file mode 100644 index 5522021..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs +++ /dev/null @@ -1,15 +0,0 @@ -// A simple logger class that uses Console.WriteLine by default. -// Can also do Logger.LogMethod = Debug.Log for Unity etc. -// (this way we don't have to depend on UnityEngine.DLL and don't need a -// different version for every UnityEngine version here) -using System; - -namespace Telepathy -{ - public static class Logger - { - public static Action Log = Console.WriteLine; - public static Action LogWarning = Console.WriteLine; - public static Action LogError = Console.Error.WriteLine; - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs.meta deleted file mode 100644 index 304866f..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Logger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aa8d703f0b73f4d6398b76812719b68b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs deleted file mode 100644 index c5b3b04..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs +++ /dev/null @@ -1,18 +0,0 @@ -// incoming message queue of -// (not a HashSet because one connection can have multiple new messages) -// -> a struct to minimize GC -namespace Telepathy -{ - public struct Message - { - public readonly int connectionId; - public readonly EventType eventType; - public readonly byte[] data; - public Message(int connectionId, EventType eventType, byte[] data) - { - this.connectionId = connectionId; - this.eventType = eventType; - this.data = data; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs.meta deleted file mode 100644 index 5937bb9..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Message.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aedf812e9637b4f92a35db1aedca8c92 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs b/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs deleted file mode 100644 index a4a887e..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.IO; -using System.Net.Sockets; - -namespace Telepathy -{ - - public static class NetworkStreamExtensions - { - // .Read returns '0' if remote closed the connection but throws an - // IOException if we voluntarily closed our own connection. - // - // let's add a ReadSafely method that returns '0' in both cases so we don't - // have to worry about exceptions, since a disconnect is a disconnect... - public static int ReadSafely(this NetworkStream stream, byte[] buffer, int offset, int size) - { - try - { - return stream.Read(buffer, offset, size); - } - catch (IOException) - { - return 0; - } - } - - // helper function to read EXACTLY 'n' bytes - // -> default .Read reads up to 'n' bytes. this function reads exactly 'n' - // bytes - // -> this is blocking until 'n' bytes were received - // -> immediately returns false in case of disconnects - public static bool ReadExactly(this NetworkStream stream, byte[] buffer, int amount) - { - // there might not be enough bytes in the TCP buffer for .Read to read - // the whole amount at once, so we need to keep trying until we have all - // the bytes (blocking) - // - // note: this just is a faster version of reading one after another: - // for (int i = 0; i < amount; ++i) - // if (stream.Read(buffer, i, 1) == 0) - // return false; - // return true; - int bytesRead = 0; - while (bytesRead < amount) - { - // read up to 'remaining' bytes with the 'safe' read extension - int remaining = amount - bytesRead; - int result = stream.ReadSafely(buffer, bytesRead, remaining); - - // .Read returns 0 if disconnected - if (result == 0) - return false; - - // otherwise add to bytes read - bytesRead += result; - } - return true; - } - } -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs.meta deleted file mode 100644 index e7e5744..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/NetworkStreamExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7a8076c43fa8d4d45831adae232d4d3c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs b/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs deleted file mode 100644 index e92a875..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Net 4.X has ConcurrentQueue, but ConcurrentQueue has no TryDequeueAll method, -// which makes SafeQueue twice as fast for the send thread. -// -// uMMORPG 450 CCU -// SafeQueue: 900-1440ms latency -// ConcurrentQueue: 2000ms latency -// -// It's also noticeable in the LoadTest project, which hardly handles 300 CCU -// with ConcurrentQueue! -using System.Collections.Generic; - -namespace Telepathy -{ - public class SafeQueue - { - readonly Queue queue = new Queue(); - - // for statistics. don't call Count and assume that it's the same after the - // call. - public int Count - { - get - { - lock (queue) - { - return queue.Count; - } - } - } - - public void Enqueue(T item) - { - lock (queue) - { - queue.Enqueue(item); - } - } - - // can't check .Count before doing Dequeue because it might change inbetween, - // so we need a TryDequeue - public bool TryDequeue(out T result) - { - lock (queue) - { - result = default(T); - if (queue.Count > 0) - { - result = queue.Dequeue(); - return true; - } - return false; - } - } - - // for when we want to dequeue and remove all of them at once without - // locking every single TryDequeue. - public bool TryDequeueAll(out T[] result) - { - lock (queue) - { - result = queue.ToArray(); - queue.Clear(); - return result.Length > 0; - } - } - - public void Clear() - { - lock (queue) - { - queue.Clear(); - } - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs.meta deleted file mode 100644 index f3a9310..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/SafeQueue.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8fc06e2fb29854a0c9e90c0188d36a08 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs deleted file mode 100644 index 085215a..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Threading; - -namespace Telepathy -{ - public class Server : Common - { - // listener - public TcpListener listener; - Thread listenerThread; - - // class with all the client's data. let's call it Token for consistency - // with the async socket methods. - class ClientToken - { - public TcpClient client; - - // send queue - // SafeQueue is twice as fast as ConcurrentQueue, see SafeQueue.cs! - public SafeQueue sendQueue = new SafeQueue(); - - // ManualResetEvent to wake up the send thread. better than Thread.Sleep - // -> call Set() if everything was sent - // -> call Reset() if there is something to send again - // -> call WaitOne() to block until Reset was called - public ManualResetEvent sendPending = new ManualResetEvent(false); - - public ClientToken(TcpClient client) - { - this.client = client; - } - } - - // clients with - readonly ConcurrentDictionary clients = new ConcurrentDictionary(); - - // connectionId counter - int counter; - - // public next id function in case someone needs to reserve an id - // (e.g. if hostMode should always have 0 connection and external - // connections should start at 1, etc.) - public int NextConnectionId() - { - int id = Interlocked.Increment(ref counter); - - // it's very unlikely that we reach the uint limit of 2 billion. - // even with 1 new connection per second, this would take 68 years. - // -> but if it happens, then we should throw an exception because - // the caller probably should stop accepting clients. - // -> it's hardly worth using 'bool Next(out id)' for that case - // because it's just so unlikely. - if (id == int.MaxValue) - { - throw new Exception("connection id limit reached: " + id); - } - - return id; - } - - // check if the server is running - public bool Active => listenerThread != null && listenerThread.IsAlive; - - // the listener thread's listen function - // note: no maxConnections parameter. high level API should handle that. - // (Transport can't send a 'too full' message anyway) - void Listen(int port) - { - // absolutely must wrap with try/catch, otherwise thread - // exceptions are silent - try - { - // start listener on all IPv4 and IPv6 address via .Create - listener = TcpListener.Create(port); - listener.Server.NoDelay = NoDelay; - listener.Server.SendTimeout = SendTimeout; - listener.Start(); - Logger.Log("Server: listening port=" + port); - - // keep accepting new clients - while (true) - { - // wait and accept new client - // note: 'using' sucks here because it will try to - // dispose after thread was started but we still need it - // in the thread - TcpClient client = listener.AcceptTcpClient(); - - // set socket options - client.NoDelay = NoDelay; - client.SendTimeout = SendTimeout; - - // generate the next connection id (thread safely) - int connectionId = NextConnectionId(); - - // add to dict immediately - ClientToken token = new ClientToken(client); - clients[connectionId] = token; - - // spawn a send thread for each client - Thread sendThread = new Thread(() => - { - // wrap in try-catch, otherwise Thread exceptions - // are silent - try - { - // run the send loop - SendLoop(connectionId, client, token.sendQueue, token.sendPending); - } - catch (ThreadAbortException) - { - // happens on stop. don't log anything. - // (we catch it in SendLoop too, but it still gets - // through to here when aborting. don't show an - // error.) - } - catch (Exception exception) - { - Logger.LogError("Server send thread exception: " + exception); - } - }); - sendThread.IsBackground = true; - sendThread.Start(); - - // spawn a receive thread for each client - Thread receiveThread = new Thread(() => - { - // wrap in try-catch, otherwise Thread exceptions - // are silent - try - { - // run the receive loop - ReceiveLoop(connectionId, client, receiveQueue, MaxMessageSize); - - // remove client from clients dict afterwards - clients.TryRemove(connectionId, out ClientToken _); - - // sendthread might be waiting on ManualResetEvent, - // so let's make sure to end it if the connection - // closed. - // otherwise the send thread would only end if it's - // actually sending data while the connection is - // closed. - sendThread.Interrupt(); - } - catch (Exception exception) - { - Logger.LogError("Server client thread exception: " + exception); - } - }); - receiveThread.IsBackground = true; - receiveThread.Start(); - } - } - catch (ThreadAbortException exception) - { - // UnityEditor causes AbortException if thread is still - // running when we press Play again next time. that's okay. - Logger.Log("Server thread aborted. That's okay. " + exception); - } - catch (SocketException exception) - { - // calling StopServer will interrupt this thread with a - // 'SocketException: interrupted'. that's okay. - Logger.Log("Server Thread stopped. That's okay. " + exception); - } - catch (Exception exception) - { - // something went wrong. probably important. - Logger.LogError("Server Exception: " + exception); - } - } - - // start listening for new connections in a background thread and spawn - // a new thread for each one. - public bool Start(int port) - { - // not if already started - if (Active) - return false; - - // clear old messages in queue, just to be sure that the caller - // doesn't receive data from last time and gets out of sync. - // -> calling this in Stop isn't smart because the caller may - // still want to process all the latest messages afterwards - receiveQueue = new ConcurrentQueue(); - - // start the listener thread - // (on low priority. if main thread is too busy then there is not - // much value in accepting even more clients) - Logger.Log("Server: Start port=" + port); - listenerThread = new Thread(() => { Listen(port); }); - listenerThread.IsBackground = true; - listenerThread.Priority = ThreadPriority.BelowNormal; - listenerThread.Start(); - return true; - } - - public void Stop() - { - // only if started - if (!Active) - return; - - Logger.Log("Server: stopping..."); - - // stop listening to connections so that no one can connect while we - // close the client connections - // (might be null if we call Stop so quickly after Start that the - // thread was interrupted before even creating the listener) - listener?.Stop(); - - // kill listener thread at all costs. only way to guarantee that - // .Active is immediately false after Stop. - // -> calling .Join would sometimes wait forever - listenerThread?.Interrupt(); - listenerThread = null; - - // close all client connections - foreach (KeyValuePair kvp in clients) - { - TcpClient client = kvp.Value.client; - // close the stream if not closed yet. it may have been closed - // by a disconnect already, so use try/catch - try { client.GetStream().Close(); } catch { } - client.Close(); - } - - // clear clients list - clients.Clear(); - - // reset the counter in case we start up again so - // clients get connection ID's starting from 1 - counter = 0; - } - - // send message to client using socket connection. - public bool Send(int connectionId, byte[] data) - { - // respect max message size to avoid allocation attacks. - if (data.Length <= MaxMessageSize) - { - // find the connection - ClientToken token; - if (clients.TryGetValue(connectionId, out token)) - { - // add to send queue and return immediately. - // calling Send here would be blocking (sometimes for long times - // if other side lags or wire was disconnected) - token.sendQueue.Enqueue(data); - // interrupt SendThread WaitOne() - token.sendPending.Set(); - return true; - } - // sending to an invalid connectionId is expected sometimes. - // for example, if a client disconnects, the server might still - // try to send for one frame before it calls GetNextMessages - // again and realizes that a disconnect happened. - // so let's not spam the console with log messages. - //Logger.Log("Server.Send: invalid connectionId: " + connectionId); - return false; - } - Logger.LogError("Client.Send: message too big: " + data.Length + ". Limit: " + MaxMessageSize); - return false; - } - - // client's ip is sometimes needed by the server, e.g. for bans - public string GetClientAddress(int connectionId) - { - // find the connection - ClientToken token; - if (clients.TryGetValue(connectionId, out token)) - { - return ((IPEndPoint)token.client.Client.RemoteEndPoint).Address.ToString(); - } - return ""; - } - - // disconnect (kick) a client - public bool Disconnect(int connectionId) - { - // find the connection - ClientToken token; - if (clients.TryGetValue(connectionId, out token)) - { - // just close it. client thread will take care of the rest. - token.client.Close(); - Logger.Log("Server.Disconnect connectionId:" + connectionId); - return true; - } - return false; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs.meta deleted file mode 100644 index 9cee8b7..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Server.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb98a16841ccc4338a7e0b4e59136563 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef b/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef deleted file mode 100644 index cd8d16a..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "Telepathy", - "references": [], - "optionalUnityReferences": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [] -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef.meta deleted file mode 100644 index 572c127..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Telepathy.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 725ee7191c021de4dbf9269590ded755 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs b/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs deleted file mode 100644 index 115bf15..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Threading; - -namespace Telepathy -{ - public static class ThreadExtensions - { - // helper function to abort a thread and not return until it's fully done - public static void AbortAndJoin(this Thread thread) - { - // kill thread at all costs - // -> calling .Join would sometimes wait forever - // -> calling .Interrupt only interrupts certain states. - // => Abort() is the better solution. - thread.Abort(); - - // wait until thread is TRULY finished. this is the only way - // to guarantee that everything was properly cleaned up before - // returning. - // => this means that this function may sometimes block for a while - // but there is no other way to guarantee that everything is - // cleaned up properly by the time Stop() returns. - // we have to live with the wait time. - thread.Join(); - } - } -} \ No newline at end of file diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs.meta deleted file mode 100644 index 77c885d..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/ThreadExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 64df4eaebe4ff9a43a9fb318c3e8e321 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs b/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs deleted file mode 100644 index 12d32b7..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Telepathy -{ - public static class Utils - { - // fast int to byte[] conversion and vice versa - // -> test with 100k conversions: - // BitConverter.GetBytes(ushort): 144ms - // bit shifting: 11ms - // -> 10x speed improvement makes this optimization actually worth it - // -> this way we don't need to allocate BinaryWriter/Reader either - // -> 4 bytes because some people may want to send messages larger than - // 64K bytes - // => big endian is standard for network transmissions, and necessary - // for compatibility with erlang - public static byte[] IntToBytesBigEndian(int value) - { - return new byte[] { - (byte)(value >> 24), - (byte)(value >> 16), - (byte)(value >> 8), - (byte)value - }; - } - - // IntToBytes version that doesn't allocate a new byte[4] each time. - // -> important for MMO scale networking performance. - public static void IntToBytesBigEndianNonAlloc(int value, byte[] bytes) - { - bytes[0] = (byte)(value >> 24); - bytes[1] = (byte)(value >> 16); - bytes[2] = (byte)(value >> 8); - bytes[3] = (byte)value; - } - - public static int BytesToIntBigEndian(byte[] bytes) - { - return - (bytes[0] << 24) | - (bytes[1] << 16) | - (bytes[2] << 8) | - bytes[3]; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs.meta b/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs.meta deleted file mode 100644 index 0a9253b..0000000 --- a/Assets/Mirror/Runtime/Transport/Telepathy/Utils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 951d08c05297f4b3e8feb5bfcab86531 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs b/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs deleted file mode 100644 index 8ba3bc7..0000000 --- a/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs +++ /dev/null @@ -1,261 +0,0 @@ -// wraps Telepathy for use as HLAPI TransportLayer -using System; -using System.Net; -using System.Net.Sockets; -using UnityEngine; -using UnityEngine.Serialization; - -// Replaced by Kcp November 2020 -namespace Mirror -{ - [HelpURL("https://github.com/vis2k/Telepathy/blob/master/README.md")] - [Obsolete("This transport has been replaced by the Kcp Transport and will be removed in a future release.")] - public class TelepathyTransport : Transport - { - // scheme used by this transport - // "tcp4" means tcp with 4 bytes header, network byte order - public const string Scheme = "tcp4"; - - public ushort port = 7777; - - [Tooltip("Nagle Algorithm can be disabled by enabling NoDelay")] - public bool NoDelay = true; - - [Header("Server")] - [Tooltip("Protect against allocation attacks by keeping the max message size small. Otherwise an attacker might send multiple fake packets with 2GB headers, causing the server to run out of memory after allocating multiple large packets.")] - [FormerlySerializedAs("MaxMessageSize")] public int serverMaxMessageSize = 16 * 1024; - - [Tooltip("Server processes a limit amount of messages per tick to avoid a deadlock where it might end up processing forever if messages come in faster than we can process them.")] - public int serverMaxReceivesPerTick = 10000; - - [Header("Client")] - [Tooltip("Protect against allocation attacks by keeping the max message size small. Otherwise an attacker host might send multiple fake packets with 2GB headers, causing the connected clients to run out of memory after allocating multiple large packets.")] - [FormerlySerializedAs("MaxMessageSize")] public int clientMaxMessageSize = 16 * 1024; - - [Tooltip("Client processes a limit amount of messages per tick to avoid a deadlock where it might end up processing forever if messages come in faster than we can process them.")] - public int clientMaxReceivesPerTick = 1000; - - - protected Telepathy.Client client = new Telepathy.Client(); - protected Telepathy.Server server = new Telepathy.Server(); - - void Awake() - { - // tell Telepathy to use Unity's Debug.Log - Telepathy.Logger.Log = Debug.Log; - Telepathy.Logger.LogWarning = Debug.LogWarning; - Telepathy.Logger.LogError = Debug.LogError; - - // configure - client.NoDelay = NoDelay; - client.MaxMessageSize = clientMaxMessageSize; - server.NoDelay = NoDelay; - server.MaxMessageSize = serverMaxMessageSize; - - Debug.Log("TelepathyTransport initialized!"); - } - - public override bool Available() - { - // C#'s built in TCP sockets run everywhere except on WebGL - return Application.platform != RuntimePlatform.WebGLPlayer; - } - - // client - public override bool ClientConnected() => client.Connected; - public override void ClientConnect(string address) => client.Connect(address, port); - public override void ClientConnect(Uri uri) - { - if (uri.Scheme != Scheme) - throw new ArgumentException($"Invalid url {uri}, use {Scheme}://host:port instead", nameof(uri)); - - int serverPort = uri.IsDefaultPort ? port : uri.Port; - client.Connect(uri.Host, serverPort); - } - public override void ClientSend(int channelId, ArraySegment segment) - { - // telepathy doesn't support allocation-free sends yet. - // previously we allocated in Mirror. now we do it here. - byte[] data = new byte[segment.Count]; - Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count); - client.Send(data); - } - - bool ProcessClientMessage() - { - if (client.GetNextMessage(out Telepathy.Message message)) - { - switch (message.eventType) - { - case Telepathy.EventType.Connected: - OnClientConnected.Invoke(); - break; - case Telepathy.EventType.Data: - OnClientDataReceived.Invoke(new ArraySegment(message.data), Channels.DefaultReliable); - break; - case Telepathy.EventType.Disconnected: - OnClientDisconnected.Invoke(); - break; - default: - // TODO: Telepathy does not report errors at all - // it just disconnects, should be fixed - OnClientDisconnected.Invoke(); - break; - } - return true; - } - return false; - } - public override void ClientDisconnect() => client.Disconnect(); - - // IMPORTANT: set script execution order to >1000 to call Transport's - // LateUpdate after all others. Fixes race condition where - // e.g. in uSurvival Transport would apply Cmds before - // ShoulderRotation.LateUpdate, resulting in projectile - // spawns at the point before shoulder rotation. - public void LateUpdate() - { - // note: we need to check enabled in case we set it to false - // when LateUpdate already started. - // (https://github.com/vis2k/Mirror/pull/379) - if (!enabled) - return; - - // process a maximum amount of client messages per tick - for (int i = 0; i < clientMaxReceivesPerTick; ++i) - { - // stop when there is no more message - if (!ProcessClientMessage()) - { - break; - } - - // Some messages can disable transport - // If this is disabled stop processing message in queue - if (!enabled) - { - break; - } - } - - // process a maximum amount of server messages per tick - for (int i = 0; i < serverMaxReceivesPerTick; ++i) - { - // stop when there is no more message - if (!ProcessServerMessage()) - { - break; - } - - // Some messages can disable transport - // If this is disabled stop processing message in queue - if (!enabled) - { - break; - } - } - } - - public override Uri ServerUri() - { - UriBuilder builder = new UriBuilder(); - builder.Scheme = Scheme; - builder.Host = Dns.GetHostName(); - builder.Port = port; - return builder.Uri; - } - - // server - public override bool ServerActive() => server.Active; - public override void ServerStart() => server.Start(port); - public override void ServerSend(int connectionId, int channelId, ArraySegment segment) - { - // telepathy doesn't support allocation-free sends yet. - // previously we allocated in Mirror. now we do it here. - byte[] data = new byte[segment.Count]; - Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count); - - // send - server.Send(connectionId, data); - } - public bool ProcessServerMessage() - { - if (server.GetNextMessage(out Telepathy.Message message)) - { - switch (message.eventType) - { - case Telepathy.EventType.Connected: - OnServerConnected.Invoke(message.connectionId); - break; - case Telepathy.EventType.Data: - OnServerDataReceived.Invoke(message.connectionId, new ArraySegment(message.data), Channels.DefaultReliable); - break; - case Telepathy.EventType.Disconnected: - OnServerDisconnected.Invoke(message.connectionId); - break; - default: - // TODO handle errors from Telepathy when telepathy can report errors - OnServerDisconnected.Invoke(message.connectionId); - break; - } - return true; - } - return false; - } - public override bool ServerDisconnect(int connectionId) => server.Disconnect(connectionId); - public override string ServerGetClientAddress(int connectionId) - { - try - { - return server.GetClientAddress(connectionId); - } - catch (SocketException) - { - // using server.listener.LocalEndpoint causes an Exception - // in UWP + Unity 2019: - // Exception thrown at 0x00007FF9755DA388 in UWF.exe: - // Microsoft C++ exception: Il2CppExceptionWrapper at memory - // location 0x000000E15A0FCDD0. SocketException: An address - // incompatible with the requested protocol was used at - // System.Net.Sockets.Socket.get_LocalEndPoint () - // so let's at least catch it and recover - return "unknown"; - } - } - public override void ServerStop() => server.Stop(); - - // common - public override void Shutdown() - { - Debug.Log("TelepathyTransport Shutdown()"); - client.Disconnect(); - server.Stop(); - } - - public override int GetMaxPacketSize(int channelId) - { - return serverMaxMessageSize; - } - - public override string ToString() - { - if (server.Active && server.listener != null) - { - // printing server.listener.LocalEndpoint causes an Exception - // in UWP + Unity 2019: - // Exception thrown at 0x00007FF9755DA388 in UWF.exe: - // Microsoft C++ exception: Il2CppExceptionWrapper at memory - // location 0x000000E15A0FCDD0. SocketException: An address - // incompatible with the requested protocol was used at - // System.Net.Sockets.Socket.get_LocalEndPoint () - // so let's use the regular port instead. - return "Telepathy Server port: " + port; - } - else if (client.Connecting || client.Connected) - { - return "Telepathy Client ip: " + client.client.Client.RemoteEndPoint; - } - return "Telepathy (inactive/disconnected)"; - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs.meta b/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs.meta deleted file mode 100644 index 99cde3e..0000000 --- a/Assets/Mirror/Runtime/Transport/TelepathyTransport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c7424c1070fad4ba2a7a96b02fbeb4bb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 1000 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/Transport/Transport.cs b/Assets/Mirror/Runtime/Transport/Transport.cs deleted file mode 100644 index 86a4819..0000000 --- a/Assets/Mirror/Runtime/Transport/Transport.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Events; - -namespace Mirror -{ - // UnityEvent definitions - [Serializable] public class ClientDataReceivedEvent : UnityEvent, int> { } - [Serializable] public class UnityEventException : UnityEvent { } - [Serializable] public class UnityEventInt : UnityEvent { } - [Serializable] public class ServerDataReceivedEvent : UnityEvent, int> { } - [Serializable] public class UnityEventIntException : UnityEvent { } - - /// - /// Abstract transport layer component - /// - /// - /// note: Not all transports need a port, so add it to yours if needed. - /// - public abstract class Transport : MonoBehaviour - { - /// - /// The current transport used by Mirror. - /// - public static Transport activeTransport; - - /// - /// Is this transport available in the current platform? - /// Some transports might only be available in mobile - /// Many will not work in webgl - /// Example usage: return Application.platform == RuntimePlatform.WebGLPlayer - /// - /// True if this transport works in the current platform - public abstract bool Available(); - - #region Client - /// - /// Notify subscribers when when this client establish a successful connection to the server - /// - [HideInInspector] public UnityEvent OnClientConnected = new UnityEvent(); - - /// - /// Notify subscribers when this client receive data from the server - /// - // Note: we provide channelId for NetworkDiagnostics. - [HideInInspector] public ClientDataReceivedEvent OnClientDataReceived = new ClientDataReceivedEvent(); - - /// - /// Notify subscribers when this client encounters an error communicating with the server - /// - [HideInInspector] public UnityEventException OnClientError = new UnityEventException(); - - /// - /// Notify subscribers when this client disconnects from the server - /// - [HideInInspector] public UnityEvent OnClientDisconnected = new UnityEvent(); - - /// - /// Determines if we are currently connected to the server - /// - /// True if a connection has been established to the server - public abstract bool ClientConnected(); - - /// - /// Establish a connection to a server - /// - /// The IP address or FQDN of the server we are trying to connect to - public abstract void ClientConnect(string address); - - /// - /// Establish a connection to a server - /// - /// The address of the server we are trying to connect to - public virtual void ClientConnect(Uri uri) - { - // By default, to keep backwards compatibility, just connect to the host - // in the uri - ClientConnect(uri.Host); - } - - /// - /// Send data to the server - /// - /// The channel to use. 0 is the default channel, - /// but some transports might want to provide unreliable, encrypted, compressed, or any other feature - /// as new channels - /// The data to send to the server. Will be recycled after returning, so either use it directly or copy it internally. This allows for allocation-free sends! - public abstract void ClientSend(int channelId, ArraySegment segment); - - /// - /// Disconnect this client from the server - /// - public abstract void ClientDisconnect(); - - #endregion - - #region Server - - - /// - /// Retrieves the address of this server. - /// Useful for network discovery - /// - /// the url at which this server can be reached - public abstract Uri ServerUri(); - - /// - /// Notify subscribers when a client connects to this server - /// - [HideInInspector] public UnityEventInt OnServerConnected = new UnityEventInt(); - - /// - /// Notify subscribers when this server receives data from the client - /// - // Note: we provide channelId for NetworkDiagnostics. - [HideInInspector] public ServerDataReceivedEvent OnServerDataReceived = new ServerDataReceivedEvent(); - - /// - /// Notify subscribers when this server has some problem communicating with the client - /// - [HideInInspector] public UnityEventIntException OnServerError = new UnityEventIntException(); - - /// - /// Notify subscribers when a client disconnects from this server - /// - [HideInInspector] public UnityEventInt OnServerDisconnected = new UnityEventInt(); - - /// - /// Determines if the server is up and running - /// - /// true if the transport is ready for connections from clients - public abstract bool ServerActive(); - - /// - /// Start listening for clients - /// - public abstract void ServerStart(); - - /// - /// Send data to a client. - /// - /// The client connection id to send the data to - /// The channel to be used. Transports can use channels to implement - /// other features such as unreliable, encryption, compression, etc... - /// - public abstract void ServerSend(int connectionId, int channelId, ArraySegment segment); - - /// - /// Disconnect a client from this server. Useful to kick people out. - /// - /// the id of the client to disconnect - /// true if the client was kicked - public abstract bool ServerDisconnect(int connectionId); - - /// - /// Get the client address - /// - /// id of the client - /// address of the client - public abstract string ServerGetClientAddress(int connectionId); - - /// - /// Stop listening for clients and disconnect all existing clients - /// - public abstract void ServerStop(); - - #endregion - - /// - /// The maximum packet size for a given channel. Unreliable transports - /// usually can only deliver small packets. Reliable fragmented channels - /// can usually deliver large ones. - /// - /// GetMaxPacketSize needs to return a value at all times. Even if the - /// Transport isn't running, or isn't Available(). This is because - /// Fallback and Multiplex transports need to find the smallest possible - /// packet size at runtime. - /// - /// channel id - /// the size in bytes that can be sent via the provided channel - public abstract int GetMaxPacketSize(int channelId = Channels.DefaultReliable); - - /// - /// Shut down the transport, both as client and server - /// - public abstract void Shutdown(); - - // block Update() to force Transports to use LateUpdate to avoid race - // conditions. messages should be processed after all the game state - // was processed in Update. - // -> in other words: use LateUpdate! - // -> uMMORPG 480 CCU stress test: when bot machine stops, it causes - // 'Observer not ready for ...' log messages when using Update - // -> occupying a public Update() function will cause Warnings if a - // transport uses Update. - // - // IMPORTANT: set script execution order to >1000 to call Transport's - // LateUpdate after all others. Fixes race condition where - // e.g. in uSurvival Transport would apply Cmds before - // ShoulderRotation.LateUpdate, resulting in projectile - // spawns at the point before shoulder rotation. -#pragma warning disable UNT0001 // Empty Unity message - public void Update() { } -#pragma warning restore UNT0001 // Empty Unity message - - /// - /// called when quitting the application by closing the window / pressing stop in the editor - /// virtual so that inheriting classes' OnApplicationQuit() can call base.OnApplicationQuit() too - /// - public virtual void OnApplicationQuit() - { - // stop transport (e.g. to shut down threads) - // (when pressing Stop in the Editor, Unity keeps threads alive - // until we press Start again. so if Transports use threads, we - // really want them to end now and not after next start) - Shutdown(); - } - } -} diff --git a/Assets/Mirror/Runtime/Transport/Transport.cs.meta b/Assets/Mirror/Runtime/Transport/Transport.cs.meta deleted file mode 100644 index 2d451cf..0000000 --- a/Assets/Mirror/Runtime/Transport/Transport.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cfffcac25d6d64ced9de620159e221b8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Runtime/UNetwork.cs b/Assets/Mirror/Runtime/UNetwork.cs deleted file mode 100644 index 282f32c..0000000 --- a/Assets/Mirror/Runtime/UNetwork.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using UnityEngine; - -namespace Mirror -{ - // Handles network messages on client and server - public delegate void NetworkMessageDelegate(NetworkConnection conn, NetworkReader reader, int channelId); - - // Handles requests to spawn objects on the client - public delegate GameObject SpawnDelegate(Vector3 position, Guid assetId); - - public delegate GameObject SpawnHandlerDelegate(SpawnMessage msg); - - // Handles requests to unspawn objects on the client - public delegate void UnSpawnDelegate(GameObject spawned); - - // invoke type for Cmd/Rpc - public enum MirrorInvokeType - { - Command, - ClientRpc - } - - public enum Version - { - Current = 1 - } - - public static class Channels - { - public const int DefaultReliable = 0; - public const int DefaultUnreliable = 1; - } - - // -- helpers for float conversion without allocations -- - [StructLayout(LayoutKind.Explicit)] - internal struct UIntFloat - { - [FieldOffset(0)] - public float floatValue; - - [FieldOffset(0)] - public uint intValue; - } - - [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/Assets/Mirror/Runtime/UNetwork.cs.meta b/Assets/Mirror/Runtime/UNetwork.cs.meta deleted file mode 100644 index 0ee79ed..0000000 --- a/Assets/Mirror/Runtime/UNetwork.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b530ce39098b54374a29ad308c8e4554 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirror/Version.txt b/Assets/Mirror/Version.txt deleted file mode 100644 index 40fab6c..0000000 --- a/Assets/Mirror/Version.txt +++ /dev/null @@ -1 +0,0 @@ -26.2.2 \ No newline at end of file diff --git a/Assets/Mirror/Version.txt.meta b/Assets/Mirror/Version.txt.meta deleted file mode 100644 index 097f259..0000000 --- a/Assets/Mirror/Version.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c6b1f72568a9340178b4c34608fbdbc3 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/menu.unity b/Assets/Scenes/menu.unity index cd8b3ef..00e2318 100644 --- a/Assets/Scenes/menu.unity +++ b/Assets/Scenes/menu.unity @@ -2446,111 +2446,6 @@ MonoBehaviour: m_EditorClassIdentifier: Leaderboard: {fileID: 741433536} LeaderboardMenuButton: {fileID: 1608626357} ---- !u!1 &1193692630 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1193692633} - - component: {fileID: 1193692632} - - component: {fileID: 1193692631} - m_Layer: 0 - m_Name: Network Manager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1193692631 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1193692630} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} - m_Name: - m_EditorClassIdentifier: - OnClientConnected: - m_PersistentCalls: - m_Calls: [] - OnClientDataReceived: - m_PersistentCalls: - m_Calls: [] - OnClientError: - m_PersistentCalls: - m_Calls: [] - OnClientDisconnected: - m_PersistentCalls: - m_Calls: [] - OnServerConnected: - m_PersistentCalls: - m_Calls: [] - OnServerDataReceived: - m_PersistentCalls: - m_Calls: [] - OnServerError: - m_PersistentCalls: - m_Calls: [] - OnServerDisconnected: - m_PersistentCalls: - m_Calls: [] - Port: 7777 - NoDelay: 1 - Interval: 10 - FastResend: 0 - CongestionWindow: 1 - SendWindowSize: 128 - ReceiveWindowSize: 128 - debugGUI: 0 ---- !u!114 &1193692632 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1193692630} - 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 - offlineScene: - onlineScene: - transport: {fileID: 1193692631} - networkAddress: localhost - maxConnections: 4 - disconnectInactiveConnections: 0 - disconnectInactiveTimeout: 60 - authenticator: {fileID: 0} - playerPrefab: {fileID: 0} - autoCreatePlayer: 1 - playerSpawnMethod: 0 - spawnPrefabs: [] ---- !u!4 &1193692633 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1193692630} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 583.6838, y: 290.13907, z: -37.34695} - 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 &1508130826 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/monopoly/AI.cs b/Assets/Scripts/monopoly/AI.cs index 774f840..f0e4936 100644 --- a/Assets/Scripts/monopoly/AI.cs +++ b/Assets/Scripts/monopoly/AI.cs @@ -10,4 +10,33 @@ public class AI * Trade * Etc... */ + + System.Random random = new System.Random(); //Random Function. + + //Dice Rolling Mechanism + public int dice1; //First dice. + public int dice2; //Second dice. + private int roll; //Total of both dice. + + public AI() + { + + } + + public int NextTask() + { + /* TASK DESCRIPTIONS: + * 0 - Move + */ + return 0; + } + + public void RollDice() + { + dice1 = random.Next(1, 7); + dice2 = random.Next(1, 7); + + roll = dice1 + dice2; + } + } diff --git a/Assets/Scripts/monopoly/Main.cs b/Assets/Scripts/monopoly/Main.cs index 1462263..00f28df 100644 --- a/Assets/Scripts/monopoly/Main.cs +++ b/Assets/Scripts/monopoly/Main.cs @@ -138,24 +138,33 @@ public class Property public class Board //Creating the class for the board mechanics. { + //Property Variables public int houses; //Initialising houses public int hotels; //Initialising hotels public int totalProperties; //Defining how many properties can exist. - private TextHandler textHandler; - private ButtonHandler buttonHandler; - public List players; - public int currentPlayer = 0; public List existingProperties; public List avaliableProperties = new List(); //Has a list of all the available properties. + + //Player Variables + public int currentPlayer = 0; + public List players; + + //Card Variables public List chance = new List(); private int chancePointer; public List communityChest = new List(); private int communityPointer; + private bool onCard; //This becomes true when the player was on the card previously which increases finance. + + //Handlers + private TextHandler textHandler; + private ButtonHandler buttonHandler; public Board(List players, List properties, List existingCards) { this.players = players; //Imports all of the players playing Debug.Log(this.players.Count); //Prints how many players are playing + onCard = false; //This is the default (the player can never start on a card) textHandler = GameObject.FindObjectOfType(); //Finds the text handler script buttonHandler = GameObject.FindObjectOfType(); //Finds the button handler script existingProperties = properties; //This sets all of the properties that exist @@ -255,6 +264,11 @@ public class Board //Creating the class for the board mechanics. break; } + if (onCard) //If the player was previously on a card... + { + payment *= 2; //Make the player pay 2x the owed fee. + } + break; case "utilities": //If it is a utility. @@ -268,6 +282,11 @@ public class Board //Creating the class for the board mechanics. break; } + if (onCard) + { + payment = players[currentPlayer].diceRoll * 10; + } + break; default: //Else, if it's a normal property. @@ -320,7 +339,15 @@ public class Board //Creating the class for the board mechanics. currentPlayer++; //Increments the queue to the next player } textHandler.UpdateMoney(players[currentPlayer].money); //Changes the amount of money the new player has. - buttonHandler.EnableRollDice(); //Re-enables the user to roll the dice. + + if (players[currentPlayer].isAI) + { + players[currentPlayer].AI.NextTask(); + } + else + { + buttonHandler.EnableRollDice(); //Re-enables the user to roll the dice. + } } public bool CheckProperty(int position) //This checks if the property can be bought by the user. @@ -516,7 +543,8 @@ public class Board //Creating the class for the board mechanics. int hotels; //This is initialised to calculate the total cost of each hotel. int extra; //This is used for converting extra to an int. int payment; //This is used to calculate the total payment required. - + + int playerPosition; switch (card.card_function) //This performs the function of the card. { case 1: @@ -536,11 +564,10 @@ public class Board //Creating the class for the board mechanics. break; case 4: //4 - advance to the nearest station - requires calculation pay the owner 2x the rent - //TODO - + //Finds the player's current position. - int playerPosition = players[currentPlayer].position; + playerPosition = players[currentPlayer].position; /* Station Positions: * @@ -550,7 +577,7 @@ public class Board //Creating the class for the board mechanics. * Liverpool St. Station - 35 */ - int station; + int station; //This is the station that the player will travel to. if (playerPosition < 5) //If it is before Kings Cross. { @@ -573,11 +600,41 @@ public class Board //Creating the class for the board mechanics. station = 5; //Go to Kings Cross. } - players[currentPlayer].CardMove(4, station); + onCard = true; //This then sets the future financing options for the player. + + players[currentPlayer].CardMove(4, station); //This moves the player to the closest station. break; case 5: //5 - advance to the nearest utility - make player roll dice, then pay owner 10x entitled pay. //TODO + //Finds the player's current position. + + playerPosition = players[currentPlayer].position; + + /* Utility Positions: + * + * Electric Company - 12 + * Marylebone Station - 28 + */ + + int utility; //This is the utility the player will have to travel to. + + if (playerPosition < 12) //If it is before Electric Company. + { + utility = 12; //Go to Electric Company. + } + else if (playerPosition < 28) //If it is before Water Works. + { + utility = 28; //Go to Water Works. + } + else //If it is past Water Works. + { + utility = 12; //Go to Electric Company. + } + + onCard = true; //This then sets the future financing options for the player. + + players[currentPlayer].CardMove(4, utility); //This moves the player to the closest station. break; case 6: //6 - pay each player a sum of money | extra - money x @@ -667,34 +724,65 @@ public class Board //Creating the class for the board mechanics. public class Player { - public string name; //This is the username of the player - private bool isAI; //This defines if the player is an AI. false = not an AI. true = is an AI. - private int playerNumber; //This is the player number in the queue + //Player Info + public string name; //This is the username of the player. + private int playerNumber; //This is the player number in the queue. + + //Player Variables public int money; //Initializes the variable for money. public int position; //Positions vary from 0-39 (40 squares on the board) (Go is 0) public bool inJail; //This enables specific in jail functions public int getOutOfJailCards; //This counts the amount of get out of jail cards the user has. public int diceRoll; public List ownedProperties; //This is the list of properties that the player owns. + + //AI + public bool isAI; //This defines if the player is an AI. false = not an AI. true = is an AI. + public AI AI; //This initialises the AI class. + + //Other public GameObject player; private Movement movement; private TextHandler textHandler; public Player(string playerName, bool isAI, int playerNumber, GameObject player) { + //Player Info name = playerName; //This initialises the username of the player + this.playerNumber = playerNumber; //This is the position in the queue that the player is in + + //AI this.isAI = isAI; + if (this.isAI) + { + AI = new AI(); + } + + //Player Variables position = 0; //This sets to the default position - GO inJail = false; //This initialises that the player isn't in jail getOutOfJailCards = 0; //This initialises the player to have 0 get out of jail free cards. - this.playerNumber = playerNumber; //This is the position in the queue that the player is in money = 1500; //Set the default starting money. - this.player = player; //This links the object that the player is linked to in the game ownedProperties = new List(); + + //Other + this.player = player; //This links the object that the player is linked to in the game movement = GameObject.FindObjectOfType(); //This finds the movement script in the game textHandler = GameObject.FindObjectOfType(); //Finds the text handler script } + public void AINextTask() + { + switch (AI.NextTask()) + { + case 0: + int dice1 = AI.dice1; + int dice2 = AI.dice2; + Move(dice1, dice2); + break; + } + } + public void Move(int roll1, int roll2) //This moves the player a certain length (what they got from rolling the dice). { @@ -916,7 +1004,7 @@ public class Main : MonoBehaviour //Names the game object player and a unique number Instantiate(playerTemplate, playerTemplate.transform.position, Quaternion.identity, playerParentGameObject.transform).name = $"Player{i}"; playersGameObjects.Add(GameObject.Find($"/Players/Player{i}")); //Adds to a list of GameObjects by searching for the GameObject. - players.Add(new Player($"Player {i}", false, i, playersGameObjects[i])); //Creates a unique player class for that specific GameObject + players.Add(new Player($"Player {i}", true, i, playersGameObjects[i])); //Creates a unique player class for that specific GameObject } Destroy(playerTemplate); //Deletes the player template GameObject. diff --git a/Assets/Scripts/monopoly/Movement.cs b/Assets/Scripts/monopoly/Movement.cs index ad1f909..d52bb74 100644 --- a/Assets/Scripts/monopoly/Movement.cs +++ b/Assets/Scripts/monopoly/Movement.cs @@ -46,7 +46,6 @@ public class Movement : MonoBehaviour if (!forward) { - Debug.Log("yes"); if ((Vector3.Distance(waypoints[position].transform.position, players[currentPlayer].transform.position) < WPradius) && position != roll) { position--; diff --git a/Assets/Scripts/monopoly/RollDice.cs b/Assets/Scripts/monopoly/RollDice.cs index a7f0848..758f567 100644 --- a/Assets/Scripts/monopoly/RollDice.cs +++ b/Assets/Scripts/monopoly/RollDice.cs @@ -50,6 +50,6 @@ public class RollDice : MonoBehaviour } - main.board.MovePlayer(1, 1); + main.board.MovePlayer(dice1, dice2); } } \ No newline at end of file