Leaving and rejoining a room with objects intact

Options
I didn't find something like this already in the forums, so...

Using v1.26.1 of PUN, I have been working on a way to support the case where, if a player leaves the room, all the game objects he owned remain in the scene, and players can leave and rejoin the game any time (a returning player would no longer own the objects he owned before, but that's OK for my purposes). I came up with the following solution, thanks to some research and tips I received and posts I found from the Exit Games team. It seems to work flawlessly so far, so I thought I'd post it here in case it helps anyone else. If I find any problems with it I'll try to edit this post accordingly.

NOTE: Something this does not attempt to address is updating room or player states (score, inventory, etc.), but that's more implementation-specific. You might use room and player custom properties for that, as I do for some data. Frequently-changing state data I treat differently: when a player joins a room in progress, he requests the game state from the master client (repeating the call if needed, in case the RPC wasn't received because the master client left), who sends the state data via another RPC to the requesting player. Anyway, back to the problem at hand...

The idea is, when a player leaves the room, the master client takes ownership of all the player's objects and tells everybody to re-create those PhotonViews, applying new view IDs. I tried just reassigning the view IDs, but that resulted in a bunch of warnings and sometimes errors every way I tried, so now I just replace the PhotonView components themselves. I still get one warning, "DoInstantiate re-defines a GameObject. Destroying old entry...", but that seems innocuous so I'm living with it.

First, after connecting to Photon, I set PhotonNetwork.autoCleanUpPlayerObjects = false so a player's objects won't be automatically removed when he leaves a room.

Second, I have these methods on exactly one script that's always in the scene:
void OnPhotonPlayerDisconnected(PhotonPlayer player)
{
	if (PhotonNetwork.isMasterClient)
	{
		// Take over the player's game objects
		foreach (PhotonView view in FindObjectsOfType<PhotonView>())
		{
			if (view.owner == null)
			{
				int newViewID = PhotonNetwork.AllocateViewID();
				PhotonView.RPC("RPC_ReassignView", PhotonTargets.AllBuffered, view.viewID, newViewID);
			}
		}
	}
}

[RPC]
void RPC_ReassignView(int oldID, int newID)
{
	PhotonView oldView = PhotonView.Find(oldID);
	if (oldView != null)
	{	// Replace the view with a new one, using the new view ID
		GameObject obj = oldView.gameObject;
		Destroy(oldView);
		PhotonView view = obj.AddComponent<PhotonView>();
		view.viewID = newID;
		view.observed = oldView.observed;
		view.synchronization = oldView.synchronization;
	}
}

If you try this and it works, or especially if it doesn't, I'd appreciate knowing!

Thanks.

Comments

  • J_Troher
    J_Troher
    edited September 2014
    Options
    i am about to test this, with the RPC sent AllBufferedViaServer (so it stays when you leave). I'm using this method on my vehicles to see if it works out better than what I have. The only thing I'm wondering about is when you reassign. If you destroy the oldview, how can you set the new view to the oldview's observed and synced components?

    --

    Did it. Works phenominally. Now, I'm using this for vehicles, and not for people who leave. But I will definitely try yours out for that! My only thing is that it does throw a warning, when you delete the old view. It complains that you aren't using Network Destroy. So I did it with a network destroy just to see what would happen. And it seemed to delete me and my vehicle lol. So switched back to reg destroy, screw the warning.

    Send me a PM sometime or add me on Skype: FatalNickle
    I'll show you what I'm working on. Doesnt hurt to have people to collab with.
  • The call to Destroy just marks it to be destroyed, which actually happens later, sometime after the method returns. Until then you can access the view's members.

    Let me know if it works for you. I haven't tried using AllBufferedViaServer. Is there a reason you need to use that instead of just AllBuffered? My understanding is, either way, new players will get the RPC so long as PhotonNetwork.autoCleanUpPlayerObjects is false and you don't explicitly remove players' RPCs, but I could be missing something.
  • J_Troher
    Options
    I use allbuffervia server in this sense because I'm doing it for vehicles/mountables. Which I initially spawn as scene objects. (RPC sent to masterclient telling them where to spawn it).

    I actually have a post about it: viewtopic.php?f=17&t=5202&p=19911#p19911
    Where I toggle around their owner ID's. But this works out waaay better, atleast it seems that way.

    When I do some more testing of the situation, I may write up a small tutorial for vehicles. Since I couldn't seem to find anything anywhere on the matter. And it was the first thing I decided to figure out when I jumped into Photon..

    Your post for sure helped me out though! So my hats off to you sir. I will let you know when I use it for your intended purpose :) I think yours will come in handy for player owned structures. Except at that point, there is still a limit to 999 objects one person can own.

    I experimented with changing SubID's, for scene objects. Where i could give it a random range (in my case I said, why not 300k to 600k, that leaves room for some unique ID's). @Tobias - I think this would be nice, since afterall it is just a number. I don't like the limit to each player owning 999 photonviews. (now I could be completely wrong on this and there could be a way to do what i speak of, but is out of my knowledge. If so please enlighten me!!)

    I will stop writing now.. back to moar Testings!
  • Nice. Glad it helped.