AI:Save/Load

From OpenTTD

Jump to: navigation, search


Contents

[edit] Save

If you create a Save() function in your AI, you can store some data inside the savegame. You can only store integers, strings, arrays, tables and booleans. Instances of classes can't be saved. Please note that this includes AIList, so if you want to store an AIList, you have to convert it to an array or table on save and convert it back on load. The Save() function should return a table with the information you want to store. That table can contain integers, strings, arrays, tables and booleans, but only nested to a maximum level of 5 deep. As soon as the users saves the game, the Save() function of your AI is called. This happens while your AI is still active doing what ever you made it do. For example, in the middle of a pathfinding, or maybe when you are changing an internal array. The point here is, that your AI won't notice it, besides the fact that the Save() is called for a moment. When you return from that function, your AI continues like nothing happen. Warning: if you change a variable that you also store, and want to make absolutely sure no race-conditions happen, do it right after a Sleep(). The chances of the Squirrel fair-scheduler kicking in just after a Sleep() are very slim, so you should be relative safe.

Note: No other information is saved, so for example all pending events are lost as soon as the game is loaded. To circumvent this you can store all events (converted to allowed types) in the savegame yourself. However, the game will continue normally after the Save() function is called, so you also need to handle those events.

[edit] Load

If a savegame with an AI in it is loaded, OpenTTD tries to start the same AI as the game was saved with. If this fails (for example, you send your savegame to your friend who does not have all AIs you have), it'll load a random AI that is available. First the constructor of your AI is called, and after that your Load() function is called, even if the AI that saved the data is not the same as the one that is started now. Because of this you should check all savedata for validity before trying to do anything with it. The Load() function gets exactly one parameter with as value the data that was saved by the AI. If an AI didn't save any data, the Load() function won't be called.

[edit] What data to save?

Of course what data you save exactly is up to you, but as a general rule you shouldn't save anything that can be easily detected by reading the map again. So you can store a mapping of truck station to industry, but storing just a station list is useless.

[edit] What you can't do in your Save() and Load() function

Both the Save() and Load function() are called from within the main thread. This means that it is not possible to execute any command that builds / removes / changes something in the game. You can execute some API functions, but only those that fetch data. Please try to minimize the code in Save() and Load(), as the user has to wait for those functions everytime they save and load a game.

[edit] Example Save() / Load() code

class testai extends AIController
{
  constructor()
  {
    counter = 0;
  }

  counter = null;
};

function testai::Save()
{
  local table = {counter_value = this.counter};
  return table;
}

function testai::Load(data)
{
  if (data.rawin("counter_value")) {
    this.counter = data.rawget("counter_value");
  }
}

function testai::Start()
{
  while(true) {
    AILog.Info("Tick " + this.counter);
    this.Sleep(70);
    this.counter++;
  }
}
Personal tools