ID:158181
 
So in my current project there will only be three players (two of my friends and I), and when any one of us is logged into the server they need to be able to see where the other two are. Because of this, I thought it easiest just to save everything in a World save-file rather than seperate player save-files.

So far it's going okay, but I've always struggled with save-files. Firstly, I've got the small problem that before the first time we log in our mobs won't already exist. Also, with the code I have developed, it seems that when I run the game I am automatically attached to my mob, skipping the log in sequence. I guess that's because the world saves my mob's client/key. Anyway, here's the code I have so far. Any and all advice will be greatly appreciated!

world


New()
..()
var/savefile/F = new("World")
world.log = file("Log.txt")
world.log<<"Turn: [Turn]"
F>>Turn
F>>Phase
F>>Finished
F>>Players
var/xx,yy,zz
for(var/mob/a in Players)
world.log<<"Player [a]"
F["[a]loc_x"]>>xx
F["[a]loc_y"]>>yy
F["[a]loc_z"]>>zz
a.loc = locate(xx,yy,zz)
//RunOnce()
Del()
..()
var/savefile/F = new("World")
F<<Turn
F<<Phase
F<<Finished
F<<Players
for(var/mob/a in Players)
world.log<<"aPlayer [a]"
F["[a]loc_x"]<<a.x
F["[a]loc_y"]<<a.y
F["[a]loc_z"]<<a.z


proc
RunOnce()

Players=new/list()
var/mob/Pointer/Ease = new/mob/Pointer()
Ease.loc = locate(38,16,2)
Ease.name = "Ease"
Players.Add(Ease)
var/mob/Pointer/Arlthain = new/mob/Pointer()
Arlthain.loc = locate(37,16,2)
Arlthain.name = "Arlthain"
Players.Add(Arlthain)
var/mob/Pointer/Zaineph = new/mob/Pointer()
Zaineph.loc = locate(36,16,2)
Zaineph.name = "Zaineph"
Players.Add(Zaineph)


Also, we each will have two mobs (Generals) attached to us. Will these be saved with us? Or do I need a for loop for them as well?

~Ease~
You will need to handle the x,y,z saving (as well as any additional work that should be done when saving) in Write(), not in a generic load() proc:

mob/Write(var/savefile/F)
..()
if(isturf(loc))
F["x"] << x
F["y"] << y
F["z"] << z

mob/Read(var/savefile/F)
..()
var/turf/T = locate(F["x"], F["y"], F["z"])
if(T)
loc = T


From there, all you need to do is save / load your list of players. Doing that will save every mob in the list. Each mob saved then handles its x,y,z locations.

Similarly, to save anything belonging to the mob, you simply need to have a list on that mob which gets saved, and contains any other objects you wish to save (note: if the objs have map locations, you will need to change the above to apply to objs as well by making it atom/movable/Write() and Read()).

Note that references to other player mobs is dangerous (IE: var/mob/my_enemy = Ease). It will save the other mob in the savefile along with your mob. However, this is not a major issue in this case as there will only be one savefile for every player.

If you want to know more about savefiles, I strongly suggest you use ExportText() to see the format.

Oh, and as for your "skipping the login process" issue: the default action of client/New() is to first connect you to an already-existing mob if it has your key. So if you've already loaded the mob, you will log into it.
Ease wrote:
Firstly, I've got the small problem that before the first time we log in our mobs won't already exist.

Is that part of the question? If so, I counter it with one of my own: is that what RunOnce() is for?

Just check to see if the players are in the savefile before you try to extract them. If not, then create a new one. You can check to see if the savefile directory for a specific player is in the savefile contents before trying to read the player.

Also, with the code I have developed, it seems that when I run the game I am automatically attached to my mob, skipping the log in sequence. I guess that's because the world saves my mob's client/key.

Yes, that would do that. Look up client/New() in the reference for all circumstances of how clients get attached to mobs when they log in. If one already exists with your key when you log in, it connects you to it. If an object exists with a default-name equal to your key, it creates an instance of that mob and logs you into it. If neither of the above applies, only then does it create a mob of the world's default mob type and connect the client to it.

Anyway, here's the code I have so far. Any and all advice will be greatly appreciated!
...

I'm not sure I understand why you are showing the code based on the questions you are asking. Is there some other problem with it as well?

Also, we each will have two mobs (Generals) attached to us. Will these be saved with us? Or do I need a for loop for them as well?

You are looping through all mobs in the Players list to save, so yes, as long as they are all in the Players list. Anything at all which is both in the Players list and is of type or subtype of /mob will be saved.
In response to Loduwijk (#2)
Loduwijk wrote:
Ease wrote:
Firstly, I've got the small problem that before the first time we log in our mobs won't already exist.

Is that part of the question? If so, I counter it with one of my own: is that what RunOnce() is for?


Yup, that is what RunOnce() is for at the moment, though that doesn't seem the 'right' way to do it.


Anyway, here's the code I have so far. Any and all advice will be greatly appreciated!
...

I'm not sure I understand why you are showing the code based on the questions you are asking. Is there some other problem with it as well?


I've always been told on BYOND to post relevant code, even if it doesn't seem like it will help to me. Better than I waste space in the first message, than waste your time making you ask for the code.



Also, we each will have two mobs (Generals) attached to us. Will these be saved with us? Or do I need a for loop for them as well?

You are looping through all mobs in the Players list to save, so yes, as long as they are all in the Players list. Anything at all which is both in the Players list and is of type or subtype of /mob will be saved.


I think I already know the answer, but I'll double check : And if the Generals aren't in the Player list? Just in a list that belongs to a mob in the Player list? They'll still be loaded right?

And thanks for the help Loduwijk!
In response to Garthor (#1)
Thank you for the advice Garthor! It is late, so I won't put it into practise until the weekend, but thank you for the information you've already provided.

~Ease~
In response to Ease (#3)
Ease wrote:
And if the Generals aren't in the Player list? Just in a list that belongs to a mob in the Player list? They'll still be loaded right?

Yes, as Garthor pointed out, references made by anything that is saved will cause recursive saving.

Think of it this way...

When you save a mob, all of its variables get saved (as that's the point of saving it), so you have its health, its ammo, the weapon its holding, etc. Now, think about this; if it's saving your weapon, or your pet, or whatever, that's another object that it's saving, so it has to save another entire object. Now what if your pet currently had its mob/target variable set to another player? Well, that's one of its variables, so it's part of the pet in a way and it gets saved too, and then that player's pet, and that player's pet's target, etc.

In the same way, if your main player has a variable that references any other mob, that mob will get saved along with it, assuming you are saving the entire mob.
proc/test()
var/savefile/S = new()
var/mob/M = new
var/mob/N = new
M.enemy = N
S << M // saves M, which includes all its variables, which N is one of, so it saves N too

This is why you use tmp. If something should not be saved, it should be a tmp variable. In the above example, if mob's enemy variable were defined "mob/var/tmp/mob/enemy" instead of "mob/var/mob/enemy" the enemy would not get saved along with you.