• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

GUI save/load system?

Status
Not open for further replies.
Level 8
Joined
Mar 3, 2009
Messages
327
Firstly, i know this is possible.

Im a little scratchy on exactly how to make a save/load code, convert it, then load it properly.

I'm making one for my map that needs to save 24 items, hero level, gold, attributes etc. I know it'll probably be long but there are plenty of tutorials on compressing it :p

Don't say it will be easy to crack.. i'll fill it with ciphers and stuff :p

Thanks for any help.
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
1. using full GUI for save/load is not a good idea, since for some reason unit-type and item-type (both integers) are not integers in GUI. You'll need JASS for this.

The process of converting is pretty simple, you convert everything to a number (not a problem for level, gold and attributes, for items it's also easy with JASS), then just convert numbers to symbols (create a huge string with all symbols you'll want to use, then you can write number X as SubString( theHugeString, x, x) ).
What you need to be careful about are values, that could be higher than the string count (for example you have 70-symbols long string, but attributes can go higher), so you will need to encode them with two symbols.

That's a very basic and inefficient way to do it, here is a better one: create 64-symbol long string, so that every symbol represents 6 bits. Then, when storing the numbers, you determine how many bits you need to save each (for example if level can go up to 99, you need 7 bits to save it) and just put the bits in sequence and write each 6 down as one symbol (if you then need to save two 3-bit numbers, you can save them in one symbol, while in the previous method, you would need 2)
 
  • Like
Reactions: Rui
Level 8
Joined
Mar 3, 2009
Messages
327
yeah im fine with the odd custom script i guess. I'm still not too clear on what to do though. Could you please explain how to do the second one a bit more? The main thing i dont know is what functions to actually use to do all that...
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
Well, first, save somewhere all the values you want to get into the save code
  • Set value[0] = Level of Hero[index]
  • Set value[1] = Current Gold of Player(index)
  • ........
  • Set value[4] = Agility of Hero[index]
  • Set value[5] = Intelligence of Hero[index]
  • ........
Then, you just define a long string, like
"abcdefghijklmnopqrtstvxwyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-_!()" and write all values as symbols:
  • Set saveTable = "abcdefghijklmnopqrtstvxwyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-_!()"
  • For (Integer A) from 0 to numValues
    • Set saveCode = saveCode + SubString( saveTable, value[(Integer A)-1], value[(Integer A)])
Ofc "saveTable" will be same every time, you can move the definition in map init.

This only saves values between 0 and 66 (because there are 67 chracters in the saveTable string), to save higher values, you'll need to input them like this:
  • .........
  • Set value[1] = Current Gold of Player(index) / 66
  • Set value[2] = ModuloInteger( Current Gold of Player(index), 66)
  • .........
this way you can save values up to 66^2 (~4300), which is enough for almost everything.

