public void RegisterDelegateDoesntOverwrite() { // registerdelegate is protected, but we can use // RegisterCommandDelegate which calls RegisterDelegate int registeredHash1 = RemoteCallHelper.RegisterDelegate( typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate), MirrorInvokeType.Command, NetworkBehaviourDelegateComponent.Delegate, false); // registering the exact same one should be fine. it should simply // do nothing. int registeredHash2 = RemoteCallHelper.RegisterDelegate( typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate), MirrorInvokeType.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 = RemoteCallHelper.RegisterDelegate( typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate), MirrorInvokeType.Command, NetworkBehaviourDelegateComponent.Delegate2, false); // clean up RemoteCallHelper.RemoveDelegate(registeredHash1); RemoteCallHelper.RemoveDelegate(registeredHash2); RemoteCallHelper.RemoveDelegate(registeredHash3); }
public void GetDelegate() { // registerdelegate is protected, but we can use // RegisterCommandDelegate which calls RegisterDelegate int registeredHash = RemoteCallHelper.RegisterDelegate( typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate), MirrorInvokeType.Command, NetworkBehaviourDelegateComponent.Delegate, false); // get handler int cmdHash = RemoteCallHelper.GetMethodHash(typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate)); CmdDelegate func = RemoteCallHelper.GetDelegate(cmdHash); CmdDelegate expected = NetworkBehaviourDelegateComponent.Delegate; Assert.That(func, Is.EqualTo(expected)); // invalid hash should return null handler CmdDelegate funcNull = RemoteCallHelper.GetDelegate(1234); Assert.That(funcNull, Is.Null); // clean up RemoteCallHelper.RemoveDelegate(registeredHash); }
public void HandleRpc() { CreateNetworked(out GameObject _, out NetworkIdentity identity, out RpcTestNetworkBehaviour comp0); // register the command delegate, otherwise it's not found int registeredHash = RemoteCallHelper.RegisterDelegate(typeof(RpcTestNetworkBehaviour), nameof(RpcTestNetworkBehaviour.RpcGenerated), MirrorInvokeType.ClientRpc, RpcTestNetworkBehaviour.RpcGenerated); // identity needs to be in spawned dict, otherwise command handler // won't find it NetworkIdentity.spawned[identity.netId] = identity; // call HandleRpc and check if the rpc was called in the component int functionHash = RemoteCallHelper.GetMethodHash(typeof(RpcTestNetworkBehaviour), nameof(RpcTestNetworkBehaviour.RpcGenerated)); NetworkReader payload = new NetworkReader(new byte[0]); identity.HandleRemoteCall(0, functionHash, MirrorInvokeType.ClientRpc, payload); Assert.That(comp0.called, Is.EqualTo(1)); // try wrong component index. rpc shouldn't be called again. // warning is expected LogAssert.ignoreFailingMessages = true; identity.HandleRemoteCall(1, functionHash, MirrorInvokeType.ClientRpc, payload); LogAssert.ignoreFailingMessages = false; Assert.That(comp0.called, Is.EqualTo(1)); // try wrong function hash. rpc shouldn't be called again. // warning is expected LogAssert.ignoreFailingMessages = true; identity.HandleRemoteCall(0, functionHash + 1, MirrorInvokeType.ClientRpc, payload); LogAssert.ignoreFailingMessages = false; Assert.That(comp0.called, Is.EqualTo(1)); // clean up RemoteCallHelper.RemoveDelegate(registeredHash); }
public void CommandMessageCallsCommandTest() { // listen NetworkServer.Listen(1); Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add connection LocalConnectionToClient connection = new LocalConnectionToClient(); connection.connectionToServer = new LocalConnectionToServer(); NetworkServer.AddConnection(connection); // set as authenticated, otherwise removeplayer is rejected connection.isAuthenticated = true; // add an identity with two networkbehaviour components GameObject go = new GameObject(); NetworkIdentity identity = go.AddComponent <NetworkIdentity>(); identity.netId = 42; // for authority check identity.connectionToClient = connection; CommandTestNetworkBehaviour comp0 = go.AddComponent <CommandTestNetworkBehaviour>(); Assert.That(comp0.called, Is.EqualTo(0)); CommandTestNetworkBehaviour comp1 = go.AddComponent <CommandTestNetworkBehaviour>(); Assert.That(comp1.called, Is.EqualTo(0)); connection.identity = identity; // register the command delegate, otherwise it's not found int registeredHash = RemoteCallHelper.RegisterDelegate(typeof(CommandTestNetworkBehaviour), nameof(CommandTestNetworkBehaviour.CommandGenerated), MirrorInvokeType.Command, CommandTestNetworkBehaviour.CommandGenerated, true); // identity needs to be in spawned dict, otherwise command handler // won't find it NetworkIdentity.spawned[identity.netId] = identity; // serialize a removeplayer message into an arraysegment CommandMessage message = new CommandMessage { componentIndex = 0, functionHash = RemoteCallHelper.GetMethodHash(typeof(CommandTestNetworkBehaviour), nameof(CommandTestNetworkBehaviour.CommandGenerated)), netId = identity.netId, payload = new ArraySegment <byte>(new byte[0]) }; NetworkWriter writer = new NetworkWriter(); MessagePacking.Pack(message, writer); ArraySegment <byte> segment = writer.ToArraySegment(); // call transport.OnDataReceived with the message // -> calls NetworkServer.OnRemovePlayerMessage // -> destroys conn.identity and sets it to null Transport.activeTransport.OnServerDataReceived.Invoke(0, segment, 0); // was the command called in the first component, not in the second one? Assert.That(comp0.called, Is.EqualTo(1)); Assert.That(comp1.called, Is.EqualTo(0)); // send another command for the second component comp0.called = 0; message.componentIndex = 1; writer = new NetworkWriter(); MessagePacking.Pack(message, writer); segment = writer.ToArraySegment(); Transport.activeTransport.OnServerDataReceived.Invoke(0, segment, 0); // was the command called in the second component, not in the first one? Assert.That(comp0.called, Is.EqualTo(0)); Assert.That(comp1.called, Is.EqualTo(1)); // sending a command without authority should fail // (= if connectionToClient is not what we received the data on) // set wrong authority identity.connectionToClient = new LocalConnectionToClient(); comp0.called = 0; comp1.called = 0; Transport.activeTransport.OnServerDataReceived.Invoke(0, segment, 0); Assert.That(comp0.called, Is.EqualTo(0)); Assert.That(comp1.called, Is.EqualTo(0)); // restore authority identity.connectionToClient = connection; // sending a component with wrong netId should fail // wrong netid message.netId += 1; writer = new NetworkWriter(); // need to serialize the message again with wrong netid MessagePacking.Pack(message, writer); ArraySegment <byte> segmentWrongNetId = writer.ToArraySegment(); comp0.called = 0; comp1.called = 0; Transport.activeTransport.OnServerDataReceived.Invoke(0, segmentWrongNetId, 0); Assert.That(comp0.called, Is.EqualTo(0)); Assert.That(comp1.called, Is.EqualTo(0)); // clean up NetworkIdentity.spawned.Clear(); RemoteCallHelper.RemoveDelegate(registeredHash); NetworkServer.Shutdown(); // destroy the test gameobject AFTER server was stopped. // otherwise isServer is true in OnDestroy, which means it would try // to call Destroy(go). but we need to use DestroyImmediate in // Editor GameObject.DestroyImmediate(go); }