• 🏆 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!

CodeGen 1.0.2

Introduction

Sometimes you need to transfer data between games in order to keep the progress you've made. For example in RPG maps you probably want to save your hero, levels, gold and items so you can continue next time you play. The way this is done in Warcraft III by generating codes that contain all of your data, which can later be re-entered to restore that saved information. This is nothing new in the modding world however it's commonly asked about and requested yet many people still have issues. This is part of the reason why I decided to create an easy to use, universal, GUI-friendly save and load system which I'm calling the Code Generator.

Main Features
  1. Player-name sensitive (optional).
  2. Highly configurable.
  3. Can be used in the normal World Editor (doesn't require JNGP).
  4. Very easy to use.


  • -------- -------------------- --------
  • -------- The below options are for saving load codes to the Warcraft III folder. --------
  • -------- You can modify the file name via the SaveLoad_Filename variable within the save trigger. --------
    • -------- -------------------- --------
    • Set SaveLoad_SaveToDisk = True
    • Set SaveLoad_Directory = Save
    • -------- -------------------- --------
    • -------- Some configurables --------
    • -------- -------------------- --------
    • Set SaveLoad_Alphabet = abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789
    • Set SaveLoad_CheckName = True
    • Set SaveLoad_Security = True
    • Set SaveLoad_HyphenSpace = 4
    • Set SaveLoad_SeperationChar = -
    • Set SaveLoad_Lower = |c002a4580
    • Set SaveLoad_Number = |cffffcc00
    • Set SaveLoad_Upper = |cff008000
    • -------- -------------------- --------
    • -------- Increase the value if you want to save bigger numbers --------
    • -------- Decrease it if you want to generate a smaller save code but only be able to save smaller values --------
    • -------- It's suggested to not increase it above 7 --------
    • -------- -------------------- --------
    • Set SaveLoad_MaxValue = 6
    • -------- -------------------- --------
    • -------- Store all the heroes you want to be able to be saved below. --------
    • -------- -------------------- --------
    • Set SaveLoad_Hero[0] = Blood Mage
    • Set SaveLoad_Hero[1] = Lich
    • Set SaveLoad_Hero[2] = Blademaster
    • Set SaveLoad_Hero[3] = Demon Hunter
    • Set SaveLoad_HeroCount = 3
    • -------- -------------------- --------
    • -------- Store all the abilities you want to be able to be saved below. --------
    • -------- -------------------- --------
    • Set SaveLoad_Abilities[0] = Flame Strike
    • Set SaveLoad_Abilities[1] = Siphon Mana
    • Set SaveLoad_Abilities[2] = Phoenix
    • Set SaveLoad_Abilities[3] = Banish
    • Set SaveLoad_AbilityCount = 3
    • -------- -------------------- --------
    • -------- Store all the items you want to be able to be saved below. --------
    • -------- -------------------- --------
    • Set SaveLoad_Item[0] = (Item-type of No item)
    • Set SaveLoad_Item[1] = Claws of Attack +15
    • Set SaveLoad_Item[2] = Crown of Kings +5
    • Set SaveLoad_Item[3] = Kelen's Dagger of Escape
    • Set SaveLoad_Item[4] = Mask of Death
    • Set SaveLoad_Item[5] = Orb of Frost
    • Set SaveLoad_Item[6] = Ring of Protection +5
    • Set SaveLoad_ItemCount = 6
    • -------- -------------------- --------
    • -------- Don't modify below this line. --------
    • -------- This is just here to copy variables to your map --------
    • -------- -------------------- --------
    • Set SaveLoad_Full = SaveLoad_Alphabet
    • Set SaveLoad_Error = <Empty String>
    • Set SaveLoad_Base = (Length of SaveLoad_Alphabet)
    • Set SaveLoad_Char[0] = <Empty String>
    • Set Load[0] = 0
    • Set LoadCount = 0
    • Custom script: call CodeGen_Init()
Installation
  1. Make sure your settings allow copying variables (Image)
  2. Copy the CodeGen folder over to your map.
  3. Paste the maps script into yours (Image)

How do I use it?

Let's take a look at the most basic example.

  • Set Save[0] = (Player 1 (Red) Current gold)
  • Custom script: set udg_Code = CodeGen_Compile()
  • Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code

The above will save Players 1's gold. Simple, isn't it? Now you're probably asking "How do I load it?".

  • -------- Check if load is valid --------
  • Set Code = (Substring((Entered chat string), 7, 999))
  • Custom script: call CodeGen_Load(udg_Code)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • SaveLoad_Valid Equal to False
    • Then - Actions
      • Game - Display to (Player group((Triggering player))) for 10.00 seconds the text: SaveLoad_Error
      • Skip remaining actions
    • Else - Actions
  • Player - Set Player 1 (Red) Current gold to Load[0]

Equally as simple and there are more examples are available in the demo map.

Keywords:
save,load,save load,save and load,code,codegen,code gen,triggerhappy,password,gen,generator,generate,preloadgen,preload,file,io,to,disk
Contents

CodeGen v1.0.2 (Map)

Reviews
8 March 2014 PurgeandFire: Approved. Review: http://www.hiveworkshop.com/forums/2496968-post145.html 21 December 2013 Bribe: changed status to needs fix. 8 Sep 2011 Bribe: Deprecated in favor of: Save/Load with Snippets 21:27, 29th Aug...
Level 8
Joined
Apr 8, 2009
Messages
499
Ehh,, This will require all of us who used it to find out Anti-Cheat triggers. Because im more of a skill inspector and so what i found out that is: If you type in cheats and then kill really hard creeps then the person types "-save" well i realized that well....... If you load your code in Local Area Network, Or Battle.net it will load and that person had done nothing. So im looking forward for everyone who uses this to find Anti-Cheat Triggers so then they have the opportunity to save in Single Player Mode but cant cheat as for me i have a link for you guys and here it is http://www.hiveworkshop.com/forums/spells-569/anti-cheat-version-0-a-184377/

what the hell are you babbling about?
 
Ehh,, This will require all of us who used it to find out Anti-Cheat triggers. Because im more of a skill inspector and so what i found out that is: If you type in cheats and then kill really hard creeps then the person types "-save" well i realized that well....... If you load your code in Local Area Network, Or Battle.net it will load and that person had done nothing. So im looking forward for everyone who uses this to find Anti-Cheat Triggers so then they have the opportunity to save in Single Player Mode but cant cheat as for me i have a link for you guys and here it is http://www.hiveworkshop.com/forums/spells-569/anti-cheat-version-0-a-184377/

anti-cheat? not needed. why? because you can just disable the save or load system on SinglePlayer mode, which takes up less processing power than using anti-cheats...

and PLEASE DO NOT POST SOMETHING JUST TO PROMOTE YOUR RESOURCE ON OTHER THREADS...
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Pretty bad. 16 characters w/ all of the security disabled for this data.
JASS:
struct tester extends array
    private static method onInit takes nothing returns nothing
        set udg_SaveLoad_Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        set udg_SaveLoad_CheckName = false
        set udg_SaveLoad_HyphenSpace = 50
        set udg_SaveLoad_Lower = "|c002a4580"
        set udg_SaveLoad_Number = "|cffffcc00"
        set udg_SaveLoad_Upper = "|cff1142aa"
        // Store all the items you want to be able to be saved below.
        set udg_SaveLoad_Item[1] = 'ratf'
        set udg_SaveLoad_ItemCount = 0
        // Store all the heroes you want to be able to be saved below.
        set udg_SaveLoad_Hero[1] = 'Hblm'
        set udg_SaveLoad_HeroCount = 0
        // Don't modify below this line.
        set udg_SaveLoad_Base = StringLength(udg_SaveLoad_Alphabet)
        set udg_SaveLoad_Char = ""
        set udg_Load[0] = 0
        set udg_LoadCount = 0
        call CodeGen_Init()
        set udg_Save[0] = 1
        set udg_Save[1] = 1000
        set udg_Save[2] = 100
        set udg_Save[3] = 300
        set udg_Save[4] = 1
        set udg_Save[5] = 0
        set udg_Save[6] = 7
        set udg_Save[7] = 10
        set udg_SaveCount = 7
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, CodeGen_Compile())
    endmethod
