Exemplo n.º 1
0
        // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
        protected void SendRPCInternal(string functionFullName, NetworkWriter writer, int channelId, bool includeOwner)
        {
            // this was in Weaver before
            if (!NetworkServer.active)
            {
                Debug.LogError($"RPC Function {functionFullName} called on Client.");
                return;
            }

            // This cannot use NetworkServer.active, as that is not specific to this object.
            if (!isServer)
            {
                Debug.LogWarning($"ClientRpc {functionFullName} called on un-spawned object: {name}");
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = (byte)ComponentIndex,
                functionIndex  = RemoteProcedureCalls.GetIndexFromFunctionHash(functionFullName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            NetworkServer.SendToReadyObservers(netIdentity, message, includeOwner, channelId);
        }
Exemplo n.º 2
0
        // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
        protected void SendCommandInternal(string functionFullName, NetworkWriter writer, int channelId, bool requiresAuthority = true)
        {
            // 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)
            {
                Debug.LogError($"Command Function {functionFullName} called without an active client.");
                return;
            }

            // previously we used NetworkClient.readyConnection.
            // now we check .ready separately.
            if (!NetworkClient.ready)
            {
                // Unreliable Cmds from NetworkTransform may be generated,
                // or client may have been set NotReady intentionally, so
                // only warn if on the reliable channel.
                if (channelId == Channels.Reliable)
                {
                    Debug.LogWarning("Send command attempted while NetworkClient is not ready.\nThis may be ignored if client intentionally set NotReady.");
                }
                return;
            }

            // local players can always send commands, regardless of authority, other objects must have authority.
            if (!(!requiresAuthority || isLocalPlayer || hasAuthority))
            {
                Debug.LogWarning($"Trying to send command for object without authority. {functionFullName}");
                return;
            }

            // IMPORTANT: can't use .connectionToServer here because calling
            // a command on other objects is allowed if requireAuthority is
            // false. other objects don't have a .connectionToServer.
            // => so we always need to use NetworkClient.connection instead.
            // => see also: https://github.com/vis2k/Mirror/issues/2629
            if (NetworkClient.connection == null)
            {
                Debug.LogError("Send command attempted with no client running.");
                return;
            }

            // construct the message
            CommandMessage message = new CommandMessage
            {
                netId          = netId,
                componentIndex = (byte)ComponentIndex,
                functionIndex  = RemoteProcedureCalls.GetIndexFromFunctionHash(functionFullName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            // IMPORTANT: can't use .connectionToServer here because calling
            // a command on other objects is allowed if requireAuthority is
            // false. other objects don't have a .connectionToServer.
            // => so we always need to use NetworkClient.connection instead.
            // => see also: https://github.com/vis2k/Mirror/issues/2629
            NetworkClient.connection.Send(message, channelId);
        }
Exemplo n.º 3
0
        public void GetDelegate()
        {
            // registerdelegate is protected, but we can use
            // RegisterCommandDelegate which calls RegisterDelegate
            int registeredHash = RemoteProcedureCalls.RegisterDelegate(
                typeof(NetworkBehaviourDelegateComponent),
                nameof(NetworkBehaviourDelegateComponent.Delegate),
                RemoteCallType.Command,
                NetworkBehaviourDelegateComponent.Delegate,
                false);

            // get handler
            int cmdHash                 = nameof(NetworkBehaviourDelegateComponent.Delegate).GetStableHashCode();
            RemoteCallDelegate func     = RemoteProcedureCalls.GetDelegate(cmdHash);
            RemoteCallDelegate expected = NetworkBehaviourDelegateComponent.Delegate;

            Assert.That(func, Is.EqualTo(expected));

            // invalid hash should return null handler
            RemoteCallDelegate funcNull = RemoteProcedureCalls.GetDelegate(1234);

            Assert.That(funcNull, Is.Null);

            // clean up
            RemoteProcedureCalls.RemoveDelegate(registeredHash);
        }
Exemplo n.º 4
0
        public void RegisterDelegateDoesntOverwrite()
        {
            // registerdelegate is protected, but we can use
            // RegisterCommandDelegate which calls RegisterDelegate
            int registeredHash1 = RemoteProcedureCalls.RegisterDelegate(
                typeof(NetworkBehaviourDelegateComponent),
                nameof(NetworkBehaviourDelegateComponent.Delegate),
                RemoteCallType.Command,
                NetworkBehaviourDelegateComponent.Delegate,
                false);

            // registering the exact same one should be fine. it should simply
            // do nothing.
            int registeredHash2 = RemoteProcedureCalls.RegisterDelegate(
                typeof(NetworkBehaviourDelegateComponent),
                nameof(NetworkBehaviourDelegateComponent.Delegate),
                RemoteCallType.Command,
                NetworkBehaviourDelegateComponent.Delegate,
                false);

            // registering the same name with a different callback shouldn't
            // work
            LogAssert.Expect(LogType.Error, $"Function {typeof(NetworkBehaviourDelegateComponent)}.{nameof(NetworkBehaviourDelegateComponent.Delegate)} and {typeof(NetworkBehaviourDelegateComponent)}.{nameof(NetworkBehaviourDelegateComponent.Delegate2)} have the same hash.  Please rename one of them");
            int registeredHash3 = RemoteProcedureCalls.RegisterDelegate(
                typeof(NetworkBehaviourDelegateComponent),
                nameof(NetworkBehaviourDelegateComponent.Delegate),
                RemoteCallType.Command,
                NetworkBehaviourDelegateComponent.Delegate2,
                false);

            // clean up
            RemoteProcedureCalls.RemoveDelegate(registeredHash1);
            RemoteProcedureCalls.RemoveDelegate(registeredHash2);
            RemoteProcedureCalls.RemoveDelegate(registeredHash3);
        }
Exemplo n.º 5
0
        public virtual void TearDown()
        {
            NetworkClient.Shutdown();
            NetworkServer.Shutdown();

            // some tests might modify NetworkServer.connections without ever
            // starting the server.
            // NetworkServer.Shutdown() only clears connections if it was started.
            // so let's do it manually for proper test cleanup here.
            NetworkServer.connections.Clear();

            foreach (GameObject go in instantiated)
            {
                if (go != null)
                {
                    GameObject.DestroyImmediate(go);
                }
            }

            GameObject.DestroyImmediate(transport.gameObject);
            Transport.activeTransport = null;
            NetworkManager.singleton  = null;

            // clear rpc lookup caches.
            // this can cause problems in tests otherwise.
            RemoteProcedureCalls.ResetStatics();
        }
Exemplo n.º 6
0
        // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
        protected void SendTargetRPCInternal(NetworkConnection conn, string functionFullName, NetworkWriter writer, int channelId)
        {
            if (!NetworkServer.active)
            {
                Debug.LogError($"TargetRPC {functionFullName} called when server not active");
                return;
            }

            if (!isServer)
            {
                Debug.LogWarning($"TargetRpc {functionFullName} 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)
            {
                Debug.LogError($"TargetRPC {functionFullName} was given a null connection, make sure the object has an owner or you pass in the target connection");
                return;
            }

            if (!(conn is NetworkConnectionToClient))
            {
                Debug.LogError($"TargetRPC {functionFullName} requires a NetworkConnectionToClient but was given {conn.GetType().Name}");
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = (byte)ComponentIndex,
                functionIndex  = RemoteProcedureCalls.GetIndexFromFunctionHash(functionFullName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            conn.Send(message, channelId);
        }