ID:1297771
 
(See the best response by NNAAAAHH.)
Problem description:
There is something that has been bothering me lately.
When should the player be saved ? Logout, LevelUP, CharacterCustomization Done, Reboot ?
What about when a servers crash or host simply shutdowns the server ? What I do here to avoid data loss ?
Autosave feature (Ex: 10 minutes) might lag the server a bit even if savefile size isn't big ?
Should I only save for every mob that is client ?
Should I avoid anything that is overlays and skills in my save system ?

Thanks in advance. BloodyJr
Best response
Ideally, you'd save every time a variable has been changed. Realistically, you want to have a auto save and a save-on-exit. I've seen this implemented and it does take up some CPU to do, but it's not going to lag you unless you have 100 people saving at the same time. Saving on level-up depends on the leveling of the game, if it's slow, you want to save as much of the exp as you earn as possible so it doesn't take that much longer(so save between the levels). If it's fast, you don't want to save all the time and cause it to run the cpu up(so don't save every level). If it's a decent timed leveling, I'm not sure if you'd be able to get away with saving each level, but it could work and maybe even add a degree of old-school 'difficulty', having to re-earn where you were and what you had.

I don't think overlays are supposed to save, you might want to have variables you can check in the log in of the player to re-add the overlays. Skills, you should either have a list or vars to tell you what verbs the mob is keeping.

Autosaves should probably be between 2-5 minutes, so a minimum amount of data is lost. This shouldn't cause much of any lag outside of 100+ players saving at or around the same time(or on a really old/crappy cpu). And are a good feature to have WITH log out saving, to avoid the most data loss as possible. BUT, as already stated; is dependent on your game.

Saving for mobs outside of player's mobs is up to you, some NPCs might have things you want to save, this just really depends on your preference and the game you're working on.
As for auto saves you could space them apart a bit as to decrease the workload; alternatively you could make the auto save loop per player- for example if they have been on for longer than 30 minutes it starts saving every 30 minutes.

Also if you have a world-wide auto-save loop, be sure to use for() to look for clients then refer to their mobs, not for() all mob and look for clients.

As for data loss, there's no real way to prevent that.

I usually just rely on logout-saves.

