ID:2049723
 
(See the best response by Ter13.)
mob/proc
Load_Player(var/slot_number)
var/savefile/F = new(SAVEFILE_PATH(slot_number))
var/mob/player/T = new/mob/player()
var/mob/old_mob = client.mob
client.mob = T
T.client = client
del(old_mob)
T.SetLoadStuff(F)


Problem description: I'm sure I'm doing something that will be obvious to most, but I just don't see it. When I load the character, nothing happens and the screen is just black. Any help would be appreciated ^.^

You're not showing the part of the code that's actually loading the data, I'd assume that's in SetLoadStuff().
Oh right, my apologies.

mob/player/proc/SetLoadStuff(var/savefile/F)
Read(F)
loc = locate(last_x,last_y,last_z)
var/list/itemlist
var/list/jutsus
var/list/usable
F["jutsus"]>>jutsus
F["itemlist"]>>itemlist
F["usable"]>>usable
for(var/obj/items/K in itemlist)K.loc=src
for(var/obj/usable/K in usable)K.loc=src
initialized=1
barset()
for(var/obj/jutsu/K in jutsus)
K.loc=src
K.overlays=0
//if(K.name==slot1||K.name==slot2||K.name==slot3||K.name==slot4||K.name=slot5||K.name==slot6||K.name==slot7||K.name==slot8||K.name==slot9||K.name==slot10||K.name==slot11||K.name==slot12||K.name==slot13||K.name==slot14||K.name==slot15||K.name==slot16)client.screen+=K
if(K.name==slot1)
client.screen+=K
K.screen_loc = "1:3,17:-1"
for(var/obj/hotslot/hotslot1/M in client.screen)M.icon_state=""
else if(K.name==slot2)
client.screen+=K
K.screen_loc = "1:3,16:-1"
for(var/obj/hotslot/hotslot2/M in client.screen)M.icon_state=""
else if(K.name==slot3)
client.screen+=K
K.screen_loc = "1:3,15:-1"
for(var/obj/hotslot/hotslot3/M in client.screen)M.icon_state=""
else if(K.name==slot4)
client.screen+=K
K.screen_loc = "1:3,14:-1"
for(var/obj/hotslot/hotslot4/M in client.screen)M.icon_state=""
else if(K.name==slot5)
client.screen+=K
K.screen_loc = "1:3,13:-1"
for(var/obj/hotslot/hotslot5/M in client.screen)M.icon_state=""
else if(K.name==slot6)
client.screen+=K
K.screen_loc = "1:3,12:-1"
for(var/obj/hotslot/hotslot6/M in client.screen)M.icon_state=""
else if(K.name==slot7)
client.screen+=K
K.screen_loc = "1:3,11:-1"
for(var/obj/hotslot/hotslot7/M in client.screen)M.icon_state=""
else if(K.name==slot8)
client.screen+=K
K.screen_loc = "1:3,10:-1"
for(var/obj/hotslot/hotslot8/M in client.screen)M.icon_state=""
else if(K.name==slot9)
client.screen+=K
K.screen_loc = "1:3,9:-1"
for(var/obj/hotslot/hotslot9/M in client.screen)M.icon_state=""
else if(K.name==slot10)
client.screen+=K
K.screen_loc = "1:3,8:-1"
for(var/obj/hotslot/hotslot10/M in client.screen)M.icon_state=""
else if(K.name==slot11)
client.screen+=K
K.screen_loc = "1:3,7:-1"
for(var/obj/hotslot/hotslot11/M in client.screen)M.icon_state=""
else if(K.name==slot12)
client.screen+=K
K.screen_loc = "1:3,6:-1"
for(var/obj/hotslot/hotslot12/M in client.screen)M.icon_state=""
else if(K.name==slot13)
client.screen+=K
K.screen_loc = "1:3,5:-1"
for(var/obj/hotslot/hotslot13/M in client.screen)M.icon_state=""
else if(K.name==slot14)
client.screen+=K
K.screen_loc = "1:3,4:-1"
for(var/obj/hotslot/hotslot14/M in client.screen)M.icon_state=""
else if(K.name==slot15)
client.screen+=K
K.screen_loc = "1:3,3:-1"
for(var/obj/hotslot/hotslot15/M in client.screen)M.icon_state=""
else if(K.name==slot16)
client.screen+=K
K.screen_loc = "1:3,2:-1"
for(var/obj/hotslot/hotslot16/M in client.screen)M.icon_state=""
client.screenproc()
I think it may have something to do with the line:

del(old_mob)


in the Load_Player proc.

If you want to load the client's mob use:

client
New()
//Load Here
var/savefile/F = new(SAVEFILE_PATH(slot_number))
F["mob"] >> src.mob
..()


You also want your save proc to have something like this in it to save the mob:

var/savefile/F = new(SAVEFILE_PATH(slot_number))
F["mob"] << src.mob


Atleast I tried something like that and it seemed to work. When you are deleting the old mob I think you are actually deleting the player because the old mob is just a reference to the player's mob, that's why you have a black screen.

