I'm surprised the coroutine isn't overflowing the stack from infinite recursion. This *could* be your problem, but not very likely.
I don't have TNet3 so I can't check the params you're passing to TNManager.Instantiate, but make sure the objects are being marked as persistent.
There could be a bug with channels but it's doubtful. Place a Debug.Log n your object's OnDestroy function and examine the call stack.
To be clear (and to summarize for when Aren swoops in) this is what's happening:
1. Two players join
2. The Host begins instantiating network objects from a coroutine
3. The Host leaves
4. Some time later, the player that was previously hosting rejoins
5. The rejoining player does not see all of the network objects that the other player sees.
What happens if you completely restart the game before rejoining?
Also, perhaps you shouldn't instantiate objects in the coroutine? There could be a race condition during the disconnect process. Actually, a modification could solve that:
// Spawn Timer
IEnumerator spawnObjects(spawnableItem itemToSpawn)
{
int lastCount;
// Make Sure Is Host
while ((TNManager.isConnected) && (TNManager.isInChannel) && (TNManager.isHosting))
{
while (GlobalSettings.currentOptions == null) yield return null;
// Spawn Objects
if ((spawnedObjects[itemToSpawn.objectPath].Count < itemToSpawn.maxSpawn) && (spawnedObjects[itemToSpawn.objectPath].Count != lastCount))
{
lastCount = spawnedObjects[itemToSpawn.objectPath].Count;
string go = itemToSpawn.objectPath;
Vector3 spawnPointY
= new Vector3
(Random
.Range(-(worldSize
.x/2),
(worldSize
.x/2)), worldSize
.y, Random
.Range(-(worldSize
.z/2),
(worldSize
.z/2))); RaycastHit hit
= new RaycastHit
();
if (Physics.Raycast(spawnPointY, Vector3.down, out hit))
{
int objID = Random.Range(1, 99999);
if (go.Contains("Blob"))
TNManager.Instantiate(1, "CreateBlob", go, true, hit.point, transform.rotation, go, objID, true, 1);
else
TNManager.Instantiate(1, "CreateObject", go, true, hit.point, transform.rotation, go, objID);
}
}
// Timer
yield return new WaitForSeconds
(itemToSpawn
.spawnTimerInSeconds); }
}
The above should only be called once per join per itemToSpawn. The coroutine will stop running if the player is not the host, is not in a channel, OR is not connected.
Additionally, I read somewhere that local variables are persistent throughout the coroutine's lifetime, so I'm assuming int lastCount will function properly.
This should eliminate race conditions and attempts to ensure objects are given enough time to instantiate fully.
Even with all this I don't know what exactly is going wrong. For player B to see the object means it's passed through the server which means it's been saved on the channel. Packets are kept in a queue and processed in order. If a player disconnects the queue is cleared. So when the Instantiate packet comes in it means the player currently exists on the server so it'll properly be assigned an owner. When the player disconnects any persistent object owned by that player is transferred to player[0] (this is done after the disconnecting player is removed from the list, so 0 would be player B in this case). Then the SetHost packet is sent out. Then the ResponsePlayerLeft packet is sent out. In this, every TNObject on every client that's owned by the disconnected player sets its owner to TNManager.hostID (which was set in response to the SetHost packet that preceded this one).
When a player joins, the channel's list of objects is iterated over and each object is created on the connecting client. The only way player B can see an object and player A can't is if player B ignored (or fails to execute) a networked Destroy call or player A ignored (or fails to execute) a networked Instantiate call.
Other than that, the only possible way I can see this happening is if the objects aren't being marked as persistent. Again, check your TNManager.Instantiate call to verify that the persistent flag is true.