PhotonNetwork.Instantiate / Different Scenes

Options
Hi guys,

We have a very special situation here we need a little advice for.

Unfortunately we have the situation were a PhotonNetwork.Instantiate call can be received by another player which is in a difference scene already. (this is by design, so player A can switch to scene X when player B is still in scene Y). We can't change this as this is more or less a requirement. (though it doesn't fit the photon way of doings things perfectly).

As we mostly use scene local game objects with corresponding photon views, RPCs sent to those objects are not a problem on scene switches because they simply don't exists anymore then.

But obviously not so for PhotonNetwork.Instantiate as this call doesn't work on a photonView but globally.

Now my question, is there any way to discard the received instantiate call on a client if the scene is not correct? (correct or not correct scene can/should be checked locally when the call is received).

Basically we would need something like this:

virtual OnInstantiateNetworkObject(...)
{
if (sceneIsWrong)
return;

base.OnInstantiateNetworkObject(...);
}


Comments

  • robertsze
    robertsze
    edited February 2017
    Options
    Maybe just one more thing, we don't look for a solution like manual instantiating (where we could handle this ourself), using synchronous scene switching to not get into this situation at all or something similar...
    We just would like to know if there is a way to prevent instantiation a game object which was originally targeted for a different scene. (the game object is rather complex with a lot of child game objects, animations, scripts, etc... for which we would like not to even run the Awake method in this case). Thanks!
  • Spaggi
    Options
    I had exactly the same issue and wasn't able to find a solution. PUN is awesome but there are some assumptions made by the devs which lead to little flexibility when the given path is not followed properly (meaning in your case, instantiating objects for users in the same room but different scenes).

    I ended up with a completely different approach using another application (Gamesparks) for player matching and joining the same room only when both users are in the same scene. Not sure this is feasable in your use case
  • robertsze
    robertsze
    edited February 2017
    Options
    We use playfab too (very similar to Gamesparks) but really want to use Photon for the game/lobby communication as it would make things much easier. (we have heavy realtime traffic in the lobby too so playfab is not really appropriate for this, not sure about game sparks, but way too late to switch backend again ;) )

    We are able to handle most special cases like starting only when game scene is loaded, pausing message queue here and there, handshakes, etc...

    But this very special situation as described above make us major troubles...
  • jeanfabre
    Options
    Hi,

    uhm, that's going to be tricky to solve this they way you intend.

    This is how pun works, scenes do not matters, it's the concept of "Room" that matters.

    EVERY players in a room MUST have an prefab instance on each clients. So if I join a room and the players already in that room is not in the right scene, then, I should not be allowed to join the room in the first place.

    What I would suggest is maybe to create a network prefab that is a stub, so depending on the scene a particular player is, you can then show a different avatar or no avatar at all, yet you acknowledge the instantiation of that remote player locally and grant him the photonViews so that network processes can occur without failing.

    mind you things don't have to look the same or behave the same on every instance of a player across the various clients. Typically, VR is a good example, you don't see yourself but others have to see you, so the prefab you build for VR has to have a very distinct behavior and look when you own it ( how you see yourself in the scene) and when you don't ( what other sees of you).

    I hope I am making sense :)

    Or is it more a problem of scene synchronization and you are running into problem because you would like all players to always be in the same scene?


    bye,

    Jean
  • robertsze
    robertsze
    edited February 2017
    Options
    >> EVERY players in a room MUST have an prefab instance on each clients. So if I join a room and the players already in that room is not in the right scene, then, I should not be allowed to join the room in the first place.

    This is actually more or less the problem.

    Player 1 and 2 are in Scene A. Both decide to go to scene B. (after a handshake we pause the message queue, load scene B, and resume the message queue). As soon as the game objects awake we network instantiate player objects for scene B. Works fine.

    But not in a very special case.

    Same situation as above.
    Player 1 and 2 are in Scene A. Both decide to go to scene B. (after a handshake we pause the message queue, load scene B, and resume the message queue).

    Now lets say Player 1 loaded Scene B and immediately leaves the game (or better, returns to scene A immediately). Player 2 is still loading scene B. Player 2 finally loaded scene B, instantiates his player game objects and resume the message queue.

    Now it can happen that Player 1 is already in Scene A and receives the instantiate call from player 2 originally targeted for scene B.

    In our case, scene A is the game scene itself and scene B is more a less a match results screen. (We can't use handshakes or something similar to prevent player 1 going back to scene A because this is mostly a "give up", "abort game now" feature. In the worst case player 2 doesn't respond for any technical reason and player 1 would sit forever in scene B ).

    We use the same room for both scenes, as in the game scene and scene match result there is heavy photon traffic. As said above, we don't have problems with usual RPCs because destroying the photon view (when switching scenes) takes care of not existing game objects anymore. But only for such global actions like object instantiation this is a problem.

    Hope this makes sense to you.

    If there would be the possibility to additionally specify the scene name when instantiating objects and not instantiating them if the current scene name is different than the specified one all would be perfect ;)
    (we could just modify the instantiate methods by hand, pass the scene name as instantiationData and compare the scene names there I guess, but this will make updating more difficult for us in the future...)
  • jeanfabre
    Options
    Hi,

    yes, I think that I would tackle this using a stub prefab instance, indeed. In this case you need to have a higher virtual player that just never stops being active while transiting from scene to scene.

    also, maybe you could explore using room custom properties? what if each player is always keeping upto date a room property defining in which room he his. maybe you can then take actions on other player instances based on this information? Player 2 in Scene B, Player 1 knows that know because the room property was changed and Player 1 sits in scene A for nothing.

    The room custom properties could also be used for giving a contextual variable in which player can refer when the process messed up for various reasons, so a custom room property could be "Pending process":"GotoSceneB"

    Would one of the solution be a possible avenue for solving these issues?
    ------

    There is something that still puzzle me is why you need to kill the instance GameObject of the player when loading a new Scene and reinstantiate it then? if you can precise a bit around this, that could help me understanding the process. this seems to me the source of the issue.


    Have you checked the PUN basics demo? it's a simple demo yet featuring a complex scene loading system where the scene is different depending on the number of players. so when the system detects 2 players it loads the scene for two players, when it's 4, it's yet a different and bigger room being loaded. All the loading of scenes is synchronized via the PhotonNetwork.automaticallySyncScene = true;

    maybe it holds the solution, because I keep the instance of the player prefabs during the loading ( flaged it with DontDestroyOnLoad()), and it works just fine :)

    Bye,

    Jean
  • robertsze
    robertsze
    edited February 2017
    Options
    Think of scene A as the actual game scene and scene B as a menu scene, There is nothing like a player object in the menu. Its just menus to display tournament results, manage player accounts, etc.. but still connected to the room to exchange messages, restart the game for a revenge, etc...

    room properties will not work as player 2 instantiates its objects before enabling its message queue and thus will not receive the updated properties before instantiating.

    To make it more clear, think about a game like Battlefield but with the following difference:
    You join a room in the menu (lobby) already, then you load the game and when the game is done you return to a complete different menu scene while still staying in the same room.

    I completely understand your suggestion to keep the player object in all scenes. But for our situation this is more of a workaround. Keeping a global player object makes sense when switching scene likes levels, but not for complete unrelated scenes like 2D menus and 3D game scenes.
  • robertsze
    robertsze
    edited February 2017
    Options
    Looking through the source a bit more it looks like there is no way to handle this. No interface to hook up, no methods to override. We will just make this possible the "manual" way:

    We will just modify:

    internal Hashtable SendInstantiate(string prefabName, Vector3 position, Quaternion rotation, int group, int[] viewIDs, object[] data, bool isGlobalObject)
    {
    ...
    ...
    instantiateEvent[(byte)9] = Application.loadedLevel;
    ...
    ..}

    internal GameObject DoInstantiate(Hashtable evData, PhotonPlayer photonPlayer, GameObject resourceGameObject)
    {
    ...
    ...
    if (evData.ContainsKey((byte)9))
    {
    int remoteScene = (int)evData[(byte)9];
    if (Application.loadedLevel != remoteScene)
    {
    Debug.LogWarning("NetworkingPeer: Removed instantiate from scene " + remoteScene + " where local scene is " + Application.loadedLevel + ", skipping");
    return;
    }
    }
    .....
    }
  • jeanfabre
    Options
    Hi,

    I see, then what you need is the chat SDK AND PUN SDK to work together.

    the problem you are facing if you want player to keep communicating outside the game action itself, for this, we recommend using the chat SDK which allow for All players to communicate ( chat, but it's really a messaging system, so you can send commands and hidden calls, not just 'chat').

    With this, you completly remove form having to hack around the concept of room in Photon

    Players of the same "Party" can all subscribe to a chat channel, and only when they want to actually play do they join the room.

    also, without the above mention of chat + Pun, I see no problem with having a photon stub like I mentionned originally. I think it totally fits here.

    you can even have several gameobjects belonging to the same player, one of them being the root and always on gameobject,

    Your DoInstantiate() modification if of course something I don't think we would encourage nor modify in future versions of PUN.

    Check out the manual instantiation section here :https://doc.photonengine.com/zh-tw/pun/current/manuals-and-demos/instantiation

    maybe it holds a possible ways for you to have more control on this without hacking ( though if that hack works and it's 3 line of code... go for it...)


    Bye,

    Jean
  • robertsze
    Options
    Hmm, didn't know the chat api allowed sending commands, dictionaries, etc... and works "across" rooms.... Now Photon Chat actually makes sense to me :)

    I will investigate this, maybe we can redesign our lobby/game/results architecture and make use of this...

    (Just a quick questions after taking a quick look at the API. Is it possible to get the amount of players subscribed to a channel?)
  • jeanfabre
    Options
    Hi,

    unfortunatly no, I also wished about this feature too. Maybe in future releases.

    Bye,

    Jean
  • jeanfabre
    Options
    Hi,

    also make sure to fully grasp the status update feature, it allow sending any status, not just the predefined ones and also send a complex message, this is great to reach all friends directly.

    bye,

    Jean