Loading is a bit more complicated, since warcraft doesn't have many natives for working with strings
  • Set saveTable = "abcdefghijklmnopqrtstvxwyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-_!()"
  • For (Integer A) from 0 to numValues
    • For (Integer B) from 0 to 66
      • If
        • Conditions
          • ( SubString(saveCode, IntegerA-1, Integer A) == SubString(saveCode, IntegerB-1, Integer B)
          • Then
            • Set value[Integer A] = Integer B
and then "apply" those values one after another
  • Hero - Set Hero[index] Hero-level to value[0]
  • Player - Set Player(index) current gold to value[1]*66 + value[2]
  • Hero - Modify Agility of Hero[index]: Set to value[4]
  • Hero - Modify Intelligence of Hero[index]: Set to value[5]
  • .........
 
Level 8
Joined
Mar 3, 2009
Messages
327
thankies +rep
ill just trawl through this for the next few hours and see if i can make it work :p

just a question... for the gold, the modulo integer? i can see that its needed but what should i put for it and how does it work exactly?
 
Last edited:
Level 12
Joined
Apr 15, 2008
Messages
1,063
Just one more thing: security. It's not worth creating some super-secure code, since everyone will have acces to to script (considering people that will want to crack it). Only thing you need to worry about is that players won't steal each other's code in the game, so just save player's number somewhere in the code (to ensure that it won't be same number every time, add some hash variable). For example:
  • Set value[10] = (value[0]+value[3]+value[6]+value[9]) mod 33 + StringHash( Name of Player(index) ) mode 33
Then, when you load the code, generate it again and compare
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
well JASS considers unit-type and item-type as integer, so to convert any of those to integer you can use this:
  • Custom script: udg_integerVar = udg_itemtypeVar
with two globals, integer "integerVar" and item-type "itemtypeVar".

So conversion of some real items would look like this:
  • Set tempIType = (Item-type of (Item carried by Hero[index] in slot 1))
  • Custom script: set udg_tempInt = udg_tempIType
  • Set value[11] = udg_tempInt
or, if you are not afraid of some more JASS functions:
  • Custom script: udg_value[11] = GetItemTypeId(UnitItemInSlotBJ(udg_Hero[udg_index], 1))
(I simply converted the above trigger to custom text and merged the three lines in one. It won't work any better, it will just save some space)

EDIT: I forgot very important thing: offseting. Item ID's start at 'i000' (it's a number), so you need to substract it from the real ID when saving and add it when loading (the IDs are a very large numbers, this way you decrease them without losing precision). Hero unit types start at 'H000' I think. (use CTRL+D to view the ID's in object editor).
 
Level 8
Joined
Mar 3, 2009
Messages
327
ah shit its giving me script errors again...
It wasnt, so i did like 12 custom scripts for 12 of the item slots, saved, and now the errors again >_>.
Set udg_Savevalue[6] = GetItemTypeId(UnitItemInSlotBJ(udg_Hero[GetConvertedPlayerId(GetTriggerPlayer())], 1))

That x12 expected a code statement.
 
Last edited:
Level 8
Joined
Mar 3, 2009
Messages
327
Alright, heres what i have so far. I hope you know your variables.

First, you need a save string. for example:
  • Set savestring = qwertyuiopasdfghjklzxcvbnm1234567890!@#$%^&*()
It can be as long as you want. i think that ones 46 characters.

next, you need a big save integer array, as big as the number of values you want to save.

what you need to do is this:

  • Event: Player 1 red types a message containing -save as an exact match.
  • Player 2 blue....
  • etc
  • Actions:
  • Set savevalue[1] = Current cold of triggering player / 45 (so you can save a decent amount of gold without it glitching)
  • -------when loading make sure you do thatsavevalue X 45 so you end up with the same amount-------
  • Set savevalue[2] = Strength of hero[player number of(triggering player)]
  • Set savevalue[3] = blah blah blah
what you can also do for a bit of security is like...

  • Set savevalue[6] = savevalue[1]+savevalue[2]
so its harder to crack. of course make it a bit more complicated.


i havnt really worked my way through loading.

Also, M0RT, what happens if the amount of gold is not divisible by 45?
a test map would be good :p
 
Level 8
Joined
Mar 3, 2009
Messages
327
i think we meant a test map that involves the stuff we're talking about/the making of save/load codes... thanks anyway...

But really could dividing the values add or remove points either way? even if it does like one im stuffed...
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
Yeah I can make a demo map, I'll add it later.

Well I used two variables to save gold:
  • Set value[1] = Current Gold of Player(index) / 66
  • Set value[2] = ModuloInteger( Current Gold of Player(index), 66)
The first two saves the part that is divisible by 66 (replace by 45 in your case), the other one the undivisible part. If you add them together later( value[1]*66+value[2]), you get the whole number again.
About jass error: do you have the variable Hero? I just wrote it there as example, it should have been the global where you store a hero for each player. Also, I don't know where you store the 18 extra items, but I guess that somewhere else than slot 7-24, so you'll need to save them some other way.
And to security: 1. very important is that you include player name in the hash, otherwise players could steal codes from each other. Also, you should add some hash from all values, since clearly every character represents one value, and if player managed to find out which one are not in security hash, he could change them as he wants.
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
Ok, here is the example map. It contains some more "tricks" i didn't mention here and I realized while making the map, so check them out. This system has some disadvantages so far: only works for custom heroes with custom item, while all heroes should be based of one (to have simillar unitIDs, so you can save their IDs directly, without indexing like some other systems do) and it won't save learned abilities, but that can be added simply (just detect who learns what with "Unit - unit learns a skill", save it somewhere and then input it in code)

One last advice: compression
Each character in the string can save a number up to 71 (that is the length I came up with in the example map, your's can be different). So if you are saving a number, that you know will never reach a fraction of it (for example some variable that can reach 0-6, like the main quest stage), you can use the rest of the avaiable numbers to store another variable.
Following rule applies: the multiple of their increased maximums(maximal value the variable can have +1) must be lower than the total maximum (in this case 71).
So into that 0-6 variable (IncMax 7) , you can save another one that has values of 0-9 (IncMax 10), because 7*10 < 71

You save the number as (A + (ImaxA)*B) (in this case it would be (A+7*B)
When you load it, A = value modulo (ImaxA) and B = value/(ImaxA+1)

I hope this is understandable, if not, then ignore compression :grin: until you get better with the codes, at that point you will propably realize how this works for yourself.
 

Attachments

  • saveloadtest.w3x
    24.3 KB · Views: 148
Level 8
Joined
Mar 3, 2009
Messages
327
Alright ive done a lot of stuffing around with it, and i've come up with this. The thing is, if the player doesnt have anything in their backpacks it will come up with a big qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq for some of the items. also i think i stuffed up somewhere and it doesnt load properly. Do you reckon you could fix up the thing for me? please :D

also i think the item thing i added would be kinda insecure.. if you could fix that up too :)

ill put credit to you in the quests :p
 
Last edited:
Level 12
Joined
Apr 15, 2008
Messages
1,063
Well of course I can, but I thought you wanted to learn how to do the system by yourself. If you didn't, you could have just used one of many systems there are on hive. I'll upload the modified test map when I get home (I already fixed it, my internet connection just failed)
Dude use CodeGen 0.5 !!! Its best ! :<
There is no point in using downloaded system, if you can make your own. Your's will always be better optimized for your map. (but in this case, I would indeed recommend using CodeGen than this one, there still may be some bug or security issue I didn't think of, it's still version 0.0.1, put together in half an hour :grin: )
(or at least make some heavy modifications in it, so you can consider it your own code, which would also be a valid reason to choose it over some other system :wink: )
EDIT: uploaded
 

Attachments

  • saveloadtest.w3x
    24.5 KB · Views: 131
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Convert each item into an index for an array (with all items you can obtain in it). The number should go from a 32 bit unsigned to only a 7-8 bit signed. Logically this is easier and smaller to store.

For name protection, build it into the hash system so you kill two birds with one stone. 2 digits is all that is really needed to give a near unguessable code (needs 100s of trys to guess a working code).

Heres an example of a code generator I made in under a day. It aint the best probably but it is better than most in current use. It is also semi O(1) effeciency, thus it should lag less than simlar save systems.
 

Attachments

  • savesystem.w3x
    19.3 KB · Views: 275
Level 8
Joined
Mar 3, 2009
Messages
327
I think codegen is vJass,i get a crapload of compile errors from it. And ive never been able to get JNGP to work.

Yeah M0RT i did try :p I'm not really good a fixing stuff thats way out of my league, but still, i have a way better understanding now, thanks :D

I'll have a look at your thing now Dr Super Good.

EDIT: is yours vJass Dr? D:
Oh i just realised the map didnt attach to my post before, so you ended up editing the one that i hadnt modified :/ oh well i'll quit pestering you and try to redo the thing myself..
 
Level 13
Joined
Feb 18, 2009
Messages
1,381
Hey man, i've been watching this thread a long time, i downloaded the 24 mb. file, and tried to set the trigger on my map. I just can't find
"Action :
  • Set Value[5] : ((Player 1 (Red) Current gold) / MAXVALUE how do i find that???
  • And Value[6] ((Player 1 (red) current gold) mod maxValue i can't either...
 
Level 13
Joined
Feb 18, 2009
Messages
1,381
No i mean, in that row. "Player 1 (Red) Current gold" /Maxvalue... how can i get Maxvalue after Current gold, i don't know how to do that.
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
Oh, use "Function: arithmetic" and fill those two in.
I attached a screenshot (it shows arithmetic function for real variable, but it is the same for integer)
 

Attachments

  • scrn.gif
    scrn.gif
    3.9 KB · Views: 82
Level 13
Joined
Feb 18, 2009
Messages
1,381
OK, when i get home, ill try that out... Rep+ if working...

THANKS it works!

I am so so so sorry for triple posting, but the custom script dosen't work, i copied exactly as it said.
 
Last edited by a moderator:
Status
Not open for further replies.
Top