- Joined
- Jul 8, 2018
- Messages
- 1,140
- Reaction score
- 504
- First Language
- English (USA)
- Primarily Uses
- RMMV
After reading a recent discussion on "save scumming" I decided that I'd like to improve my casino implementation by making the number of casino tokens illegible. Since MV and MZ use base64 to provide a basic form of game data protection I decided that perhaps the easiest way to avoid this kind of exploit is to also make the number of casino tokens a base64 value, decode it to make deductions or additions and then immediately convert it back to base64. Most likely I am going to do it at the immediate point where the calculation occurs in order to maximize the amount of data protection, and I may also consider stacking the base64 effect for additional protection.
Anyway, here's the means to do this: btoa encodes to base64, and atob reverses the encoding. So for example, if you have 21 casino tokens saved to variable 77 and you want to encode the value to make it less susceptible to scumming then you would set the variable to use the following script evaluation:
And the resulting value would be MjE=. To get back to 21 tokens you would then use atob() like this:
Note that this is not a perfect solution of course: if you have any text or other variable data that cannot be easily handled in an 8-bit value (read: anything in the Unicode range) then the game will throw an error and stop working. This isn't the game's fault of course, just a limitation of the Javascript function. MDN has a complete explanation over here. Also, it's meant to make it more difficult to modify the variable even if you don't go through the hassle of encrypting the data, the latter of which would be somewhat more involved than this basic mechanism.
Now here's where it gets interesting: what if you want to stack the base64 effect for extra protection of sensitive game data? Consider the following example, this time using a script evaluation:
Starting from 0 (which in programming is actually 1) this counts to 4 (or rather 5) and stacks the encoding that many times. Now instead of the original, four-character value you have an insane, 32-character value of Vm10YWEyUXhTbk5SYkVwUlZrUkJPUT09. And to get back to 21 you use the same number of encoding steps that you used to stack the encoding as follows:
Note the addition of parseInt: this is a Javascript function which takes the returned value (which is a string of text) and parses out the numeric portion into an integer format (so that it's usable as a number). C++, C# and ObjectiveC programmers may consider it the Javascript version of int.Parse, however there is no int object in Javascript and so the parse function is called separately from an object designation. This is important because otherwise mathematical operations will either fail or append to the end of the number depending on the operation, so if you don't do this then something like 99999 + 18 will result in a value of 99999018 or similar instead of the expected result of 100017, which can send your calculations to infinity and beyond.
Anyway, here's the means to do this: btoa encodes to base64, and atob reverses the encoding. So for example, if you have 21 casino tokens saved to variable 77 and you want to encode the value to make it less susceptible to scumming then you would set the variable to use the following script evaluation:
JavaScript:
btoa($gameVariables.value(77))
And the resulting value would be MjE=. To get back to 21 tokens you would then use atob() like this:
JavaScript:
atob($gameVariables.value(77))
Note that this is not a perfect solution of course: if you have any text or other variable data that cannot be easily handled in an 8-bit value (read: anything in the Unicode range) then the game will throw an error and stop working. This isn't the game's fault of course, just a limitation of the Javascript function. MDN has a complete explanation over here. Also, it's meant to make it more difficult to modify the variable even if you don't go through the hassle of encrypting the data, the latter of which would be somewhat more involved than this basic mechanism.
Now here's where it gets interesting: what if you want to stack the base64 effect for extra protection of sensitive game data? Consider the following example, this time using a script evaluation:
JavaScript:
for (var i = 0; i <= 4; i++) {
data = btoa($gameVariables.value(77));
$gameVariables.setValue(77, data);
}
Starting from 0 (which in programming is actually 1) this counts to 4 (or rather 5) and stacks the encoding that many times. Now instead of the original, four-character value you have an insane, 32-character value of Vm10YWEyUXhTbk5SYkVwUlZrUkJPUT09. And to get back to 21 you use the same number of encoding steps that you used to stack the encoding as follows:
JavaScript:
for (var i = 0; i <= 4; i++) {
data = atob($gameVariables.value(77));
$gameVariables.setValue(77, data);
$gameVariables.setValue(77, parseInt($gameVariables.value(77)));
}
Note the addition of parseInt: this is a Javascript function which takes the returned value (which is a string of text) and parses out the numeric portion into an integer format (so that it's usable as a number). C++, C# and ObjectiveC programmers may consider it the Javascript version of int.Parse, however there is no int object in Javascript and so the parse function is called separately from an object designation. This is important because otherwise mathematical operations will either fail or append to the end of the number depending on the operation, so if you don't do this then something like 99999 + 18 will result in a value of 99999018 or similar instead of the expected result of 100017, which can send your calculations to infinity and beyond.
Last edited: