Online save backup using events

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
Hello ^^ I've been working on this online save backup system for quite some time now. It turned out pretty good and it's highly customizable since it is fully evented.
Want a demonstration?
Save.gifYes, I know proceed is spelled wrong here btw. The Account.txt file is auto generated for verification purposes. Without this file, if anyone enters a name and password that isn't contained in your dev's dropbox, they'll get the 'account exists' message (in the 'Yes, I have an account' choice) but files won't get uploaded or downloaded. That's why it was important for me to create this file. The event checks if this account.txt file exists or not in the dropbox folder and then goes on to say if account truly exists or not.

load.gif

Before I get to the explanations, there's some things you should know:

What is this?
-->This is an evented system through which the players can backup their saves in the developer’s dropbox and retrieve them again when needed.

Why Dropbox?
-->Because I could actually wrap my head around their api. Google drive also has an api but I couldn't understand anything no matter how much I browsed the web for answers. And me being a non-programmer definitely doesn't help. But can you use google drive? Obviously. But honestly, I really hope someone would make a plugin for something like this. Eventing this was toughhh.

Who is this for?
-->People like me… who don’t understand codes and stuff and simply can’t use this plugin right here: https://forums.rpgmakerweb.com/inde...ger-simple-cloud-based-savegame-system.57750/ (If you can, please consider using this plugin. Because making this system work is tedious. Don't proceed if you don't want to go through a lot of trial and error. You have been warned.)

Why would you need to use this?
-->Well… because you can? XD Honestly, I don’t think it’s such a big requirement since it’s not cross platform (it’s only for desktop). But I spent quite some time on this (a lot actually… because I’m lifeless and I sort of enjoyed the process :p) so I’m making a tutorial regardless ✧*。٩(ˊᗜˋ*)و✧*。

But seriously- If a player forgets to backup their saves and they lose the files for whatever reason, they can get them back. This also works if the game is on different computers.

And it doesn’t have to be saves. You can get any other information from the player like a survey. Or maybe a report to see how far they got in the game. As it reads text contents, you can make the game save Player’s info like level, play time, achievements, whatever you want to know about in to a txt file so it gets uploaded to you. I don’t know about other people but I will certainly find it amusing to know how my players are doing ^^

It might work for browser deployment too but I’m not that smart to figure it out. Maybe someone else can utilize this and make a plugin that offers that function.
-----------------------***------------------------​
Well, now that you know if you should use this, let's get to the actual tutorial.

Requirements:
A Dropbox account

-Setting up your Dropbox account-

If your existing dropbox account has decent amount of space, you don’t need a new account since we’re just going to store written content (.txt, .rpgsave, .json etc.) and they're fairly small in size. Consider making a separate dropbox account if you think your remaining space isn’t enough.

Go to https://www.dropbox.com/ and make an account if you want a new one. Or skip to the next step if you already have one.
Go to https://www.dropbox.com/developers/apps and click create an app.
Select the following options:
tutorial1.png

Hit create app
Next, you’ll be taken to a new page with a bunch of settings.

Under the permissions tab,
Tick files.content.read and files.content.write. These are the only ones we’ll need.
Remember to click submit!
tutorial2.png

Under the settings tab,
Click generate access token. You’ll be given a looong random string. You’ll need that so copy it somewhere or it will disappear and you’ll need to generate a new one.
Set Access Token expiration to No expiration.
tutorial3.png

We’re done with the dropbox part.

-Eventing-

Uploading files:


Make a section where you ask the player for their name and password. You can use the Name Input scene for this or any of these plugins here:
Here, I’m using name_password as the folder name. You might not even need a password but a name along with a password makes the combination stronger. This way players can’t access another player’s folder. If my name is HyouryuuNa and my password is iloveprocrastinating~, then my folder name is HyouryuuNa_ iloveprocrastinating~. Unique enough? Yes. What you do here is up to you. You can ask whether the player has a profile. If they do, you ask if they want to load saves. If they don’t have a profile, you can ask whether they’d like to make one. Basically, you can event this part in any way you like.

I’m making the game upload the save file every time the player saves. For this you’ll need Caethyril’s Save Load Switch plugin
(Thank you so much for taking my request Caethyril!)
Get the plugin here: https://forums.rpgmakerweb.com/index.php?threads/caethyrils-plugins.106255/ [under general]
Set the plugin parameters. I’ve set the save switch to 1 and the save Id variable to 4.

