Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
it depend on what variable you want to save, so you can't just copy & paste.
Step 1: you can create a string character:
char_string = "abcdefg.....ABCDEFG...1234567890" // around 60-70 character wrong
Step 2: assign characters to information you want to save
if your save code have 5 character : 1234567
1st character = which race (pick 1 character from char_string, up to 60-70 difference race)
2nd character = level of hero (pick 1 character from 60-70 difference character
3rd character = first ability
4rd character = level of first ability
etc.....
Step 3: Improve Step 2 by shorten code
eg:
1st character = combine which race and level of hero in 1 character (because you have 60-70 character, long enough to cover all possibility of race+level)
2nd character = 1st ability's name & level
3rd character = 2nd ability's name & level
etc
Step 4: Code Protection, so player can't enter random code to guess
if your code is 8 character long, then you can add 2 more character as protection.
there are many way for protection, here is one example:
Remainder : (eg, 11/3 ==> remainder is 2 )
1, convert code string to number ( by index of char_string, eg, a = 1, b=2, Z=24 etc)
2, use JASS's math function to calculate remander (mudule)
3, if number is too big, you can cut them to smaller part ( need good math/logic )
4, a good example is get module from : divide by 5 & 7
so if your code is 8 character long, then
- 9th character can generate from divide by 5
- 10th character can generate from divide by 7
now, if player try enter random character, chance for enter right code is like winning lotto
local NumberStack c = NumberStack.create(Base["abcdefghijklmnopqrstuvwxyz"])
call c.push(variable,variableMax)
call DisplayTimedTextToPlayer(Player(0),0,0,60,EncryptNumber(c,1000000,3,0))
call c.destroy()
Load
JASS:
local NumberStack c = DecryptNumber(string,Base["abcdefghijklmnopqrstuvwxyz"],1000000,3,0)
if (0!=c) then
set variable = c.pop(variableMax)
call c.destroy()
endif
local NumberStack c = NumberStack.create(Base["abcdefghijklmnopqrstuvwxyz"])
call c.push(variable,variableMax)
call DisplayTimedTextToPlayer(Player(0),0,0,60,EncryptNumber(c,1000000,3,0))
call c.destroy()
Load
JASS:
local NumberStack c = DecryptNumber(string,Base["abcdefghijklmnopqrstuvwxyz"],1000000,3,0)
if (0!=c) then
set variable = c.pop(variableMax)
call c.destroy()
endif
I havn't try, if my final code is 10 character long, what is the length of encrypted string after encrypt by your method ?
my Save/load will save follow information:
(1), how many race unlock, I put them in array, 0 = havn't unlock, 1=unlock. 15 race atm, more in future
(2), player name, include color name start with |.ffeeooName
3, 3 bit hash code (calculate from module)
for (1) : because 1 race = 1 bit of 0 or 1, total 15 equal to something like: 010101010101010) to number. so I create a binary function to convert them from binary to integer. (15 race = integer with 5 digit. 20 race = 8 digit)
for (2) : I use a long character string that cover all possible character, then convert user's name to integer
for (3), it calculate from : combine (1) + (2), save them in array (because integer is too big), then calculate remainder from them.
Final code : (1) + (3) , I don't really need 2 because it is too long.
It work so far and easy to understand/modified. (of course, there are more hash involve in (1) so people can't read (1) directly)
do you have any idea to make (1) shorter ?
eg:
15 race = 15 digit of 010101010101.. . if I convert to binary, it will be 5 digit
in near future, race will like 20, which result in 8 digit integer.
Just keep them as booleans with 1 being the max value. Have 15 booleans.
Now why are you saving the player's name? If it's for name specific codes, the encryption already does that (it's player specific encryption). For saving the player's name, you would need to retrieve each Ascii value and put it into a delimited array, meaning that you'd need Encoder for its tree based structure. If you were to save a specific max amount of letters, like 20, then you'd end up having larger codes than you need for small names.
I'd save the color as a hexadecimal value. Color for strings is 6 digits, so you can make room for it with FFFFFF+1, which is 16777217.
Just keep them as booleans with 1 being the max value. Have 15 booleans.
Now why are you saving the player's name? If it's for name specific codes, the encryption already does that (it's player specific encryption). For saving the player's name, you would need to retrieve each Ascii value and put it into a delimited array, meaning that you'd need Encoder for its tree based structure. If you were to save a specific max amount of letters, like 20, then you'd end up having larger codes than you need for small names.
I'd save the color as a hexadecimal value. Color for strings is 6 digits, so you can make room for it with FFFFFF+1, which is 16777217.
the save/load code is unique to each player's name, so they can't share their code.
and I don't want to make code too long, so I will use player's name as a salt and create a 3 digit hash value.
so for my decrypt function, it cannot decrypt player's name, but it can verified player's name by compare the hash value.
anyway, I have better idea for shorter code:
15 booleans = 15 digit Binary number
15 digit binary --> convert to Base36 hexatridecimal = max 3 digit (rank from [A-Z,0-9]
3 digit hexatridecimal + 3 digit hash = 6 digit final code !!!
I am not sure if I need 3 digit for hash. I still need to read & understand your hash method.
can you write 2 JASS function that :
ConvertToBase36 ( take int[] num, return string)
ConvertToBase2 ( take string, return int[] num)
here is similar function in C# ( I can't take int num because number is out of range for JASS)
Code:
public String ConvertToBase(int num, int nbase)
{
String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// check if we can convert to another base
if(nbase < 2 || nbase > chars.Length)
return "";
int r;
String newNumber = "";
// in r we have the offset of the char that was converted to the new base
while(num >= nbase)
{
r = num % nbase;
newNumber = chars[r] + newNumber;
num = num / nbase;
}
// the last number to convert
newNumber = chars[num] + newNumber;
return newNumber;
}
Ok listen... my encryption method is 100% unique to the players. The shuffling is based off of a modified hash from the player's nickname. This player uniqueness adds 0 data to the code. It's just a simple StringHash though and convert to base 8 and add 1 to all the digits of 0 ; P.
So no, you don't need 3 digits for the hash for the player's nick. You need 0 ; P.
The only thing you need are the 15 binary digits and you are done = ). Let the encryption do the checksum and yea, you're set ; P. Custom Hero Foots uses similar save/load techniques (although it's a bit more advanced in that map since they have player unique checksums and bases as well) and it has yet to be cracked (and believe me, there was a guy doing all he could to crack it).
For player unique bases
encryptionKey = BigInt that just converts the base into a string (flip 0 with 1 in front)
baseEncryptionKey = the encryption key as a base
JASS:
call Scramble(encryptionKey,playerId,3,baseEncryptionKey,true)
set bases[playerId]=Base[encryptionKey.toString()]
From here, you use a player unique base when generating your number, thus most players have a different base (numbers are totally different).
The next thing is player unique checksums, which uses variance in checksums between players that I won't go into = P.
The only thing that the encrypt function does is a checksum (not player unique) with scrambling (player unique). I could add the other 2 security features if you want though =).
This is the equation for player unique checksums where CHECKSUM_VARIANCE is some constant (suggested .85) and maxChecksum is the security value (6-7 digits). PLAYER_CHECKSUM_SALT is a constant string that just muddles the player name (different checksum).
Code:
checksum=StringHash(StringCase(GetPlayerName(player)+PLAYER_CHECKSUM_SALT,false))
if (0>checksum) then
set checksum=-checksum
endif
minChecksum=R2I(maxChecksum*CHECKSUM_VARIANCE)
checksumRange=maxChecksum-minChecksum
checksum=checksum-checksum/checksumRange*checksumRange+minChecksum
Again, the only thing my encrypt function has is scrambling. The other 2 techniques mentioned in this post are not in it.
Oh and these are your 15 binary digits max in base 36
9ZLDR or 5 digits, meaning that with the checksum, you're looking at around 5Y3CGMWG0, or 8 digits (1000000 checksum).
100000 would be LEQG2AG0, still 8 digits.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.