Doing it this way it will save the player's list and the objects in the list so you shouldn't have to worry about resetting the screen locs for them (I think :S).
        if(K.name==slot1)
client.screen+=K
K.screen_loc = "1:3,17:-1"
for(var/obj/hotslot/hotslot1/M in client.screen)M.icon_state=""
else if(K.name==slot2)
client.screen+=K
K.screen_loc = "1:3,16:-1"
for(var/obj/hotslot/hotslot2/M in client.screen)M.icon_state=""
else if(K.name==slot3)
client.screen+=K
K.screen_loc = "1:3,15:-1"
for(var/obj/hotslot/hotslot3/M in client.screen)M.icon_state=""
else if(K.name==slot4)
client.screen+=K
K.screen_loc = "1:3,14:-1"
for(var/obj/hotslot/hotslot4/M in client.screen)M.icon_state=""
else if(K.name==slot5)
client.screen+=K
K.screen_loc = "1:3,13:-1"
for(var/obj/hotslot/hotslot5/M in client.screen)M.icon_state=""
else if(K.name==slot6)
client.screen+=K
K.screen_loc = "1:3,12:-1"
for(var/obj/hotslot/hotslot6/M in client.screen)M.icon_state=""
else if(K.name==slot7)
client.screen+=K
K.screen_loc = "1:3,11:-1"
for(var/obj/hotslot/hotslot7/M in client.screen)M.icon_state=""
else if(K.name==slot8)
client.screen+=K
K.screen_loc = "1:3,10:-1"
for(var/obj/hotslot/hotslot8/M in client.screen)M.icon_state=""
else if(K.name==slot9)
client.screen+=K
K.screen_loc = "1:3,9:-1"
for(var/obj/hotslot/hotslot9/M in client.screen)M.icon_state=""
else if(K.name==slot10)
client.screen+=K
K.screen_loc = "1:3,8:-1"
for(var/obj/hotslot/hotslot10/M in client.screen)M.icon_state=""
else if(K.name==slot11)
client.screen+=K
K.screen_loc = "1:3,7:-1"
for(var/obj/hotslot/hotslot11/M in client.screen)M.icon_state=""
else if(K.name==slot12)
client.screen+=K
K.screen_loc = "1:3,6:-1"
for(var/obj/hotslot/hotslot12/M in client.screen)M.icon_state=""
else if(K.name==slot13)
client.screen+=K
K.screen_loc = "1:3,5:-1"
for(var/obj/hotslot/hotslot13/M in client.screen)M.icon_state=""
else if(K.name==slot14)
client.screen+=K
K.screen_loc = "1:3,4:-1"
for(var/obj/hotslot/hotslot14/M in client.screen)M.icon_state=""
else if(K.name==slot15)
client.screen+=K
K.screen_loc = "1:3,3:-1"
for(var/obj/hotslot/hotslot15/M in client.screen)M.icon_state=""
else if(K.name==slot16)
client.screen+=K
K.screen_loc = "1:3,2:-1"
for(var/obj/hotslot/hotslot16/M in client.screen)M.icon_state=""


The logic center of my brain just turned right off.
Is there a better way to do it that you could explain to me? I'm always wanting to learn
If you can explain what it's supposed to do, I sure can.
It's just checking to see if the techniques in your technique list are saved to one of your hotslots, if it is, add it to your screen.
Actually, I'm having a lot of trouble getting my saving and loading to work, and I've long known you're the guy to go to if help is needed in that area. May I have some assistance? I've tried everything I can think of lol
I recently wrote quite a system that handles this for someone else. This isn't it, but this is the gist of what you need to do.

Basically, when the client logs in, add however many hotbars to their screen. Store these hotbar objects in a list.

client
var
list/hotbar_objs
New()
. = ..()
BuildHotbar()
proc
BuildHotbar() //creates the hotbar objects and positions them on the screen
hotbar_objs = list()
for(var/count in 1 to 16)
hotbar_objs += new/obj/hotslot(count)
screen += hotbar_objs

ClearHotbar() //called to clear the hotbar's graphics
var/obj/hotslot/h
for(var/count in 1 to 16)
h = hotbar_objs[count]
h.overlays = null

obj
hotslot
var
slot
New(pos)
slot = pos
screen_loc = "1:3,[17-pos+1]:-1"


Now, these objects belong to the client, but the attacks bound to the bars belong to the mob.

mob
var
list/hotbar_binds[16]
proc
clearBinds() //call when you want to clear all binds
var/l[16]
hotbar_binds = l
if(client) client.ClearHotbar()

setBind(pos,obj/jutsu/jutsu) //call when you want to change a bind
hotbar_binds[pos] = jutsu
if(client)
var/obj/hotslot/h = client.hotbar_objs[pos]
h.overlays = list(jutsu) //set the attack as an overlay of the hotbar object

updateHotbar() //called when you need to update the hotbar graphics on the client all at once.
if(client)
var/list/l = client.hotbar_objs
var/obj/hotslot/h
var/obj/jutsu/j
for(var/count in 1 to 16)
h = l[count]
j = hotbar_binds[count]
h.overlays = j ? list(j) : null