endstruct

That data can be stored in 7 chars with 0 security, so 16 is rather terrible.

You should update this to use BigInt to minimize the character count >.>.
 
Level 2
Joined
May 1, 2011
Messages
19
Okay This Is Friking Me Out....Ive Been Trying So Much Shit To Fix It But Wont Work Error call CodeGen_Init() Error set udg_Save[udg_SaveCount] = CodeGen_ConvertUnit(GetUnitTypeId(udg_Hero)) Error set udg_Save[udg_SaveCount] = CodeGen_ConvertItem(GetItemTypeId(udg_Item)) Error set udg_Code = CodeGen_Compile() Error call CodeGen_Load(udg_Code)
PPWWWWEEEEEEEEZE HELP ME BEFORE I GO MAD !!!!!!!!:goblin_cry::eekani:
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Still if you want someone to do something great in GUI, it's Bribe :) (as we others don't have the time clicking and clicking over and over again... stupid GUI)

Naaahhh way too time consuming to remake in vanilla, download jngp and latest jh will take less time (captain obvious strikes again)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,467
I have been thinking about doing a vanilla-WE-compatible version and it is doable, I just have so many other things that I have almost no time for.

Ideally this would need to be in custom script. World Editor slows down the more statements you have in a trigger so to do something like BigInt would need to be custom script.

