Handling of level prefixes PUN != Unity networking!?

jashan ✭✭
I'm still in the process of converting my Unity networking based project to PUN and running into another issue: It seems that PUN is handling level prefixes differently from how Unity handles it. The way I understand Unity's level prefixes is that you set the level prefix and all objects loaded from then on get this level prefix (this only applies to scene objects, though - Instantiated prefabs seem to still run in their own space). This makes a lot of sense for many use cases including loading multiple levels simultaneously on the server.

PUN seems to do it the other way round: When you call PhotonNetwork.SetLevelPrefix all known PhotonViews get a new level prefix. So instead of having an effect "in the future" (all objects loaded from that point on), it has an effect on the past (all objects that have been loaded up to this point).

So, what I'm getting are lots of messages "Received RPC ... on viewID ... with a prefix of ..., our prefix is -1. The RPC has been ignored."; these messages did not occur under Unity's networking - and the relevant functionality worked. So it's certainly not that Unity just didn't let me know there was a problem (btw, I really like those explicit and informative error messages - they really do help!)

The first issue I had here had to do with levels that were loaded before networking was initiated. Interestingly, PUN will give me an error when I try to set the level prefix when I'm not connected, yet. I think the "VerifyCanUseNetwork()" is a bit over-used; IMHO, it should only be used for operations that really do need a connection (SetLevelPrefix does not; if I remove the "can use network"-check, it works alright, and of course, it also worked in Unity when not connected).

Anyways, I changed the logic to work the other way round (the way I'm used to from Unity networking and the way I think this really makes sense): When I'm setting the level prefix, only a static variable is set in NetworkingPeer. Any objects already loaded are not touched. Then, in the awake of PhotonView, if it is a scene object, I set the prefix to the current prefix.

With that fix, I could play my first Photon based multiplayer session - YAY! Well, at least with a single player and in a single level.

I'm expecting some more issues because PUN seems to assume that there's only ever one level loaded - and in my case, I'm loading all levels on the server; so I'm getting non-unique viewIDs (not sure whether Unity assured those were unique across levels or used the level prefix to avoid confusion here - I assume the latter is the case) ... so I guess that thread will continue ;-)


  • I just double checked, and it seems that Unity networking does use prefix + viewID to do lookups; unlike PUN which only uses prefix to prevent receiving messages.

    This can be a real problem in projects that use SetLevelPrefix in order to separate viewIDs stored in different levels (keep in mind that "different levels" could be nothing but different "areas" of the same level).

    So I guess I'll have to add one layer of lookups. EDIT: Ooops ... Unity uses NetworkViewIDs for the lookups (NetworkView.Find(...)) - which probably have the level prefix included ... PUN only uses the int, and this is where this means trouble :-(

    Would be nice to have some more precise documentation of how Unity *really* does this ... but one answer by Larus on the Unity forums that lets me conclude it really is the way I think it is would be: http://forum.unity3d.com/threads/7094-Double-netWork-id
  • Makes sense for it to be bound, the prefixes were useless if prefix or ID were mutually exclusive and seperated, after all the target is UIDs and they require both to be generated.
  • I ended up adding "prefix" to PhotonViewID and replacing the int -> PhotonView lookups with PhotonViewID lookups.

    One thing I'm struggling with is that the "ID" and "player" are mixed into one int inside of PhotonViewID. While this saves bandwidth and provides a nice flexibility, this does give me a bit of a headache because it means that when the PhotonPlayer changes its ID (which, if my understanding is correct, can happen when a player switches rooms), PhotonViewID.ID would also change ... which would create a major mess.

    Not sure if I really need prefix to be a full int ... I might cut this down to byte. 256 level prefixes should be fine (personally, I'll never need more than 13 - at least for this game). And I might move the IDs of players to ushort and the ID of PhotonViewID also to ushort. I don't need as many players and neither do I need as many networkViews, so while I think combining those two and having the flexibility this provides is pretty cool, it simply makes things too complicated for me (and personally, I don't need the flexibility).
  • er woot? why would the ID change upon room change. That makes no sense at all ... an ID should identify an entity from the moment of join until the moment of leave, be it an ID in Photon or a SessionID in a website ...
  • I haven't checked if they really do change - but the way I understand it, actorNrs are only unique per room and NetworkingPeer has
    public void ChangeLocalID(int newID)

    ... so I wouldn't rely on the ActorNrs not changing.

    Btw, changing stuff to ushort was a *very* bad idea. Very very bad to be precise. While doing so, I changed:
    this.mLocalActor = new PhotonPlayer(true, -1, this.playername);

    this.mLocalActor = new PhotonPlayer(true, 0, this.playername);

    ... and did have this feeling of "oh, I might have just broken something". A little later, I spent a few hours trying to figure out why my login procedure just stopped in the middle. Reason was: My client considered itself to be the MasterClient because CheckMasterClient failed because the ID was no longer -1. Epic fail! ;-)

    Well, now I still got some issues with NetworkViewIDs getting "0" as viewIDs sometimes. Not sure what the problem is with that, yet ... and too tired to figure it out today. But it certainly feels much better to have proper "level prefixes" again :-)
  • Jashan is right: ActorNumbers are per room. Once you leave a room and join another, you will get a new ID. Per room, all IDs are used just once: If player 1 leaves, that actorNumber won't be used again in this room.
  • Ah, awesome: DONE :-)

    Now I have "level prefixes PUN == level prefixes Unity networking" (at least according to how I understand level prefixes in Unity ... basically, I got PhotonViewIDs working like NetworkViewIDs ... at least the way I understand it ;-) ).
  • @Exit Games: Who should I send my changes to for review? I've got the package plus a document with all the changes I made and why I made those changes ... feel free to use this, or not ... whatever the needs are. It's mostly the issue with the prefixes that PUN used in a very different way from how it is done Unity. My version does it "more the same way as Unity does it" but it's incompatible with the previous version (if someone uses level prefixes extensively ... and also in some other areas).
  • If you like please send it to Tobias via PM or to [email protected], thank you!
    It might take a while to get feedback since he's currently attending the Unite conference.