UNet pickup Script

Hi guys,
I am struggling to get my pick up script to work across the network. I am using UNet, and that all works gloriously. The pick up script I was using in initial testing works fine on monobehaviour but I am struggling to adapt it with the required [Command] and [RPClient] functions.

The script is attached to the object I want the players to be able to pick up and move. If I understand correctly this means that only the host has authority, and that is how it plays out in testing. What I can’t find a way to do is to assign authority to the player that has picked up the object so that the RPClient calls can be made.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class mouseDrag2NetworkAttempt : NetworkBehaviour
{
    public float distance = 1.0f;
    [SyncVar]
    private Transform objTransform;
    [SyncVar]
    private NetworkIdentity objNetId;

    [ClientRpc]
    void RpcMoveTo(Vector3 objPosition, Quaternion objRotation)
    {
       transform.position = objPosition; //now set the player gameObject to the objects location
       transform.rotation = objRotation; //and rotation
    }

    [Command]
    void CmdPositionRotation(Vector3 objPosition, Quaternion objRotation)
    {
        objNetId = GetComponent<NetworkIdentity>();        // get the object's network ID
        objNetId.AssignClientAuthority(connectionToClient);    // assign authority to the player who is changing the color

        RpcMoveTo(objPosition, objRotation);

        objNetId.RemoveClientAuthority(connectionToClient);    // remove the authority from the player who changed the color
    }

    private void newPositionAndRotation()
    {
        Camera playerCamera = Camera.main;
        Vector3 mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
        transform.position = playerCamera.ScreenToWorldPoint(mousePosition);
        transform.rotation = playerCamera.transform.rotation;
    }

    public void OnClick()
    {
        newPositionAndRotation();
    }

    void OnMouseDrag()
    {
        newPositionAndRotation();

        Vector3 objPosition = transform.position;
        Quaternion objRotation = transform.rotation;

        CmdPositionRotation(objPosition, objRotation);
    }
}

with the AssignClientAuthority calls I get a load of errors about the client being null,
without the AssignClientAuthority calls i don’t get any errors but the object always moves back to the hosts last known location.

I am trying to find a way to identify the client other than connectionToClient but have been hitting a brick wall for over a week now.

Any help would be very very welcome at this point

You have to choose how you are going to sync the movement of your object. Using Rpc, [Sync] attribute or using the network transform component… but no all of them!!. If you add the network transform component to your object, Unet is going to take care about the update (prediction and corrections) for the transform in the rest of the clients I think is the better aproach.

You should be sure that the client has authority before call an Cmd, Are you using a PlayerPrefab? The player always have authority about their own player prefab and you can always call a Command method, but then you need to send the transform or the game (only works with a network tranform).

Also you dont need to Sync the network identity, actually I think is not going to work in that way.

If you want to send a command through a network object, you need to be sure you have authority first. Has to have a Network identity component, marked as local player authority and then before assign a new owner you need to remove the actual owner before (via PlayerPrefab)

Check the basic tutorials for networking to have more clear the concepts.

Thanks for your reply, the script is attached to the object itself. I have a separate player prefab, but it is stack full of scripts already and so I was hoping to have a pickup script separate from it.

Using a similar script as monobehaviour, but with network transforms on the objects to do the synching. I got a result where the object would move under player authority, but then ping back to where the host last used it.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class RayCastPickUp : NetworkBehaviour
{
    [SerializeField]
    private float distance = 1.0f;
    private int range = 2;
    private RaycastHit hit;
    [SyncVar]
    private GameObject objectID;
    private NetworkIdentity objNetId;

    private int layerMask = 1 << 9; //pickUpLayer is 9

    void Update()
    {
        if (isLocalPlayer)
        {
            CheckIfMoving();
        }
    }

    void CheckIfMoving()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        Debug.DrawRay(ray.origin, ray.direction * 100, Color.cyan);


        if (isLocalPlayer && Input.GetMouseButton(0))
        {

            if (Physics.Raycast(ray.origin, ray.direction, out hit, Mathf.Infinity, layerMask))
            {
                objectID = GameObject.Find(hit.transform.name);                                    // this gets the object that is hit 
                CmdPickUp(objectID);
            }
        }
    }


    [ClientRpc]
    void RpcPickUp(GameObject obj, Vector3 objPosition, Quaternion objRotation)
    {
        obj.transform.position = objPosition;
        obj.transform.rotation = objRotation;
    }

    [Command]
    void CmdPickUp(GameObject obj)
    {
        objNetId = obj.GetComponent<NetworkIdentity>();        // get the object's network ID
        objNetId.AssignClientAuthority(connectionToClient);    // assign authority to the player who is changing the color

        Camera playerCamera = Camera.main;
        Vector3 mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
        Vector3 objPosition = playerCamera.ScreenToWorldPoint(mousePosition);
        Quaternion objRotation = playerCamera.transform.rotation;

        RpcPickUp(obj, objPosition, objRotation);                                    // use a Client RPC function to "paint" the object on all clients

        this.GetComponent<Renderer>().material.color = Color.clear; //finally change color to transparent
        objNetId.RemoveClientAuthority(connectionToClient);    // remove the authority from the player who changed the color
    }
}

So i solved the issue by making the script part of the spawned player prefab. Then anything that needs to be picked up is now part of the pickUp layer (10).

Just leaving this here to assist others down the line

1 Like

Thank you sir, I was looking on how to use commands for game objects. You’re the best

would you mind showing how you set up the pickup item