Now let’s create the save common event. Every time the player saves, the game will upload the save file to the dropbox account. We use the save switch defined in the plugin parameter (it's 1 in my case) and set the trigger to parallel.
I’ve used this script (Unfortunately I couldn’t find the original source(s) of this snippet. But anyways, thank you strangers. Because seriously, putting this together was really tough for someone with no coding experience like me. I had to browse through numerous threads because one answer didn’t have the whole thing. Oh and you guys will probably need to squish it so it fits the 12 line script space -_-):
JavaScript:
var xhr = new XMLHttpRequest();
xhr.open("GET", "save/file" + $gameVariables.value(4) + ".rpgsave", false); //Reads the save file's contents. Variable 4= Save ID. //You should change the path to www/save/... for after deployment.
xhr.send(null);
var fileContent = xhr.responseText;
var path = "/" + $gameVariables.value(1) + "_" + $gameVariables.value(2) + "/file" + $gameVariables.value(4) + ".rpgsave";
//Variable 1= name and variable 2= password. Here, the folder name is name_password. You can make it name+password, name*password, name&password or simply namepassword lmao
var accessToken = "<Your Access Token here, without the angle brackets>";
var uploadUrl = "https://content.dropboxapi.com/2/files/upload"; //Do not change this
var result;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        result = xhr.responseText;
        //console.log(result);
    }
};
xhr.open("POST", uploadUrl, true);
xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
xhr.setRequestHeader("Content-type", "application/octet-stream");
xhr.setRequestHeader('Dropbox-API-Arg', JSON.stringify({
    path: path,
    mode: 'overwrite',
    autorename: true,
    mute: false
}));
xhr.send(fileContent);
1593279376592.png
Remember to turn the switch off or it will keep on running and you don’t want that.

Writing multiple files:

And I’ve made a ‘Save multiple’ common event too. This is useful when the player decides to upload all saves that has been made beforehand… when they didn’t have a profile. This doesn’t need a switch. Simply call it when the player chooses ‘backup saves’ or something like that.
JavaScript:
for (checker = 1; checker <= 5; checker++) { //Replace 5 with your maximum save file number
    var xhr = new XMLHttpRequest();
    const fs = require("fs");
    if (fs.existsSync("save/file" + checker + ".rpgsave")) {
        xhr.open("GET", "save/file" + checker + ".rpgsave", false); //You should change the path to www/save/... for after deployment.
        xhr.send(null);
        var fileContent = xhr.responseText;
        var path = "/" + $gameVariables.value(1) + "_" + $gameVariables.value(2) + "/file" + checker + ".rpgsave"; //Var 1=name, var 2=password
        var accessToken = "<Your Access Token here, without the angle brackets>";
        var uploadUrl = "https://content.dropboxapi.com/2/files/upload"; //Do not change this
        var result;
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                result = xhr.responseText;
                //console.log(result);
            }
        };
        xhr.open("POST", uploadUrl, true);
        xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
        xhr.setRequestHeader("Content-type", "application/octet-stream");
        xhr.setRequestHeader('Dropbox-API-Arg', JSON.stringify({
            path: path,
            mode: 'overwrite',
            autorename: true,
            mute: false
        }));
        xhr.send(fileContent);
    } else {}
}

Reading files:

I swear, this part had me banging my head against the pillow. I don’t want to get hurt ( ≧Д≦). I managed to make it work… but with the help of two variables. I wanted to do this without any game variables at all but for loop was not working and I had to step outside the little script call space.

JavaScript:
var path2 = "save/" + $gameVariables.value(11); //var 11= the ID of the save file. Saves in the 'save' folder. Change it to www/save/ for after deployment
var path = "/" + $gameVariables.value(1) + "_" + $gameVariables.value(2) + "/" + $gameVariables.value(11); //var 1= name, var 2 = password
var token = "<Your Access Token here, without the angle brackets>";
var url = "https://content.dropboxapi.com/2/files/download"; //as usual, don't change the url please
var result;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status != 409) {
        result = xhr.responseText;
        var fs = require('fs');
        fs.writeFile(path2, result, function(err) {
            if (err) throw err;
            console.log(result);
        });
    } else if (xhr.status == 409) {
        $gameVariables.setValue(12, $gameVariables.value(12) + 1) //when save files are missing, simply ignore them and continue forward
    }
};
xhr.open("GET", url, true);
xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.setRequestHeader('Dropbox-API-Arg', JSON.stringify({
    path: path
}))
console.log(JSON.stringify({
    path: path
}));
//console.log(path2 + " " + result);
xhr.send();
1593280019093.png

