Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Question ServerRpc doesn't get called on a script added during runtime

Discussion in 'Unity Transport' started by LazyProgerReal, Aug 30, 2023.

  1. LazyProgerReal

    LazyProgerReal

    Joined:
    Sep 20, 2021
    Posts:
    9
    I have this very basic code that should print a message on the server

    Code (CSharp):
    1. private void Update()
    2. {
    3.     if (Input.GetKeyDown(KeyCode.Space))
    4.     {
    5.         TestServerRpc();
    6.     }
    7. }
    8.  
    9. [ServerRpc]
    10. private void TestServerRpc()
    11. {
    12.     print("SERVER RPC GOT CALLED");
    13. }

    Normally the host would be able to call it no problem and the client would be able to call it only on the host. But this script gets added during runtime (only to the objects that are owner). and as a result when the host calls it nothing happens and when the client calls I get this error "only the owner can invoke a serverrpc that requires ownership"
    Now I have tried adding this in the editor instead of during runtime it works fine but for my purposes this script needs to be added during runtime.

    Before you ask I have also tried setting RequireOwnership to false no luck there either. The error disappears when I set it to false but then the host receives a warning instead of the actual message getting printed:
    "[Netcode] Deferred messages were received for a trigger of type OnSpawn with key 0, but that trigger was not received within within 1 second(s)."

    Any help would be much appreciated
     
  2. jackward84

    jackward84

    Joined:
    Jan 26, 2017
    Posts:
    87
    You'd have to post code of how you're spawning the object.

    By having TestServerRpc() be called without a check whether you're the owner of the object or not means any client (including host) that pushes the spacebar should either get the result: "SERVER RPC GOT CALLED" or an error about server RPC not being valid for non owners.

    The fact that nothing happens at all when you press space on the host tells me you probably aren't spawning this object over the network at all - you're probably instantiating it directly on a client? This is most likely what the OnSpawn messages are about - the host is unaware of what network object your ServerRPC is trying to communicate with.

    Bottom line: the host should spawn it and call
    NetworkObject.Spawn()
    on the object to have it spawned over the network. More specifically, the host should also specify the owner of the object, with
    NetworkObject.SpawnWithOwnership(clientId)
    or
    NetworkObject.SpawnAsPlayerObject(clientId)


    PS: If you ever find your solution is to set RequireOwnership to false, and you don't understand all the consequences of what that would do, don't do it.
     
    Last edited: Aug 31, 2023
  3. LazyProgerReal

    LazyProgerReal

    Joined:
    Sep 20, 2021
    Posts:
    9
    @jackward84 I didn't check if it's owner because this script already sits on the owner. There's another script that checks if this object is owner and only then adds the combat script. Here let me show you:

    Code (CSharp):
    1. // this is called inside the OnNetworkSpawn
    2. // the script that executes this sits on the player prefab
    3.  
    4. if (IsOwner)
    5. {
    6.     var playerInput = gameObject.AddComponent<PlayerInput>();
    7.     playerInput.actions = actionAsset;
    8.     gameObject.AddComponent<CombatController>(); // the script that calls the rpc
    9.     playerInput.actions.Enable();
    10. }
     
  4. LazyProgerReal

    LazyProgerReal

    Joined:
    Sep 20, 2021
    Posts:
    9
    Okay I also tried removing the component where it's not needed instead of adding it. Basically the reverse of what I was doing previously and now unity throws an error about not finding a client id. Let me describe what it is I wanna do. I have a player controller and I don't want to deal with !isOwner checks all the time so I added the NetworkBehaviour during runtime only to the owner. Is that not possible because unity freaks out in so many different ways. And also another question I found says that it is not possible and every client should have instance of the script:
    https://forum.unity.com/threads/net...ent-to-a-network-object.1429699/#post-8975812
     
  5. jackward84

    jackward84

    Joined:
    Jan 26, 2017
    Posts:
    87
    If you spawn a network object for everyone and then individual clients disable or destroy it, you'll get warnings/errors since that is not how you're supposed to operate with NetworkObjects.

    You'll be fighting a bit of a losing battle trying to avoid IsOwner checks entirely since at the very least the host/server needs to spawn the networkobject too, and you don't want the host to execute the other clients' ServerRPCs when they push the spacebar, so the host needs to check whether or not it's the owner of the CombatController.

    You can definitely add networkobjects during runtime and if you wanted you could control who can "see" the networkobject using object visibility.

    There's a good chance you'll find if your class grows much that it is useful for more than just the host and client to be aware of your CombatController, especially if you put any clientrpcs or networkvariables in there that more than just the host and owner client need to be aware of. To me I'd say premature (and possibly unwarranted) optimisation is making you run into more advanced issues you're not ready to deal with yet.
     
  6. LazyProgerReal

    LazyProgerReal

    Joined:
    Sep 20, 2021
    Posts:
    9
    Thanks for helping @jackward84 I solved it by not instantiating the class during runtime and just having it on the prefab. Well that means now I have to do isOwner checks but at least it works now and that's what's important