#ServerRpc is not triggering by any client, why?

54 messages · Page 1 of 1 (latest)

rocky solstice
#

What I'm trying to do: Drag an object and sync.

  1. Player press E, sends a RequestOwnership function and it is [ServerRpc(RequireOwnership = false)]
  2. Server side should trigger the RequestOwnership function and then do the nob.GiveOwnership(newOwner);
  3. All players should get public override void OnOwnershipClient(NetworkConnection newOwner) called.

Player that is also a server works fine. All other non-server clients do not work.

I've attached a unitypackage of all objects in scene and scripts (excluding the FishNet Pro).
Basically import the given unitypackage, start a new scene, delete the default camera and light, drag the "FishNet Ownership Test Scene" prefab into the scene, make build, etc. run it.

What am I doing wrong here? Why is the SimpleDragObject.cs > RequestOwnership not triggering on server side called from a client?
Using the following:
FishNet Pro 2.4.5hf0
Unity 2020.3.26f1
Half cup of coffee...

subtle trail
#

Maybe the Clients are not added to the default scene, so they are not Observers? You can run a client as editor and check the object's status easily in the inspector /w debug mode

rocky solstice
#

Checking...

#

I'm not sure I understand. I know about debug mode in the inspector. Check the object's status -- the draggable object or the player or ? And which script to check?

#

This one, maybe?

#

Both player A and B have the same nob debug settings.

#

OH I see NetworkObserver script.
Both player A and B have the same settings.

#

I've included everything so that you can run it on your end and see what I did wrong.... I'm really hoping to solve this as it is an important feature for my game - Player A to be able to pick up object and then player B pick up object from A.

subtle trail
#

As the client that can not set the RPC, you should get error when you try to make the call and you can check if the Object you're trying to call this RPC on is active for him

rocky solstice
#

No error at all. No warning. How do I check if object is active? Assume I'm 5 years old, I'm new to networking world.

subtle trail
#

Pretend this is a NetworkObject

#

The network events not having been called.

rocky solstice
#

The game object never got deactivated / greyed out. Have you downloaded the unity package and tested it? Maybe that would help narrow down to what I've done wrong... ?

subtle trail
#

No, sorry having to set this up and then dig into your code myself is highly time and mental effort consuming.

Your issue sound like a simple logic error. You can look at a example transform controller character.

Now imagine you spawn this, but you want to move it with the mouse instead, then all you need to do is write the code for that and let the NetworkTransform sync it for you. Alternatively once you have solved your Spawn/IsSpawn/Active issue by comparing to a working object/setup, you can call a ServerRpc with the endDragPosition. And let the server lerp the movement for all to see.

rocky solstice
#

Hmm. Okay since downloading and testing is time-consuming, I'll try to make it easy by sharing pics, scripts, and summarizing what I did and the result.

#

The above is a simple scene. Player(Clone) is sync thru network using NetworkTransform.
The Draggable Object (cube) has NetworkTransform and SimpleDraggableObject script.

#

The SimpleDraggableObject.cs has this:

[RequireComponent(typeof(NetworkTransform))]
public class SimpleDraggableObject : NetworkBehaviour
{
    public override void OnStartClient()
    {
        base.OnStartClient();

        if (!IsServer)
        {
            Rigidbody rigid = GetComponent<Rigidbody>();
            rigid.useGravity = false;
            rigid.isKinematic = true;
        }
    }

    // Server side calls nob.GiveOwnership(...) and then OnOwnershipClient is called, 
    // however this is triggered on server side, not clients... 
    public override void OnOwnershipClient(NetworkConnection newOwner)
    {
        base.OnOwnershipClient(newOwner);
        if (Owner == newOwner)
        {
            Debug.Log("<color=#55ff55>I'm now owning this drag object! DraggableObject</color>", gameObject); 
            SimpleDragObject.instance.PickUpObject(this);
        }
        else
        {
            Debug.Log("<color=#55ff55>I'm losing this drag object! DraggableObject</color>");
            SimpleDragObject.instance.DropObject(this);
        }
    }
}```
#

The SimpleDragObject.instance is a script that's on a player (not other players) which is this:

public class SimpleDragObject : NetworkBehaviour
{
    public static SimpleDragObject instance;
    public Transform holdParent;
    private bool init = true;
    private RaycastHit hit;
    private Transform isHoldingObject;

    public override void OnStartClient()
    {
        base.OnStartClient();
        if (!IsOwner)
        {
            Destroy(this);
            return;
        }
        instance = this;
        init = true;
    }

    private void Update()
    {
        if (!init) return;

        if (Input.GetKeyDown(KeyCode.E))
        {
            // Blah blah physics raycast, etc. deleted several lines for summary purpose
            // raycast did hit and has SimpleDraggableObject script
            Debug.Log("It has SimpleDraggableObject. Calling RequestOwnership");
            RequestOwnership(Owner, hit.collider.GetComponent<NetworkObject>());
        }
    }

    [ServerRpc(RequireOwnership = false)]
    private void RequestOwnership(NetworkConnection newOwner, NetworkObject nob)
    {
        Debug.Log("Giving ownership now...");
        nob.GiveOwnership(newOwner);
    }

    [ServerRpc(RequireOwnership = false)]
    private void ReleaseObject(NetworkObject nob)
    {
        Debug.Log("<color=#55FF55>Releasing ownership now...</color>");
        nob.GiveOwnership(null);
    }

    public void PickUpObject(SimpleDraggableObject dragObject)
    {
        dragObject.transform.SetParent(holdParent);
        isHoldingObject = dragObject.transform;
    }

    public void DropObject(SimpleDraggableObject dragObject)
    {
        // Blah blah
    }
}```
#

