Search Unity

SyncList not Initialized during Awake()

Discussion in 'Multiplayer' started by Zullar, Sep 21, 2015.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I am using SyncLists and I notice they throw errors when I use them during the Awake() method. This seems to be new to 5.2. Anybody else having this problem?

    The flow I'd like to achieve is:
    -Instantiate object on server
    -Set SyncVar's during server Awake()
    -Spawn object on client. All SyncVar's should be set by the spawn so correct values are there when OnStartClient() is called... this is why I'm trying to set SyncVar's during Awake() and not Start()

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking; //needed for NetworkBehavior
    5.  
    6. public class TestSyncListAwake : NetworkBehaviour
    7. {
    8.     private SyncListInt syncListIntTest = new SyncListInt();
    9.  
    10.     private void Awake()
    11.     {
    12.         syncListIntTest.Add(5); //this causes error "SyncList not initialized"!!!!
    13.     }
    14.  
    15.     private void Start()
    16.     {
    17.         syncListIntTest.Add(3); //this works fine without error
    18.     }
    19. }
    20.  
    Thanks in advance.
     
  2. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    87
    I've found Awake isn't safe for other UNet things too, such as isServer. Though I noticed this before 5.2, and have generally adapted to use Start for any initialization reliant on the network.

    Might be really handy to see an updated version of the Unity Execution Order doc, with UNet and UnityUI referenced.

    (for reference: http://docs.unity3d.com/Manual/ExecutionOrder.html)
     
    Zullar likes this.
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Thanks for the link. I agree that would be handy if manual was updated with UNet initialization orders.
     
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
  5. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Thanks for link. I agree with the object creation flow and I'm *trying* to do that, but running into "SyncList not initialized" errors when attempting to set SyncList values during Awake() on the server before spawning. See picture below. I'm not sure the proper way to handle this.

    upload_2015-9-21_12-59-23.png
     
  6. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I'm still struggling with this.

    If I set SyncList during Awake() it throws "SyncList not initialized" error
    If I set SyncList with external initialization function (called immediately after instantiate) it throws "SendBytesToReady object TestPrefab(Clone) (UnityEngine.GameObject) has not been spawned" warning.
    If I set SyncList during Start() the SyncList will not be set before spawning unless somehow I add a frame or two delay between instantiate and spawn.

    What's the proper way to set SyncList before spawning?

    Thanks in advance.
     
    Last edited: Sep 22, 2015
  7. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    So I've been doing some more testing and found something that works (although it throws error messages). My current flow is to.

    1: Instantiate prefab on server
    2: During prefab server Awake() method I set the SyncList (this throws "SyncList not initialized" errors... but functionally works just fine!)
    3: Spawn prefab on clients (they get the proper SyncList values)
     
  8. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    why do you need to use Awake? why cant it just be an initialization function you call on the object before it is spawned?
     
  9. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I tried an initialization function called externally to the prefab after Awake() but before Start(). This throws "SendBytesToReady object TestPrefab(Clone) (UnityEngine.GameObject) has not been spawned" warnings.

    I am not sure why it is throwing warnings when setting SyncList before spawning, because that is the intended flow from my understanding.
     
  10. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Still struggling with this. Is anybody else using SyncList's? If so how do you initialize the SyncList before spawning?
     
  11. Capn_Andy

    Capn_Andy

    Joined:
    Nov 20, 2013
    Posts:
    80
    SyncValues don't seem to initialize until OnStartClient is called, which is called after Awake but before Start (typically, anyway). I get around this by either creating my own "Init" function which I call OnStartClient, or by feeding the variables to another controller object for storage.
     
    Zullar likes this.
  12. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Does OnStartClient call Init, or does your Init call OnStartClient? Do you mind pasting your code?
     
  13. Capn_Andy

    Capn_Andy

    Joined:
    Nov 20, 2013
    Posts:
    80
  14. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    I put this info in:
    Code (CSharp):
    1. public override void OnStartClient()
    2.     {
    3. }
    and it get's rid of your errors
     
    Zullar likes this.
  15. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I am still having problems with this. OnStartClient() call is delayed and occurs after spawning (not before!).

    I instantiate object and immediately spawn it. Adding debuggers shows things occur in this order on the server.

    -Instantiate prefab on host
    -Prefab.Awake()
    -Spawn
    -Prefab.OnStartClient()
    -Prefab.OnStart()

    I suppose maybe delaying the spawn (i.e. have it called OnStart) would work for instantiated objects. But how do you handle scene objects?
     
  16. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I think I figured out the proper order to initialize.

    For SceneObjects
    The order things are called
    Server.Awake()
    Server.OnStartClient()
    Server.Start()
    ---at some point here the object is "Spawned" automatically on the client
    Client.OnStartClient()
    Client.Start()

    SyncVars/SyncList should be set during Server.OnStartClient() or Server.Start(). If you set them during Awake() or through external initialization before OnStartClient then it causes errors. Even if the SyncVars/SyncList values are set during Server.Start() the correct values are replicated to the client by the time Client.Start() is called.

    For SpawnedObjects the correct order seems to be
    -Spawn prefab on server
    -During server prefab Start() or OnStartClient() set the SyncVars/SyncList values
    -At the end of server Start() call NetworkServer.Spawn(gameObject). Do NOT call spawn externally before prefab.Start() is called or the SyncVars/SyncList values will not be initialized.
    -The SyncVars/SyncList values will be correct by the time Client.Start() is called.
     
  17. chenyuchih

    chenyuchih

    Joined:
    Jun 3, 2015
    Posts:
    37
    That's because unity sneakly add some code in Awake function to initialize synclist

    so for your code, it will become
    Code (CSharp):
    1. private void Awake()
    2.   {
    3.         syncListIntTest.Add(5); //this causes error "SyncList not initialized"!!!!
    4.        this.syncListIntTest.InitializeBehaviour(this, ...);  // initialize here
    5.   }
     
    Zullar likes this.
  18. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
  19. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Am I missing something? How do you do an initialization function call on the object of SyncLists before it is spawned in? Or am I thinking too hard on this?
     
  20. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    It seems that objects are spawned after Start() is called. So the order of events is something like this.

    1: Host: Awake (tied/random)
    1: Client: Awake (tied/random)
    2: Host: Start
    3: Host calls Spawn:
    4: Client: Start

    So if you initialize the SyncList during Host Start they will be the recent updated values when Client Start is called. I *think*...

    It's all very finicky to get working right, but the 1 rule I have is don't do ANYTHING during Awake(). Hope this helps.
     
  21. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Alright, finally got my mind cleared out. Thanks @Zullar.
     
  22. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    5.3.4p1 still not fixed. Throwing "SyncList not initialized" errors if you try and use SyncList.Add() during Awake()
     
  23. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Please show your SyncList code, so we can take a look at it. I don't know if your code has been updated with the suggestions given above, or the code is still the same as the very top post of this thread.
     
  24. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I did some testing. 5.3.4p1

    It appears that calling SyncList.Add() during Awake still throws "SyncList not initialized" errors in the editor console, but it actually seems to work just fine.

    Here's code to replicate error (again even though error is thrown it still seems to work OK and adds to the SyncList correctly). I'll bug report.

    Code (csharp):
    1.  
    2. public class TestSyncListInitialize : NetworkBehaviour
    3. {
    4.     private SyncListInt syncListInt = new SyncListInt();
    5.     private void Awake()
    6.     {
    7.         syncListInt.Add(10);  //This throws "SyncList not initialized" error
    8.     }
    9. }
    10.  
     
    Last edited: Apr 4, 2016
  25. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    EDIT: This post is super irrelevant. Please read my other post below this post.
     
    Last edited: Apr 5, 2016
  26. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    SyncListInt isn't a MonoBehaviour and doesn't have .Awake() and .Start() methods.
     
  27. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Sorry about that. I scanned your code very quickly, and thought something differently. Now that I've checked the documentations, have you tried InitializeBehaviour() ?

    You pass in a NetworkBehaviour class and a hashcode. Problem is, I don't know what cmdHash is supposed to be. Maybe a custom hashcode?
     
    Zullar likes this.
  28. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    I know this is kinda old thread, but I'm trying to implement a custom SyncList based on bitbucket source to test custom serialization. Does anyone know how is cmdHash generated for InitializeBehaviour?

    Edit: nvm, you can actually override serialization code without writing a custom class.
     
    Last edited: Jun 27, 2017