I’ve been playing with Unity Networking, trying to have a prefab created when a client connects and also to create another separate object which contains the player data, (yes I could put them into one GameObject but I am trying to have them separate for now).
I have a NetworkManager object containing code along the lines of the following:
public class MyNetManager : NetworkManager
{
public static NetworkHash128 PlayerInfoAssetId =
NetworkHash128.Parse("79797901");
[SerializeField]
private GameObject _LobbyPlayerPrefab = null;
protected void Awake()
{
// Register handler to spawn linked player info object
ClientScene.RegisterSpawnHandler(MyNetManager.PlayerInfoAssetId,
PlayerSpawnHandler, PlayerUnSpawnHandler);
// Register the prefab we wish to use for the player in the lobby
ClientScene.RegisterPrefab(_LobbyPlayerPrefab);
}
private GameObject PlayerSpawnHandler(
Vector3 position, NetworkHash128 assetID)
{
return ServerClass.LocalInstance.AddLocalPlayer();
}
private void PlayerUnSpawnHandler(GameObject gameObject)
{
ServerClass.LocalInstance.RemoveLocalPlayer(gameObject);
}
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject playerGameObj = ServerClass.SvrAddPlayer();
PlayerClass pi = playerGameObj.GetComponent<PlayerClass>();
GameObject panel = (GameObject)GameObject.Instantiate(
_LobbyPlayerPrefab, Vector3.zero, Quaternion.identity);
panel.name = string.Format("Player-Lobby-Panel-{0:00}", pi.PlayerId);
NetworkServer.AddPlayerForConnection(conn, playerGameObj,
playerControllerId, IbuNetManager.PlayerInfoAssetId);
}
}
And another class along the lines of:
public class ServerClass : MonoBehaviour
{
internal GameObject AddLocalPlayer()
{
GameObject playerGameObj = new GameObject("Player-???", typeof(PlayerClass));
playerGameObj.transform.SetParent(this.transform);
playerGameObj.transform.position = new Vector3();
return playerGameObj;
}
internal void RemoveLocalPlayer(GameObject obj)
{
UnityEngine.Object.Destroy(obj);
}
public static GameObject SvrAddPlayer()
{
var svr = LocalInstance;
// Create the master version of the player object
var p = svr.AddLocalPlayer();
PlayerClass pi = p.GetComponent<PlayerClass>();
// Set our synced variables as we are on the server
pi.SvrSetPlayerId(svr._NextPlayerId++);
return p;
}
}
When a client connects I have it successfully creating the prefab object, and sucessfully spawning off the seperate player game object. Everything appears to work correctly for the clients and server/host programs, except I keep getting the following error when a separate client is connecting to the server, (note not on the server/host connecting to itself):
NullReferenceException: Object reference not set to an instance of an object
UnityEngine.Networking.NetworkClient.OnCRC (UnityEngine.Networking.NetworkMessage netMsg) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:626)
UnityEngine.Networking.NetworkConnection.HandleMessage (System.Collections.Generic.Dictionary`2 handler, UnityEngine.Networking.NetworkReader reader, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:302)
UnityEngine.Networking.NetworkClient.Update () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:472)
UnityEngine.Networking.NetworkClient.UpdateClients () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:686)
UnityEngine.Networking.NetworkIdentity.UNetStaticUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:725)
After scratching my head a lot, I did find one method to stop this error from occurring… I added a new Prefab to the project containing a single component (the player class spawned by the AddLocalPlayer method), I then added this prefab to the Network manager registered spawnable prefabs.
So adding a prefab I never use, but containing a component that I spawn within a Spawn Handler function appears to have stopped this error from being thrown within the Unity code… This feels wrong to me as I don’t like having the additional prefab created which is never used anywhere and everything appears to work correctly except for the Null Reference exception error messages!
Is there a better way to stop getting this NullReferenceException? Is it a bug in Unity? Or am I just meant to have the unused prefab registered with the Network Manager?