Working on GUI UnitEvent, for example, had been painfully slow.
 

Deleted member 219079

D

Deleted member 219079

I was just about to search for a save/load system to my map at the spells section. And this was updated. No kidding :D

Though I was going to add Nestharus' system, I will give this a try. The length of the code is the conclusive point, I don't want my map to irritate its players with long codes :(

Edit: I can't get your system working. I tried to modify it so that it only saves gold. Here's how I modified it:
  • CodeGen Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- -------------------- --------
      • -------- Some configurables --------
      • -------- -------------------- --------
      • Set SaveLoad_Alphabet = abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789
      • Set SaveLoad_CheckName = True
      • Set SaveLoad_HyphenSpace = 4
      • Set SaveLoad_Lower = |c002a4580
      • Set SaveLoad_Number = |cffffcc00
      • Set SaveLoad_Upper = |cff008000
      • -------- -------------------- --------
      • -------- Increase the value if you want to save bigger numbers --------
      • -------- Decrease it if you want to generate a smaller save code but only be able to save smaller values --------
      • -------- It's suggested to not increase it above 7 --------
      • -------- -------------------- --------
      • Set SaveLoad_MaxValue = 6
      • -------- -------------------- --------
      • -------- Don't modify below this line. --------
      • -------- This is just here to copy variables to your map --------
      • -------- -------------------- --------
      • Set SaveLoad_Full = SaveLoad_Alphabet
      • Set SaveLoad_Base = (Length of SaveLoad_Alphabet)
      • Set SaveLoad_Char[0] = <Empty String>
      • Set Load[0] = 0
      • Set LoadCount = 0
      • Custom script: call CodeGen_Init()
  • CodeGen Save
    • Events
      • Player - Player 1 (Red) types a chat message containing -save as An exact match
      • Player - Player 2 (Blue) types a chat message containing -save as An exact match
      • Player - Player 3 (Teal) types a chat message containing -save as An exact match
      • Player - Player 4 (Purple) types a chat message containing -save as An exact match
    • Conditions
    • Actions
      • Set SaveCount = 0
      • Set Save[SaveCount] = ((Triggering player) Current gold)
      • -------- Show Code --------
      • Custom script: set udg_Code = CodeGen_Compile()
      • Game - Display to (Player group((Triggering player))) for 60.00 seconds the text: Code
  • CodeGen Load
    • Events
      • Player - Player 1 (Red) types a chat message containing -load as A substring
      • Player - Player 2 (Blue) types a chat message containing -load as A substring
      • Player - Player 3 (Teal) types a chat message containing -load as A substring
      • Player - Player 4 (Purple) types a chat message containing -load as A substring
    • Conditions
      • (Substring((Entered chat string), 1, 6)) Equal to -load
    • Actions
      • -------- Check if load is valid --------
      • Set Code = (Substring((Entered chat string), 7, 999))
      • Custom script: call CodeGen_Load(udg_Code)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SaveLoad_Valid Equal to False
        • Then - Actions
          • Game - Display to (Player group((Triggering player))) for 10.00 seconds the text: Invalid code.
          • Skip remaining actions
        • Else - Actions
      • Set LoadCount = 0
      • Player - Set (Triggering player) Current gold to Load[LoadCount]
I really want to give this system 5/5 since it's so straight forward and practical, but it always gives me LhK TT

Edit2: I got it working for a while, then it stopped working again...
 
Last edited by a moderator:
@jondrean

It was an issue when trying to save just one value (and setting SaveCount to 0). I've fixed it now thanks for pointing that out.

Code:
v1.0.1
--SaveLoad_Error variable added that displays the last error in loading
--Can now toggle code security
--Hyphen character now configurable
--Fixed an issue where some integers wouldn't get colored
--Fixed an bug when trying to save one value
 

Deleted member 219079

D

Deleted member 219079

Now it works like a charm :) Thank you for this awesome system! The codes are short and secure (arguably), also it's very easy to apply, 5/5 from me.

