I am kind of blindly making my way to creating a simple multiplayer game for a lesson I’m preparing.
Players join in a lobby (that’s all done), and once the server is ready they hit Start and the game should have all players in the session load the arena and spawn their playable characters.
However, while I have been able to use the Spawn() function in the lobby, I keep getting this error when trying to do so in the arena:
NullReferenceException: Object reference not set to an instance of an object
Unity.Netcode.Components.NetworkTransform.InternalOnNetworkObjectParentChanged (Unity.Netcode.NetworkObject parentNetworkObject) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs:3469)
Unity.Netcode.NetworkObject.InvokeBehaviourOnNetworkObjectParentChanged (Unity.Netcode.NetworkObject parentNetworkObject) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs:1820)
Unity.Netcode.NetworkObject.ApplyNetworkParenting (System.Boolean removeParent, System.Boolean ignoreNotSpawned, System.Boolean orphanedChildPass) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs:2238)
Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocallyCommon (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.UInt64 ownerClientId, System.Boolean destroyWithScene) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs:1113)
Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocally (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.UInt64 ownerClientId, System.Boolean destroyWithScene) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs:1021)
Unity.Netcode.NetworkObject.SpawnInternal (System.Boolean destroyWithScene, System.UInt64 ownerClientId, System.Boolean playerObject) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs:1594)
Unity.Netcode.NetworkObject.Spawn (System.Boolean destroyWithScene) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs:1706)
SessionManager.SpawnNetworkObject (Unity.Netcode.NetworkObject obj) (at Assets/Scripts/Network/SessionManager.cs:150)
Gamemode_LastOneStanding.SpawnPlayer (Player player) (at Assets/Scripts/Classes/Gamemode_LastOneStanding.cs:88)
Gamemode_LastOneStanding.OnPlayerJoin (System.UInt64 player) (at Assets/Scripts/Classes/Gamemode_LastOneStanding.cs:74)
GamemodeBase.<OnEnable>b__2_0 (System.UInt64 clientId, System.String sceneName, UnityEngine.SceneManagement.LoadSceneMode loadSceneMode) (at Assets/Scripts/Classes/GamemodeBase.cs:17)
Unity.Netcode.NetworkSceneManager.OnSessionOwnerLoadedScene (System.UInt32 sceneEventId, UnityEngine.SceneManagement.Scene scene) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs:1911)
Unity.Netcode.NetworkSceneManager.OnSceneLoaded (System.UInt32 sceneEventId) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs:1836)
Unity.Netcode.SceneEventProgress.<SetAsyncOperation>b__37_0 (UnityEngine.AsyncOperation asyncOp2) (at ./Library/PackageCache/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventProgress.cs:272)
UnityEngine.AsyncOperation.InvokeCompletionEvent () (at <0900e0d4bb644dafbfd59eb7fd222a68>:0)
Here are the scripts mentioned:
public abstract class GamemodeBase : NetworkBehaviour
{
public GamemodeSO gamemodeSO;
public static GamemodeBase Singleton;
private void OnEnable()
{
NetworkManager.SceneManager.OnLoadComplete += (ulong clientId, string sceneName, LoadSceneMode loadSceneMode) => OnPlayerJoin(clientId);
}
private void OnDisable()
{
NetworkManager.SceneManager.OnLoadComplete -= (ulong clientId, string sceneName, LoadSceneMode loadSceneMode) => OnPlayerJoin(clientId);
}
public abstract void Init();
public abstract void OnFirstPlayerSpawn(PlayerScript player);
public abstract void OnLastPlayerSpawn(PlayerScript lastPlayer);
public abstract void OnPlayerJoin(ulong player);
public abstract void OnAllPlayersSpawn();
public abstract void OnPlayerDisconnect(Player player);
public abstract void OnPlayerConnect(Player player);
public abstract void Victory(PlayerScript[] winners);
public abstract void Defeat(PlayerScript[] losers);
public abstract bool OnPlayerKilled(PlayerScript player, FragDetails details);
public abstract bool OnTickPassed();
public abstract void SpawnPlayer(Player player);
[Rpc(SendTo.Server)]
public void NotifyPlayerArrivalToGamemodeRpc(ulong playerID)
{
Debug.Log(playerID);
this.OnPlayerJoin(playerID);
}
public void SetAsSingleton()
{
Singleton = this;
}
}
This is the script throwing the error
public class Gamemode_LastOneStanding : GamemodeBase
{
public NetworkObject playerPrefab;
public NetworkVariable<bool> matchStarted = new NetworkVariable<bool>(false);
public NetworkVariable<bool> readyToStart = new NetworkVariable<bool>(false);
public override void Init()
{
}
public override void Defeat(PlayerScript[] losers)
{
throw new System.NotImplementedException();
}
public override void OnAllPlayersSpawn()
{
throw new System.NotImplementedException();
}
public override void OnFirstPlayerSpawn(PlayerScript player)
{
throw new System.NotImplementedException();
}
public override void OnLastPlayerSpawn(PlayerScript lastPlayer)
{
throw new System.NotImplementedException();
}
public override void OnPlayerConnect(Player player)
{
throw new System.NotImplementedException();
}
public override void OnPlayerDisconnect(Player player)
{
throw new System.NotImplementedException();
}
public override bool OnPlayerKilled(PlayerScript player, FragDetails details)
{
throw new System.NotImplementedException();
}
public override bool OnTickPassed()
{
throw new System.NotImplementedException();
}
public override void Victory(PlayerScript[] winners)
{
throw new System.NotImplementedException();
}
public override void OnPlayerJoin(ulong player)
{
if (!IsServer)
return;
Player targetPlayer;
if (SessionManager.Singleton.TryGetRegisteredPlayer(player, out targetPlayer))
{
SpawnPlayer(targetPlayer);
}
}
public override void SpawnPlayer(Player player)
{
if (!IsServer)
return;
var instance = Instantiate(playerPrefab);
instance.gameObject.name = "Player: " + player.playerName;
//V This line is the culprit
instance.SpawnWithOwnership(player.OwnerClientId, true);
}
}
And here’s the function where I load the scene
public void LoadSelectedMap()
{
if (HostManager.selectedMap == null)
Debug.LogError("ERROR: No map selected.");
var status = m_NetworkManager.SceneManager.LoadScene(HostManager.selectedMap.mapName, UnityEngine.SceneManagement.LoadSceneMode.Single);
if (status != SceneEventProgressStatus.Started)
{
Debug.LogWarning($"Failed to load {HostManager.selectedMap.mapName} " +
$"with a {nameof(SceneEventProgressStatus)}: {status}");
}
}
The prefab in question has the NetworkObject component assigned to it. It’s an empty game object with two playable objects parented to it (both of which also have NO components, don’t know if that’s good practice)
What am I doing wrong?