Search Unity

Third Party Photon - Will ViewIDs of scene objects be the same from build to build?

Discussion in 'Multiplayer' started by Olipool, Feb 14, 2021.

  1. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    Hi there,

    I am trying to implement a save system to my game and also need information about the hierarchy objects are in.
    For example, at the start of the game if there is a basket with apples on (0,0,0) and a player puts one apple from that basket into another basket and I only save the absolute position. Then, when starting a new game and loading the savegame the apple will be in the second basket but will move with the first one because as default it is parented to the first one.

    To identify the parent object I am thinking about using the Photon-ViewID because most of the movable objects have that ID anyway. So my question is, if I store this ID in a json file will I be able to load this again even after multiple restarts and rebuild of Unity and the game? Or may it happen one day that the apple is parented to a door or something? I don't have spawned any prefabs, just scene objects that have an ID at edit time. And I don't want to delete objects with views from the level and put them back in later (this may change the ID most likely).

    Thanks for the info!
     
  2. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,735
    As the viewIDs are allocated at runtime, I imagine you can't guarantee that any particular object will get the same viewID everytime. Certainly if you add or remove scene objects from one build to the next the viewIDs will be different.

    For serialising state, you may be better off generating a unique ID from the objects position/rotation in the scene, or better still add a component that uses system.GUID to generate an ID when you place the object in the scene, which was the approach I took for my latest game.
     
    Olipool likes this.
  3. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    Thanks, so maybe I just make a simple ID component where I can input an ID that never gets changed. Regarding the viewID I am doing the same with the PhotonViews, I assign/get assigned IDs at edit time, they are not newly generated at runtime (are they??) because players will have to have the same IDs on different computers.

    One issue I don't know how to assure though is when I deleted an object from the scene and add it back or change it etc. that the object ALWAYS has the same ID because savegames that are 3 years old should still work.
     
  4. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,735
    ViewIDs are generated at runtime and synchronised with all connected clients at the time they are allocated. There are a number of factors that influence the viewID that is allocated to any particular networked object making it practically impossible to guarantee any object will always have the same viewID.

    I guess it's possible to achieve that, but, if I understand you correctly, it means you'll need to maintain a database of every GUID you ever allocate to every scene object when designing scenes, and then if you remove and subsequently re-add that object you can check the database and give it the same GUID it had originally. I think however, this is prone to errors and ultimately won't work.

    Preferably, I would just have the save/load game system ignore or convert anything it tries to load that doesn't exist anymore, that's how I do it myself.
     
    Olipool likes this.
  5. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    Thanks, I guess I will try to maintain such a database/excel sheet with the IDs so if something breaks I am able to fix it in the next version. But I also will assume in code that IDs may not be working (like if a parent does not exist anymore I will parent the object to null or create a new gameobject at the position of the old parent).

    But I am curious, how are these IDs synchronized if the objects don't have fixed IDs?
    For example a cube has the viewID of 12 in the editor and at runtime an ID of 25 is generated, how does any other client know for what object the 25 is for? I thought that was the point of the IDs to identify objects between clients.
    When a new object is instantiated it is no problem, it may be a message to all clients "create a cube with id 30". But with fixed scene objects...I don't know :)
     
  6. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,735
    How and when are you creating these scene objects? Are you using PhotonNetwork.InstantiateSceneObject() or some other method?
     
  7. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    No, I am creating them in the editor e.g. I am placing a cube, putting a PhotonView on it and it gets a new number between 1 and 999 (being scene object). So it sits already in the scene when the game starts (it is an escape room style game where you inspect and combine objects). So I thought those IDs stay the same.
     
  8. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,735
    I've only ever instantiated networked scene objects at runtime, however placing them in the scene will mean they will keep that ID at runtime.

    You might want to check with the PUN developers if the ID allocated in the editor is guaranteed to stay the same long term, as ultimately that's out of your control, being something that is controlled by their code.
     
    Olipool likes this.
  9. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,072
    The editor scripts will try to keep the IDs static but every time you add one, there may be a clash (the prefab has the ID as well, sadly, and may clash with an existing ID). The result is that the clashed IDs are replaced by some that don't clash.
    Long story short: Sadly, you can not rely on the IDs staying the same, without customization.
     
    Olipool and Munchy2007 like this.
  10. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    Thanks to you both, I am not using prefabs right now but who knows and who knows if the Photon logic changes someday, so to be on the safe side I will make my own IDs. :)
     
    Munchy2007 likes this.
  11. Olipool

    Olipool

    Joined:
    Feb 8, 2015
    Posts:
    322
    Just to round this up for future devs, this is my first design of the ID-class.
    Reset() gives the next available number automatically when the component is put on a gameobject and OnValidate() makes sure you can't have to same IDs without getting an error in the log:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Linq;
    3.  
    4. [DisallowMultipleComponent]
    5. public class GameObjectId : MonoBehaviour {
    6.  
    7.     [SerializeField]
    8.     private int id;
    9.  
    10.     public int Id
    11.     {
    12.         get
    13.         {
    14.             return id;
    15.         }
    16.  
    17.         set
    18.         {
    19.             id = value;
    20.         }
    21.     }
    22.  
    23.     private void Reset()
    24.     {
    25.         if (id > 0) return;
    26.  
    27.         int highestId = 0;
    28.         GameObjectId[] gameObjectIds = Resources.FindObjectsOfTypeAll<GameObjectId>();
    29.         if (gameObjectIds.Length > 0)
    30.         {
    31.             highestId = gameObjectIds.Max(go => go.id);
    32.         }
    33.         id = highestId + 1;
    34.     }
    35.  
    36.     private void OnValidate()
    37.     {
    38.         GameObjectId[] gameObjectIds = Resources.FindObjectsOfTypeAll<GameObjectId>();
    39.         if (gameObjectIds.Length == 0)
    40.         {
    41.             return;
    42.         }
    43.         GameObjectId gameObjectId = gameObjectIds.FirstOrDefault(go => go.id == this.id && go!=this);
    44.         if (gameObjectId == null || gameObjectId==this)
    45.         {
    46.             return;
    47.         }
    48.         Debug.LogError("id " + id + " on "+gameObject.name+" already taken by " + gameObjectId.gameObject.name, this.gameObject);
    49.     }
    50. }
    Also, I made this editor menu add-in to give this component to all selected objects, so you don't have to do all this by hand (needs to be in the Editor folder in the project):
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class MenuHelperFunctions : MonoBehaviour {
    5.  
    6.     [MenuItem("Component/Plugins/Add IDs to selected gameobjects")]
    7.     static void Execute()
    8.     {
    9.         foreach (GameObject obj in Selection.gameObjects)
    10.         {
    11.             obj.AddComponent(typeof(GameObjectId) );
    12.         }
    13.     }
    14.  
    15.     [MenuItem("Component/Plugins/Remove IDs from selected gameobjects")]
    16.     static void Remove()
    17.     {
    18.         foreach (GameObject obj in Selection.gameObjects)
    19.         {
    20.             DestroyImmediate(obj.GetComponent(typeof(GameObjectId)));
    21.         }
    22.     }
     
    Munchy2007 likes this.