I guess we’re done with all the basic stuff. The rest is up to your creativity. You can use the save and load script in combination to create any type of 'menu' you want.
Don't hesitate to ask me if you have any questions ^^ Though I don't have much coding knowledge, I'll try to help. Have fun eventing ^^
 
Last edited:

Kes

Veteran
Veteran
Joined
Aug 3, 2012
Messages
22,299
Reaction score
11,718
First Language
English
Primarily Uses
RMVXA
A very neat idea, and you've obviously put a lot of work into this, so well done.

There is one potential problem. At one time if someone's dropbox got a lot of traffic, dopbox would decide that really it was a business account, and therefore you either had to upgrade to a paid box, or they would shut it down. I don't know if that is still the case, and it would only be a potential problem if your game was popular and you had a lot of players saving to dropbox. But it might be worth checking that out.
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
Oh I didn't know this :( That certainly is a problem... Personally I don't have any fear of this happening to me since in no way I'm getting so many people play my game :") But other people might face this problem. Maybe I should update my post with this bit of info
 
Last edited:

Kes

Veteran
Veteran
Joined
Aug 3, 2012
Messages
22,299
Reaction score
11,718
First Language
English
Primarily Uses
RMVXA
Before you do that, check out that the info is up to date. It might be that things have changed over the years.
 

ShadowDragon

Veteran
Veteran
Joined
Oct 8, 2018
Messages
3,184
Reaction score
1,185
First Language
Dutch
Primarily Uses
RMMV
the other issue (not major), if you let players to have maxmum 2 save files or event 1,
they can create as many accounts as they wish as well for multiple save files that way.

what if the player lost his account or forgot to write it down? they have to start from
the very beginning, if not overwriting if the the other person have the exact same
name/account (name + password) it will be rare, but possible :p

the idea is nice though, but error's might come if the save file is not compitable with
a newer version ^^ nice job otherwise.

No idea that this was even possible :)
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
@ShadowDragon That is true. I actually intended for this to happen and even I used 4 different accounts to test it. I don't think this would cause players to misuse the system as they can already do this by backing up saves manually within their computers. The whole idea is to just keep... less attentive players from losing their saves and to let devs keep an eye on their players XD (not gonna lie, my interest is the latter one)

It is probable that players might forget their name/password. But I've made it so that the game remembers... sort of like 'remember this password?' setting in browsers. All you need is a little bit of creativity to solve these issues. Hint: a txt file is what you need ^^

And yeah, I have no answers for the this one... There's nothing to do if save files aren't compatible with newer versions... I think they might be if the game doesn't change anywhere in the middle. Games with chapters might work... like, after chapter 1, chapter 2 was released as a completely different segment. Then the save files will work I think. But if any new content is added in chapter 1, it might break. That's a problem...

But if you decide to use this for something other than saves, then none of this might be a problem because you can just let the game upload anonymous files. For example, I don't need to know who is doing what, I don't even know these people by name... so why? I only need an overall report of the situation. I'll probably make the game update me on how many times a person has died, how and at what difficulty so that I can change the settings to be more appropriate. Or I can just laugh at how bad my players are at the game XD (or cry because that means I didn't balance the difficulty properly)
 
Last edited:

ShadowDragon

Veteran
Veteran
Joined
Oct 8, 2018
Messages
3,184
Reaction score
1,185
First Language
Dutch
Primarily Uses
RMMV
you can rather say? it's a basic built to get you started :p

but there are many things that needs to be fixed.
either way, the 12 line and without the big parts can be way shorter
if you create a simple plugin with a fuction like,
function api(var1, var2, api) {
code here
}

than you can basicly use api(var1, var2, apikey)

and your good to go (you have to test to see if its work), and you can adjust the code
in the plugin easier, but you still need to do a bunch of work to get a smooth non-cheat way
like, check the OS of the player if they have an savefile/account, if it exist, warn the player,
or want to delete the current savefile to create a new one? and or ID.

creative ways must be added for sure, but nice basis :)

