Search Unity

Safe Coroutine

Discussion in 'Assets and Asset Store' started by Dantus, Apr 27, 2014.

  1. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Safe Coroutine overcomes several limitations of Unity's coroutines and provides you with flexible controls.

    Main Features
    - Stopping of any safe coroutine
    - Pausing and resuming
    - Nesting
    - Exception handling
    - Returning of typed results
    - Source code

    Converting your code to use safe coroutines is straight forward.



    Example
    Code (csharp):
    1. //
    2. // Author:
    3. //   Andreas Suter (andy@edelweissinteractive.com)
    4. //
    5. // Copyright (C) 2014 Edelweiss Interactive (http://www.edelweissinteractive.com)
    6. //
    7.  
    8. using UnityEngine;
    9. using System.Collections;
    10. using Edelweiss.Coroutine;
    11.  
    12. namespace Edelweiss.Examples {
    13.    
    14.     public class SafeCoroutinesExample : MonoBehaviour {
    15.        
    16.         private SafeCoroutine m_SafeCoroutine;
    17.        
    18.         private void Awake () {
    19.             m_SafeCoroutine = this.StartSafeCoroutine (ExampleCoroutine ());
    20.         }
    21.        
    22.         private IEnumerator ExampleCoroutine () {
    23.             while (true) {
    24.                 yield return (null);
    25.             }
    26.         }
    27.        
    28.         private void OnGUI () {
    29.             GUILayout.Label ("Safe Coroutine State: " + m_SafeCoroutine.State);
    30.  
    31.             GUILayout.BeginHorizontal ();
    32.             GUI.enabled = m_SafeCoroutine.IsSelfPaused;
    33.             if (GUILayout.Button ("Resume")) {
    34.                 m_SafeCoroutine.Resume ();
    35.             }          
    36.             GUI.enabled = m_SafeCoroutine.IsRunning || (m_SafeCoroutine.IsParentPaused  !m_SafeCoroutine.IsSelfPaused);
    37.             if (GUILayout.Button ("Pause")) {
    38.                 m_SafeCoroutine.Pause ();
    39.             }
    40.             GUI.enabled = m_SafeCoroutine.IsRunning || m_SafeCoroutine.IsPaused;
    41.             if (GUILayout.Button ("Stop")) {
    42.                 m_SafeCoroutine.Stop ();
    43.             }
    44.             GUILayout.EndHorizontal ();
    45.         }
    46.     }
    47. }
     
    Last edited: May 7, 2014
  2. kenshin

    kenshin

    Joined:
    Apr 21, 2010
    Posts:
    940
    It seems really interesting, great work Dantus!
     
  3. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,649
    Bookmarked, that for me will generally mean deal...
     
  4. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Looks like a good plug. How much?
     
    Last edited: May 6, 2014
  5. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    10$
     
  6. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks for the interest. I am surprised that there is already positive feedback, even if no one couldn't try it out so far :)
     
  7. kenshin

    kenshin

    Joined:
    Apr 21, 2010
    Posts:
    940
    We absolutely trust in you and your nice video! ;)
     
  8. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    This is...great! Gimme, I need that now! :D
     
  9. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    That feels like getting a trustworthiness diploma :)

    It seems that the review took longer than usual recently, so try to stay cool meanwhile :D
     
  10. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    I'm also interested in this package. two features i would like to see to make the package "complete" in comparison to similar packages:
    pushing the coroutine back and forth between Unity's main thread and a background thread.
    serializing the state of a coroutine into a binary (or arbitrary) formatter so it can be saved to disc or sent over network. (note: whydoidoit's Radical Coroutines do this by using reflection of the inner states of a gameobject)
    i don't know how much work is involved with these feature requests or if they are possible at all. But maybe you could consider them.
     
  11. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Even if both ideas kind of sound interesting, I struggle to see use cases that make sense in an actual production.
    When code is being executed outside of the main thread, it can't e.g. perform any MonoBehaviour calls, unless there is a special solution for that. But in that case, it is good to be aware that something special is happening and to consciously consider that when coding. There are pretty good solutions for threads available like https://www.assetstore.unity3d.com/#/content/3847 . I believe that coroutines and threads should not be merged.
    I wasn't aware of Radical Coroutines up until now. To be honest, I never though about serializing a safe coroutine and I am really unsure whether it is a good idea to serialize them at all. Right now, I can only see cases where this may lead to invalid application states, so it feels pretty dangerous and unstable to me and I think there are probably better solutions for that than serializing coroutines themselves. Having that functionality in UnitySerializer can somehow make sense, but integrating serialization into safe coroutines that can't serialize its internal state at all...
    Do you use serialization for coroutines in an actual production? And could you explain me, why you decided to use it and nothing else?

    If I had a marketing department, they would probably kill me after such an answer :)
    I could have written that I thank you a lot for those ideas and consider them for a future release and bla bla bla. As I don't have any use cases in mind that can only be achieved like that or it would be far more complex to achieve them, I don't see a reason to have that kind of functionality. But please, feel free to name me use cases that are relevant in a production environment.
     
  12. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    killing is bit harsh, but torturing ... ;).

    i'm aware of that. thats why some packages allow to run a coroutine in a thread and when it needs access to unity main thread stuff join it in and after that let it run again in a separate thread. i have sent you a pm with some examples to avoid advertising other packages.
    albeit i have not used it yet it seems quite handy to me.

    i have tried the package of whydoidoit a while back and found it way too bloated and dependent. so i could not extract the coroutine stuff i need and i did not want to include the whole package as i run my own serialization and want more controll. so currently i don't use coroutine serialization.

    what do you mean with "nothing else"? to me a coroutine is a black box and so i cannot know in which state it is when i want to save the game and more importantly i cannot resume it from that state later on after loading. so i must find "workarounds" which lead to coroutines not beeing useable for the things i thought they should be used for.

    a more or less artificial usecase example:
    a missile is started, travels to the target, the missile is removed and an explosion spawned and after it has finished it is also removed. i have not worked on the weapon handling in detail just collected some thoughts about it so maybe i'm doing it wrong. sure there may be other ways to accomplish this but are coroutines a completely improper way? if not then beeing not able to save them is still a hindrance and thats why i asked what you think about this.

    anyway. please don't feel obligated to add this stuff. i was just curious what you think about it. your package has some nice features (esp. exceptions) and thus it would be cool to have features i have seen in other packages in one place. having them distributed over packages (currently i have 3 or 4 at hand) requires to decide which is needed most in which case and choose the used package and also to learn several packages. kind of inconvenient. thats why i asked. i see this could be a big struggle to add and don't know if its worth it for you (revenue) and other users. maybe see what other people think about it.
    thanks anyway for the discussion.
     
  13. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    :)

    As I said, I have no marketing department ;) . Though I appreciate it, that you didn't post the links!
    https://www.assetstore.unity3d.com/#/content/15717
    https://www.assetstore.unity3d.com/#/content/15106
    https://www.assetstore.unity3d.com/#/content/2597
    https://www.assetstore.unity3d.com/#/content/3586

    I am going to have a look at them.

    If you tell me what kind of access you would need to serialize a safe coroutine, let me know. Maybe we find a solution like that. Supporting one serialization may absolutely be possible, but would be too restrictive for my taste. So if I could provide some kind of API to allow the serialization and deserialization, I would absolutely be open to implement that as long as there is a maintainable solution with a clean API.

    What I meant with "nothing else" was, and not any other solution than serializing the coroutines. In my opinion a coroutine should never contain state information that is relevant to resume a game.

    You would want to be able to save the game while a missile is being shot and then resume at this point some days later? It would be very uncommon to allow that.

    Thanks for the feedback. I am always open to discuss!
     
  14. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    Just one thing:

    You mentioned in your video, that there is only one limitation: One can't yield a Unity Coroutine inside a SafeCoroutine.

    The question: When using your SafeCoroutines, is there still any need using Uniy Coroutines? SafeCoroutines give so much control (Pause, Resume, Stop. Maybe "Rewind" in the future, too?), why should I still use Unity Coroutines, especially inside SafeCoroutines?
     
  15. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    There is no need to use Unity coroutines anymore if you have Safe Coroutines. It was mentioned for the sake of completeness. Rewind doesn't exist and is not planned at the moment.
     
  16. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Safe Coroutine was updated. It now contains state change notifications. The video was updated as well.
     
  17. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    Updated? Is is already out and I missed it? :D
     
  18. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Sorry, my message was confusing. I updated it and submitted it for review. It is still pending.
     
  19. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Safe Coroutine is now available in the asset store.
     
  20. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    Finally. Bought it. Can't wait to play around :)
     
  21. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Great! Let me know if you have questions or feedback!
     
  22. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Bought! I might not get to use this for awhile. Wish I had this a month ago, there were 2 great things I could have used it for. Thanks for making this.
     
  23. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I am glad you like it!
     
  24. Merrik44

    Merrik44

    Joined:
    May 8, 2013
    Posts:
    38
    Do safe coroutines persist even if the script is disabled and re enabled? Unity's coroutines are killed if you disable the script, which really annoys me.
     
  25. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The answer is unfortunately no. As you disable a script, all its safe coroutines will also be stopped. Safe coroutines rely on Unity's coroutines, that's why the behavior regarding disabling scripts is identical.
     
  26. Merrik44

    Merrik44

    Joined:
    May 8, 2013
    Posts:
    38
    Damn, thanks for the quick reply. I will keep dreaming :)
     
  27. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You may consider to implement your custom extension method for that. Just create a new game object that is unknown to all others as much as possible. As you then e.g. perform a call like:
    Code (csharp):
    1. this.StartYourCoroutine (...);
    It is supposed to forward the execution to that special game object, that may even be created dynamically as needed.
     
  28. Merrik44

    Merrik44

    Joined:
    May 8, 2013
    Posts:
    38
    Thanks Dantus, I will try that
     
  29. Teku-Studios

    Teku-Studios

    Joined:
    Sep 29, 2012
    Posts:
    257
    Thanks for this asset, it is just what we needed and you saved us a lot of time. Simple, easy to learn and very professional, we wrote a review in the Asset Store to help you gain some attention :)

    We are planning to jump to Unity 5 anytime soon, will this package also work there, or do you need to update it first (don't know how Assets work in Unity 5)?
     
  30. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks a lot for the kind words :)

    Safe Coroutine already works in Unity 5. The versions for Unity 4 and 5 are identical. As far as I know, you can only see that there is a version for Unity 5, if you open the Asset Store in Unity 5.
     
    Teku-Studios likes this.
  31. ramonjlongiii

    ramonjlongiii

    Joined:
    May 10, 2014
    Posts:
    3
    Hello!

    I am very interested in this asset, and I am wondering if this asset has been tested with WebGL in Unity 5.x? Dies this asset rely on the .NET threading libraries?

    Thank you for any feedback.
     
  32. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The last time I checked it with WebGL, it worked without any issues. It doesn't rely on any threading library, but only on Unity's coroutines. As such it is only using a single thread.
     
  33. ramonjlongiii

    ramonjlongiii

    Joined:
    May 10, 2014
    Posts:
    3
    Thank you for the prompt feedback. What I am hoping to achieve is to "block" on a coroutine until it is finished; specifically, my games rely on certain data being available from a WebSocket (using the WebGL socket example published by Unity) before the game manager class can finish initializing. How can I use your asset to wait until a CoRoutine is finished before executing the next statement in a method?
     
  34. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You can even achieve that with Unity's coroutine. Just start a coroutine, execute the required functionality in it and as the last step you finish the initialization.
    With Safe Coroutine, you may subscribe to such a safe coroutine and let the finish initialization be executed after the coroutine is done. However, for this use case, you don't get an actual advantage and you should rather stick to using Unity's coroutines.
     
  35. mirrorlink

    mirrorlink

    Joined:
    Dec 22, 2014
    Posts:
    1
    Hello Dantus! I have a question.

    When I put a safe coroutine to download a huge file on android, can I pause the download and resume it by user interation or when the application is paused and goes to background?

    Thanks!
     
  36. matej_mnoucek

    matej_mnoucek

    Joined:
    Mar 6, 2014
    Posts:
    17
    Hello,

    please does this asset support WebGL ?

    Thanks!
    M.
     
  37. BrendanLoBuglio

    BrendanLoBuglio

    Joined:
    Apr 9, 2014
    Posts:
    7
    Hi, there! So I'm noticing a specific issue when pausing:

    if I start a SafeCoroutine, let it hit a `yield return new WaitForSeconds(10f)` wait for >10 seconds, and then resume it, the SafeCoroutine will resume at the end of the WaitForSeconds line, even though it was paused during it. In other words, it seems that the timer for a WaitForSeconds will "keep counting" even while paused.

    Notably, the SafeCoroutine will not go past the yield -- just right at the end. All the same, this is a decently sizable problem, and I'd love to know if there's a workaround!