Crash when sending RPC

This baffled me for long enough. I have this small script here that crashes unity every time a RPC is called from it. It doesn’t matter what the RPC does, even if it’s empty. Unity just dies.

I’ve submitted a bug report, but the Unity team haven’t answered yet.

This is the script (C#):

using UnityEngine;

public class SpawnScript : MonoBehaviour 
{
	public Transform PlayerPrefab;
	private Transform spawned;
	public Color PlayerColor = Color.white;

	void OnLevelWasLoaded ()
	{
		if (Application.loadedLevel != 0 && Application.loadedLevel != 1)
			Spawnplayer();
	}

	void Spawnplayer ()
	{
		spawned = Network.Instantiate(PlayerPrefab, transform.position, transform.rotation, 0) as Transform;
		networkView.RPC("SetPlayerDetails", RPCMode.AllBuffered, GetComponent<LocalClient>().PlayerName);
	}

	[RPC]
	void SetPlayerDetails(string pName)
	{
		spawned.name = pName;
		spawned.renderer.material.color = PlayerColor;
	}

	void OnDisconnectedFromServer(NetworkDisconnection info)
	{
		Application.LoadLevel(0);
		GetComponent<Menus>().CurrentWindow = 0;
	}
}

Any ideas?

It seems you have a little logic problem. I’m not sure if that’s the reason for your crash but your code doesn’t make much sense:

Network.Instantiate is realised via buffered RPC behind the scenes. The function itself returns the local object reference of the created object. You store this reference in your spawned-variable, but only on the client that spawns the player.

SetPlayerDetails is sent to all clients, but the spawned variable isn’t set to the same object on all clients. Every client will hold it’s own player object.

The usual way to set any variable (name / health / …) for a specific player is to use the NetworkView on the playerobject itself. This way the RPC is sent to this specific object on each client. You also have to submit the data you want to set in your RPC. Data on different PCs isn’t automatically available, it need to by synced in some way.

So on your player object you should have a script that receives the RPC:

[RPC]
void SetPlayerDetails(string aPlayerName,Color aPlayerColor)
{
   name = "Player:" + aPlayerName;
   renderer.material.color = aPlayerColor;
}

And send your RPC like this:

spawned = Network.Instantiate(PlayerPrefab, transform.position, transform.rotation, 0) as Transform;
spawned.networkView.RPC("SetPlayerDetails", RPCMode.AllBuffered, GetComponent<LocalClient>().PlayerName, PlayerColor);

Note: Your player prefab of course need a NetworkView attached. Network.Instantiate will take care of assigning a new NetworkViewID and sync it across all clients (with the buffered RPC).

I’m not sure if you can omit the int parameter on OnLevelWasLoaded, but i guess it should work since Unity calls most callback-functions via their SendMessage system with propably uses some kind of reflection. Anyway it’s better to use the “correct” version since you actually need the current level inside the function.

void OnLevelWasLoaded (int aLoadedLevel)
{
    if (aLoadedLevel > 1)
        Spawnplayer();
}

In scripting reference it shows that OnLevelWasLoaded function takes an integer parameter. It also says that this parameter is index of currently loaded level.There is not an explanation about OnLevelWasLoaded with no parameter.

http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnLevelWasLoaded.html