maybe when you find a way or simple way to avoid issues.
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
That'd be VERY convenient. But as I said, I know nothing about javascript and plugins. I started to work on this for my own use but later decided that I'd share it as it is. I'll see if I can make a small plugin out of this.
As for the remember setting, this is a relevant part of it:
1593369206663.png
I saved the name,password to a txt file after the player filled the info AND the account doesn't exist in the dev's dropbox (it's free to use)[for new account creation] and account exists[existing account] so that the game doesn't ask repeatedly every time for name and password.
 
Last edited:

KotoYama

Veteran
Veteran
Joined
Apr 20, 2019
Messages
210
Reaction score
18
First Language
Spanish
Primarily Uses
RMMV
Would it be possible to just make Dropbox store player's variable's values etc without them having to login or anything?
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
You can store variables but how will you know which one belongs to which player? They'll be overwritten if there's no identifier and you can't retrieve them later on. So a login method is necessary. Or you can just differentiate them via their IP addresses. That way they won't need to type in anything. You can do so by using a node module that gets a device's IP address. Instead of maling a folder with name, you just make a folder with their IP.
Edit: I'm not sure if using IP address for this sort of thing is an ok to do :/ Best not to I suppose.
 
Last edited:

KotoYama

Veteran
Veteran
Joined
Apr 20, 2019
Messages
210
Reaction score
18
First Language
Spanish
Primarily Uses
RMMV
I don't need to know which one belongs to whom. I was thinking about doing that to balance my game properly. Welp, using their IP doesn't sound so hot xD

I'm sure there's a way to do that through Steam Stats, but Archeia's Greenworks plugin doesn't support them and I can't figure it out by myself :D

Also, I really dought she's gonna include this feature... Considering plugin's new unwelcoming $100 price tag.

Alright, probably gonna create a separate thread for that. Thanks anyways.
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
Yep, better make a thread. This is a very basic way to do stuff and not very efficient or reliable for complex game mechanics. Personally, I won't even use this XD I just need to store a few variables like playtime and choices to understand what most players are going for or if they're taking too long to solve a puzzle. Sort of like analytics. So I don't even need the login method. Wouldn't matter if it's anonymous.
 

KotoYama

Veteran
Veteran
Joined
Apr 20, 2019
Messages
210
Reaction score
18
First Language
Spanish
Primarily Uses
RMMV
Well, that's exactly what I'm looking for but I don't know how that will work with Steam's privacy policy. Plus, what are the chances that someone has used Stats for their Steam game?
I'll probably need to hire someone for that :DD when I make some money...
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
There was a google analytics plugin but I don't remember where I found it. It was japanese and I didn't understand anything so I couldn't use it. Basically it does the same thing- keeps track of some variables and switches and acts like a statistics of sorts.
 

KotoYama

Veteran
Veteran
Joined
Apr 20, 2019
Messages
210
Reaction score
18
First Language
Spanish
Primarily Uses
RMMV
Oh, @SigmaSuccour knows something about that? :D Though I think it's a bit too much to ask...
If not, I'll try to find it by myself and will contact Steam support. See what they have to say.
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
You could make a thread about that. The discussion is going off topic and not about this particular evented system.
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,548
Reaction score
3,298
First Language
Binary
Primarily Uses
RMMZ
neat system! I do think the code could be more generalized and made into a small plugin with various script calls. That'd also make things neater when using the calls in events. :)
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
I thought about that too but I don't have much knowledge on plugin making XD I tried to make a very basic plugin to make simple script calls but there was always one issue or another. I guess basic js is all I can handle ;__;
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,548
Reaction score
3,298
First Language
Binary
Primarily Uses
RMMZ
Code:
class HyosCustomClass {
    static trigger() {
        console.log("I am being triggered!!!");
    }
}

Would perhaps be the simplest example for how to write a custom 'script call'. All a script call is, is a way to trigger a function on an instanced class object, or a static class function. Static functions do not require an instance of the class to be initialized (ie, new HyosCustomClass()).

Using the above snippet in a plugin, and then triggering `HyosCustomClass.trigger()` would print to the console, or run whatever code in in the function. Hope that helps give a little better understanding at least!! :)
 

Hyouryuu-Na

Very very lazy
Veteran
Joined
Jun 15, 2017
Messages
1,047
Reaction score
2,440
First Language
Not English
Primarily Uses
RMMV
Thanks for the explanation! It definitely helps ^^
 

Latest Threads

Latest Posts

Latest Profile Posts

Stream will be live shortly! I will be beginning a play-through of Resident Evil 4! Feel free to drop by!

1st iteration on castle interior in Tiled.
I've started up Pillars of Eternity. It's interesting how the game does a "select choice" cutscene using still image art for dramatic flair. I wonder if that might work for my RPGMaker project.
The self-righteous indignation of family when you expect them to pay back money you've leant to them never ceases to amaze me.
Gamedev for relaxing? yes or no?

Forum statistics

Threads
107,743
Messages
1,031,790
Members
139,883
Latest member
MoBard
Top