GetComponent doesn't work in [ClientRPC] function.

From the tiny scraps of documentation I can find, it seems like calling a function on every client should be as simple as calling a command (client → server) and creating an RPC (server → clients). This is what I have:

[Command]
public void CmdSendMessage(string message)
{
RpcSendMessage (message);
}

[ClientRpc]
public void RpcSendMessage(string message)
{
this.transform.Find (“ChatCanvas/Border/Panel/ChatText”).gameObject.GetComponent ().text += “\n” + characterName + “:” + message;
}

I call my command whenever the player submits the chat message, but it only shows up on the local instance (either client or server), and throws my favorite error “Object reference not set to an instance of an object” for the foreign object when I call GetComponent in the RPC.

From the research I’ve done, the GetComponent can only be called on objects that have LocalPlayerAuthority. If you can’t call GetComponent in an RPC, then how on earth are you supposed to update a component for clients?

Just a couple things. I wouldn’t use “XXXSendMessage()” as a name because Unity already uses a method name of SendMessage(), and i get nervous with naming, because Unity does a fair bit of magic behind the scenes to make all that work. This probably doesn’t matter, but i’m just noting it. Also, that line in your RPC has a lot of assumptions in it. When i get null-refs i break it down - first do the Find() and ensure that that actually returned what you think it did. Then do the GetComponent<>() on that, and ensure that that retuned what you thought it should. Note also that sometimes RPCs get called before the object they are on are “ready” and so the Find() or GetComponent() are not in a state to work yet. Anyway, those are a couple of quick notes, good luck!

Thanks Jos-Yule for the response. Good point on the SendMessage reservation.

The bigger issue was trying to access the client components within the RPC. For anyone reading this, my solution was to call a local function (ReceiveMessage) from the RPC rather than using GetComponent and adding my message from within the RPC.

These were the steps that worked for me:

  1. Trigger the message in Update() when the Return key is pressed
  2. Send a command to the server, passing the message as a string
  3. Within the command, find the Player objects on the server
  4. Loop through the players and call the RPC method (for each), again passing the message as a string
  5. Use the RPC to call the local “RecieveMessage” method, which in my case adds the new text to the chat window and clears the input field

I have included my working code in the order in which it is executed

void Update()
{
if (!isLocalPlayer)
return;
    if (Input.GetKeyDown (KeyCode.Return) && this.chatting)
     {
        string message = "\n" + CharacterName + ":" + this.transform.Find  ("Chat").gameObject.GetComponent<InputField>().text;
       CmdSendMessage (message);
     }
}

[Command]
public void CmdSendMessage(string message)
{
GameObject[] recipients = GameObject.FindGameObjectsWithTag ("Player");

foreach(GameObject recipient in recipients)
recipient.GetComponent<Player>().RpcSendMessage (message);
}

[ClientRpc]
public void RpcSendMessage(string message)
{
RecieveMessage (message);
}

public void RecieveMessage(string message)
{
if (!isLocalPlayer)
return;

this.gameObject.transform.Find ("ChatCanvas/Border/Panel/ChatText").gameObject.GetComponent<Text> ().text += message;
this.transform.Find ("ChatCanvas/InputBackground/ChatInput").gameObject.GetComponent<InputField>().text = "";
}

It looks like most of the components you are trying to find could be cached in the inspector: Text and Input field.

I’ve used quite a bit of other network libraries, but not UNET. But I am guessing UNET has a way to retrieve a player room/server list. If not, then recipients could be cached in a list upon joining the room.

Yeah you can use OnConnectedToServer() and call a command that adds the player to a list.

With UNET, though, you can’t just write a normal method that iterates through network objects and makes changes. If I handled the chat that way, the results of sending a message would only be seen on the client that sent the message.

If it has a network identity you have to tell the server to make the same change for each client.