ID:2679505
 
(See the best response by Kaiochao.)
I'm trying to figure out an issue where logging in sometimes spawns me at the wrong location. I noticed that on Login() the mob's location will be two different values depending on when I print the mob's loc.

mob/PC/Login()
..()
world << "loc 1: [src.x];[src.y];[src.z]."
spawn(20) world << "loc 2: [src.x];[src.y];[src.z]."

Will return these values:
loc 1: 144;5;1.
loc 2: 163;24;1.

The first value seems to have no connection to any value whatsoever in my code or where I'm standing when saving. The second value however, is the value loaded from the savefile, which I confirmed by checking the saved data, and is the value I would expect. Though sometimes the mob's location will be set to the 1st one.
client
var/tmp
savefile/Savefile

proc/LoadCharacter(char)
var/mob/new_mob
var/char_ckey = ckey(char)
var/savefile/F = PlayerSavefile()
Savefile = null

F.cd = "/players/[ckey]/mobs/"
var/list/characters = F.dir
if (!characters.Find(char_ckey))
world.log << "[key]'s client.LoadCharacter() could not locate character [char]."
mob << "Unable to load [char]. Please contact a GM."
return null
F["[char_ckey]/mob"] >> new_mob
if (new_mob)
mob = new_mob
return new_mob
return null
proc
PlayerSavefile()
if(!Savefile)
var/first_initial = copytext(ckey, 1, 2)
var/filename = "players/[first_initial]/[ckey].sav"
Savefile = new(filename)
return Savefile

proc/SaveMob()
if (!mob || !mob.save_allowed)
return
var/savefile/F = PlayerSavefile()
var/mob_ckey = ckey(mob.name)
var/directory = "/players/[ckey]/mobs/[mob_ckey]"
F.cd = directory
F["name"] << mob.name
F["mob"] << mob
Savefile = null

mob
Write(savefile/F)
..()
if (world.maxx)
F["last_x"] << x
F["last_y"] << y
F["last_z"] << z
return

Read(savefile/F)
..()
if (world.maxx)
F["last_x"] >> x
F["last_y"] >> y
F["last_z"] >> z
return


EDIT: I think I found the issue. Moving ..() inside Read() below the if makes the Login() print the correct value both times. I'm not sure what difference the ..() makes here or what parent code it runs by default. Though I still don't know where it gets 144;5;1 from. Does it come from the ..() call?
Best response
..() calls the previous definition (or default/built-in behavior) of the current proc.

The default behavior of mob.Login() is to place the mob on the map (if it's not already on the map), looking for a spot by scanning the map from the bottom up, left to right. It's really bad and no one should allow it to run, in my opinion, since that search can take a long time or place the mob somewhere you don't want it to be. But that probably explains the mystery location of your mob before its saved location is loaded.

Login() is called whenever a client takes over a mob, whether it's in the default behavior of client.New(), or a mob's key gets loaded (such as by the default behavior of Read()) to the key of a client in the world. So, when that happens before your location is loaded, Login happens before your location is loaded.

Basically:
1. The mob is loaded, calling its Read().
2. Read's ..() sets the mob's key to the saved key (your key), which calls mob.Login().
3. Login's ..() puts you on the map, apparently at (144, 5, 1). When Login returns, it returns back into Read, after the ..().
4. Your location is loaded.
5. The spawn() in Login passes, and your loaded location is outputted.

Also, since key is being saved and loaded with your mob, you probably don't even have to set mob in LoadCharacter(), it's happening automatically.

Also, I suggest not assigning each coordinate separately like you are in Read. If you don't have a location to begin with, setting individual coordinates has no effect, they're immediately reset to 0 if any one of them are 0. Instead, use locate() on the loaded coordinates to get the loaded location.
I see. The location (144,5,1) would seem to correspond to the first tile that is set to density=0, since anything below is dense water. So ..() in Login() is what causes the delay in loading the actual location. So as you say, I should really just delete ..().

Didnt't know about the coordinates being reset to 0, so that might save me some trouble in the future!
So if I understand correctly, it should looks like this:
mob
Read(savefile/F)
if (world.maxx)
loc = locate(F["last_x"],F["last_y"],F["last_z"])
..()
return

and in LoadCharacter() I can change this:
F["[char_ckey]/mob"] >> new_mob
if (new_mob)
mob = new_mob
return new_mob
return null

to just this:
F["[char_ckey]/mob"] >> new_mob

This works, but I don't understand how it knows to automatically load the new_mob into mob? unless it's some behind the scenes magic of the >> operator?
In response to John007qwe
When a mob's key is set to the key of an existing client, that causes the client to log into the mob, which sets client.mob and mob.client and calls Login. The same happens when you set client.mob/mob.client to a different mob/client. The 3 vars (and ckey) are kept in sync and changing any of them causes the others to change, with Login as a side-effect.

And yeah, Read's ..() is loading the saved key variable of the mob being loaded.