Just a question: does old codes work with newer system? Because I'll add this as an experience system, which counts experience points from each game. It'd be irritating to lose all the experience.
 
Could you post the code in the main post or in some post in the thread? Otherwise I can't review it for a little while.

You can't view it on the moderation page's trigger viewer?

JASS:
function CodeGen_Init takes nothing returns nothing
    local integer i = 1
    local integer b = udg_SaveLoad_Base
    local integer m = udg_SaveLoad_MaxValue
    loop
        exitwhen i >= udg_SaveLoad_MaxValue
        set udg_SaveLoad_Char[i] = SubString(udg_SaveLoad_Alphabet, i, i+1)
        set i = i + 1
    endloop
    set udg_SaveLoad_Alphabet = SubString(udg_SaveLoad_Alphabet, 0, 1) + SubString(udg_SaveLoad_Alphabet, m + 1, b)
    set udg_SaveLoad_Base     = b - m
endfunction

function CodeGen_ConvertItem takes integer id returns integer
    local integer i = 1
    loop
        exitwhen i > udg_SaveLoad_ItemCount
        if (id == udg_SaveLoad_Item[i]) then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction

function CodeGen_ConvertUnit takes integer id returns integer
    local integer i = 1
    loop
        exitwhen i > udg_SaveLoad_HeroCount
        if (id == udg_SaveLoad_Hero[i]) then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction

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

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

function CodeGen_Decode takes string s returns integer
    local integer a = 0
    
    loop
        exitwhen StringLength(s) == 1
        set a = a * udg_SaveLoad_Base + udg_SaveLoad_Base * CodeGen_StrPos(SubString(s, 0, 1))
        set s = SubString(s, 1, 99)
    endloop
    
    return a+CodeGen_StrPos(s)
endfunction

