System CodeGen - Save and Load

Reaction score
341
CodeGen
v0.4

What is CodeGen?
CodeGen is used convert integers into strings. Those strings can later be typed and the integers can be loaded. These systems are commonly called 'Save and Load' Systems. They are generally popular in the RPG genre where a player can 'convert his hero into a string' and then next game type it, and his hero would be back.​

How do I use this?
First open the attached demo map and copy the maps Custom Script code into your maps custom script.
Next copy the CodeGen folder into your map and you should be all set!

As for adding new values it's pretty easy. This system can only save integers, which most handles (variable-types) in warcraft can be converted to. Lets say you wanted to save the players lumber, you would add this to the save trigger;

Code:
Set SaveCount = (SaveCount + 1)
Set Save[SaveCount] = ((Triggering player) Current lumber)

And in the load trigger you would add;

Code:
Set LoadCount = (LoadCount + 1)
Player - Set (Triggering player) Current lumber to Load[LoadCount]

But please remember, you must load everything in the order you saved them.​

What does this save?
Well the demo map saves the heroes level, items, and gold as well as the players name. But the system can save anything which can be converted to an integer. So please I don't want to hear any 'Can this save XXX?'.​
Frequently Asked Questions
Does this save the players name?
Yes, but you can disable it in the config trigger.

Is this secure?
I think so, if anyone cracks it please PM me or reply. But as for the general public who will be playing your game, they probably won't crack it. The chances are very low of guessing a code and probably will never happen.

How short is the code?
It will get longer with the more values you save. Also increasing the alphabet size decreases the code size.


Code

Please note that you do not need to use any jass in order to use this system. This is the backend of the system.
JASS:
function CG_Init takes nothing returns nothing
    set udg_Compress = SubString(udg_Alphabet, StringLength(udg_Alphabet)-1, 999)
    set udg_Alphabet = SubString(udg_Alphabet, 0, StringLength(udg_Alphabet)-1)
endfunction

function CG_Encode takes integer i returns string
    local integer b
    local string s = ""
    if i < udg_Base then
        return SubString(udg_Alphabet, i, i + 1)
    endif
    loop
        exitwhen i <= 0
        set b = i - (i / udg_Base) * udg_Base
        set s = SubString(udg_Alphabet, b, b + 1) + s
        set i = i / udg_Base
    endloop
    return s
endfunction

function CG_SaveChar takes string c returns integer
    local string low  = "abcdefghijklmnopqrstuvwxyz"
    local string high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    local string int  = "0123456789"
    local integer i   = S2I(c)
    if i > 0 then
        return i
    endif
    if c == "0" then
        return 0
    endif
    set i = 0
    loop
        exitwhen i > 26
        if SubString(low, i, i + 1) == c then
            return i
        elseif SubString(high, i, i + 1) == c then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction

function CG_SaveString takes string name returns string
    local integer i   = 0
    local integer a   = StringLength(name)
    local integer c   = 0
    loop
        exitwhen i > a
        set c = c + CG_SaveChar(SubString(name, i, i + 1))
        set i = i + 1
    endloop
    return CG_Encode(c)
endfunction

function CG_StrPos takes string s returns integer
    local integer i = 0
    loop
        exitwhen i > udg_Base
        if s == SubString(udg_Alphabet, i, i + 1) then
            return i
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function CG_Decode takes string s returns integer
    local integer a = 0
    loop
        exitwhen StringLength(s) == 1
        set a = a * udg_Base + udg_Base * CG_StrPos(SubString(s, 0, 1))
        set s = SubString(s, 1, 50)
    endloop
    return a+CG_StrPos(s)
endfunction

function CG_SaveBoolean takes boolean flag returns integer
    if flag then
        return 1
    endif
    return 0
endfunction

function CG_SaveHero takes unit it returns integer
    local integer i = 1
    loop
        exitwhen i > udg_HeroCount
        if udg_SaveHero<i> == GetUnitTypeId(it) then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction

function CG_SaveItem takes item it returns integer
    local integer i = 1
    loop
        exitwhen i &gt; udg_ItemCount
        if udg_SaveItem<i> == GetItemTypeId(it) then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction

function CG_Seperate takes string s returns string
    local integer i = 0
    local integer b = StringLength(s)
    local integer a = 0
    loop
        exitwhen i &gt; b
        if a == 4 then
            set s = SubString(s, 0, i) + &quot;-&quot; + SubString(s, i, 999)
            set a = 0
        else
            set a = a + 1
        endif
        set i = i + 1
    endloop
    return s
