| 03-29-2007, 02:14 AM | #2 |
If after trying saving and loading the code is identical in both cases and it cannot be loaded, same username and same map then I can't think of any good reason for this to happen. If you can make sure that it always fails and it is not a typo or something like it then I might have to check the map out myself to find the reason of the problem. |
| 03-11-2008, 05:52 AM | #3 |
Edit: I have attached 2 example maps showing my problem. The two maps are identical the only difference is that I replaced the default Hero save/load functions in the codemaker implementation map with the ones shown below. The second map does not work as you can see. JASS:function InitTrig_Hero_Save_Functions takes nothing returns nothing endfunction //##Start## //************************************************************************************************* //* //* Hero Save/Load Functions //* //************************************************************************************************* //================================================================================================= constant function HeroSave_MaxHeroLevel takes nothing returns integer return 100 endfunction constant function HeroSave_MaxHeroStat takes nothing returns integer return 511 endfunction constant function HeroSave_MaxItemCharges takes nothing returns integer return 7 endfunction constant function HeroSave_MaxAbilityLevels takes nothing returns integer return 3 endfunction constant function HeroSave_MaxFreeSkillPoints takes nothing returns integer return 15 endfunction constant function HeroSave_LinkSize takes nothing returns integer return 2 endfunction constant function HeroSave_MaxGold takes nothing returns integer return 1000 endfunction constant function HeroSave_MaxLumber takes nothing returns integer return 1000 endfunction constant function HeroSave_mapversion takes nothing returns integer return 1 // // Increase this with a 1 on every (official) map update that changes the objects, contents of // the pools, so codes from previous versions can't be restored (Since they would probably cause // messy results) // // very Big values would cause code increasement, another option is changing the charmap // on every update. // endfunction //================================================================================================= function HeroSave takes nothing returns gamecache if (udg_herosave==null) then call FlushGameCache(InitGameCache("herosave")) set udg_herosave=InitGameCache("herosave") endif return udg_herosave endfunction function StartHeroSave takes integer heroes, integer items, integer abils returns nothing local gamecache g=HeroSave() local integer x call StoreInteger(g,"Constants","herolevelsize", Codemaker_GetRequiredSize(HeroSave_MaxHeroLevel()) ) set x=CountItemsInPool(heroes)-1 //Pool positions start with 1, but we'll use numbers from 0 call StoreInteger(g,"Constants","herosize",Codemaker_GetRequiredSize(x)) set x=CountItemsInPool(items)-1 //Pool positions start with 1, but we'll use numbers from 0 call StoreInteger(g,"Constants","itemsize",Codemaker_GetRequiredSize(x)) call StoreInteger(g,"Constants","itemNsize",Codemaker_GetRequiredSize(bj_MAX_INVENTORY)) set x=CountItemsInPool(abils)-1 //Pool positions start with 1, but we'll use numbers from 0 call StoreInteger(g,"Constants","abilsize",Codemaker_GetRequiredSize(x)+1) call StoreInteger(g,"Constants","chargsize",Codemaker_GetRequiredSize(HeroSave_MaxItemCharges())) call StoreInteger(g,"Constants","levelsize",Codemaker_GetRequiredSize(HeroSave_MaxAbilityLevels())) call StoreInteger(g,"Constants","skillsize",Codemaker_GetRequiredSize(HeroSave_MaxFreeSkillPoints())) call StoreInteger(g,"Constants","statssize",Codemaker_GetRequiredSize(HeroSave_MaxHeroStat())) call StoreInteger(g,"Constants","goldsize",Codemaker_GetRequiredSize(HeroSave_MaxGold())) call StoreInteger(g,"Constants","lumbersize",Codemaker_GetRequiredSize(HeroSave_MaxLumber())) call StoreInteger(g,"pools","heroes",heroes) call StoreInteger(g,"pools","items",items) call StoreInteger(g,"pools","abils",abils) set g=null endfunction function HeroSave_BrowseAbilities takes nothing returns nothing local integer p=CreatePool() local integer i=1 local integer ap=GetStoredInteger(HeroSave(),"pools","abils") local integer a local integer n=CountItemsInPool(ap) local unit u=bj_groupRandomCurrentPick set udg_codemaker_vals[9]=p loop exitwhen (i>n) set a=PoolGetItem(ap,i) if (GetUnitAbilityLevel(u,a)>0) then call PoolAddItem(p,a) endif set i=i+1 endloop set u=null endfunction function HeroSave_SaveHero takes unit hero returns string //It Actually uses 2 codes!, first code is always of the same size, but contains information for //the size of second code, which holds abilities and items, a random link value is added to both //So if they don't match it dies. // local integer link=GetRandomInt(0,R2I( Pow(2,HeroSave_LinkSize())-1 )) local gamecache g=HeroSave() local string r local integer p=GetStoredInteger(g,"pools","heroes") local integer ap local integer a local integer aN local integer iN local integer x local integer y local integer i local item it set udg_codemaker_vals[0]=10 //Link · Version · Type · Level · Skillpoints · Int · Agi · Str · AbilN · ItemN set udg_codemaker_size[1]=HeroSave_LinkSize() set udg_codemaker_vals[1]=link set udg_codemaker_size[2]=Codemaker_GetRequiredSize(HeroSave_mapversion()) set udg_codemaker_vals[2]=HeroSave_mapversion() set udg_codemaker_size[3]=GetStoredInteger(g,"Constants","herosize") set udg_codemaker_vals[3]=GetItemPositionInPool(p,GetUnitTypeId(hero)) - 1 set udg_codemaker_size[4]=GetStoredInteger(g,"Constants","herolevelsize") set udg_codemaker_vals[4]=GetHeroLevel(hero) set udg_codemaker_size[5]=GetStoredInteger(g,"Constants","skillsize") set udg_codemaker_vals[5]=IMinBJ(HeroSave_MaxFreeSkillPoints(),GetHeroSkillPoints(hero)) set x=GetStoredInteger(g,"Constants","statssize") set udg_codemaker_size[6]=x set udg_codemaker_vals[6]=GetHeroInt(hero,false) set udg_codemaker_size[7]=x set udg_codemaker_vals[7]=GetHeroAgi(hero,false) set udg_codemaker_size[8]=x set udg_codemaker_vals[8]=GetHeroStr(hero,false) set bj_groupRandomCurrentPick=hero call ExecuteFunc("HeroSave_BrowseAbilities") set ap=udg_codemaker_vals[9] set aN=CountItemsInPool(ap) set iN=UnitInventoryCount(hero) set x=GetStoredInteger(g,"Constants","abilsize") set udg_codemaker_size[9]=x set udg_codemaker_vals[9]=aN set udg_codemaker_size[10]=GetStoredInteger(g,"Constants","itemNsize") set udg_codemaker_vals[10]=iN if (HeroSave_MaxGold()!=0) then set udg_codemaker_vals[0]=11 set udg_codemaker_size[11]=GetStoredInteger(g,"Constants","goldsize") set udg_codemaker_vals[11]=GetPlayerState(GetOwningPlayer(hero),PLAYER_STATE_RESOURCE_GOLD) endif if (HeroSave_MaxGold()!=0) then set x=udg_codemaker_vals[0]+1 set udg_codemaker_vals[0]=x set udg_codemaker_size[x]=GetStoredInteger(g,"Constants","lumbersize") set udg_codemaker_vals[x]=GetPlayerState(GetOwningPlayer(hero),PLAYER_STATE_RESOURCE_LUMBER) endif set r=Codemaker_GenerateCode(GetOwningPlayer(hero)) //First Code done, now the second one... set udg_codemaker_vals[0]=1+(aN+iN)*2 set udg_codemaker_size[1]=HeroSave_LinkSize() set udg_codemaker_vals[1]=link set y=GetStoredInteger(g,"Constants","levelsize") set i=1 set p=GetStoredInteger(g,"pools","abils") loop exitwhen (aN<=0) set i=i+1 //Ability set udg_codemaker_size[i]=x set a=PoolGetItem(ap,aN) set udg_codemaker_vals[i]=GetItemPositionInPool(p,a)-1 set i=i+1 //Level set udg_codemaker_size[i]=y set udg_codemaker_vals[i]=GetUnitAbilityLevel(hero,a) set aN=aN-1 endloop set iN=0 set x=GetStoredInteger(g,"Constants","itemsize") set y=GetStoredInteger(g,"Constants","chargsize") set p=GetStoredInteger(g,"pools","items") loop exitwhen iN>=bj_MAX_INVENTORY set it=UnitItemInSlot(hero,iN) if (it!=null) then set i=i+1 set udg_codemaker_size[i]=x set udg_codemaker_vals[i]=GetItemPositionInPool(p,GetItemTypeId(it))-1 set i=i+1 set udg_codemaker_size[i]=y set udg_codemaker_vals[i]=GetItemCharges(it) endif set iN=iN+1 endloop call DestroyPool(ap) set r=r+Codemaker_GenerateCode(GetOwningPlayer(hero)) //All is done set g=null set it=null return r endfunction function HeroSave_LoadHero takes player owner, string cod, real px, real py, real f returns integer local unit u local integer link local gamecache g=HeroSave() local string r local integer p=GetStoredInteger(g,"pools","heroes") local integer ap local integer a local integer aN local integer iN local integer x local integer y local integer i local item it local integer error set udg_codemaker_vals[0]=10 //Link · Version · Type · Level · Skillpoints · Int · Agi · Str · AbilN · ItemN //Prepare Sizes for first code: set udg_codemaker_size[1]=HeroSave_LinkSize() set udg_codemaker_size[2]=Codemaker_GetRequiredSize(HeroSave_mapversion()) set udg_codemaker_size[3]=GetStoredInteger(g,"Constants","herosize") set udg_codemaker_size[4]=GetStoredInteger(g,"Constants","herolevelsize") set udg_codemaker_size[5]=GetStoredInteger(g,"Constants","skillsize") set x=GetStoredInteger(g,"Constants","statssize") set udg_codemaker_size[6]=x set udg_codemaker_size[7]=x set udg_codemaker_size[8]=x set x=GetStoredInteger(g,"Constants","abilsize") set udg_codemaker_size[9]=x set udg_codemaker_size[10]=GetStoredInteger(g,"Constants","itemNsize") if (HeroSave_MaxGold()!=0) then set udg_codemaker_vals[0]=11 set udg_codemaker_size[11]=GetStoredInteger(g,"Constants","goldsize") endif if (HeroSave_MaxLumber()!=0) then set udg_codemaker_vals[0]=udg_codemaker_vals[0]+1 set udg_codemaker_size[udg_codemaker_vals[0]]=GetStoredInteger(g,"Constants","lumbersize") endif set y=Codemaker_TotalCodeLength() set error=Codemaker_ReadCode(owner,SubString(cod,0,y)) if (error>0) then set g=null return error endif if (udg_codemaker_vals[2]!=HeroSave_mapversion()) then set g=null return 10 //Invalid Map Version? endif set cod=SubString(cod,y,StringLength(cod)) set link=udg_codemaker_vals[1] set u=CreateUnit(owner,PoolGetItem(p,udg_codemaker_vals[3]+1),px,py,f) set bj_lastCreatedUnit=u call SetHeroLevelBJ(u,udg_codemaker_vals[4], false) call ModifyHeroSkillPoints(u,bj_MODIFYMETHOD_SET,udg_codemaker_vals[5]) call SetHeroInt(u,udg_codemaker_vals[6],true) call SetHeroAgi(u,udg_codemaker_vals[7],true) call SetHeroStr(u,udg_codemaker_vals[8],true) if (HeroSave_MaxGold()!=0) then call SetPlayerState(GetOwningPlayer(u), PLAYER_STATE_RESOURCE_GOLD, udg_codemaker_vals[11]) endif if (HeroSave_MaxLumber()!=0) then call SetPlayerState(GetOwningPlayer(u), PLAYER_STATE_RESOURCE_LUMBER, udg_codemaker_vals[udg_codemaker_vals[0]]) endif set aN=udg_codemaker_vals[9] set iN=udg_codemaker_vals[10] //Done loading stuff from first code //Prepare Second one: set udg_codemaker_vals[0]=1+(aN+iN)*2 set udg_codemaker_size[1]=HeroSave_LinkSize() set i=1 set error=GetStoredInteger(g,"Constants","levelsize") set y=aN loop exitwhen (y<=0) set i=i+1 set udg_codemaker_size[i]=x //Ability set i=i+1 set udg_codemaker_size[i]=error //Level set y=y-1 endloop set y=iN set x=GetStoredInteger(g,"Constants","itemsize") set error=GetStoredInteger(g,"Constants","chargsize") loop exitwhen (y<=0) set i=i+1 set udg_codemaker_size[i]=x //Item set i=i+1 set udg_codemaker_size[i]=error //Charge set y=y-1 endloop set error=Codemaker_ReadCode(owner,cod) if (error>0) then call RemoveUnit(u) set u=null set g=null return error*100 endif if (udg_codemaker_vals[1]!=link) then call RemoveUnit(u) set u=null set g=null return 11 //Links don't match endif set i=1 set p=GetStoredInteger(g,"pools","abils") //Time to load abilities loop exitwhen (aN<=0) set i=i+1 set a=PoolGetItem(p,udg_codemaker_vals[i]+1) call UnitAddAbility(u,a) set i=i+1 call SetUnitAbilityLevel(u,a,udg_codemaker_vals[i]) set aN=aN-1 endloop set p=GetStoredInteger(g,"pools","items") loop exitwhen (iN<=0) set i=i+1 set it=UnitAddItemById(u,PoolGetItem(p,udg_codemaker_vals[i]+1)) set i=i+1 call SetItemCharges(it,udg_codemaker_vals[i]) set iN=iN-1 endloop set u=null set g=null set it=null return 0 endfunction function HeroSave_LoadHeroLoc takes player owner, string cod, location loc, real f returns integer return HeroSave_LoadHero(owner,cod,GetLocationX(loc),GetLocationY(loc),f) endfunction //================================================================================================= //##End## The original Hero Functions work perfectly, so I know it has something to do with these functions whether it be an error or I'm not using the functions right. Do I need to change my save or load triggers to use these functions? Thank you for any help. |
| 03-15-2008, 08:28 PM | #4 |
Same problem: Codes worked fine up untill I started having longer, serial codes. Before it became a serial code with a lot of info, it worked fine. Now: when having codes like "nnne-ennn-prjn-nots-nnn9-9nnn-++nn-n664", even though double-checking shows it's identical, it doesn't work. Note that the last 2 characters are always randomly added, perhaps this is the problem? |
| 03-15-2008, 09:24 PM | #5 |
Found an error: JASS:public function Code2Serial takes string cod, string token , integer charspergroup, string cColor, string lColor, string sColor returns string local integer i=charspergroup local integer j=0 local gamecache g=GetCodemakerCache() local string k=CurrentCharmap() local integer b=GetStoredInteger(g,k+"bitsperchar","now") local integer mx=R2I(Pow(2,b)-1) local string r="" local string c loop exitwhen (ModuloInteger(StringLength(cod),i)==0) set cod=cod+GetStoredString(g,k+"bin2char", Int2BinStr(GetRandomInt(0,mx),b) ) endloop loop set c=SubString(cod,j,j+i) exitwhen (c=="") or (c==null) if (r=="") then set r=HighlightCode(c,cColor,lColor,sColor) else set r=r+"-"+HighlightCode(c,cColor,lColor,sColor) // <----- ERROR endif set j=j+i endloop set g=null return r endfunction Should be JASS:set r=r+token+HighlightCode(c,cColor,lColor,sColor) EDIT: but that didn't fix the problem :/ EDIT 2: I found the error! JASS:local integer T=TotalCodeLength() EDIT 3: When setting that T to a fixed value it malfunctions again? o.O Anyhow, I localized the error to this function, which only works after GenerateCode was executed before JASS:private function ReadCode_thread takes nothing returns nothing local player p=bj_groupEnumOwningPlayer local string cod=TRANSFERSTRING local integer T=TotalCodeLength() local integer L=StringLength(cod) call BJDebugMsg("Reading: " + cod) set bj_groupEnumTypeId=5 if (L<T) then set bj_groupEnumTypeId=1 else if (L>T) then set cod=SubString(cod,0,T) call BJDebugMsg("Cut: " + cod) endif set cod=DecodeBinStr(cod) if (cod=="") then set bj_groupEnumTypeId=2 else if (p!=null) then set cod=DecodeForPlayer(cod,p) endif set cod=CheckCRC(cod) if (cod=="") then set bj_groupEnumTypeId=3 else set bj_groupEnumTypeId=FromBinToArray(cod) endif endif endif set p=null endfunction Note that I changed a bj into TRANSFERSTRING for my own reasons. What it returns when loading before saving is this: When I input xxxx-xxxx-xxxx-xxxx-xxxx: Reading: xxxxxxxxxxxxxxxxxxxx Cut: xx For reference: GenerateCode: JASS:private function GenerateCode_thread takes nothing returns nothing local string r set r=FromArrayToBin() set r=AddCRC(r) if (bj_groupEnumOwningPlayer!=null) then set r=EncodeForPlayer(r,bj_groupEnumOwningPlayer) endif set TRANSFERSTRING=EncodeBinStr(r) endfunction Something in here is called that allows ReadCode to function (both ReadCode in se as the character length inside ReadCode malfunction if GenerateCode wasn't run once before) |
| 03-15-2008, 09:48 PM | #6 | |
That's not an error. Quote:
|
| 03-15-2008, 10:11 PM | #7 |
Magentix if you figure it out an example showing what needs to be changed would be great. I'm not sure if I'm having the same problem or not but it looks promising. |
| 03-15-2008, 10:21 PM | #8 |
I traced it down to this: If you start a map and prompt for a load code then, BEFORE ANYTHING WAS SAVED, it will return error 3. If someone saved, BUT NOT YOU YOURSELF and then you try to load, it will return error 3. If YOU saved ANYTHING (even default values) before trying to load, your load (even different, CORRECT, one than previously saved) code will work. So basically: GenerateCode has to have been called for YOUR player before or else ReadCode will malfunction in many ways (both string-length reading as well as other things) |
| 03-15-2008, 10:23 PM | #9 |
Something tells me you are not initializing it correctly. |
| 03-15-2008, 10:29 PM | #10 |
Here is the vJASSed version I made: JASS:library Codemaker initializer Init globals private gamecache ascii = null private gamecache codemaker = null public integer array vals public integer array size private constant string CONSTANT_Charmap = < censored :) > private constant integer CONSTANT_FCSsize = 7 private string TRANSFERSTRING endglobals function Ascii_cache takes nothing returns gamecache if (ascii==null) then call FlushGameCache(InitGameCache("arcii.vx")) set ascii=InitGameCache("arcii.vx") endif return ascii endfunction constant function Ascii_SafePercent takes nothing returns string if ("%"=="") then return "%%" endif return "%" endfunction function AsciiCharToInteger_sub takes string u returns integer local string charMap = " !\"#$"+Ascii_SafePercent()+"&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" local string c local integer i = 0 if (u == "\b") then return 8 elseif u == "\t" then return 9 elseif u == "\n" then return 10 elseif u == "\f" then return 12 elseif u == "\r" then return 13 endif loop set c = SubString(charMap, i, i + 1) exitwhen c == "" if c == u then return i + 32 endif set i = i + 1 endloop return 0 endfunction function AsciiCharToInteger takes string char returns integer local string k local string u = SubString(char, 0, 1) local integer r if (u == "") or (u == null) then return 0 endif if (StringCase(u,true)==u) then set k=u else set k=u+"1" endif if HaveStoredInteger(Ascii_cache(),"ascii",k) then return GetStoredInteger(Ascii_cache(),"ascii",k) endif set r=AsciiCharToInteger_sub(u) call StoreInteger(Ascii_cache(),"ascii",k,r) return r endfunction function GetStringIdentity takes string s, integer range returns integer local integer len = StringLength(s) local integer i = 0 local integer Result = 0 loop exitwhen (i>=len) set Result = Result+AsciiCharToInteger(SubString(s,i,i+1)) if (Result>=range) then set Result=Result-range endif set i = i + 1 endloop return Result endfunction private function GetCodemakerCache takes nothing returns gamecache if (codemaker==null) then call FlushGameCache(InitGameCache("codemaker")) set codemaker=InitGameCache("codemaker") endif return codemaker endfunction private function GetVal takes integer i returns integer return vals[i] endfunction private function GetSize takes integer i returns integer return size[i] endfunction private function GetMaxVals takes nothing returns integer return vals[0] endfunction private function UseCharmap takes integer id returns boolean local string k=I2S(id) if GetStoredBoolean(GetCodemakerCache(),"charmaps",k) then call StoreInteger(GetCodemakerCache(),"charmaps","current",id) return true endif return false endfunction private function CurrentCharmap takes nothing returns string return I2S(GetStoredInteger(GetCodemakerCache(),"charmaps","current")) endfunction private function BinStr_NOT takes string bin, integer bits returns string local integer i=0 local string r="" loop exitwhen (i>=bits) if (SubString(bin,i,i+1)=="1") then set r=r+"0" else set r=r+"1" endif set i=i+1 endloop return r endfunction private function BinStr_ADD takes string bina, string binb, integer n returns string local string r="" local string c1 local string c2 local string c3 local boolean cr=false loop exitwhen (n<=0) set c1=SubString(bina,n-1,n) set c2=SubString(binb,n-1,n) if (c2!=c1) then if cr then set c3="0" else set c3="1" endif elseif (c1==c2) and (c1=="1") then if cr then set c3="1" else set c3="0" set cr=true endif else if cr then set c3="1" set cr=false else set c3="0" endif endif set r=c3+r set n=n-1 endloop return r endfunction private function BinStr_XOR takes string bin1, string bin2, integer bits returns string local string r="" local integer i=1 local integer c1=1 local integer c2=1 local integer L1=StringLength(bin1) local integer L2=StringLength(bin2) loop exitwhen (i>bits) if ( (SubString(bin1,c1-1,c1)=="1") != (SubString(bin2,c2-1,c2)=="1") ) then set r=r+"1" else set r=r+"0" endif set i=i+1 set c1=c1+1 set c2=c2+1 if (c1>L1) then set c1=1 endif if (c2>L2) then set c2=1 endif endloop return r endfunction private function Int2BinStr takes integer i, integer bits returns string local integer div local string r="" local string max="" if (bits<32) then if (i<0) then return Int2BinStr(0,bits) endif elseif (i<0) then set r=Int2BinStr(-i,31) set r=BinStr_NOT(r,31) set r=BinStr_ADD(r,Int2BinStr(1,31),31) return "1"+r+max endif loop exitwhen (bits==0) set div=i/2 if (div*2==i) then set r="0"+r else set r="1"+r endif set max="1"+max set i=div set bits=bits-1 endloop if (i!=0) then return max endif return r endfunction private function BinStr2Int takes string bin, integer bits returns integer local integer div local string ch local integer r=0 local integer p=1 loop exitwhen (bits<=0) set ch=SubString(bin,bits-1,bits) if (ch=="1") then set r=r+p endif set p=p*2 set bits=bits-1 endloop return r endfunction private function EncodeBinStr takes string bin returns string local gamecache g=GetCodemakerCache() local string k=CurrentCharmap() local integer sz=GetStoredInteger(g,k+"bitsperchar","now") local integer l local integer i=0 local string ch local string r="" set k=k+"bin2char" loop set ch=SubString(bin,i,i+sz) exitwhen (ch=="") or (ch==null) if HaveStoredString(g,k,ch) then set r=r+GetStoredString(g,k,ch) else set r=r+GetStoredString(g,k,"def") endif set i=i+sz endloop set g=null return r endfunction private function DecodeBinStr takes string cod returns string local gamecache g=GetCodemakerCache() local integer i=0 local string k=CurrentCharmap()+"char2bin" local string r="" local string ch loop set ch=SubString(cod,i,i+1) exitwhen (ch=="") or (ch==null) if (StringCase(ch,true)==ch) then set ch=ch+"1" endif if HaveStoredString(g,k,ch) then set r=r+GetStoredString(g,k,ch) else set g=null return "" endif set i=i+1 endloop set g=null return r endfunction private function FromArrayToBin takes nothing returns string local integer n=GetMaxVals() local integer i=1 local string r="" loop exitwhen (i>n) set r=r+Int2BinStr(GetVal(i),GetSize(i)) set i=i+1 endloop return r endfunction function GetCRC takes string bin, integer n returns string local integer mod=R2I(Pow(2,n)) local integer s=0 local string c local integer i=0 loop set c=SubString(bin,i,i+n) exitwhen (c=="") or (c==null) set s= ModuloInteger(s+BinStr2Int(c,n),mod) set i=i+n endloop return Int2BinStr(s,n) endfunction private function AddCRC takes string bin returns string local integer n=GetStoredInteger( GetCodemakerCache() , CurrentCharmap() , "FCS") local string crc=GetCRC(bin,n) return( crc+ BinStr_XOR(bin,crc,StringLength(bin)) ) endfunction private function FixBitNumber takes string bin returns string local integer sz=GetStoredInteger(GetCodemakerCache(),CurrentCharmap()+"bitsperchar","now") loop exitwhen (ModuloInteger(StringLength(bin) , sz)==0) set bin=bin+"0" endloop return bin endfunction private function EncodeForPlayer takes string bin, player p returns string local string in=FixBitNumber(bin) local integer i=0 local integer l=StringLength(in) local integer tt= IMinBJ(l, 31) local string id= Int2BinStr( GetStringIdentity(GetPlayerName(p),R2I( Pow(2,tt) )) , tt) local string r="" loop exitwhen i>=l if (i+tt>=l) then set tt=l-i endif set r=r+BinStr_XOR(SubString(in,i,i+tt),id,tt) set i=i+tt endloop return r endfunction private function DecodeForPlayer takes string bin, player p returns string local integer i=0 local integer l=StringLength(bin) local integer tt= IMinBJ(l, 31) local string id= Int2BinStr( GetStringIdentity(GetPlayerName(p),R2I( Pow(2,tt) )) , tt) local string r="" loop exitwhen i>=l if (i+tt>=l) then set tt=l-i endif set r=r+BinStr_XOR(SubString(bin,i,i+tt),id,tt) set i=i+tt endloop return r endfunction private function TotalBits takes nothing returns integer local integer i=vals[0] local integer r=0 loop exitwhen (i<=0) set r=r+size[i] set i=i-1 endloop return r endfunction private function TotalCodeLength takes nothing returns integer local string k=CurrentCharmap() local integer r=TotalBits()+GetStoredInteger( GetCodemakerCache() , k , "FCS") local integer l=GetStoredInteger (GetCodemakerCache(),k+"bitsperchar","now") loop exitwhen (ModuloInteger(r,l)==0) set r=r+1 endloop return (r/l) endfunction private function CheckCRC takes string bin returns string local integer n=GetStoredInteger( GetCodemakerCache() , CurrentCharmap() , "FCS") local integer T=TotalBits() local string rbin= SubString(bin,n,n+T) local string crc= SubString(bin,0,n) set rbin=BinStr_XOR(rbin,crc,T) if (GetCRC(rbin,n)!=crc) then return "" endif return rbin endfunction private function FromBinToArray takes string bin returns integer local integer n=GetMaxVals() local integer i=1 local integer j=0 local integer sz local string ch loop exitwhen (i>n) set sz=GetSize(i) set ch=SubString(bin,j,j+sz) if (StringLength(ch)< sz ) then return 4 //Missing bits endif set vals[i] = BinStr2Int(ch,sz) set i=i+1 set j=j+sz endloop return 0 endfunction private function GetId takes trigger t returns integer return t return 0 endfunction private function AskString_Child takes nothing returns nothing local gamecache g=GetCodemakerCache() local string k= I2S( GetId( GetTriggeringTrigger() ) ) local string cmd=GetStoredString(g,k,"cmd") local integer l=StringLength(cmd) local boolean b=false local string chat=GetEventPlayerChatString() local string r if (chat==GetStoredString(g,k,"cnl")) then call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,2,chat) set b=true set r="" elseif (SubString(chat,0,l)==cmd) then set r=SubString(chat,l,StringLength(chat)) set b=((r!=null) and (r!="")) endif if not(b) then call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,GetStoredReal(g,k,"rem"),GetStoredString(g,k,"prm")) else call StoreString(g,k,"result",r) endif set g=null endfunction private function GenerateCode_thread takes nothing returns nothing local string r set r=FromArrayToBin() set r=AddCRC(r) if (bj_groupEnumOwningPlayer!=null) then set r=EncodeForPlayer(r,bj_groupEnumOwningPlayer) endif set TRANSFERSTRING=EncodeBinStr(r) endfunction private function ReadCode_thread takes nothing returns nothing local player p=bj_groupEnumOwningPlayer local string cod=TRANSFERSTRING local integer T=TotalCodeLength() local integer L=StringLength(cod) set bj_groupEnumTypeId=5 if (L<T) then set bj_groupEnumTypeId=1 else if (L>T) then set cod=SubString(cod,0,T) endif set cod=DecodeBinStr(cod) if (cod=="") then set bj_groupEnumTypeId=2 else if (p!=null) then set cod=DecodeForPlayer(cod,p) endif set cod=CheckCRC(cod) if (cod=="") then set bj_groupEnumTypeId=3 else set bj_groupEnumTypeId=FromBinToArray(cod) endif endif endif set p=null endfunction public function GenerateCode takes player p returns string local string r set bj_groupEnumOwningPlayer=p call GenerateCode_thread.execute() set r=TRANSFERSTRING return r endfunction public function ReadCode takes player p, string cod returns integer set TRANSFERSTRING=cod set bj_groupEnumOwningPlayer=p call ReadCode_thread.execute() return bj_groupEnumTypeId endfunction public function SetCharmap takes integer id, string ch, integer FCSsize returns nothing local gamecache g=GetCodemakerCache() local integer i=0 local integer log=0 local integer p=1 local string c local string k=I2S(id) local integer EXITTHREAD local string bin if (FCSsize>30) then call BJDebugMsg("|cffff0000Invalid FCS size: Must be <= 30") call FlushGameCache(g) set EXITTHREAD=EXITTHREAD endif call StoreBoolean(g,"charmaps",k,true) loop set c=SubString(ch,i,i+1) exitwhen (c=="") if (StringCase(c,true)==c) then set c=c+"1" endif set i=i+1 if (i>p) then set p=p*2 set log=log+1 endif endloop if (i!=p) then call BJDebugMsg("|cffff0000Invalid charmap: Length must be a power of 2") call FlushGameCache(g) set EXITTHREAD=EXITTHREAD endif if (ModuloInteger(p,FCSsize)==0) then call BJDebugMsg("|cffff0000Invalid charmap/FCS size: FCS size can't be a multiple of the number of bits per character") call FlushGameCache(g) set EXITTHREAD=EXITTHREAD endif set i=0 call StoreInteger(g,k,"FCS",FCSsize) call StoreInteger(g,k+"bitsperchar","now",log) loop exitwhen (i>=p) set bin=Int2BinStr(i,log) set c=SubString(ch,i,i+1) call StoreString(g,k+"bin2char",bin,c) if (i==0) then call StoreString(g,k+"bin2char","def",c) endif if (StringCase(c,true)==c) then set c=c+"1" endif call StoreString(g,k+"char2bin",c,bin) if (i==0) then call StoreString(g,k+"char2bin","def",bin) endif set i=i+1 endloop set g=null endfunction public function AskString takes player p, string prompt, string cmd, string canc, real timeout returns string local gamecache g=GetCodemakerCache() local trigger t=CreateTrigger() local triggeraction ac=TriggerAddAction(t,function AskString_Child ) local string k= I2S( GetId(t) ) local string pk=I2S(GetPlayerId(p)) local string r local timer x loop exitwhen not( GetStoredBoolean(g,pk,"notfree") ) call StoreBoolean(g,pk,"haltnow",true) call TriggerSleepAction(0) endloop call StoreBoolean(g,pk,"notfree",true) call DisplayTimedTextToPlayer(p,0,0,timeout,prompt) call TriggerRegisterPlayerChatEvent(t,p,cmd,false) call TriggerRegisterPlayerChatEvent(t,p,canc,true) call StoreString(g,k,"cmd",cmd) call StoreString(g,k,"prm",prompt) call StoreString(g,k,"cnl",canc) set x=CreateTimer() call TimerStart(x,timeout,false,null) loop exitwhen HaveStoredString(g,k,"result") or (TimerGetRemaining(x)<=0) or GetStoredBoolean(g,pk,"haltnow") call StoreReal(g,k,"rem",TimerGetRemaining(x)) call TriggerSleepAction(0) endloop call StoreBoolean(g,pk,"haltnow",false) set r=GetStoredString(g,k,"result") call FlushStoredMission( g,k) call TriggerRemoveAction(t,ac) call DestroyTrigger(t) call DestroyTimer(x) call StoreBoolean(g,pk,"notfree",false) set x=null set ac=null set g=null set t=null return r endfunction public function HighlightCode takes string cod, string cColor, string lColor, string sColor returns string local integer l=StringLength(cod) local integer i=0 local string r="" local string c local string x local boolean b loop exitwhen (i>=l) set c=SubString(cod,i,i+1) set x="" loop exitwhen (i>=l) set b= (StringCase(c,true)==c) and (StringCase(c,false)!=c) exitwhen not( b) set x=x+c set i=i+1 set c=SubString(cod,i,i+1) endloop if (x!="") then set r=r+"|c"+cColor+x+"|r" endif set x="" loop exitwhen (i>=l) set b= (StringCase(c,true)!=c) and (StringCase(c,false)==c) exitwhen not ( b) set x=x+c set i=i+1 set c=SubString(cod,i,i+1) endloop if (x!="") then set r=r+"|c"+lColor+x+"|r" endif set x="" loop exitwhen (i>=l) set b= (StringCase(c,true)==c) and (StringCase(c,false)==c) exitwhen not ( b) set x=x+c set i=i+1 set c=SubString(cod,i,i+1) endloop if (x!="") then set r=r+"|c"+sColor+x+"|r" endif endloop return r endfunction public function Code2Serial takes string cod, string token , integer charspergroup, string cColor, string lColor, string sColor returns string local integer i=charspergroup local integer j=0 local gamecache g=GetCodemakerCache() local string k=CurrentCharmap() local integer b=GetStoredInteger(g,k+"bitsperchar","now") local integer mx=R2I(Pow(2,b)-1) local string r="" local string c loop exitwhen (ModuloInteger(StringLength(cod),i)==0) set cod=cod+GetStoredString(g,k+"bin2char", Int2BinStr(GetRandomInt(0,mx),b) ) endloop loop set c=SubString(cod,j,j+i) exitwhen (c=="") or (c==null) if (r=="") then set r=HighlightCode(c,cColor,lColor,sColor) else set r=r+token+HighlightCode(c,cColor,lColor,sColor) endif set j=j+i endloop set g=null return r endfunction public function Serial2Code takes string serial, string token returns string local string r="" local string c="" local integer i=0 loop set c=SubString(serial,i,i+1) exitwhen (c=="") or (c==null) if (c!=token) then set r=r+c endif set i=i+1 endloop return r endfunction public function GetRequiredSize takes integer i returns integer local integer p=1 local integer r=0 loop exitwhen (p>i) set r=r+1 set p=p*2 endloop return r endfunction //====================================================================================== private function Init takes nothing returns nothing call SetCharmap(0,CONSTANT_Charmap,CONSTANT_FCSsize) endfunction endlibrary |
| 03-15-2008, 10:32 PM | #11 |
On my test maps you can do everything the exact same way but one errors out and the other one doesn't. Not really helpful but the maps are there to examine. I can say for sure in my maps, that I have successfully loaded codes before saving. The weirdest error 3 I have gotten is this: I changed a few characters in my charmap and started getting error 3 for no reason even though I resaved my heros and got new codes. I replaced characters so the number of characters had to be a power of 2. Anyway I just reverted back to the default charmap and everything worked again. Pointless info I know but I'm just throwing it out there. Am I initializing wrong? This is how I am doing it: |
| 03-15-2008, 10:53 PM | #12 |
by vJassed you mean you just put it inside a library? Double check that one cause there must be something wrong, add debug messages to load and save, cause I am quite sure the original codemaker doesn't have issues with loading a hero without saving first. Dp1983: I said "not initializing correctly" to magentix, can I please look at your charmap though? |
| 03-15-2008, 11:05 PM | #13 |
Vex, my problem happens with the default charmap. You can see everything in my example maps. They are very small I made them specifically to make it easier for you to look at them. If you are talking about my above post where I said I changed the charmap I don't have it anymore but I changed like 3 characters or something. It was something like this: Default and working: abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789@+!* changed and not working: abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789$#!* That was pretty much it. I changed the + because it looks to much like a lowercase t depending on ones handwriting. And I changed @ because I find it annoying to write on paper. This was a completely different problem though from the main problem that I am having, which is getting the Wood and Gold saving to work. This problem is not that big of a deal to me because the default charmap still works. But maybe it will help you. Here I will run a test on my map and see what exact charmap didn't work for me. Edit: Ok, this charmap worked for me when I did a quick test: abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789$#!* It's possible I made an error when I was messing around with it the first time. Again, that is a completely different problem though and just something that I remembered giving me an error 3 but can't reproduce right now. My main problem is still not being able to make use of the Hero/Save Functions that add Gold and Lumber saving. Oh and my problem is Error 300, I fixed my Error 3 problem, it had something to do with a mistake I made in my Save trigger. I didn't know I was suppose to change this: Trigger: Set unitVar = No unitto Trigger: Set unitVar = Triggering UnitIf someone could attach a simple example map where you have gold and lumber saving I could probably figure out what is wrong with the way I am implementing those functions. Again, the below maps show my failure in implementing the saving of gold and lumber resulting in Error 300. Thanks. |
| 03-15-2008, 11:13 PM | #14 |
I'll implement the "regular" Codemaker tomorrow. Please note the error I reported concerning de-serializing though: it only works for "-". By vJASSing I meant adding it into ONE library alltogether, making an Init function for initializing, making private what's supposed to be private and generalizing the globals in a globals block so I don't need GUI variables. |
| 03-16-2008, 12:02 AM | #15 |
For example you could change that thread function to use arguments and .execute(). I have an incomplete sort of vJass version that behaves like streams. I didn't notice that "token" in the line I read it without concatenating token so it looked like the fix was worse than the original line, but now I know you are right that was a bug. Dp1983: Is it error 3 or error 300 (I can't really debug maps anymore, only code) ? Error 3 is a CRC check failed, 300 is a CRC failed in the second phase. So, knowing which of them it is it should be easier to find the problem. |
