Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Running on main thread issues when using _channel.Bind() in Pusher SDK

Discussion in 'Scripting' started by miladxandi, May 2, 2024.

  1. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    That`s my code which we changed a lot because of an error!

    This is "LoadingRoom.cs":

    Code (CSharp):
    1. private string baseUrl = "https://example.com/";
    2.  
    3. void Start()
    4. {
    5.         try
    6.         {
    7.             StartCoroutine(InitialisePusher());
    8.         }
    9.  
    10.         catch (Exception e)
    11.         {
    12.             Debug.Log(e.Message);
    13.         }
    14. }
    Then we initialize the pusher & sign in the user, then subscribe it to a channel and bind for an event in the code:

    Code (CSharp):
    1. private IEnumerator InitialisePusher()
    2. {
    3.         if (_pusher == null && (APP_KEY != "APP_KEY") && (APP_CLUSTER != "APP_CLUSTER"))
    4.  
    5.         {
    6.              _pusher = new Pusher(APP_KEY, new PusherOptions()
    7.  
    8.             {
    9.                 Cluster = APP_CLUSTER,
    10.  
    11.                 Encrypted = true,
    12.                 Authorizer = new HttpAuthorizer(baseUrl + "api/auth/authorizer")
    13.                 {
    14.                     AuthenticationHeader = AuthenticationHeaderValue.Parse("Bearer " + PlayerPrefs.GetString("token"))
    15.                 },
    16.             });
    17.             _pusher.Error += OnPusherOnError;
    18.             _pusher.ConnectionStateChanged += PusherOnConnectionStateChanged;
    19.             _pusher.Connected += PusherOnConnected;
    20.             yield return new WaitUntil(() =>
    21.  
    22.             {
    23.                 _channel = _pusher.SubscribeAsync("private-" + PlayerPrefs.GetString("Channel")).Result;
    24.  
    25.                 if (_channel != null)
    26.                 {
    27.                     return true;
    28.                 }
    29.  
    30.                 return false;
    31.             });
    32.             _pusher.Subscribed += OnChannelOnSubscribed;
    33.             _pusher.ConnectAsync();
    34.         }
    35.  
    36.         else
    37.         {
    38.              Debug.Log("Error in credentials");
    39.         }
    40. }
    41.  
    42. private void PusherOnConnected(object sender)
    43. {
    44.         _channel.Bind("connected", (PusherEvent data) =>
    45.  
    46.         {
    47.             StartCoroutine(GetList()); //⬅️Everything is ok but a bug happens here when we want to run the StartCoroutine() method in here. I found out it`s because it will run on a different thread than the main thread so I cannot use the StartCoroutine() or even any other simple method in here!
    48.         });
    49. }
    But I got this error:
    Error:
    Error invoking the action for the emitted event connected:
    IsObjectMonoBehaviour can only be called from the main thread.
    Constructors and field initializers will be executed from the loading thread when loading a scene.
    Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

    Because we want to wait for the "GetList" method which that`s an IEnumerator; to be completed, we cannot run it on the Start or Awake methods.
     
    Last edited: May 2, 2024
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,657
    Bunny83 likes this.
  3. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,657
    If I had any idea I would've helped. :)
     
  5. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    Yes if you had so.
     
  6. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    Is GetList() awaitable? If so, await it.

    Otherwise make a call to a method on the main thread and start the coroutine there.

    UnityMainThreadDispatcher is one way to do so.


    But I would scrutinize the whole setup. Particularly the WaitUntil part makes me think (also: cringe) there must be a better way than to try to subscribe every frame (!) to an async event. Is the Pusher API generally awaitable to begin with, for instance? Then you wouldn't need that first coroutine.
     
    miladxandi likes this.
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,657
    I'm here moderating the forum. I was here to tell you about code-tags and removing your cross-post on General Discussion.
     
    Bunny83 likes this.
  8. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    This is a very short summary of larger code & the InitialisePusher() should run inside a Coroutine, so do not waste your time on code optimizations, the challenge is in threads and other things are working properly.
     
  9. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    Thanks, now let us focus on the main challenge please. You posted more than me and problem solvers on this thread.
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,657
    That's fine but please edit your post to use code-tags.

    Thanks.
     
  11. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    557
    Store the Unity SynchronizationContext in a field during Awake or Start
    _contextField = System.Threading.SynchronizationContext.Current

    Then use it to invoke your code on the "main" thread
    _contextField.Post(x => { StartCoroutine(GetList()); }, null);
     
    miladxandi likes this.
  12. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    You mean this:
    Code (CSharp):
    1. using System.Threading;
    2. private bool lists_checked = true;
    3. private SynchronizationContext syncer;
    4. void Awake()
    5. {
    6.     syncer = SynchronizationContext.Current;
    7. }
    8.  
    9. _channel.Bind("connected", (PusherEvent data) =>
    10. {
    11.     try
    12.     {
    13.         Debug.Log("Called");
    14.         lists_checked = false;
    15.         syncer.Post(x => { StartCoroutine(GetList()); }, null);
    16.     }
    17.     catch (Exception e)
    18.     {
    19.         Debug.Log(e.Message);
    20.     }
    21. });
    22.  
    23. IEnumerator GetList()
    24. {
    25.     if (!lists_checked)
    26.     {
    27.         lists_checked = true;
    28.         Debug.Log("Calling...");[/INDENT]
    29.     }
    30. }
    But now printing a bunch of "Calling..." in the console!
    How should I stop it after one time of running?! inside of the "GetList" I`m sending a web request to my server to update the list of current players are joined to this room.

    Web 1920 – 1.png
     
    Last edited: May 2, 2024
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,362
    As long as you obdurately refuse to format your code, most people such as myself are not even going to look at it.

    If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/

    - Do not TALK about code without posting it.
    - Do NOT post unformatted code.
    - Do NOT retype code. Use copy/paste properly using code tags.
    - Do NOT post screenshots of code.
    - Do NOT post photographs of code.
    - Do NOT attach entire scripts to your post.
    - ONLY post the relevant code, and then refer to it in your discussion.

    We see this every day, people like you who think the forum rules don't apply to them. Well sure, they don't. But we also don't have to look at your code.

    Good luck!!
     
  14. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    Ok grandma! I fixed it, now check it up and stop hating me.
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,362
    Good lord your imagination is running completely wild here. I don't hate anyone. I looked over every single word of the post I made above and I have no idea where you get "hate" from. Maybe it's a language barrier thing??

    Perhaps by setting and checking a boolean??

    Either way... it sounds like it is time to start debugging!

    By debugging you can find out exactly what your program is doing so you can fix it.

    https://docs.unity3d.com/Manual/ManagedCodeDebugging.html

    Use the above techniques to get the information you need in order to reason about what the problem is.

    You can also use Debug.Log() to find out if any of your code is even running. Don't assume it is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.
     
  16. miladxandi

    miladxandi

    Joined:
    Apr 25, 2017
    Posts:
    11
    Friends pusher has some serious problems with unity, I couldn't find any solution for this because of a lack of docs & experience using Pusher!
    use ABly instead of pusher, it`s more update and useful.