Search Unity

Very new to networking: Unity freezing when connecting to Twitch

Discussion in 'Multiplayer' started by WilliamHarmon, Sep 14, 2017.

  1. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    I followed a brief tutorial and it seems like I'm getting some functional behavior, but am getting locked up somewhere.

    Behavior:
    >Run my scene with my IrcClient script attached to an object
    >enter chat in the twitch lobby
    >I have the ircClient set up to receive text typed into chat and respond. This works once, and no responses are found after that.
    >Stop running scene.
    >Run scene again: This leads to Unity freezing and having to be force closed.

    Attaching the script, I am pretty much at a loss for what it's locking up on. My script is very rudimentary so I'm hoping it's just something really basic that I'm missing? Any and all help greatly appreciated.
     

    Attached Files:

  2. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17

    To elaborate, the problem seems to be here: (for those that haven't read the script, getMessage() is called in a new thread on Start(), and this loop exists within it).

    while (true)
    {
    try
    {
    readData = irc.readMessage();
    msg();
    }
    catch (System.Exception e) //(Exception e)
    {

    }
    }

    When I receive a message, msg() is hit, I hit break points, step through it and when it returns to the subsequent irc.readMessage() call, it just dies? No idea.

    specifically, in irc.readMessage() there is a call to inputStream.ReadLine(); and this just seems to be where things are stopping? Though I have no idea why it would still allow me to close the project, and then freeze on next run attempt? Perhaps something with
    void OnDestroy()
    {
    irc.leaveRoom();
    }

    not working correctly?
     
  3. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    What you want to do:
    Make getMessage run on the main thread and return a IEnumerator. Invokr it on start and make it yield null after each iteration of the loop. Read up on Coroutines (which is ehat i just explained) to understand how it works. If you don't. Let me know and ill explain it

    And to the reason it's freezing:
    When your application exits the thread with the loop is still there. You need to exit it / join it before exit.

    But coroutines are probably more prefered in this case
     
  4. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    Thanks man! I'll try this out and look into coroutines. I've used them before but only in systems that other devs have set up and don't really know the ins and outs of them. If you have specific suggestions on how to best use them, I'd love to hear, otherwise I'll just read up on some documentation.
     
  5. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17

    Hmm still freezing on me. It makes it through a single pass of the while loop and then Unity locks up. Tutorials I'm finding seem to suggest I'm using the coroutine correctly?

    I appreciate the help. If you have time to take a look, am I doing something obviously dumb?

    https://gist.github.com/anonymous/5bb0f245567c8f6f17503741e62e7436
     
  6. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Ok now your GitHub looks much better than your first. However you are doing "getMessage" to call a function, you should just StartCoroutine(getMessage()); did you check and see if that is where it is breaking now?
     
    WilliamHarmon likes this.
  7. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    StartCoroutine(getMessage()); and StartCoroutine("getMessage"); seem equivalent in function, but it makes it into getMessage(), which successfully steps through readMessage() and msg(), and when it finishes that single iteration of the loop, it seems to step out at the yield return null (back to the end of Start() where the StartCoroutine() was called) and at that point unity freezes up. I feel like It's something with the way I'm using the coroutine itself rather than the irc aspects of it?
     
  8. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    I think that entire thing might need a rewrite, I tried to make sense of it.... in msg method it starts with if false,... if what is false, that is not an enumerator, its not checking a Boolean at all. You should also probably throw a check in there to make sure buffer size has something in it before bothering trying to do anything else. You check if completed message is true before you try to respond, then afterwards is where you set it to true so if you need that code to go off it won't until the next time it is called. Which may be the problem that would make your co routine cause a thread blocking situation.
     
    WilliamHarmon likes this.
  9. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    Yeah the if(false) was just a debug attempt to isolate the problem. I wanted the else statement to always be hit, which it is. Currently, my program is making it through the 'end of else' check comment down there (which is just checking to make sure I've connected. It receives something like a dozen messages right on connection).

    When it does that, it's basically making its way down on the next pass through the loop, and dying on message = inputStream.ReadLine(); which makes no sense to me? I assume StreamReaders have checks to make sure ReadLine() handles empty lines or something (not getting any input), so how it can just die there I'm completely lost on.

    I've moved around the coroutine call as well?

    As twoten up there said:
    "Make getMessage run on the main thread"
    Which it should now be doing, and that gets me through the sign in process, but it is still locking up as soon as that is completed.

    Current state: https://gist.github.com/anonymous/fc46151bbb522711d7d7c3444ae574cf


    Also want to say I tremendously appreciate all feedback.
     
  10. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    I've continued to poke at this, and the problem seems to really be this:
    while (true)
    {
    readData = irc.readMessage();
    StartCoroutine(msg());
    }

    Whether or not that while(true) is in a coroutine or in the main thread once the initial sign in process is completed, Unity just freezes up. But all the networking tutorials have some varient of this step where you stay in a loop to continually receive responses from the connected server and send messages back.

    If this is what's freezing unity up, how does one get around this integral step? I assume Unity -can- support irc connections without dying?
     
  11. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    A coroutine is a method that can pause execution. If you call yield return null. Then basically that will put the method on hold until the next frame.
     
    WilliamHarmon likes this.
  12. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17

    Yeah, I think I've got those working. What I've seen stepping through break points is this step:

    tcpClient = new TcpClient(ip, port);
    inputStream = new StreamReader(tcpClient.GetStream());
    .
    .
    .
    message = inputStream.ReadLine();

    when I connect to the server outside unity (running basically this same script within Visual Studio 17 using a form. The exact script is as follows : https://gist.github.com/anonymous/6c8e2d68e7b442d936e914f6a76e0999

    it prints the following:

    upload_2017-9-16_17-29-47.png

    "I'm connected" there is a message I typed into my Twitch channel manually, so it was picked up by my little bot script running. Fantastic.

    However, back to inputStream.ReadLine();
    In Unity after I receive the message: :tmi.twitch.tv ROOMSTATE #william_tgf
    it cycles back through the loop, hits ReadLine(); again, with nothing else to read, and locks up and dies. Despite being on a separate thread or within a coroutine.

    It's almost feeling like this just isn't somethig Unity supports? It doesn't even seem to be threads getting stuck in loops. It's almost as if when there is no message to read, StreamReader just can't function in that environment? Even debugging in VS just shows:

    upload_2017-9-16_17-34-53.png
     
  13. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I have not taken a good look at your code, but why are you using a coroutine, and a while(true) statement will always lock unity if its on the main thread as far as I know.

    Shouldnt you have things like this?
    Code (CSharp):
    1.   public void getMessage()
    2.     {
    3.         serverStream = irc.tcpClient.GetStream();
    4.         int buffsize = 0;
    5.         byte[] inStream = new byte[10025];
    6.         buffsize = irc.tcpClient.ReceiveBufferSize;
    7.     }
    8.  
    9.     void Update()
    10.     {
    11.         readData = irc.readMessage();
    12.         msg();
    13.     }
    14.  
    15.     void msg()
    16.     {
    17.        //......
    18.     }
     
    WilliamHarmon likes this.
  14. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    That's possible. However it doesn't seem to solve the problem. Even using that set up (and calling StartCoroutine(getMessage()) in Start(); causes Unity to die at the same point as before:

    at the first inputStream.ReadLine(); call after the initialization messages are received (basically, the first time it tries to read a message where one ought not exist).

    That StreamReader functionality being supported at all is sort of where I'm at?
     
  15. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    With the setup I gave, you should not be calling any coroutines. We removed the need for a coroutine and just used the Update method.

    Mind if you show me the updated code?
     
  16. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    I think I also see why unity fails and your windows form doesnt.
    In your windows form you have this
    Code (CSharp):
    1. try
    2. {
    3.     readData = irc.readMessage();
    4.     msg();
    5. }
    6. catch(Exception e)
    7. {
    8.  
    9. }
    but in unity you dont have that try catch block.

    If you put this, then it should avoid the error, but you still have an error that you should really fix...
    Code (CSharp):
    1.     void Update()
    2.     {
    3.         try
    4.         {
    5.             readData = irc.readMessage();
    6.             msg();
    7.         }
    8.         catch(Exception e)
    9.         {
    10.             Debug.LogError("Somethings wrong!");
    11.         }
    12.     }
     
    Last edited: Sep 17, 2017
    WilliamHarmon likes this.
  17. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    The Debug log there would never be, and upon testing isn't hit, because the problem seems to be the inputStream.ReadLine(); call within readMessage();

    it seems like within Unity, for whatever reason, if the StreamReader doesn't have a line for ReadLine() to read, it just torpedoes the whole engine.

    Would a better question be, when dealing with connecting to irc servers, does Unity have some class other than StreamReaders that it prefers? If anyone has done irc connection within Unity, that would be a great first place to start I think?
     
  18. WilliamHarmon

    WilliamHarmon

    Joined:
    Mar 9, 2017
    Posts:
    17
    In fact even this does nothing to stop the engine from crashing:

    Code (CSharp):
    1.  
    2.     public string readMessage()
    3.     {
    4.         string message = "";
    5.         try
    6.         {
    7.             message = inputStream.ReadLine();
    8.         }
    9.         catch (System.Exception e)
    10.         {
    11.             UnityEngine.Debug.LogError("Somethings wrong!");
    12.         }
    13.         return message;
    14.     }
    15.     }
    Goes into the try block. Trying to call ReadLine(); and dies.
     
  19. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Googling the issue, it seems people using c# StreamReader.ReadLine even outside of unity seem to have their program hang as well. They say that ReadLine basically hangs the program until it finds a line to read. The reason your windows form didnt seem to have any problems is because you put the StreamReader in a separate thread while in unity its on the main thread.
    Some say to do this...
    Code (CSharp):
    1.     public string readMessage()
    2.     {
    3.         string message = "";
    4.         try
    5.         {
    6.             if(inputStream.Peek() >= 0)
    7.             {
    8.                 message = inputStream.ReadLine();
    9.             }
    10.         }
    11.         catch (System.Exception e)
    12.         {
    13.             UnityEngine.Debug.LogError("Somethings wrong!");
    14.         }
    15.         return message;
    16.     }