public void GetDelegate() { // registerdelegate is protected, but we can use // RegisterCommandDelegate which calls RegisterDelegate NetworkBehaviour.RegisterCommandDelegate( typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate), NetworkBehaviourDelegateComponent.Delegate); // get handler int cmdHash = NetworkBehaviour.GetMethodHash(typeof(NetworkBehaviourDelegateComponent), nameof(NetworkBehaviourDelegateComponent.Delegate)); NetworkBehaviour.CmdDelegate func = NetworkBehaviour.GetDelegate(cmdHash); NetworkBehaviour.CmdDelegate expected = NetworkBehaviourDelegateComponent.Delegate; Assert.That(func, Is.EqualTo(expected)); // invalid hash should return null handler NetworkBehaviour.CmdDelegate funcNull = NetworkBehaviour.GetDelegate(1234); Assert.That(funcNull, Is.Null); // clean up NetworkBehaviour.ClearDelegates(); }
private static bool Prefix(NetworkBehaviour __instance, NetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId) { if (!NetworkServer.active) { Debug.LogError("TargetRPC Function " + rpcName + " called on client."); return(false); } if (conn == null) { conn = __instance.connectionToClient; if (conn == null) { return(false); } } if (conn is ULocalConnectionToServer) { Debug.LogError("TargetRPC Function " + rpcName + " called on connection to server"); return(false); } if (!__instance.isServer) { Debug.LogWarning("TargetRpc " + rpcName + " called on un-spawned object: " + __instance.name); return(false); } RpcMessage msg = new RpcMessage { netId = __instance.netId, componentIndex = __instance.ComponentIndex, functionHash = NetworkBehaviour.GetMethodHash(invokeClass, rpcName), payload = writer.ToArraySegment() }; conn.Send <RpcMessage>(msg, channelId); return(false); }
public void CommandMessageCallsCommandTest() { // listen NetworkServer.Listen(1); Assert.That(NetworkServer.connections.Count, Is.EqualTo(0)); // add connection ULocalConnectionToClient connection = new ULocalConnectionToClient(); connection.connectionToServer = new ULocalConnectionToServer(); 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 NetworkBehaviour.RegisterCommandDelegate(typeof(CommandTestNetworkBehaviour), nameof(CommandTestNetworkBehaviour.CommandGenerated), CommandTestNetworkBehaviour.CommandGenerated); // 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 = NetworkBehaviour.GetMethodHash(typeof(CommandTestNetworkBehaviour), nameof(CommandTestNetworkBehaviour.CommandGenerated)), netId = identity.netId, payload = new ArraySegment <byte>(new byte[0]) }; NetworkWriter writer = new NetworkWriter(); MessagePacker.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(); MessagePacker.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 ULocalConnectionToClient(); 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 MessagePacker.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 NetworkBehaviour.ClearDelegates(); NetworkIdentity.spawned.Clear(); NetworkBehaviour.ClearDelegates(); 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); }