function CodeGen_StringChecksum takes string in returns integer
    local integer i = 0
    local integer l = StringLength(in)
    local integer t = 0
    local integer o = 0
    loop
        exitwhen i >= l
        set t = CodeGen_Decode(SubString(in, i, i + 1))
        set o = o + t
        set i = i + 1
    endloop
    return o
endfunction

function CodeGen_Color takes string char returns string
    local integer i = 0
    local integer l = StringLength(udg_SaveLoad_Full)
    local string x  = ""
    loop
        exitwhen i > l
        set x = SubString(udg_SaveLoad_Full, i, i + 1)
        if char == x then
            if (x=="0" or S2I(x) > 0) then
                return udg_SaveLoad_Number + char + "|r"
            elseif StringCase(x, false) == x then
                return udg_SaveLoad_Lower + char + "|r"
            elseif StringCase(x, true) == x then
                return udg_SaveLoad_Upper + char + "|r"
            endif
        endif
        set i = i + 1
    endloop
    return char
endfunction

function CodeGen_Format takes string s returns string
    local integer i = 0
    local integer x = StringLength(s)
    local integer j = 1
    local string s2 = ""
    
    loop
        exitwhen i >= x
        
        set s2 = s2 + CodeGen_Color(SubString(s, i, i + 1))
        
        if (j >= udg_SaveLoad_HyphenSpace and i != (x-1)) then
            set j = 0
            set s2 = s2 + udg_SaveLoad_SeperationChar
        endif
        
        set j = j + 1
        set i = i + 1
    endloop
    
    return s2
endfunction

function CodeGen_Strip takes string s returns string
    local integer i  = 0
    local integer x  = StringLength(s)
    local string out = ""
    local string a   = ""
    
    loop
        exitwhen i > x
        set a = SubString(s, i, i + 1)
        if (a != udg_SaveLoad_SeperationChar) then
            set out = out + a
        endif
        set i = i + 1
    endloop
    
    return out
endfunction

// yeeahh descriptive variables
function CodeGen_Load takes string s returns nothing
    local string str = CodeGen_Strip(s)
    local string tmp = ""
    local string c   = ""
    local integer x  = 0
    local integer i  = 1
    local integer l  = 0
    local integer j  = 1
    local integer f  = 0
    local boolean b  = true
    
    set udg_SaveLoad_Valid = false
    
    if (udg_SaveLoad_Security) then
        loop
            exitwhen i > 3
            if (CodeGen_Decode(SubString(str, 0, i)) == CodeGen_StringChecksum(SubString(str, i, 999))) then
                set udg_SaveLoad_Valid = true
                set str = SubString(str, i, 999)
                set i = 4
            endif
            set i = i + 1
        endloop
    endif
    
    if (not udg_SaveLoad_Valid) then
        set udg_SaveLoad_Error = "Ivalid code"
        return
    endif
    
    set i = 0
    set l = StringLength(str)
    
    if (udg_SaveLoad_CheckName) then
        set c = CodeGen_Encode(CodeGen_StringChecksum(GetPlayerName(GetTriggerPlayer())))
        set i = StringLength(c)
        if (c != SubString(str, l - i, i)) then
            set udg_SaveLoad_Valid = false
            set udg_SaveLoad_Error = "Wrong username"
            return
        endif
        set l = l - i
    endif
    
    set i = 0
    
    loop
        exitwhen i >= l
        set tmp = SubString(str, i, i + 1)
        
        set b = true
        set f = 0
        set j = 1
        
        loop
            exitwhen f >= (udg_SaveLoad_MaxValue)
            if (tmp == udg_SaveLoad_Char[f]) then
                set j = f + 2
                set udg_Load[x] = CodeGen_Decode(SubString(str, i + 1, i + (j)))
                set b = false
                set f = udg_SaveLoad_MaxValue
            endif
            set f = f + 1
        endloop
        
        if (b) then
            set udg_Load[x] = CodeGen_Decode(tmp)
        endif
        
        set i = i + j
        set x = x + 1
    endloop
    
    set udg_SaveLoad_Valid = true