Login()
..()
updateHotbar()


Things I fixed:

1) You don't need to loop through the client's screen. If you are ever looping through client.screen, you are doing something wrong. You should NEVER do it.

2) You don't need to loop through every attack the player knows to update 16 graphics. In this example, you need to loop through 16 positions. That is all.

3) You don't need to do anything special on save. This all should be managed appropriately during a save.

Also, your loading function is completely wrong because your saving function is completely wrong. You are doing way more work than you should ever have to do and it may be completely unfixable because the source code you are using is probably unfixable. When your game is structured correctly, saving should look like this:

var/savefile/F = new/savefile("herpderp.sav")
F << src


And loading should look like this:

var/savefile/F = new/savefile("herpderp.sav")
var/mob/m
F >> m


Because you are trying to micromanage what the savefile does, you have actually wasted a lot of energy and introduced quite a lot of problems in your code. Unfortunately, much of this was done for you before you even started modifying this source code.
It was my understanding that the way it was done is poor and I was attempting to improve it. The only problems I'm having with my saving at this point, is it's calling Login() twice for some reason. I've fixed most of the other problems.

mob/proc                    
Load_Player(var/slotty)
if(initialized)return
var/savefile/F = new(SAVEFILE_PATH(slotty))

var/mob/player/T = new/mob/player()
T.current_slot=slotty
T.Read(F)
// var/mob/old_mob = src
T.client = src
T.SetLoadStuff(F)

// spawn() del(old_mob)


This is the current load proc I have. Do you see any reason why it'd call Login() twice? Please try to understand that not everyone is as experienced as you. When we come on the forums attempting to learn, and then we're shot down and criticized for the effort, it makes us want to quit. That isn't how it should be. I do appreciate that you've taken the time to reply, as does everyone else you've helped.
var/mob/player/T = new/mob/player()
Calling new() on a mob forces a Login()
But I have to make a new player there, don't I?
In response to SinfulPhoenix
No, not really. Ideally, you should be checking to see if a savefile exists with the client's ckey; not creating a new mob, using that mob to read the savefile(you should never be using Read() directly either), and then setting the client to that mob. That's just a big mess.
Best response
Well, no. The beauty of BYOND's built in savefile management, is that it does everything you are already doing.

mob
var
this_is_saved
tmp/this_is_not


Any variable that is:

1) Marked tmp, const, or static

2) The same value as the default

will not be saved when you pass an object into a savefile.

Read() and Write() are automatically called when you output an object to a savefile, and when you read an object from a savefile. You should never have to call these functions manually, and further, you should never call them manually because doing so is dangerous as it can cause object duplication and all kinds of other messes.

Also, by default, mob.key is saved in the savefile. When the savefile reads the old key value of the mob, it will automatically switch the client to that mob.

That means there's no reason to create a new mob to read from the savefile, and there's no reason to set the mob's client after loading from the savefile.


This is your new saving code:

var/savefile/F = new/savefile("herp.sav")
F << src


And this is your new loading code:

var/saveilfe/F = new/savefile("herp.sav")
var/mob/m
F >> m



You best start digging through your source code and start marking variables you don't want to save as tmp.

A few rules for saving:

1) If you have a variable that ever points to another player, mark it tmp. You don't want to save multiple players in one savefile.

When you load the savefile, everything attached to it comes with it. If they had another player stored in a variable somewhere, and that player is currently logged in, that player's client will switch to the old saved copy that got stuffed into the other player's savefile. This will potentially cause rollbacks, meaning they lose progress in the game.

2) You should never put anything in the player's contents that doesn't log out with them. Most rip source codes do something like this:

Login()
new/obj/screen_obj(src)

obj/screen_obj
New(mob/owner)
owner.client.screen += src


This is dangerous, because the first argument for atom/New() is always the location argument. You are inadvertently creating a new screen object that's saved with the player every time they log out. A quick fix would be to pass the client as the first argument, or pass null as the first argument. That way the screen objects won't be saved.

This will cause leaks that will require player wipes to get rid of.

Login()
new/obj/screen_obj(client)

obj/screen_obj
New(client/owner)
owner.screen += src


Or, my preferred method:

Login()
client.screen += list(
new/obj/screen_obj(null,"somearg"),
new/obj/screen_obj(null,"someotherarg"),
new/obj/screen_obj(null,"somecompletelydifferentarg")
)


3) You will want to make sure that you don't save things that may change in the future. So if you remove an item from the game, or remove a skill from the game, it doesn't necessitate a wipe. It's usually best to save unique ids instead of the objects themselves to prevent the need to wipe out old savefiles when you update the game.

4) You also want to make sure that any references to global objects are tmp or are properly managed. Saving global objects can cause portions of the map to be overwritten when a player logs in, or cause object duplication that can result in massive leaks.
Thank you guys. You've been a great help. I also appreciate the help with the hotslots. It really goes a long way that you take the time to actually explain these things.