Saving and loading a coroutine state

I’m betting that what I’m looking for can’t be accommodated by Unity/Mono, but it’s worth a shot to ask:

Imagine you are using coroutines for aspects of the game and mission. You want the ability to save a game, which implies saving the states of all coroutines, and the ability to load up the level and resume those coroutines at the point they were when the game level was saved.

It’s something I have working in a different game using Lua coroutines (with a plugin called Pluto), but I suspect that a Mono coroutine is a very different beast.

Does anyone know if this can be done in Unity?

I’m looking to do this as well. The way I understand it a coroutine stores its state in an enumerator, so if you could save that enumerator you should be able to restore the coroutine later. The question is: how do you store the enumerator? It’s a complete black box, and it isn’t serializable.

Well… here’s a blog post that talks about continuation in mono:

Not sure if it is possible, however I have noticed posts from people who talk about serializing IEnumerble types. How it’s done I’m not sure…

This is over complicated to think about, and you can simplify it. Although I don’t know if I will have the time to do the modifications by this weekend, you can get the save/load xml code from the wiki that I posted, expand the UserData to support all of the aspects of an object you want to save, change it so that it doesn’t look at the Player gameobject but instead is attached to the object you want to save then have an OnApplicationQuit() code that says to save that object.

All objects that you want to have saved state, do something like

void OnApplicationQuit()
{
   SaveMe();
}

Here is the catch 22, this will work fine for saving the object, but this means you have to have a “Intro” scene that is your “load game” or “start new game” menu, that sets a variable of do not destroy on load to true if it is to load a previously saved game, then all Start() routines look to see if this global variable is true, if it is true, then you use LoadMe() and have it load the data.

I realize this sounds complicated, but it really isn’t to bad once you think about it. Also, the “load game” could also load a list of saved games and give them an option of which one they want to load, images and all if you want, and then when you loadlevel, you keep a few things by not destroying them, one which is a variable saying that you are loading in a prior game, another which is the file name of the file to load from, then the LoadMe() pulls info from that saved file.

That is all the process really is.
Once the data is loaded, you just apply transform to the object, and set its variables during the Start() routine.

Sorry zumwalt, but that’s not what we’re asking for. It’s not saving the state of game objects – it’s saving the state of coroutines running on game objects.

I already have a fully working save system using XML and whatnot to save the position, rotation, movement etc. of characters. The only missing piece is the ability to save the state of any actions those characters are performing. And since those actions are defined as coroutines, I’m looking for a way to save coroutines.

There is no difference -at all- between the actions and anything else. Your character has properties and what not associated with it, you simply save the last state of those to the xml file. Your not going to be able to ‘freeze’ the state and save that binary information. You simply add to your save routine, more child elements that you can load in and reset the actions to.

This includes items like ammo count, inventory information, location, rotation, etc etc. As I mentioned earlier, at the load you have your start routine simply capture that from the file and apply it back to your variables for your characters or items or what ever.

Any variable you can think of, you can save its information, anything you can save, you can load and re-apply.

If you already have a save routine, just expand it to save this additional information. Its not that complicated since you already know how to save stuff.

Thanks zumwalt, but I’m afraid you’re still barking up the wrong tree. What we’re asking isn’t the general “How do you save stuff?” but the very specific “Is it possible to save the state of a coroutine?”

Let me give an example. Say I have the following script with a coroutine that gets called from somewhere:

public class Character extends MonoBehaviour
{
  public IEnumerator DanceWith(Character target)
  {
    GrabHands(target);
    yield return new WaitForSeconds(2);
    DoTheChaCha(target);
    yield return new WaitForSeconds(3);
    Spin(target);
    yield return new WaitForSeconds(2);
    DoTheRumba(target);
  }

  ...
}

Now, what if that coroutine is running and has gotten to the second yield when the user saves the game. If I just save the variables of the character, then when I load the game again, the coroutine won’t be running anymore, and the spin and rumba will never happen.

I know that one solution to the problem is to not use coroutines at all, or to use coroutines but save state to variables yourself, or to use a state machine etc. But that’s not what I’m asking for. What I’m asking is if there is a general way to save the state of a coroutine and resume it later? The state is obviously stored somewhere internally, but is it possible for us to get to it?

Thanks for the links and details. For now I’ve relegated myself to save-points, which aren’t so bad, and will fit the bill. I’ve created an API of sorts where you leap from coroutine to coroutine (one at a time), with a save point occurring in-between each leap. When the saved level is loaded, the next coroutine starts up.

As simple solution which points back to my original comments, a coroutine is absolutely nothing more than a method being run that has public and private variables. You area “saving” some things but you want to know what state your coroutine is in, follow my original instructions and ad the following example, hopefully this is more clear as to how to do this:

public class Character extends MonoBehaviour 
{ 
  public int DanceWithState;
  public bool DanceStateBegin;
  public IEnumerator DanceWith(Character target) 
  { 
    if(!DanceStateBegin)
    {
        GrabHands(target); 
        DanceWithState=0;
        yield return new WaitForSeconds(2); 
        DoTheChaCha(target); 
        DanceWithState=1;
        yield return new WaitForSeconds(3); 
        Spin(target); 
        DanceWithState=2;
        yield return new WaitForSeconds(2); 
        DoTheRumba(target); 
        DanceWithState=3;
     }
     else
     {
        Switch(DanceWithState)
        {
            Case 0:
            {
               GrabHands(target); 
               DanceStateBegin=false;
            }
            Break;
        }
     }
  } 
  ... 
}