endfunction

function CodeGen_Compile takes nothing returns string
    local integer i  = 0
    local integer j  = 0
    local string out = ""
    local string ln  = ""
    local string x   = ""

    loop
        exitwhen i > udg_SaveCount
        set x = CodeGen_Encode(udg_Save[i])
        set j = StringLength(x)

        if (j > 1) then
            set out = out + udg_SaveLoad_Char[j-1]
        endif
        
        set out = out + x
        set i = i + 1
    endloop

    if (udg_SaveLoad_CheckName) then
        set out = out + CodeGen_Encode(CodeGen_StringChecksum(GetPlayerName(GetTriggerPlayer())))
    endif
    
    if (udg_SaveLoad_Security) then
        set out = CodeGen_Encode(CodeGen_StringChecksum(out)) + out
    endif
    
    return CodeGen_Format(out)
endfunction
 
Review:
  • In CodeGen_Load, just for readability purposes, you may want to use exitwhen true instead of set i = 4 in your loop.
  • udg_SaveLoadError says "Ivalid Code" instead of "Invalid Code".
  • In CodeGen_Strip, the loop runs one extra time (I think. I always hate iterating over a string in JASS). The condition should be exitwhen i >= x. Same for CodeGen_Color. I assume this doesn't cause any problems though.
  • CodeGen_ConvertItem and CodeGen_ConvertUnit could use a hashtable for O(1) complexity. I don't think people will be saving too many objects, so I suppose it doesn't matter. It is just something to consider. :)

But overall, this system is well coded and very easy to use. Nothing is better than a system that is straight-forward and to the point (and kudos for making the code so clean). I'll be recommending this to users.

And about the "review", those are all minor–just food for thought. Approved.

TriggerHappy said:
You can't view it on the moderation page's trigger viewer?

To be honest, I didn't know such a thing existed. Does it?
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
  • -------- Check if load is valid --------
  • Set Code = (Substring((Entered chat string), 7, 999))
  • Custom script: call CodeGen_Load(udg_Code)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
  • If - Conditions
  • SaveLoad_Valid Equal to False
  • Then - Actions
  • Game - Display to (Player group((Triggering player))) for 10.00 seconds the text: SaveLoad_Error
  • Skip remaining actions
  • Else - Actions
  • Player - Set Player 1 (Red) Current gold to Load[0]
how if that call CodeGen_Load(udg_Code) returns boolean? then you dont need that ITE udg_SaveLoad_Valid
 

EdgeOfChaos

E

EdgeOfChaos

Hello TriggerHappy,
I used your save/load system in my map, Return of Legends. It works fine for most users, but some users are having problems. No code they obtain from the system will work.

I've tried spoofing on LAN as the user and entering their code (copied myself from a screenshot) and everything. Nothing seems to work for a few users. Most get the "Wrong username" message but one has recently got the "Ivalid Code" message.

Do you have any idea what is going on? Is there some fix I can apply to the code?

The codes in question are all legitimate copied from the code output.


More info: http://clanrc.enjin.com/forum/page/11/m/20718693/viewthread/11165843-bug-reports
Last post on that page.
Thanks.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Hello TriggerHappy,
I used your save/load system in my map, Return of Legends. It works fine for most users, but some users are having problems. No code they obtain from the system will work.

I've tried spoofing on LAN as the user and entering their code (copied myself from a screenshot) and everything. Nothing seems to work for a few users. Most get the "Wrong username" message but one has recently got the "Ivalid Code" message.

Do you have any idea what is going on? Is there some fix I can apply to the code?

The codes in question are all legitimate copied from the code output.


More info: http://clanrc.enjin.com/forum/page/11/m/20718693/viewthread/11165843-bug-reports
Last post on that page.
Thanks.

Can you post your saveload setup? Do you see any relations with the names of the affected players?
 
Top