I am releasing my game periodically and have a bad habit of just adding variables after the fact. I have a decent amount of content so I have been asked to initialize new variables so people don’t have to replay everything from scratch.
I know it can be done via Config.saves.onLoad but my knowledge of javascript is basically nil. I’m not sure a) how to check if the variable is undefined via Javascript and b) how to then initialize it. I was thinking something along the lines of On Load If variable hammer is undefined, set hammer to 1. type deal.
I was just about to sign off and go to bed so I haven’t tested this at all (sorry), but it looks to me like you can do this:
Config.saves.onLoad = function(save) {
// Initialize undefined new variables in each moment of the saved history.
for(let i=0; i<save.state.history.length; ++i) {
let variables = save.state.history[i].variables
// Do something like these three lines for each new variable:
if(typeof variables.hammer === 'undefined') {
variables.hammer = 1
}
}
}
Probably someone else will give you a more careful answer…
If you want that, then you’ll need to set variables.hammer the same as you would for $hammer, and you may also need to check to see if those properties are already set on that variable or not.
This would also be a good time to implement version numbers for your releases using the Config.saves.version setting.
So you can check the version property of the Save object, or that code will be updating the hammer variable of every Save from now onward…
(untested)
Config.saves.onLoad = function(save) {
if (save.version === 1) {
/* Apply all the fixes required to update to version 2. */
....
save.version = 2;
}
if (save.version === 2) {
/* Apply all the fixes required to update to version 3. */
....
save.version = 3;
}
...
}
Sorry if its a stupid question but how do you do that. I’ve tried the loop above and it works for normal variables. But most of my variables are stuck in other variables (player.health, NPC.str, etc.). I’ve been tinkering with it but I know nothing about javascript. I assumed it would just be as easy as doing hammer.big instead of hammer, but i keep getting errors. I tried something like this but its not working (assuming that hammer already exists and I want to add big to it)
Config.saves.onLoad = function(save) {
// Initialize undefined new variables in each moment of the saved history.
for(let i=0; i<save.state.history.length; ++i) {
let hammer = save.state.history[i].variables.hammer
if(typeof hammer.big === 'undefined') {
hammer.big = 1
}
}
}
You have to define hammer as an object before you can give it object members or else it’ll throw an error like it’s doing right now.
So something like this:
Config.saves.onLoad = function(save) {
// Initialize undefined new variables in each moment of the saved history.
for(let i=0; i<save.state.history.length; ++i) {
let variables = save.state.history[i].variables
// Do something like these three lines for each new variable:
if(typeof variables.hammer === 'undefined') {
variables.hammer = {};
}
if(typeof variables.hammer.big === 'undefined') {
variables.hammer.big = 1;
}
}
}
Okay, I swear I tried to do something exactly like that before and it didint work and now it is. Thank you very much, I even plugged it into my main game and its doing exactly what I want it to do. Thanks again!
How to fix the problem depends on what kinds of errors you’re seeing.
That said, this should be a more robust method which is simpler to expand:
// Initialize undefined new variables in each moment of the saved history.
Config.saves.version = 1;
Config.saves.onLoad = function (save) {
/* isObject: Returns if a value is an object (not including "null"). */
function isObject (Value) {
return !!Value && typeof Value === "object";
}
/* isProperty: Returns if Prop is a property of the object Obj. */
function isProperty (Obj, Prop) {
var result = false;
if (isObject(Obj)) {
result = Obj ? hasOwnProperty.call(Obj, Prop) : false;
}
return result;
}
/* fixObj: Adds any missing object properties and gives a default value if it doesn't already have one set. */
function fixObj (varName, defaultVal) {
var props = varName.split("."), curVar = vars, n;
for (n = 0; n < props.length; n++) {
if (!isProperty(curVar, props[n])) {
if (n < props.length - 1) {
curVar[props[n]] = {};
curVar = curVar[props[n]];
} else {
curVar[props[n]] = defaultVal;
}
} else {
curVar = curVar[props[n]];
}
}
}
var i, vars;
if (save.version === undefined) {
for (i = 0; i < save.state.history.length; ++i) {
vars = save.state.history[i].variables;
fixObj("hammer.big", 1);
fixObj("hammer.tall", 2);
fixObj("hammer.wide", 3);
}
}
if (save.version < 2) {
for (i = 0; i < save.state.history.length; ++i) {
vars = save.state.history[i].variables;
/* whatever fixObj() calls you need here */
}
}
};
Now you can just keep adding fixObj() lines for any (non-array) variables you need to fix.
let hammer = save.state.history[i].variables.hammer
If hammer is already defined, setting hammer.big to 1 is fine. If hammer is undefined, saying hammer = {} will initialize it as an object, but it won’t add it to the variables object. It’ll be an object not associated with your stored variables, and so it won’t work the way that you want. If you keep referencing it as variables.hammer instead, it’ll be initialized inside the variable object like you want.
Hmm, I am running into two problems with the code.
I don’t have a save version on the older saves so its undefined would that be something along if (save.version === ‘undefined’)?
the code is adding just adding the variables as they are and not as part of other variables. So if I already have player, and I try to add player.health, it just adds health as a normal variable, not as a part of player. I am not sure if I am missing something in the fixObj implementation at the bottom