System The Shortest Save/Load Code Ever

Bomber7

New Member
Reaction score
0
I figured, thats why I also put it in a library. :p

Oh, if your using a mac, then you won't be familiar with vJASS functions. Libraries are automatically placed in an order of your choice at the top of the map .j file. This frees me from having to worry it won't be callable from some locations.

Edit: Found a bug
Edit: nvm
 

Bomber7

New Member
Reaction score
0
Very sorry for the double post, but I can't get it to work for some reason.

Ok I looked at your demo maps and found that load_code returns a boolean if security checks out. True = yes, false = no. So After building all my save code, and about 50% of the load code, I decided to test it out. To my surprise I couldn't seem to get the security to check out when I tried to load my code. (See screenshot attached)

JASS:
function Trig_Save_Actions takes nothing returns nothing
local player g = GetTriggerPlayer()
local integer ind = GetPlayerId(g)
local unit u = PlayerHero[ind]
local integer counter = 0
local string scode
local HeroClass Wetr = PlayerHeroclasses[ind]
local integer saved_gold
local integer saved_lumber
local ItemFrm array rItemT
local ItemFrm z

    call clear_bits()

    
    call push_int(GetUnitLevel(u), MAX_LEVEL)
    call push_int(R2I((GetHeroXP(u) - (GetUnitLevel(u) - 1)*1000)/RESOLUTION_DIV), R2I(MAX_LEVEL*1000/RESOLUTION_DIV))
    //    call BJDebugMsg("Xp = " + I2S((GetHeroXP(u) - (GetUnitLevel(u) - 1)*1000)/RESOLUTION_DIV))
    call push_int(R2I(GetHeroAgi(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    call push_int(R2I(GetHeroStr(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    call push_int(R2I(GetHeroInt(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    
    loop
    exitwhen counter == 6
        set z = GetItemT(UnitItemInSlot(u,counter))
        set rItemT[counter] = z
        call push_int(z,FinalStruct + 1)
        set counter = counter + 1
    endloop
    
    set counter = 0
    loop
    exitwhen counter == 6
        call push_int(GetUnitAbilityLevel(u,Wetr.Spell[counter]),MAX_ABIL_LEVEL)
        set counter = counter + 1
    endloop
    
    set saved_gold = GetPlayerState(g,PLAYER_STATE_RESOURCE_GOLD)/GOLD_RESOLUTION_DIV
    set saved_lumber = GetPlayerState(g,PLAYER_STATE_RESOURCE_LUMBER)/LUMBER_RESOLUTION_DIV
    
    if saved_gold > GOLD_MAX then
        set saved_gold = GOLD_MAX
    endif
    if saved_lumber > LUMBER_MAX then
        set saved_lumber = LUMBER_MAX
    endif
    
    call push_int(saved_gold,GOLD_MAX)
    call push_int(saved_lumber,LUMBER_MAX)
    
    call push_int(Wetr,50)
    call push_int(VERSION,50)
    
    set scode = create_code(g,7)
    set scode = format_code(scode,6)
    
    if GetLocalPlayer() == g then
        call ClearTextMessages()
    endif
    call DisplayTimedTextToPlayer(g,0,0,270,"------------------------------------------------------------------------------------------")
    call DisplayTimedTextToPlayer(g,0,0,270,"Your code is " + scode)
    call DisplayTimedTextToPlayer(g,0,0,270,"All your gold and any items (except those marked free trade) will now be untradeable")
    call DisplayTimedTextToPlayer(g,0,0,270,"Any additional gold/lumber/items you get will remaint to be tradeable")
    call DisplayTimedTextToPlayer(g,0,0,270,"------------------------------------------------------------------------------------------")
    //Permnalize stuff
    set Touchable_gold[ind] = 0
    set Touchable_lumb[ind] = 0
    
    set counter = 0
    loop
    exitwhen counter == 6
        if rItemT[counter].TradeType == VD_SAVE_LOAD_TRADE then
            call SetItemPlayer(UnitItemInSlot(u,counter),g,false)
        endif
        set counter = counter + 1
    endloop
    
    set g = null
    set u = null
endfunction

//===========================================================================
function InitTrig_Save takes nothing returns nothing
    set gg_trg_Save = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(0), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(1), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(2), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(3), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(4), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(5), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(6), "-save", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Save, Player(7), "-save", true )
    call TriggerAddAction( gg_trg_Save, function Trig_Save_Actions )
endfunction


The load code
JASS:
function Decode takes nothing returns nothing
local player g = GetTriggerPlayer()
local integer ind = GetPlayerId(g)
local unit u 
local integer counter = 0
local string scode
local HeroClass Wetr
local integer array Info
local ItemFrm array rItemT
local ItemFrm z

    if not load_code(g,7,SubString(GetEventPlayerChatString(),6,200)) then
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, code security incorrect. You get this message only if the code is spelled wrong. You get a different message if the code version is incorrect")
        call DisplayTextToPlayer(g,0,0,"%" + SubString(GetEventPlayerChatString(),6,200) + "%")
        set g = null
        set u = null
        return
    endif
    
    set Info[0] = pop_int(50)
    if not (Info[0] == VERSION) then //-load TSFn@U-UTeFA5-t1Jp0O-5B
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, code version " + I2S(Info[0]) + " is incorrect")
        set u = null
        set g = null
        return
    endif
    
    set Wetr = pop_int(50)
    set PlayerHeroclasses[ind] = Wetr
    set u = CreateUnit(g,Wetr.UnType,GetRandomReal(GetRectMinX(gg_rct_Revive), GetRectMaxX(gg_rct_Revive)),GetRandomReal(GetRectMinY(gg_rct_Revive), GetRectMaxY(gg_rct_Revive)),0) //PlayerHero[ind]
    set PlayerHero[ind] = u
    
    set Info[2] = pop_int(LUMBER_MAX) //Pop out lumber/gold
    set Info[1] = pop_int(GOLD_MAX)
    
    call SetPlayerState(g,PLAYER_STATE_RESOURCE_GOLD,Info[1]*GOLD_RESOLUTION_DIV)
    call SetPlayerState(g,PLAYER_STATE_RESOURCE_LUMBER,Info[2]*LUMBER_RESOLUTION_DIV)
    
    set counter = 5
    loop
    exitwhen counter == -1
        call pop_int(MAX_ABIL_LEVEL)//GetUnitAbilityLevel(u,Wetr.Spell[counter])
        set counter = counter - 1
    endloop
    
    //REST OF STUFF GOES HERE
    //call SetPlayerState(g,PLAYER_STATE_RESOURCE_GOLD,pop_int(
    
    //Permnalize stuff
    set Touchable_gold[ind] = 0
    set Touchable_lumb[ind] = 0
    
    set counter = 0
    loop
    exitwhen counter == 6
        if rItemT[counter].TradeType == VD_SAVE_LOAD_TRADE then
            call SetItemPlayer(UnitItemInSlot(u,counter),g,false)
        endif
        set counter = counter + 1
    endloop
    
    set g = null
    set u = null
endfunction

//===========================================================================
function InitTrig_Load takes nothing returns nothing
local string m = "-load"
    set gg_trg_Load = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(0), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(1), m, false)
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(2), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(3), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(4), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(5), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(6), m, false )
    call TriggerRegisterPlayerChatEvent( gg_trg_Load, Player(7), m, false )
    call TriggerAddAction( gg_trg_Load, function Decode )
endfunction


I already checked, the code I pass the function is exactly as I type it in. On the bright side, I was very please with how a small change in a single value changes the whole code. The speed of the save also left little to be desired. And of course the size was much smaller then I was expecting.

You may notice in the screenshot, that I made a small modification in the format function to support upper/lower case letters. Also the modification of the format color scheme will help prevent hackers from identifying which system was used in the map. (As will obfuscation)
 

Korolen

New User (Why do I keep getting those red bars?)
Reaction score
69
Just want to check here, Bomber7: the code starts with Hh6shf, while you typed in Hh5shf.

Assuming that was just a mistake when you took the screenshot, try putting call BJDebugMsg(debug_dump_bits()) after you load the code and after the code is generated to make sure it's getting through the save/encrypt/decrypt/load process. And if you screenshot those bit sequences and post them here that would be great too.

In addition, could you give me the following information:

  1. Exactly what code you changed in the main Kode script
  2. The value of Kode_charmap and Kode_encryption_strength
 

Bomber7

New Member
Reaction score
0
Ok, heres the information (screenshot)
Note that the top bit dump was done before I called create_code. This is because when I tried to call it after create_code it would display (null).
Of course the second dump is after the load.

The only code I changed was
JASS:
    function format_code takes string input, integer dash_spacing returns string
        local integer i = 0
        local string c
        local string s = ""
        loop
            exitwhen i >= StringLength(input)
            set c = SubString(input, i, i + 1)
            if c == "0" or c == "1" or c == "2" or c == "3" or c == "4" or c == "5" or c == "6" or c == "7" or c == "8" or c == "9" then
                set c = "|cffffaabb" + c + "|r"
            elseif c == "!" or c == "@" or c == "#" or c == "$" or c == "%" or c == "^" or c == "&" or c == "*" then
                set c = "|cffaabbdd" + c + "|r"
            elseif (StringCase(c,false) == c) and not (StringCase(c,false) == StringCase(c,true)) then
                set c = "|CFF18E7BD" + c + "|r"
            elseif (StringCase(c,true) == c) and not (StringCase(c,false) == StringCase(c,true)) then
                set c = "|CFF90FF90" + c + "|r"
            else
                set c = "|cffffcc00" + c + "|r" //
            endif
            if ModuloInteger(i, dash_spacing) == 0 and i != 0 and i != StringLength(input) then
                set c = "-" + c
            endif
            set s = s + c
            set i = i + 1
        endloop
        return s
    endfunction

I'm using code from Kode 0.2.1.w3x.

'war3map.j' extracted from the map's archive is inside InternalJassFile.zip. Some parts of it were generated by the vJass precompiler, so if some functions/variables look weird you'll know why.
 

Korolen

New User (Why do I keep getting those red bars?)
Reaction score
69
You're problem is your charmap starts with uppercase letters; it needs to start with lowercase letters and then go on to the uppercase ones for case sensitivity. It's because of a kludge I implemented to make entering case-insensitive codes case-insensitive. I outline setting the charmap somewhere in the Installation section, I think.

By the way, making it case-sensitive with digits and the @#%& is usually overkill. The more characters that are in the character map, the less each character contributes to code shortness. The difference between 66 (a-z, A-Z, 0-9, @#%&) and 62 (a-z, A-Z, 0-9) is only 1.5% shorter codes. Making it case-sensitive with digits as opposed to case-insensitive with digits only shortens the code 13%. And case-insensitive letters with digits is only 9% shorter then case-insensitive without digits. All in all, the monster character map you are using only produces 22% shorter codes than ABCDEFGHIJKLMNOPQRSTUVWXYZ. Usually it's best to stick with that or case-insensitive with digits, as the shortened codes take a while for the user to type in (because of all the SHIFT presses and punctuation).

EDIT: A quick way to check that is to look in the Initialize Kode trigger; the values are how many bits of information each character can "hold", based on the length of the charmap.

EDIT2: I added a graph with the number of characters in the charmap on the x-axis, and the length of a medium-sized code (50 bits) on the y-axis. As you can see, it trails off rather quickly.
 

Attachments

  • Code Length vs Charmap Size.png
    Code Length vs Charmap Size.png
    85 KB · Views: 346

Bomber7

New Member
Reaction score
0
Very sorry for the double post, but the last post is quite old and this one covers a new problem. I'm afraid KODE has reached its limits. It hits the op-limit every time it attempts to load my code.

This problem started after I added about 6 or 7 more integers. Funny enough, the load-failure happens long before it gets to the modified lines of code.

Just incase you need to see my code, here it is.

Globals
JASS:

globals
    integer MAX_LEVEL = 30
    integer RESOLUTION_DIV = 10
    integer MAX_STATS = 1000
    integer STAT_RESOLUTION_DIV = 1
    integer MAX_ABIL_LEVEL = 6
    integer GOLD_RESOLUTION_DIV = 10
    integer LUMBER_RESOLUTION_DIV = 1
    integer GOLD_MAX = 100000
    integer LUMBER_MAX = 10000
    integer VERSION = 5
    integer THROWN_STACK_RES = 10
endglobals


Save
JASS:


function SaveItemC takes item Q returns nothing
    if GetItemCharges(Q) > MAX_STACK then
        call push_int(GetItemCharges(Q)/THROWN_STACK_RES,MAX_STACK + 1)
        call push_int(0,2)
    else
        call push_int(GetItemCharges(Q),MAX_STACK + 1)
        call push_int(1,2)
    endif
endfunction


function Trig_Save_Actions takes nothing returns nothing
local player g = GetTriggerPlayer()
local integer ind = GetPlayerId(g)
local unit u = PlayerHero[ind]
local integer counter = 0
local string scode
local HeroClass Wetr = PlayerHeroclasses[ind]
local integer saved_gold
local integer saved_lumber
local ItemFrm array rItemT
local ItemFrm z
local item Q

    if PlayerHero[ind] == null then
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, you don't have a hero to save yet.")
        set g = null
        set u = null
        return
    endif
    call clear_bits()
    
    call push_int(GetUnitLevel(u), MAX_LEVEL)
    call push_int(R2I((GetHeroXP(u) - (GetUnitLevel(u) - 1)*GetReqXP())/RESOLUTION_DIV), R2I(GetReqXP()/RESOLUTION_DIV))
        //call BJDebugMsg("Xp = " + I2S((GetHeroXP(u) - (GetUnitLevel(u) - 1)*1000)/RESOLUTION_DIV))
    call push_int(R2I(GetHeroAgi(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    call push_int(R2I(GetHeroStr(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    call push_int(R2I(GetHeroInt(u,false)/STAT_RESOLUTION_DIV),R2I(MAX_STATS)/STAT_RESOLUTION_DIV)
    
    loop
    exitwhen counter == 6
        set Q = UnitItemInSlot(u,counter)
        set z = GetItemT(Q)
        set rItemT[counter] = z
        call push_int(z,FinalStruct + 1)
        call SaveItemC(Q)
        set counter = counter + 1
    endloop
    
    //Save equipped items
    call SaveItemC(HeroLeftHSlot[ind])
    call push_int(GetItemT(HeroLeftHSlot[ind]),FinalStruct + 1)
    call SaveItemC(HeroRightHSlot[ind])
    call push_int(GetItemT(HeroRightHSlot[ind]),FinalStruct + 1)
    call SaveItemC(HeroAuxSlot[ind])
    call push_int(GetItemT(HeroAuxSlot[ind]),FinalStruct + 1)
    call SaveItemC(HeroChestHSlot[ind])
    call push_int(GetItemT(HeroChestHSlot[ind]),FinalStruct + 1)
    
    
    set Q = null //A bit of cleanup
    
    set counter = 0
    loop
    exitwhen counter == TOTAL_LEARNABLE_SPELLS+1
        call push_int(GetUnitAbilityLevel(u,Wetr.Spell[counter]),MAX_ABIL_LEVEL)
        set counter = counter + 1
    endloop
    
    call push_int(GetUnitAbilityLevel(u,'A003'),MAX_LEVEL/10 + 1)
    //call BJDebugMsg("Ability pushed at " + I2S(GetUnitAbilityLevel(u,'A003')))

    set saved_gold = GetPlayerState(g,PLAYER_STATE_RESOURCE_GOLD)/GOLD_RESOLUTION_DIV
    set saved_lumber = GetPlayerState(g,PLAYER_STATE_RESOURCE_LUMBER)/LUMBER_RESOLUTION_DIV
    
    if saved_gold > GOLD_MAX then
        set saved_gold = GOLD_MAX
    endif
    if saved_lumber > LUMBER_MAX then
        set saved_lumber = LUMBER_MAX
    endif
    
    call push_int(saved_gold,GOLD_MAX)
    call push_int(saved_lumber,LUMBER_MAX)
    
    call push_int(Wetr,50)
    call push_int(VERSION,50)
    
    call push_int(GetRandomInt(1,14),15) //This adds to security.
    
    set scode = create_code(g,5)
    set scode = format_code(scode,6)
    
    if GetLocalPlayer() == g then
        call ClearTextMessages()
    endif
    call DisplayTimedTextToPlayer(g,0,0,270,"------------------------------------------------------------------------------------------")
    call DisplayTimedTextToPlayer(g,0,0,270,"Your code is " + scode)
    call DisplayTimedTextToPlayer(g,0,0,270,"All your gold and any items (except those marked free trade) will now be untradable")
    call DisplayTimedTextToPlayer(g,0,0,270,"Any additional gold/lumber/items you get will remain to be tradable")
    call DisplayTimedTextToPlayer(g,0,0,270,"------------------------------------------------------------------------------------------")
    //Permnalize stuff
    set Touchable_gold[ind] = 0
    set Touchable_lumb[ind] = 0
    
    set counter = 0
    loop
    exitwhen counter == 6
        if rItemT[counter].TradeType == VD_SAVE_LOAD_TRADE then
            call SetItemPlayer(UnitItemInSlot(u,counter),g,false)
        endif
        set counter = counter + 1
    endloop
    
    set g = null
    set u = null
endfunction


Load
JASS:
function LoadItemC takes nothing returns integer
local integer r = pop_int(2)
    call BJDebugMsg("r = " + I2S(r))
    if r == 0 then
        return PString(pop_int(MAX_STACK + 1)*THROWN_STACK_RES)
    else
        return PString(pop_int(MAX_STACK + 1))
    endif
return 0
endfunction

function Decode takes nothing returns nothing
local player g = GetTriggerPlayer()
local integer ind = GetPlayerId(g)
local unit u 
local integer counter = 0
local string scode
local HeroClass Wetr
local integer array Info
local ItemFrm array rItemT
local ItemFrm z
local group v

    //Validate code
    if HeroIsChosen[ind] then
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, you have already chosen/loaded a hero. If you'd like to load a hero type -repick. Remember you have " + I2S(LoadsRemaining[ind]) + " loads remaining.")
        set g = null
        set u = null
        return
    endif
    if LoadsRemaining[ind] < 1 then
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, you have no loads remaining")
        set g = null
        set u = null
        return
    endif
    if not load_code(g,5,SubString(GetEventPlayerChatString(),6,200)) then
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, code security incorrect. You get this message only if the code is spelled wrong. You get a different message if the code version is incorrect")
        set g = null
        set u = null
        return
    endif
    
    set HeroIsLoaded[ind] = true
    
    call pop_int(15) //This just removes the random integer
    
    set Info[0] = pop_int(50)
    if not (Info[0] == VERSION) then 
        call DisplayTextToPlayer(g,0,0,"|CFFED1C24Error, code version " + I2S(Info[0]) + " is incorrect")
        set u = null
        set g = null
        return
    endif
    
    //Disect code
    set Wetr = pop_int(50)
    set PlayerHeroclasses[ind] = Wetr
    set u = CreateUnit(g,Wetr.UnType,GetRandomReal(GetRectMinX(gg_rct_Revive), GetRectMaxX(gg_rct_Revive)),GetRandomReal(GetRectMinY(gg_rct_Revive), GetRectMaxY(gg_rct_Revive)),0) //PlayerHero[ind]
    set PlayerHero[ind] = u
    
    //SET UP CLASSES
    if (Wetr == CLASS_WARRIOR) then //Warior, set up defend
        call TriggerRegisterUnitEvent(gg_trg_Defend,u,EVENT_UNIT_DAMAGED)
        set TrainerType[ind] = 'h004'
        set FTrainerType[ind] = 'h003'
    endif
    
    
    //LOAD TRAINER
    call GenUnit(TrainerType[ind],FTrainerType[ind],g,true)
    //CONTINUE CODE DISSECTION
    set Info[2] = pop_int(LUMBER_MAX) //Pop out lumber/gold
    set Info[1] = pop_int(GOLD_MAX)
    
    
    call SetPlayerState(g,PLAYER_STATE_RESOURCE_GOLD,Info[1]*GOLD_RESOLUTION_DIV) //This sets gold & lumber to the poped out stuff
    call SetPlayerState(g,PLAYER_STATE_RESOURCE_LUMBER,Info[2]*LUMBER_RESOLUTION_DIV)
    
    
    call SetUnitAbilityLevel(u,'A003',pop_int(MAX_LEVEL/10 + 1))
    //call BJDebugMsg("Ability popped at " + I2S(GetUnitAbilityLevel(u,'A003')))
    
    
    set counter = 5 //This loads abilities and sets the trainer to use those abilities as well
    loop
    exitwhen counter == -1
        set Info[3] = pop_int(MAX_ABIL_LEVEL)//GetUnitAbilityLevel(u,Wetr.Spell[counter])
        if (counter <= 3) then
            call PlayerAbilityLevelSet(g,Wetr.Spellx[counter],FTrainerType[ind],Info[3] - 1)
        else
            call PlayerAbilityLevelSet(g,Wetr.Spellx[counter],FTrainerType[ind],Info[3] - 1)
        endif
        call SetUnitAbilityLevel(u,Wetr.Spell[counter],GString(Info[3]))
        set counter = counter - 1
    endloop
    
    //This loads the equipped items, I need to make this do more then remove them
    
    
    set z = pop_int(FinalStruct + 1)
    set HeroChestHSlot[ind] = AddUABonuses(CreateItem(z.ItemType,ITEM_DROP_LEFT_X,ITEM_DROP_LEFT_Y),u)
    call SetItemCharges(HeroChestHSlot[ind],LoadItemC())
    set z = pop_int(FinalStruct + 1)
    set HeroAuxSlot[ind] = AddUABonuses(CreateItem(z.ItemType,ITEM_DROP_LEFT_X,ITEM_DROP_LEFT_Y),u)
    call SetItemCharges(HeroAuxSlot[ind],LoadItemC())
    set z = pop_int(FinalStruct + 1)
    set HeroRightHSlot[ind] = AddUABonuses(CreateItem(z.ItemType,ITEM_DROP_LEFT_X,ITEM_DROP_LEFT_Y),u)
    call SetItemCharges(HeroRightHSlot[ind],LoadItemC())
    set z = pop_int(FinalStruct + 1)
    set HeroLeftHSlot[ind] = AddUABonuses(CreateItem(z.ItemType,ITEM_DROP_LEFT_X,ITEM_DROP_LEFT_Y),u)
    call SetItemCharges(HeroLeftHSlot[ind],LoadItemC())

 
    set counter = 5 //Loads all saved items.
    loop
    exitwhen counter == -1
        set Info[9] = LoadItemC()
        set z = pop_int(FinalStruct + 1)
        set rItemT[counter] = z
        call UnitAddItemToSlotById(u,z.ItemType,counter)
        call SetItemCharges(UnitItemInSlot(u,counter),Info[9])
        set counter = counter - 1
    endloop
    
    
    set Info[5] = pop_int(R2I(MAX_STATS/STAT_RESOLUTION_DIV))*STAT_RESOLUTION_DIV
    set Info[6] = pop_int(R2I(MAX_STATS/STAT_RESOLUTION_DIV))*STAT_RESOLUTION_DIV
    set Info[7] = pop_int(R2I(MAX_STATS/STAT_RESOLUTION_DIV))*STAT_RESOLUTION_DIV
    
    set Info[4] = pop_int(R2I(GetReqXP()/RESOLUTION_DIV)) //Set up xp and level
    set Info[10] = pop_int(MAX_LEVEL)
    call SetHeroLevel(u,Info[10],false)
    call SetUnitAbilityLevel(u,'A004',Info[10]/5 + 1)
    call AddHeroXP(u,Info[4]*RESOLUTION_DIV,false)

    call SetHeroInt(u,Info[5],true) //Now finish it off by setting up the stats
    call SetHeroStr(u,Info[6],true)
    call SetHeroAgi(u,Info[7],true)
    //Move camera
    if (GetLocalPlayer() == GetOwningPlayer(u)) then
        call PanCameraTo(GetUnitX(u), GetUnitY(u))
    endif
    //Permnalize stuff
    set Touchable_gold[ind] = 0
    set Touchable_lumb[ind] = 0
    
    
    set counter = 0
    loop
    exitwhen counter == 6
        if rItemT[counter].TradeType == VD_SAVE_LOAD_TRADE then
            call SetItemPlayer(UnitItemInSlot(u,counter),g,false)
        endif
        set counter = counter + 1
    endloop
    
    //Disable additional picking
    set HeroIsChosen[ind] = true
    
    set LoadsRemaining[ind] = LoadsRemaining[ind] - 1
    
    set v = CreateGroup()
    set bj_groupEnumTypeId = 'H002'
    call GroupEnumUnitsOfPlayer(v, g, Filter(function GetUnitsOfPlayerAndTypeIdFilter))
    call ForGroup(v,function RemoveAll)
    call DestroyGroup(v)
    
    //PLayer init add
    set PlayerBlocks[ind] = Blocker.create()
    call GroupAddUnit(UnitsWithBlock,u)
    call TriggerRegisterUnitEvent(RunBlckDef,u,EVENT_UNIT_DAMAGED)
    
    set v = null
    set g = null
    set u = null
endfunction
 

Attachments

  • save.jpg
    save.jpg
    289.3 KB · Views: 396
  • load.jpg
    load.jpg
    259 KB · Views: 375

Korolen

New User (Why do I keep getting those red bars?)
Reaction score
69
Damn, that's a long code.

As far as the technical limitations, Kode should be able to go up to 8192 (or whatever the max size is for arrays) bits in the code.

I haven't modded WC3 for long enough that I'm a little behind on some of the technology you young 'uns are using. I see you're using something that displays where errors happen in the code (I wish I had that when I was developing Kode –_I think there was something then but it was only for Windows)? Am I assuming correctly that "Hit op limit" is the event that WC3 cuts off the function mid-execution because it does too much stuff?

The encoding and decoding is fairly optimized, and my use of arrays to store the bits makes it faster than many other code systems (which often use strings), but it's not super great, and, while the final version worked pretty well (I never had it cut off after I had optimized the whole thing), that code is bigger than Texas.

I suppose you could try one of three things:
1) Optimize your code saving, for example, using progressive ints to save gold and experience and/or round them off.
2) Cut out the saving of various things to shrink code size.
3) Modify the internal workings of Kode to use timers and stuff to avoid the function getting cut off.

Honesty, though, I've never seen codes that long when playing WC3. And ones that come close are obviously hand-made in GUI and aren't exactly as efficient as Kode is as far as the code size to information ratio. I don't think users are going to appreciate typing in a code that big (with case sensitivity and punctuation to boot).
 

Bomber7

New Member
Reaction score
0
Lol, you really need to update your contact details. I've tried every method, and I finally found one that works when I realized you'd posted.

About the long code, have you ever played Defiance's ORPG? The code was longer, but much less efficient.

Would using progressive ints really help? I mean, wouldn't later on your code still be as long? Anyway, I'll try that and we'll go from there.

Oh, and the error is displayed by War3err. The main reason you've probably not used it, is its a feature of the NewGen editor. Also, hes released a realtime jass debugger! I haven't figured out how to use it yet though...

Also, trust me, I'm not really being frivolous in saving things. I did some fun tricks to lower the xp save size. Like building an xp giving system from scratch. Your hero actually requires 1000 xp per level no matter the level. The code automatically gives you less xp per kill and less if they're above your level or more if they're above. So I save your current level, and a number 1 - 1000. Which I can set to be 1 - 100 (*10)

Also, as far as I know, you appear to be correct. This is the shortest code system. Vexorians comes close, but still unacceptable for my code size.

As far as I know, the op-limit works like this.
It runs ahead reading operations, and adds them to a que. Then it executes them one at a time. When the que overflows, its known as the op limit. I'm pretty sure thats how it works. Either way, it results in that particular thread being cut off. (Which means the code becomes a jumbled mess)

I just looked at the way progressive ints work. Thats not very user friendly when I have so many values. How much space would that actually save me?

If you look at my code, you'll notice a bunch of individual values opposed to a few big ones.

I guess the main problem is saving the items. I have to save 10 items. 6 inventory items, and 4 equipped slots. However right now theres only about 25 savable items. At one point theres going to be over 200.

Also for progressive ints, what will produce a more optimized result:
High base, low exponent
low exponent, high base
same/close exponent/base

On another note, I've been thinking about modifying KODE. I would add a timer to one part of it so that it doesn't hit the Op limit. I was wondering where you might suggest I would insert the timer.
 

Korolen

New User (Why do I keep getting those red bars?)
Reaction score
69
Thank you very much, but my contact details are plenty accurate. I'm just not all the time. I'd be happy to talk to you off TH, though, you can add me on whatever you have (although I'm not on Skype as much as the other clients).

I probably should learn Vex's new JASS stuff. I stopped modding right around the time that came out (I think). If do any more modding, I'll probably try it in Boot Camp.

Anyway, about Kode.

As far as hitting the op-limit, progressive ints won't help, because you need to be able to handle the worst-case situation (the player has a bajillion gold pieces). You could, however, round players' gold if it gets too high, though.

As far as optimizing code size goes, it's important to remember the damage a value deals on code size is based on the maximum number's logarithm. So five booleans (which are ints with a max of two) is equal in code size to 32 (because log(2)*5 = log(32)). If you want, you could modify push_int and have it add to a variable that you print out and clear after each section of saving to find where the most size-heavy parts of the code saving is.

As far as items go, that kind of thing is expensive to your code size, but not that expensive. You can calculate it: with a charmap length of 75, a push_int with a max of 200 (all your items) adds about 1.25 characters. Adding charges with a push_int with a max of 100 adds about 1.05 characters (although you can add a custom amount of charges for different items, you *can't* hit the op-limit for a user, so you have to prepare for the worst-case: 6 fully 100 charged items).

As far as progressive ints go, you can think of it like it first saves the size of the number and then follows it with a number of bits that accommodates the size. Kode saves the size of the number in a number of defined steps, I.E. for a base of 10 and a max of 6, "the number is between 0 and 9" is the first step. Each step is [base] times bigger than the last. So the next step would be "the number is between 10 and 99", the next 100 and 999, the next 1000 and 9999, the next 10000 and 99999 and finally 100000 and 999999. The maximum exponent is the highest step. So the maximum the number can be is base ^ maximum exponent - 1. That's assuming Kode is bug-free. I didn't do a whole lot of testing.

Man, I should get that on the front page. Except you're probably the only person actually using Kode. And I'm lazy.

As far as timers, a easier place to optimize would be the division function. For the other three (addition subtraction multiplication) I got some crazy formulas from some place and made it in JASS. But for the division I had to make up it up: it's literally the same long division you learned in preschool. (actually I think the other ones aren't especially optimized either–_it's just division is a much more complex operation than multiplication or the others) And that's not the best way for a computer to divide something. You could rewrite that. But that would be pretty involved (it took me hours of debugging to get that shit working). Again, you might be better off trying to figure out how to get the code shorter (which would also please your users).

Anyway, good luck.
 

Arkan

Nobody rides for free
Reaction score
92
He's not the only one. I'm using Kode for my upcoming project Dark Invasion II. I have succesfully been able to save shitloads of integers and the code is still reasonable in size (I use some unordered lists for items etc.).

Kode is awesome, you forgot to remove some debug messages in some of the core functions though.
 

Bomber7

New Member
Reaction score
0
Quite simply, I don't know enough about KODE to optimize it.

On the bright side of things, I found the real reason for the op-limit. I was multiplying something during saving that I wasn't during loading. Code wise, I doubt it'll ever get smaller. However it will get bigger. I'll try to determine whats adding the bulk of space.


PS: I did see those debug messages that you forgot to remove, however they're in the un-ordered list location. I don't use unordered lists because all my data must be ordered.
 
M

MicroXen

Guest
I found a bug with the kode. I made a hero that morphs into different creatures and when you save while your in a different form it will give you a random code for another hero of that same level.
 

Bomber7

New Member
Reaction score
0
You don't sound like you know how to use KODE.


KODE is not a hero save/load system. Its an integer/string/boolean save load system. You pick and choose what you want and how you want to save your data. So say for a hero you'd want the inventory, the agi/int/str learned abilities, xp, ect...

The demo map isn't meant to be a fool proof hero saver. Its just meant to show you that KODE can do that if you want. Your supposed to script your own code to do so....
 
Reaction score
341
Ok , so i am trying to use this in my map and i get a couple errors.

First , Whenever i try 2 save 6 items my it loads none of em , but when i save 5 items it loads all of them

Second , whenever i get past lvl 11 it only loads up to level 11.

Third , when i save a hero and load it , it gives me an entire different hero (even though the saved hero is in the hero array )
 

Andyoyo

TH.net Regular
Reaction score
22
Can a person use the same code from a different computer? Is it saved somewhere as a cookie sort of, only usable from that computer?
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
This save/load system looks nice and seems to be working, but before approving,
I would like to get some more detailed feedback telling me exactly how well does it do
what it's supposed to do and how's the coding, because I have no experience
in creating save/load codes, especially in GUI.

So, anyone proficient who can give me a detailed review of this system will get +repute.
 

Korolen

New User (Why do I keep getting those red bars?)
Reaction score
69
This save/load system looks nice and seems to be working, but before approving,
I would like to get some more detailed feedback telling me exactly how well does it do
what it's supposed to do and how's the coding, because I have no experience
in creating save/load codes, especially in GUI.

So, anyone proficient who can give me a detailed review of this system will get +repute.

I don't want to review my own system, but as nobody has posted here in a while, I'll clarify some of the aspects of Kode:

  • Kode is written 100% in JASS.
  • Kode has GUI-Friendly version which simply is a wrapper to the JASS that makes it easy to work Kode without any Custom Script lines.
  • Kode is designed to be powerful, not super easy to use (that's not to say it's hard to use - anyone with a basic knowledge of programming can use it. It's just not designed for mapmakers with no background in programming just starting in on some GUI triggering)
  • The code is stored as bits in arrays as it is created and is operated on with four mathematical functions I programmed. The only reason this is done is to make an "integer" bigger than 32 bits.
  • Codes can contain an arbitrary number of integers. Each integer has a maximum value which is used to optimize code size. For example, if you wanted to store the level of an ability on a unit, the maximum value would be 4 as there are 4 possibilities: unlearned, first level, second level, and maxed out.
  • Security is simple but effective. After the code has been generated, a customizable number of 0s are appended to the bits that make up the code. Then, the bits are is encrypted using the player's name as a key. The encryption is a simple algorithm of my own design, but is as secure as a Warcraft map is going to get: it keeps out noobs. As with any code system, it's not hard to open the protected map and insert a custom bit of JASS somewhere that will make a super her and then save it (for example). It's unfortunately simply impossible to do anything more than security through obscurity with Warcraft maps.
  • The encryption algorithm was specifically designed so that changing any value will produce an entirely different code. This gives a player a better sense of security, even if it's actually no more secure then, say, appending a salted hash onto the end of the code.
  • The whole system is pretty optimized. Because of the way it works, it can handle codes way bigger than anyone will want to type in still without lagging player's computers when they save.
  • As far as I know, Kode is leakless. In reality, it probably has a few leaks.
  • Kode produces, as far as I know of, the shortest codes for any save/load system. It wastes *zero* space when saving normal integers because they have an arbitrary maximum size. Other code systems, such as Acehart's system don't do this (which makes it easier to use, of course, his intention). Others allow maximum sizes, but restrict to powers of two for technical reasons. Kode truly stores the values it's given in the absolute smallest size that's possible short of compression (which brings me to my next point).
  • Kode also gives map creators plenty of room to optimize code size with Progressive Integers and Unordered Lists, both of which can shrink code size further then a "perfect" conversion.
  • Kode has a number of customizable variables, including Encryption Strength (higher makes the encryption stronger, useful if code size is going to be big) and Charmap (the characters used in the final code).
  • Kode has a number of minor flaws that I don't have the time to fix. For example, I forgot to remove a BJDebugMsg in the Unordered List saver.
  • I've obviously tested Kode, but there's a chance that there are some serious bugs in it. I simply haven't gotten enough feedback to (read: any feedback) about bugs.
  • Kode was originally for a map I was making that got canned when SC2 was announced and I later "moved on" from mapmaking to a commercial app (to be announced!).

Hopefully this covers the workings of Kode, but I'm still assuming you will want a review from someone other then the author?
 

AceHart

Your Friendly Neighborhood Admin
Reaction score
1,494
> Kode produces, as far as I know of, the shortest codes for any save/load system.
> It wastes *zero* space when saving normal integers because they have an arbitrary maximum size.

That's open to debate.


> Other code systems, such as AceHart's system don't do this

You have some backup for that claim?
 

Reflexar

New Member
Reaction score
12
can you help me make so that this system also saves lumber and food, use the gui friendly version ? :thup:
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top