You should avoid saving as many objects/mobs as possible: skills could be datums that refer to a generated global list. Etc.
In response to Jittai
per-player save is preferable and less stressful onto the server, hence my comment about having a lot of players saving in or around the same time.
N2A4H2: You comment is ambigious as it could also imply a list of players in a global loop being saved with a delay on them.
In response to NNAAAAHH
NNAAAAHH wrote:
Ideally, you'd save every time a variable has been changed. Realistically, you want to have a auto save and a save-on-exit. I've seen this implemented and it does take up some CPU to do, but it's not going to lag you unless you have 100 people saving at the same time.
Saving on level-up depends on the leveling of the game, if it's slow, you want to save as much of the exp as you earn as possible so it doesn't take that much longer(so save between the levels). If it's fast, you don't want to save all the time and cause it to run the cpu up(so don't save every level). If it's a decent timed leveling, I'm not sure if you'd be able to get away with saving each level, but it could work and maybe even add a degree of old-school 'difficulty', having to re-earn where you were and what you had.

I don't think overlays are supposed to save, you might want to have variables you can check in the log in of the player to re-add the overlays. Skills, you should either have a list or vars to tell you what verbs the mob is keeping.

Autosaves should probably be between 2-5 minutes, so a minimum amount of data is lost. This shouldn't cause much of any lag outside of 100+ players saving at or around the same time(or on a really old/crappy cpu). And are a good feature to have WITH log out saving, to avoid the most data loss as possible. BUT, as already stated; is dependent on your game.

Saving for mobs outside of player's mobs is up to you, some NPCs might have things you want to save, this just really depends on your preference and the game you're working on.

Since this is gonna be my first game from scratch, I don't wanna mess up and that's why I would like to know everything I can..

Let's say, what if I set up this to save every 10 levels while levels are easily achievable and then once they achieve a high level, it will save every 3 or 5 levels ?

I think my MaxEXP formula everytime you level up is quite moderated, if anyone want to test:

    TestExp()
set hidden = 1
for(var/i = 1, i <= 200, i++)
var/MaxExp = round(100 + (1.1 * ((i + 1) -1) ** 2))
var/Test = "[MaxExp]"
sleep(1)
usr << output("Level [i]: [Test]", "ChatOutput")


But it depends how easily the player can get EXP too and this I haven't test because I want things well balanced.

So, I could remove overlays in Save and then add in Load ?

Autosave is what I fear most, it might be good to avoid big data loss but I don't want lag everytime it saves.

Jittai wrote:
Also if you have a world-wide auto-save loop, be sure to use for() to look for clients then refer to their mobs, not for() all mob and look for clients.

Like this:

for(var/mob/Player/P in world)

//or

for(var/client/C in world)


Sorry if I didn't understood that part well, thanks in advance.

EDIT: I think I'll save per player and only save all clients whenever I reboot.
In response to Pirion
Touche'. I apologize for being more vague than intended with my explanation of auto-saving.

OP - You understood Jittai's comment on searching for clients outside of mobs.

Autosaves shouldn't lag a server unless it's running on very small amounts of provided cpu or you're saving a LOT of variables. I've seen projects with upwards of 300 variables being saved and saving every three minutes run fine(granted a lot of the procs weren't optimized and caused lag from every which way randomly). Save procs aren't the most costly cpu-extensive thing when thinned out. As long as you're not saving every thirty seconds or saving large amounts of mobs at once, it should be fine. However, saving once every few levels on a easy-to-level game could work well, as long as it's not 10+ levels in under a minute, that save system should be fine. However, I still recommend saving when the mobs disconnect.

Also, I don't understand the need for ((i + 1) -1) as it simply adds 1 to the number, then subtracts 1 from it again.

The for() loop can be written differently, using num in num1 to num2
In response to NNAAAAHH
NNAAAAHH wrote:
Touche'. I apologize for being more vague than intended with my explanation of auto-saving.

OP - You understood Jittai's comment on searching for clients outside of mobs.

Autosaves shouldn't lag a server unless it's running on very small amounts of provided cpu or you're saving a LOT of variables. I've seen projects with upwards of 300 variables being saved and saving every three minutes run fine(granted a lot of the procs weren't optimized and caused lag from every which way randomly). Save procs aren't the most costly cpu-extensive thing when thinned out. As long as you're not saving every thirty seconds or saving large amounts of mobs at once, it should be fine. However, saving once every few levels on a easy-to-level game could work well, as long as it's not 10+ levels in under a minute, that save system should be fine. However, I still recommend saving when the mobs disconnect.

I'll do both of them for now and until I get the game properly playable to test with people, I can't decide which one would be the best for now. I've played games in Byond and it was constantly rollbacks or savefile loss. And it's not good to lose all your work, so I want to avoid data loss to my players as much as I can.

Also, I don't understand the need for ((i + 1) -1) as it simply adds 1 to the number, then subtracts 1 from it again.

Err, you are right, thanks. I already corrected it.
The numbers may seem quite low, but that's because I don't like people to have their MaxExp as 900000...
I'll try to make this a medium rate leveling game.

The for() loop can be written differently, using num in num1 to num2

I didn't really had knownledge about that, thanks! I would appreciate any tips if you have! I want to gather all information I can..!
In response to BloodyJr
for(var/client/C)

Then just set a var/mob/M = C.mob for ease under that. or just a mob.Save().

While using a specific path for players like /mob/Players works in that it identifies client based mobs I prefer to avoid that as I feel like it's less, for lack of a better word, dynamic or modular?
In response to BloodyJr
Well, to avoid rollbacks as much as possible, you could delete the files with fdel() before saving over it. Up to you.
Rollbacks usually come from referencing things that get saved in multiple save files. As such you should get familiar with temporary vars. If you have to save something like a friends list never save/refer to their mobs, use their ckeys instead.
In response to Jittai
Jittai wrote:
for(var/client/C)

Then just set a var/mob/M = C.mob for ease under that. or just a mob.Save().

While using a specific path for players like /mob/Players works in that it identifies client based mobs I prefer to avoid that as I feel like it's less, for lack of a better word, dynamic or modular?

I was checking DM Ref, so mob.Save() so mob here means that's the client it's connected to it, am I right ?

Well, to avoid rollbacks as much as possible, you could delete the files with fdel() before saving over it. Up to you.

I am already doing this, thanks to some searching in Byond.
Pretty much checking it the saves exist, then I delete it.

Rollbacks usually come from referencing things that get saved in multiple save files. As such you should get familiar with temporary vars. If you have to save something like a friends list never save/refer to their mobs, use their ckeys instead.

And yeah, I've been looking to tmp vars and so far I have some understanding with it.