Specifically the part where client (player B) press E, calls RequestOwnership which is a ServerRpc with RequireOwnership = false. I'm assuming that means client tells server to run the RequestOwnership on server side, is that correct?

subtle trail
rocky solstice
#

Ohh, that's for the draggable object. Let me remove the Destroy part. As for my question above, am I thinking that correctly?

subtle trail
rocky solstice
#

Ok then I'm assuming that nob.GiveOwnership will send to all clients, correct?

subtle trail
#

Oh your code will never work

#

You're telling it to assign it to the existing Owner, so the owner will never cxhange

#

Remove that and leave it null, the server will get the caller auto populated, sec

rocky solstice
#

Ohhhh interesting. Didn't know that.

subtle trail
#
 [ServerRpc(RequireOwnership = false)]
    private void RequestOwnership(NetworkConnection caller = null)
    {
        Debug.Log($"Giving ownership of {name} to {caller.ClientId}");
        GiveOwnership(caller);
    }
#

Passing the object is a waste because this is already called on this object.
And the caller part cover who to give it to

#

You might want to do

 [ServerRpc(RequireOwnership = false)]
    private void RequestOwnership(NetworkConnection caller = null)
    {  
        if (Owner.IsValid) return;
        Debug.Log($"Giving ownership of {name} to {caller.ClientId}");
        GiveOwnership(caller);
    }

And before the Client send the RPC too.

#

Basically if the object is currently owned by a client, another client can't take it

rocky solstice
#

So you're saying passing the NetworkObject is a waste? If so, then how would I know which object to give ownership? The script you're showing me is actually on player, not on the draggable cube object. Maybe that's why I'm confused.

subtle trail
rocky solstice
#

I should move the RequestOwnership logic over to the cube?

#

Oh yeah

#

Gotcha!

#

Let me try that.

subtle trail
#

You dont want to allow clients to be able to pass nobs arbitrarily and the server just give it to them. Heck they could take over ownership of other client's main Player Object haha

rocky solstice
#

I do want player B to be able to steal Player A's cube while A is holding it.

subtle trail
#

Cool, then adapt the "if (Owner.IsValid) return;" to whatever you want. Without limit it would be weird, since Ownership could then be changed multiple time at the same frame. You'd get potentially garbled events fighting.

rocky solstice
#

Oooo interesting. I'll adapt that and test it out - will let you know how it goes.

#

Not quite there yet. Player B press E and calls
hit.collider.GetComponent<SimpleDraggableObject>().RequestOwnership(Owner); // The script that's on the cube
The cube is the one with ServerRpc and I pass Owner. I debug the the player's Owner.ClientID and it shows 1
Then when server responded via OnOwnershipClient, the network connection returned -1
Why is that?

#

If server picks up object, OnOwnershipClient shows network connection client ID as 0.
If client picks up object, OnOwnershipClient shows network connection client ID as -1. Should be showing 1.
Is there a reason why client always get -1?

#

The point of this thread is that ServerRpc isn't triggering by any client. That has been resolved as fixed.
Solution:
Move this:

[ServerRpc(RequireOwnership = false)]
public void RequestOwnership(NetworkConnection caller = null)
{
    Debug.Log($"Giving ownership of {name} to {caller.ClientId}");
    GiveOwnership(caller);
}```
To the draggable object and have client call RequestOwnership(Owner) on that draggable object script.
Then all clients got the OnOwnershipClient triggered.
And few other tweaks above mentioned by Virosa.
#

Thank you very much @subtle trail! Marking this question as solved.