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

Save/load integers

Status
Not open for further replies.
Level 4
Joined
May 14, 2018
Messages
34
Hi guys!
I`m making a map, and i need system that would save integer array and convert it into code for loading in future by player.
I was searching for a long time, but no result.
I even tried to change classic codegen code, but it bugged and i can`t use it.

There is any possible solution, probly in JASS to do it. Asking for non-reforged one.
Thx a lot for answer
 

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,456
What is non-reforged exactly?
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
They are probably asking for code that runs in a legacy build of Warcraft III. This means that it would need to be an older version of modern I/O based save/load systems due to the lack of synchronisation natives and instead using unit section.

The basic idea is you take the integers and encode them into a string that can then be decoded to reconstruct the integers. The most simple form of this would be saving the integers as decimal directly and separating them with dash '-' characters. For example the following 3 integers...
Code:
1337
42
9001
Could be encoded as the following string...
Code:
1337-42-9001
To decode such string you would iterate through it character by character until you find the next dash '-' character and then sub string out the decimal number string and convert that into an integer, repeating for all saved values.

Logically such encoding is not very efficient and can be improved. Better encoding would convert the integer to base 64 allowing the same number to be represented with fewer digits. Instead of using key characters to separate numbers, the numbers might be encoded with a fixed width saving more characters and speeding up the decode. Instead of storing a sequence of numbers, the code could represent a sequence of bits that is derived from compressing a buffer containing such a number sequence for larger space savings. A cryptographic hash could be added to the stored data to help detect errors or tampering. Some form of encryption could be used to try to obfuscate the contents of the code.
 
I made a few util function that I used for my "write code in chat" system.

Basically, use intToBase64 to get the string (base 64) for the given integer, and fromBase64.
In both cases, you need to know the "maxLength" (how many base64 characters are used for a given field).
In my map, I know that there are less than 64 "waves", so I only need 1 character to represent the wave-number.
I know that the exp is less than 50 000 (or something like that) because that's the amount you have at max-level on my map, so I only need 3 charaters for that, etc.

ofc it is possible to use some other character as separator and do it smarter or whatever, but I made this mostly by myself to learn and it works. I might've looked at how others do certain things, I don't remember.


JASS:
function base64CharFromIndex takes integer index returns string
    return SubString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", index, index + 1)
endfunction
function base64IndexOfChar takes string input returns integer
    local integer i = 0
    loop
        exitwhen base64CharFromIndex(i) == input
        set i = i + 1
    endloop
    return i
endfunction
function intToBase64 takes integer input, integer capResultChars returns string
    local integer currentValue = input
    local string result = ""
    loop
        //call BJDebugMsg("current result=" + result + ", currentValue=" + I2S(currentValue))
        set result = base64CharFromIndex(ModuloInteger(currentValue, 64)) + result
        set currentValue = currentValue / 64
        exitwhen currentValue == 0
    endloop
    //call BJDebugMsg("Final result=" + result + ", currentValue=" + I2S(currentValue))
    return SubString(result + "====", 0, capResultChars)
endfunction
function fromBase64 takes string input, integer maxLength returns integer
    local integer result = 0
    local integer i = 0
    local string currentChar
    loop
        set currentChar = SubString(input, i, i + 1)
        exitwhen i > (maxLength - 1) or currentChar == "="
        set i = i + 1
        set result = result * 64 + base64IndexOfChar(currentChar)
    endloop
    return result
endfunction


I load by doing (I load the 6th (or 7th? depends how you count I think) character of the chat-string as the wave-number).
set udg_current_wave_nr = fromBase64(SubString(udg_load_string, 6, 7), 1)

I "save" by adding my various values together to something player has to write. There is a description and then:
call BJDebugMsg("-load " + intToBase64(udg_last_market_wave, 1) + intToBase64(udg_last_market_tot_gold, 4) + intToBase64(udg_last_market_exp, 3))

(where udg_last_market_wave, udg_last_market_tot_gold, udg_last_market_exp are the values I store, and the 1, 4, 3 are the "max lengths" I "support").

