I\'m working on and learning some basics of Unity 5, UNET, and networking. I made a simple 3D game where you go around and change the colors of objects. But I want to make i
i make a small modification to this code and add the possibility the script if we place the player he can make the change through the raycasting.
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class Raycasting_Object : NetworkBehaviour {
private int range = 200;
// [SerializeField] private Transform camTransform;
private RaycastHit hit;
[SyncVar] private Color objectColor;
[SyncVar] private GameObject objectID;
private NetworkIdentity objNetId;
void Update () {
if (isLocalPlayer) {
CheckIfPainting ();
}
}
void CheckIfPainting(){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay (ray.origin, ray.direction * 100, Color.cyan);
if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
if (Physics.Raycast (ray.origin, ray.direction, out hit, range)) {
objectID = GameObject.Find (hit.transform.name); // this gets the object that is hit
Debug.Log(hit.transform.name);
objectColor = new Color(Random.value, Random.value, Random.value, Random.value); // I select the color here before doing anything else
CmdPaint(objectID, objectColor);
}
}
}
[ClientRpc]
void RpcPaint(GameObject obj, Color col){
obj.GetComponent<Renderer>().material.color = col; // this is the line that actually makes the change in color happen
}
[Command]
void CmdPaint(GameObject obj, Color col) {
objNetId = obj.GetComponent<NetworkIdentity> (); // get the object's network ID
objNetId.AssignClientAuthority (connectionToClient); // assign authority to the player who is changing the color
RpcPaint (obj, col); // usse a Client RPC function to "paint" the object on all clients
objNetId.RemoveClientAuthority (connectionToClient); // remove the authority from the player who changed the color
}
}
Unity 5.3.2p3 Assign Client Authority to Non Player Objects
For anyone interested in setting this up this is my approach
Client Side OnLocalPlayer component -> Call commands to assign and remove object authority by passing through the objects NetworkInstanceId. You can add any UI to call these methods on this component
Server Side
[Command]
void CmdAssignObjectAuthority(NetworkInstanceId netInstanceId)
{
// Assign authority of this objects network instance id to the client
NetworkServer.objects[netInstanceId].AssignClientAuthority(connectionToClient);
}
[Command]
void CmdRemoveObjectAuthority(NetworkInstanceId netInstanceId)
{
// Removes the authority of this object network instance id to the client
NetworkServer.objects[netInstanceId].RemoveClientAuthority(connectionToClient);
}
Client Side
3. Object component ->
OnStartAuthority() - allowed to send commands to server
OnStopAuthority() - not allowed to send commands to server
That's all there is to it!
I found my answer. And it was very difficult, as almost every single question, post, example, etc... I could find was about player objects, and not non-player objects.
So, I needed to use the AssignClientAuthority
function. Which I had tried a couple of times, but wasn't using it correctly. Here is the functioning C# script to apply to the player:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class Player_Paint : NetworkBehaviour {
private int range = 200;
[SerializeField] private Transform camTransform;
private RaycastHit hit;
[SyncVar] private Color objectColor;
[SyncVar] private GameObject objectID;
private NetworkIdentity objNetId;
void Update () {
// only do something if it is the local player doing it
// so if player 1 does something, it will only be done on player 1's computer
// but the networking scripts will make sure everyone else sees it
if (isLocalPlayer) {
CheckIfPainting ();
}
}
void CheckIfPainting(){
// yes, isLocalPlayer is redundant here, because that is already checked before this function is called
// if it's the local player and their mouse is down, then they are "painting"
if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
// here is the actual "painting" code
// "paint" if the Raycast hits something in it's range
if (Physics.Raycast (camTransform.TransformPoint (0, 0, 0.5f), camTransform.forward, out hit, range)) {
objectID = GameObject.Find (hit.transform.name); // this gets the object that is hit
objectColor = new Color(Random.value, Random.value, Random.value, Random.value); // I select the color here before doing anything else
CmdPaint(objectID, objectColor); // carry out the "painting" command
}
}
}
[ClientRpc]
void RpcPaint(GameObject obj, Color col){
obj.GetComponent<Renderer>().material.color = col; // this is the line that actually makes the change in color happen
}
[Command]
void CmdPaint(GameObject obj, Color col) {
objNetId = obj.GetComponent<NetworkIdentity> (); // get the object's network ID
objNetId.AssignClientAuthority (connectionToClient); // assign authority to the player who is changing the color
RpcPaint (obj, col); // usse a Client RPC function to "paint" the object on all clients
objNetId.RemoveClientAuthority (connectionToClient); // remove the authority from the player who changed the color
}
}
!!!Important!!! Each object that you want to affect must have a NetworkIdentity component, and it must be set to LocalPlayerAuthority
So this script is just to change a random color, but you should be able to change the actual stuff to apply this to any change in the materials or anything else you want to network with a non-player object. "Should" being the optimal word - I haven't tried with any other functionality yet.
EDIT - added more comments for learning purposes.
Rather than using "Assign Object Authority",
I really recommend simply using
.SpawnWithClientAuthority
It's really very easy.
In fact it's this simple!
[Command]
void CmdPleaseSpawnSomething() {
GameObject p = Instantiate(some_Prefab);
NetworkServer.SpawnWithClientAuthority(p, connectionToClient);
}
{In that code, note that "connectionToClient" is magically available with no effort - it means "the client" who called this command.}
On the client (the one you want to "own" the thing), just call CmdPleaseSpawnSomething()
.
I mean - that's all there is to it, thank goodness.
There's a long clear explanation here:
https://forum.unity.com/threads/assign-authority-to-local-client-gameobject.371113/#post-3592541