[devtalk] load file patching


There was not much progress on chapter 11, so in this month’s “check-in” post I will discuss briefly the load file patching method I learned from the Twine discord server.

Some changes to the story are easier to update with, such as fixing typos in the narrative (or changing some locally-scoped code, like the dialogue/conversation loop). Some changes to variables can be fixed at the next chapter update, such as if I wanted to change a flag variable’s name, I can just check for its existence at the start of the next added chapter (where every reader will reach), make a new variable with the right name to replace it, then delete the old flag variable. But when I need to systematically change how a set of variables are tracked and/or organized, readers on earlier chapters will lose the variable’s values before they reach the latest chapter where the update happens. So this method is not always enough.

The solution is to use Config.saves.onLoad to make changes to a reader’s saved file when they next load it to continue the story. The main structure of the Javascript code looks like this (simplified example from my project):

Config.saves.version = 3;
/*
if this variable was never used before, starts with number 1;
if there was already a patch done before,
increment it by a whole integer value;
don't use decimal values or string values
*/

Config.saves.onLoad = function (save) {

  if (!save.version) {

    /* Do stuff to any Save created before
       Config.saves.version was assigned a value.
    */
    save.state.history.forEach(function(moment) {
      let v = moment.variables;
      v.trusts = {};
      v.trusts["yang"] = v.trustEmperor;
    });

    save.version = 1;
    /* now can go into the next switch block */

  }

  switch(save.version) {

    case 1:
      /* code to upgrade from version 1 to 2 */
      /* note: no break! no default either */
      save.state.history.forEach(function(moment) {
        let v = moment.variables;

        if (v.loveYang > 0) {
          if (v.loves === undefined) { v.loves = {}; }
          v.loves["yang"] = v.loveYang;
        }
        delete v.loveYang;

      });

    case 2:
      /* code to upgrade from version 2 to 3 */
      /* note: no break! no default either */
      save.state.history.forEach(function(moment) {
        let v = moment.variables;

        /* complicated code not shown here */

      });
  }
};

When you are first publishing a project for the public to play (who would potentially make use of the save/load feature), your code might not have a Config.saves.version value. That’s fine, which is why the first if block of the function checks if that save file doesn’t have version, make the first initial changes. Remember to give Config.saves.version a value from then on. For your first patch, that may be all you need. The next patch might be weeks or months later, so most save files readers have might already have a version number (may be 1, or another value). Assuming you increment it by 1 each time you make a new patch, you can then use a switch statement to do the incremental updates. The reason there is no “break” in this switch is because we want the patching process to go from 1 to 2 to 3, and so on without exiting before all necessary changes are made, and there should not be a “default” part either because we cannot apply the correct changes to a save file that we don’t know the version number of.

Note that inside this onLoad function, you are not doing anything to the State.variables object, only changing the contents of the save file (and specifically each moment/state in the saved history), such that they will then be copied over to the State.variables object after this function is processed. I once made a mistake of using existing functions here to set the new values, which doesn’t change the save file content.

Test your patch code as best as you can before publishing it to the web. Once it’s public, someone might have already loaded a save to continue reading the story, so if you need to fix an incomplete or faulty patch, you have to increment the Config.saves.version number and add another “case” block in the switch statement. Unless you are certain nobody has viewed the new updates yet, then just quickly upload the new code. 😅

In my example, my Config.saves.version is at 3, meaning I have already “patched” the code 3 times (not counting the simpler fixes that doesn’t require this method). Now I just need to remember to increment this version number for my next major patch… 🙏

Leave a comment

Log in with itch.io to leave a comment.