Note that the code needs to be adjusted if you plan to store values bigger than 64^4 (also known as over 16 million).
 
Level 4
Joined
May 14, 2018
Messages
34
I made a few util function that I used for my "write code in chat" system.

Basically, use intToBase64 to get the string (base 64) for the given integer, and fromBase64.
In both cases, you need to know the "maxLength" (how many base64 characters are used for a given field).
In my map, I know that there are less than 64 "waves", so I only need 1 character to represent the wave-number.
I know that the exp is less than 50 000 (or something like that) because that's the amount you have at max-level on my map, so I only need 3 charaters for that, etc.

ofc it is possible to use some other character as separator and do it smarter or whatever, but I made this mostly by myself to learn and it works. I might've looked at how others do certain things, I don't remember.


JASS:
function base64CharFromIndex takes integer index returns string
    return SubString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", index, index + 1)
endfunction
function base64IndexOfChar takes string input returns integer
    local integer i = 0
    loop
        exitwhen base64CharFromIndex(i) == input
        set i = i + 1
    endloop
    return i
endfunction
function intToBase64 takes integer input, integer capResultChars returns string
    local integer currentValue = input
    local string result = ""
    loop
        //call BJDebugMsg("current result=" + result + ", currentValue=" + I2S(currentValue))
        set result = base64CharFromIndex(ModuloInteger(currentValue, 64)) + result
        set currentValue = currentValue / 64
        exitwhen currentValue == 0
    endloop
    //call BJDebugMsg("Final result=" + result + ", currentValue=" + I2S(currentValue))
    return SubString(result + "====", 0, capResultChars)
endfunction
function fromBase64 takes string input, integer maxLength returns integer
    local integer result = 0
    local integer i = 0
    local string currentChar
    loop
        set currentChar = SubString(input, i, i + 1)
        exitwhen i > (maxLength - 1) or currentChar == "="
        set i = i + 1
        set result = result * 64 + base64IndexOfChar(currentChar)
    endloop
    return result
endfunction


I load by doing (I load the 6th (or 7th? depends how you count I think) character of the chat-string as the wave-number).
set udg_current_wave_nr = fromBase64(SubString(udg_load_string, 6, 7), 1)

I "save" by adding my various values together to something player has to write. There is a description and then:
call BJDebugMsg("-load " + intToBase64(udg_last_market_wave, 1) + intToBase64(udg_last_market_tot_gold, 4) + intToBase64(udg_last_market_exp, 3))

(where udg_last_market_wave, udg_last_market_tot_gold, udg_last_market_exp are the values I store, and the 1, 4, 3 are the "max lengths" I "support").

Note that the code needs to be adjusted if you plan to store values bigger than 64^4 (also known as over 16 million).
I`ve got the idea of the code, but stil can`t understand how to use it correctly.

JASS:
function Trig_rea_save_Actions takes nothing returns nothing
    call BJDebugMsg("-load " + intToBase64(udg_apt1[GetConvertedPlayerId(GetTriggerPlayer())],1))
endfunction

function InitTrig_rea_save takes nothing returns nothing
    set gg_trg_rea_save = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_rea_save, Player(0), "-save", true )
    call TriggerAddAction( gg_trg_rea_save, function Trig_rea_save_Actions )
endfunction

And if i load i guess

JASS:
function Trig_rea_save_Actions takes nothing returns nothing
    call BJDebugMsg("-load " + intToBase64(udg_apt1[GetConvertedPlayerId(GetTriggerPlayer())],1))
endfunction

function InitTrig_rea_save takes nothing returns nothing
    set gg_trg_rea_save = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_rea_save, Player(0), "-save", true )
    call TriggerAddAction( gg_trg_rea_save, function Trig_rea_save_Actions )
endfunction

Am i right?

I just wanna to use it in rpg maps.
I know there is a lot to can be do better like encryption or cheking code owner`s name, but for now i need to do it step by step.
 
Status
Not open for further replies.
Top