How to store the state of IEnumertor and resume the state after Load

I have a Human(usually more than 1 instance in the scene). He can do many things like Eating, Reading Books, etc.

What I want to do is **store the which of the IEnumerator is in myEnum and it’s state ** and resume the state after load. I can use other class to replace IEnumerator. I just don’t know.

For example, (see my trial below for codes) he will sleep after reading the book. Before he actually sleep, he needs to move himself to the bed in order to sleep. If the User press Save. I want to save the human what he is doing and the progress. e.g. He is going to his bed, but not yet sleep.
And later when I load the game, I want to restore it. i.e the progress of the Sleep().

The problem is here:

  1. IEnumrator cannot be serialized

  2. Other class will alter the “myEnum” field when needed like the “alarm” will change away the Sleep() to WakeUp(). The new IEnumerator like WakeUp() is public. I have access to it.

    public class Human : MonoBehaviour
    {
    public IEnumerator myEnum = ReadBook();
    Update()
    {
    myEnum.MoveNext();
    }
    IEnumerator ReadBook()
    {
    Vector3 target = Vector3.one;

         while(transform.position!=target)
         {
             transform.position = Vector3.MoveTowards (transform.position,target,1);
             yield return null;
         }
         //The human has arrived his desk
         int progress = 0;
         while(true)
         {
             progress++;
             yield return null;
             if(progress>=100)
             {
                 myEnum = Sleep();
             }
         }
     }
     IEnumerator Sleep()
     {
         Vector3 target = Vector3.zero;
         while(transform.position!=target)
         {
             transform.position = Vector3.MoveTowards (transform.position,target,1);
             yield return null;
         }
         //The human has arrived his bed
         int progress = 0;
         while(true)
         {
             progress++;
             yield return null;
             if(progress>=100)
             {
                 myEnum = ReadBook();
             }
         }
     }
    

    }

To give an actual answer: No, IEnumerators can’r be serialized by default. “Theoretically” it’s possible to use massive amounts of reflection to actually pull out every state information of the compiler generated IEnumerator class and restore it in the same state. However this is very (very) impractical. It would be much much easier to not use a coroutine and store the current progress manually like Blue-Cut said in the comment above.

Restoring the internal state of a generator can be very tricky up to impossible. It usually has several references to other objects. In our case here at least to the script component where it’s defined in. The internal state might also contain types which are difficult to serialize. So generally i wouldn’t recommend even trying this approach.

The same holds true for your MoveTowards call. You move “1 unit per frame”

ps: You don’t really use Unity’s coroutine scheduler but just run your IEnumerator manually each frame. So all your logic is completely frame-based. If a user runs your game on a high end PC without v-sync it’s possible that you get something like 1000 fps. So waiting 100 frames would just be a tenth of a second. Though if running on an iPad you might be forced to run at 30 fps so the same 100 frame delay would take more than 3 seconds.

edit

About actually serializing a coroutine

Note this is only for those who are interested in how something like that could be implemented theoretically

I quickly implemented a very basic serialization test for IEnumerators. It uses my SimpleJSON framework to actually serialize the required data.

First there’s this helper class that contains two methods, one to serialize an IEnumerator and one to deserialize it. Note that each requires two callbacks as parameters. One to handle object references to UnityEngine.Object derived types and one to handle ordinary classes and structs. “Simple” coroutines do not need those two callbacks at all. However as soon as your coroutine has a local variable, parameter of any type beyond primitive types or accesses something from it’s containing class they are necessary.

Here’s a simple testing class which contains two different coroutines. When you attach this script to an object in the scene you will have GUI buttons at runtime which allow you to start one or muliple coroutines of either type. For each running coroutine you will have a stop / remove button which will simply stop the coroutine and remove it from the list. But also a “Pause / Serialize” button which will actually stop the coroutine and serializes it. And also a button to restart / recreate the coroutine in it’s last state from the serialized data. When the coroutine is paused / serialized you will see the serialized data on the right side.

It should be mentioned that the last yield value that was “active” when we stopped the coroutine is lost. So if you do a new WaitForSeconds(3600) this “hour” won’t continue after deserializing the coroutine. There are many things you can yield on but will break when you try to deserialize it at this point. Just imagine a WWW request. That can’t be restored.

I also implemented a quick automatic save feature when you stop / exit the game / application. Every coroutine that still exists when the game exits is saved into a single playerprefs field. When you restart the game the coroutines are restored and continue from the point they were left off. This was mainly to show that it actually works across seperate executions and the state really is stored as text.

Here’s an example how the saved data for the first coroutine looks like:

{
   "coroutineClass" : "SerializeCoroutineTest+<MyCoroutine>c__Iterator0",
   "localVars" : {
      "<i>__0" : "130",
      "<localVector>__0" : {
         "_type" : "UnityEngine.Vector3",
         "x" : 0,
         "y" : 0,
         "z" : 2.15330505371094
      },
      "aTest" : "Test1",
      "$this" : "this",
      "$current" : null,
      "$disposing" : "0",
      "$PC" : "1"
   }
}

I want to address some of the data here. In “coroutineClass” i save the actual internal class name of the IEnumerator object. This is the compiler generated statemachine class which we want to save and restore. This type name is used to recreate the IEnumerator object using reflection. “localVars” simply contains all member fields of this class. The field / variables that start with a “$” sign are internal fields that are generated by the compiler and basically store the state of the statemachine. “$current” holds the last yielded value and “$PC” tells us in which state the statemachine is. However the naming and meaning of those variables are completely up to the used compiler. We don’t really care about them. We just need to restore their values.

As you can see the parameter of my coroutine (aTest) has been transformed into a member variable. So it should be clear that whatever you pass as parameter to a coroutine need to be stored / restored as well. Btw: that’s also the reason why coroutines / generator methods do not support “ref” or “out” parameters as they can’t be stored as variable.

Finally there are two more variables in the class. Originally they have been “local” variables inside the code. The variable “i” has become “__0” and the local Vector3 variable “localVector” has become “__0”. So every local variable you use in your coroutine will actually become a member field of the generated class.

Limitations

This might have given you some idea how complicated it can get to actually serialize an arbitrary IEnumerator. As you can see in the example code i’ve implemented some very crude serialization helper callbacks to handle the “this” reference as well as a Vector3 value. Without those the first coroutine would not have it’s “$this” reference which actually references this script instance. So when not properly restoring that reference the Debug.Log line where i print gameObject.name would throw a null reference exception since gameObject.name is actually this.gameObject.name.

Likewise when the Vector3 is not properly restored, when resuming / restarting the coroutine it would start from “(0,0,0)” (the default value for Vector3).

However this is by far not the end of our problems. For example generic types. To only serialize the exact type of a variable of a generic type you need to recursively rebuild the type. For example a variable like List<List<List<Someclass>>> someVar is basically just a generic List. However we have to serialize all the generic parameters as well. So to just store the type of an generic class you already need a quite complicated recursive process. It’s possible, i’ve done it already, but it’s alot of work to cover all cases.

The next problem is: What abour classes which do not have a default constructor? They can’t be created with the Activator as the only way to create them is to use the available constructor and pass the correct parameters. However it’s impossible to tell what those parameters were from looking at an instance.

A similar problem are delegates. Yes they can be serialized but when they are mixed with closures and generic types it’s a pure mess ^^.

Maybe someone have fun with this. Though as i said in my original answer it’s not really worth to implement a bullet-proof solution for all cases. Most immediate problems where this might be useful can be solved in a different way.