endfunction

function CG_Unseperate takes string s returns string
    local integer i = 0
    loop
        exitwhen i &gt; StringLength(s)
        if SubString(s, i, i + 1) == &quot;-&quot; then
            set s = SubString(s, 0, i) + SubString(s, i+1, 999)
        endif
        set i = i + 1
    endloop
    return s
endfunction

function CG_IsLower takes string s returns boolean
    return s == &quot;a&quot; or s == &quot;b&quot; or s == &quot;c&quot; or s == &quot;d&quot; or s == &quot;e&quot; or s == &quot;f&quot; or s == &quot;g&quot; or s == &quot;h&quot; or s == &quot;i&quot; or s == &quot;j&quot; or s == &quot;k&quot; or s == &quot;l&quot; or s == &quot;m&quot; or s == &quot;n&quot; or s == &quot;o&quot; or s == &quot;p&quot; or s == &quot;q&quot; or s == &quot;r&quot; or s == &quot;s&quot; or s == &quot;t&quot; or s == &quot;u&quot; or s == &quot;v&quot; or s == &quot;w&quot; or s == &quot;x&quot; or s == &quot;y&quot; or s == &quot;z&quot;
endfunction

function CG_IsUpper takes string s returns boolean
    return s == &quot;W&quot; or s == &quot;A&quot; or s == &quot;B&quot; or s == &quot;C&quot; or s == &quot;D&quot; or s == &quot;E&quot; or s == &quot;F&quot; or s == &quot;G&quot; or s == &quot;H&quot; or s == &quot;I&quot; or s == &quot;J&quot; or s == &quot;K&quot; or s == &quot;L&quot; or s == &quot;M&quot; or s == &quot;N&quot; or s == &quot;O&quot; or s == &quot;P&quot; or s == &quot;Q&quot; or s == &quot;R&quot; or s == &quot;S&quot; or s == &quot;T&quot; or s == &quot;U&quot; or s == &quot;V&quot; or s == &quot;X&quot; or s == &quot;Y&quot; or s == &quot;Z&quot;
endfunction

function CG_ColorChar takes string char returns string
    local integer i = 0
    local string s = udg_Alphabet + udg_Compress
    loop
        exitwhen i &gt; udg_Base+1
        if char == SubString(s, i, i + 1) then
            if CG_IsLower(SubString(s, i, i + 1)) then
                return udg_LOWER_CASE_COLOR + char + &quot;|r&quot;
            elseif CG_IsUpper(SubString(s, i, i + 1)) then
                return udg_UPPER_CASE_COLOR + char + &quot;|r&quot;
            elseif SubString(s, i, i + 1) != &quot;-&quot; then
                return udg_OTHER_CHARS_COLOR + char + &quot;|r&quot;
            endif
        endif
        set i = i + 1
    endloop
    return char
endfunction

function CG_Color takes string s returns string
    local integer i = 0
    local string r = &quot;&quot;
    loop
        exitwhen i &gt; StringLength(s)
        set r = r + CG_ColorChar(SubString(s, i, i + 1))
        set i = i + 1
    endloop
    return r
endfunction

function CG_ClearData takes nothing returns nothing
    local integer i = 0
    loop
        exitwhen i &gt; 50
        set udg_Save<i> = 0
        set i = i + 1
    endloop
endfunction

function CG_SaveOnline takes nothing returns integer
    if not ReloadGameCachesFromDisk() then
        return 1
    endif
    return 0
endfunction

function CG_Execute takes nothing returns nothing
    local integer i   = 1
    local integer t   = 0
    local string val  = &quot;&quot;
    
    set udg_Code = &quot;&quot;
    
    loop
        exitwhen i &gt; udg_SaveCount
        set val = CG_Encode(udg_Save<i>)
        set t   = StringLength(val)
        if t &gt; 1 then
            set udg_Code = udg_Code+udg_Compress+I2S(t)+val
        else
            set udg_Code = udg_Code+val
        endif
        set i = i + 1
    endloop
    
    if udg_SavePlayerName then
        set udg_Code = udg_Code+CG_SaveString(GetPlayerName(GetTriggerPlayer()))
    endif
    
    set udg_Code = CG_SaveString(udg_Code)+udg_Code
    set udg_Code = CG_Seperate(udg_Code)
    set udg_Code = CG_Color(udg_Code)
endfunction

function CG_Load takes string str returns nothing
    local integer i   = 0
    local integer b   = StringLength(CG_Unseperate(str))
    local integer key = 1
    local integer c   = 1
    local string tmp  = &quot;&quot;
    
    set str = CG_Unseperate(str)
    set udg_LOAD_VALID = true
    
    set tmp = CG_SaveString(SubString(str, 2, b))
    if SubString(str, 0, StringLength(tmp)) != tmp then
        set udg_LOAD_VALID = false
        return
    endif
    set str = SubString(str, StringLength(tmp), 999)
    
    if udg_SavePlayerName then
        set tmp = CG_SaveString(GetPlayerName(GetTriggerPlayer()))
        if StringLength(tmp) &gt; b then
            set udg_LOAD_VALID = false
        else
            if SubString(str, b-StringLength(tmp), b) != tmp then
                set udg_LOAD_VALID = false
            endif
        endif
        set b = b-1
        set str = SubString(str, 0, b)
    endif
    
    loop
        exitwhen i &gt;= b
        if SubString(str, i, i + 1) == udg_Compress then
            set key = S2I(SubString(str, i + 1, i + 2))
            set i = i + (key)
        endif
        set udg_Load[c] = CG_Decode(SubString(str, i, i + key))
        set c = c + 1
        set i = i + key
        set key = 1
    endloop
    
    call CG_ClearData()
endfunction
</i></i></i></i>



Changelog

Code:
Version 0.4
     -Fixed a bug where loading big values first would mess up.
     -Code is more secure.

Version 0.3
    -Rewrote Save/Load functions (fixing a common bug in which it would output wrong code).
    -Player name saving is more accurate.

Version 0.2
    -Fixed the multiline comment bug for vanilla WE users.
    -Fixed an error that would give user wrong code.
    -Made code slightly shorter, depending on circumstances.
    -Demo now saves abilities

Version 0.1
    -Initial release
 

Attachments

  • CodeGen 0.04.w3x
    34.7 KB · Views: 438

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
What base does this convert to? And does this automatically create a checksum value in the code?

But looks good so far.
 

Sevion

The DIY Ninja
Reaction score
413
So you're saying I could have an alphabet length of say... 500 and it'd convert it to base 500? If I had such an alphabet?
 

Romek

Super Moderator
Reaction score
963
You've made about 7 of these already.
Couldn't you have updated one of the many graveyarded ones?


Anyway, post the code.
 
Reaction score
341
So you're saying I could have an alphabet length of say... 500 and it'd convert it to base 500? If I had such an alphabet?

If warcraft supported 500 characters than yea.

You've made about 7 of these already.
Couldn't you have updated one of the many graveyarded ones?

This one uses a different method than all of the other ones I submitted, which where crap.
 

Romek

Super Moderator
Reaction score
963
Post the code.
 
Reaction score
341
Post the code.

Dude give me time, don't expect me to do it in the 30 seconds of your last post.

Anyways, I don't think it's neccessary since other SLC's don't have their code posted. But I attached it as a textfile as it's long and in plain JASS.

Just change the tag to demo map -_-
 

UndeadDragon

Super Moderator
Reaction score
447
I like the fact that you can add your own integer values into the save/load code.

And yes, it is nessesary for the code to be posted. Unless you want it GY'ed.
 

Romek

Super Moderator
Reaction score
963
> Dude give me time, don't expect me to do it in the 30 seconds of your last post.
This is a forum, you've got nearly as much time as you want.
I repeated myself because you appeared to completely ignore that statement in the previous post I made.

UndeadDragon speaks the truth.
 

Nestharus

o-o
Reaction score
84
It wouldn't be too much of a jump to add a few more features to this ; ), for example saving strings.

I'm going to eventually be writing a base conversion utility and a save/load code that can save anything, but since you are at it, why not take out the base conversion that this thing uses and put it in its own snippet. You should include all ascii characters for it.

From there, for the save/load, you should add things like random code sequencing (scrambling the code), random encryption keys as well as as many encryption keys as the user wants with an encryption key base (the base would be the string that you have for your settings). Other things should include save string (not save player name, let them save w/e), save reals, save integers, etc.

If you're not up for it, I guess I can keep my base conversion utility and save/load system up on my planned to write list : ).

Aren't there already base conversion utilities out there?
Yea, but they don't convert anything to anything else ><. Should be 4 versions that each take 4 parameters..

param1- string base
param2- string/int number
param3- string base
param4- string/int number

in other words-
string string string string
string int string string
string string string int
string int string int
 
Reaction score
341
It wouldn't be too much of a jump to add a few more features to this ; ), for example saving strings.

I've added a SaveString function but it just uses StringHash/division. If you remove two of the zeroes from the division it will give a unique integer, but it will be in the hundreds.
 

Romek

Super Moderator
Reaction score
963
StringHash when saving strings isn't the way to go.

When saving the string, it's possible that it'll have a different index to the next game, in which it needs to be loaded.

> If you remove two of the zeroes from the division it will give a unique integer, but it will be in the hundreds.
I wouldn't have thought that keeping the number under 100 would be more important than keeping it unique. =|
 
Reaction score
341
When saving the string, it's possible that it'll have a different index to the next game, in which it needs to be loaded.

Are you sure that StringHash's values can be different per game? So far it's always been the same, just not tested on b.net.

I wouldn't have thought that keeping the number under 100 would be more important than keeping it unique. =|

It's not unique but still safe.
 

Romek

Super Moderator
Reaction score
963
I was under the impression that StringHash is simply S2ID, as GetHandleId is H2I.
It's pretty helpful if it's consistent.
 
Reaction score
341
Version 0.2 out!

Code:
Version 0.2
    -Fixed the multiline comment bug for vanilla WE users.
    -Fixed an error that would give user wrong code.
    -Made code slightly shorter, depending on circumstances.
    -Demo now saves abilities

Version 0.1
    .Initial release
 

SerraAvenger

Cuz I can
Reaction score
234
JASS:
function CG_IsLower takes string s returns boolean
    return s == &quot;a&quot; or s == &quot;b&quot; or s == &quot;c&quot; or s == &quot;d&quot; or s == &quot;e&quot; or s == &quot;f&quot; or s == &quot;g&quot; or s == &quot;h&quot; or s == &quot;i&quot; or s == &quot;j&quot; or s == &quot;k&quot; or s == &quot;l&quot; or s == &quot;m&quot; or s == &quot;n&quot; or s == &quot;o&quot; or s == &quot;p&quot; or s == &quot;q&quot; or s == &quot;r&quot; or s == &quot;s&quot; or s == &quot;t&quot; or s == &quot;u&quot; or s == &quot;v&quot; or s == &quot;w&quot; or s == &quot;x&quot; or s == &quot;y&quot; or s == &quot;z&quot;
endfunction

function CG_IsUpper takes string s returns boolean
    return s == &quot;W&quot; or s == &quot;A&quot; or s == &quot;B&quot; or s == &quot;C&quot; or s == &quot;D&quot; or s == &quot;E&quot; or s == &quot;F&quot; or s == &quot;G&quot; or s == &quot;H&quot; or s == &quot;I&quot; or s == &quot;J&quot; or s == &quot;K&quot; or s == &quot;L&quot; or s == &quot;M&quot; or s == &quot;N&quot; or s == &quot;O&quot; or s == &quot;P&quot; or s == &quot;Q&quot; or s == &quot;R&quot; or s == &quot;S&quot; or s == &quot;T&quot; or s == &quot;U&quot; or s == &quot;V&quot; or s == &quot;X&quot; or s == &quot;Y&quot; or s == &quot;Z&quot;
endfunction


...?


JASS:
    loop
        exitwhen udg_SaveItem<i> == null
        if udg_SaveItem<i> == GetItemTypeId(it) then
            return i
        endif
        set i = i + 1
    endloop
</i></i>


You can save that loop using a hashtable, if you write Setters and Getters for your variables.

EDIT:
JASS:
        exitwhen i &gt; StringLength(s)
        if a == 4  and i != StringLength(s) then


Why not

JASS:
        exitwhen i &gt;= StringLength(s)
        if a == 4  then


and, while you're at it,
JASS:
function CG_Seperate takes string s returns string
    local integer i = StringLength(s)
    local integer a = ModuloInteger( i, 4 )
    loop
        exitwhen i &lt;= 0 
        if a == 4 then
            set s = SubString(s, 0, i) + &quot;-&quot; + SubString(s, i, 999)
            set a = 0
        else
            set a = a + 1
        endif
        set i = i -1
    endloop
    return s
endfunction
 
Reaction score
341
In all honesty, who cares about speed in save and load systems.
By the way that reminds me, I plan on releasing a vJASS version.
So I'd rather not have any code comments, and have system comments instead. As long as the code doesn't leak.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top