Now, as I mentioned in my very first response, you can save “anything” there is absolutely no difference in coroutines and the rest of your program. So, on application quit, you save the state of the value to DanceWithState, you serialize your Character class, and save the value of DanceWithState, on Start() you load this value, you give it a default of -1 or something, when it starts, you set your value to 3, also, you have a second value that says if we have to do something with the value which is the DanceStateBegin, just think outside the box, this works.

Can’t get much easier than that.

I think the problem here is not how to save the part of the function that has last been called as much as the part of the coroutine. For instance, lets look at this snippet:

GrabHands(target);
DanceWithState=0;
yield return new WaitForSeconds(2);
DoTheChaCha(target);

Lets say that we are 1.5 seconds into the WaitForSeconds statement when the user tries to save. All that is saved with your method is the fact that DanceWithState=0. If you then load the variables back to resume where you left off, it will still GrabHands for the full 2 seconds. The actual saving of the coroutine state which I believe is the problem being asked about is how do you save the 1.5 seconds that have passed so you know where in the coroutine you were when you saved.

You have to override the WaitForSeconds and write your own function that does the delay and saves the current ticks passes into a variable, it is just another level of saving. Since Unity doesn’t save this value anywhere, you have to override their method with your own, now if theirs is not overridable, you simply write your own yield method and make it do what you want. Once again, it is a simple variable you want to save, how deep into the routines you go to save things is up to you.

You follow the same logic on loading, part of the Start would have to tell the method where you left off, its something you have to write, but it is extremely easy enough to do with either overrides or overloads.

That and you can use delegates and events to trigger these save routines. It is practically the exact same logic though, just one more step deeper into the WaitForSeconds routine.

It might be possible after all. This page describes how to serialize standard iterators in .NET. I haven’t tried it with Unity coroutines yet though. I’ll let you know if it works out.

It’s worth pointing out that coroutines are not essential. (For example, I don’t think any of my games uses them.) To eliminate a coroutine which yields for N seconds, you generally would have to manually manage the current state of the object and the time elapsed. In your Update you would check if it was time to proceed to the next state… In other words, you would explicitly be tracking the time-elapsed in a variable, which makes it easy to save and restore.

So by making the timing an explicit part of your object, rather than use coroutines, you’ve made it easier to save/restore your object. (Bummer if you like coroutines, obviously.)

Depending on the game, another way to accomplish this might be to instead store all game events that occur, and the exact time they occur. Playing back the events in order, at the right times, will get you back to the state you wanted to save.

Of course you’d want to play back the events much faster. You can use Time.timeScale to speed up the physics and any action that is Time based. I believe even YieldForSeconds obeys the time scale.

This simple description hides a fair amount of work, but if the game is architected around the requirement, it should be doable. (Also lets you playback a saved game as if it were a movie, letting the player move the camera wherever they want. You could even let them “break-in” to a saved game wherever they want to see if they can improve on the earlier result.)

So here’s a hypothetical JavaScript file MyScript.js. Type Item is a light class (derived from System.Object) I wrote for interfacing with game objects. I use a helper module called MyApi.js, wherein I have a special function Wait(seconds : float), a function AwaitRange(a : Item, b : Item, range : float) that yields until two Items are within the range. OtherScript.js contains other functions that may block or yield.

api : MyApi;
api = GetComponent(MyApi);
otherScript : OtherScript;
otherScript = GetComponent(OtherScript);

function Routine1() : IEnumerator
{
   var player : Item = Item.GetPlayer();
   var informant : Item = Item.ByName("Informant");
   yield api.AwaitRange(player, informant);
   api.PlayAudio("InformantMessage1");
   yield api.Wait(6);
   yield otherScript.ThisTakesTime();
   while (!player.HasInInventory("Medicine"))
   {
      yield;
   }
   api.DisplayText("Yay!  You have the medicine.");
}
StartCoroutine(Routine1);

Zumwalt, you seem confident that if the game state is halfway through this coroutine (let’s say it is somewhere within otherScript.ThisTakesTime()), and the player pauses and performs a Save action (that I must develop code for of course), that I can save/load the state such that when the player loads the game later, I can have this coroutine pick up right wherever it left off (in this case somewhere within otherScript.ThisTakesTime())?

Call me greedy, but I’d like my local variables as they were as well ;). I guess I could live with using public fields if that won’t work, but definitely an imperfect solution.

I will take the time to explore it. I hope you’re not blowing smoke ;).

Without writting a core scripting system that supports, thta you won’t be able to leave everywhere and reenter everywhere.
You will have to accept tradeoffs.

As zumwalt (at least I guess) to imply, you best split it up in a LUA like coroutine structure.

After the finish of each coroutine section, you store the state, so should it be terminanted, it can be regenerated at that state and pickup again.

As you likely never (should) have states that take a massive amount of time for calculation without entering a clean state again (which can be saved and restored again), such a solution would be more than appropriate to handle the situation.

Such a system actually also would be pretty easy to implement. All you need is a wrapper function that calls the coroutines, and you need to pass in a single dataobject. The wrapper function then will use reflection to get and save the state of the data object before the coroutine and will get and save the state after the coroutine again.
As you can call coroutines by their string name, you can also store the coroutine to which the data were meant to go for even more flexibility.

For an editor its a different thing but editors never pickup where they were, they store the state before the processing and the state after processing, during processing they don’t store anything, the focus on doing their job as fast as possible to reduce the amount of enforced waiting.

And just to mention that: Don’t waste time even considering Unity as a solution for an MMO server. It won’t work unless you are serious and commercially funded so you get the source version, even if you freeze hell :wink: