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: 444

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
964
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
964
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
964
> 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
964
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
964
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.
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      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