15 years
edited 8 years
This is the closest you could reproduce Handle Vars' functionality and interface in (currently westfall) patch 1.24, requires jasshelper 0.9.H.2 and patch 1.24 or later.
Are intended so implementing these handle vars in your map should be able to replace Handle Vars functionality, however, in some odd cases in which you do very odd stuff it won't work (will raise compiler errors), those cases should be rare.
Faux Handle Vars do not have the I2H-related issues that plagued original handle vars, should also be mildly faster (I still recommend AgentVars for a better speed improvement, or even better, structs). However, I do not recommend these functions for anything other than porting old code to patch 1.24. It is because this interface is very leak-friendly (these leaks are also very common in code that uses handle vars, and are almost by-design) Although the leaks weren't a big issue for most maps using Handle vars (not even DOTA) they are still undesirable...
Faux CSCache works the same, except in some cases they might not work 100% well because of how in CSCache you were allowed to use inline gamecache calls and other retardedness... do notice that Faux CSCache will leak memory like ... well, like something that leaks a lot of memory...
CSCache has worked to make spell factory and also some other spell maps work again (once you also move CS to 16.0)
Due to blizzard's failed failedness, You may find some cases like:
These lines will cause a syntax error, why? Because blizzard for some INCREDIBLY STUPID reason didn't make triggeraction extend agent in common.j
The fix for that would be something like:
Differences between these handle vars and the original ones
They are called handle vars and have function names like SetHandleHandle just for the reason of compatibility, in reality, you can only use these functions to attach stuff to objects of the agent type. SetHandleHandle is only able to attach agents. I.E you cannot use SetHandleHandle to attach a lightning effect, would have to use SetHandleLightning instead) Since GetHandleHandle is basically impossible (even one that returns agent) it has been removed.
Faux Handle Vars
Faux CSCache
You will need two additional libraries from Vex's original CasterSystem. They are CSSafeCache and CSData. Their code is below and all 3 libraries are in the attached map to show how they should be implemented.
CSData
CSSafeCache
Are intended so implementing these handle vars in your map should be able to replace Handle Vars functionality, however, in some odd cases in which you do very odd stuff it won't work (will raise compiler errors), those cases should be rare.
Faux Handle Vars do not have the I2H-related issues that plagued original handle vars, should also be mildly faster (I still recommend AgentVars for a better speed improvement, or even better, structs). However, I do not recommend these functions for anything other than porting old code to patch 1.24. It is because this interface is very leak-friendly (these leaks are also very common in code that uses handle vars, and are almost by-design) Although the leaks weren't a big issue for most maps using Handle vars (not even DOTA) they are still undesirable...
Faux CSCache works the same, except in some cases they might not work 100% well because of how in CSCache you were allowed to use inline gamecache calls and other retardedness... do notice that Faux CSCache will leak memory like ... well, like something that leaks a lot of memory...
CSCache has worked to make spell factory and also some other spell maps work again (once you also move CS to 16.0)
Due to blizzard's failed failedness, You may find some cases like:
1 2 call AttachObject( meh, "...", #TriggerAddAction(t, function ff)# )
3
These lines will cause a syntax error, why? Because blizzard for some INCREDIBLY STUPID reason didn't make triggeraction extend agent in common.j
The fix for that would be something like:
1 2 call AttachObject( meh, "...", null )
3 call TriggerAddAction(t, function ff)
4
Differences between these handle vars and the original ones
They are called handle vars and have function names like SetHandleHandle just for the reason of compatibility, in reality, you can only use these functions to attach stuff to objects of the agent type. SetHandleHandle is only able to attach agents. I.E you cannot use SetHandleHandle to attach a lightning effect, would have to use SetHandleLightning instead) Since GetHandleHandle is basically impossible (even one that returns agent) it has been removed.
Faux Handle Vars
1 2 /*******************************************************************************************3 Faux Handle Vars4 ----------------5 Do not use these functions for new stuff, it is just not the right thing to do...6
7 The intention of Faux Handle Vars is to be a patch fix for a map's migration to8 patch 1.24 This library might not cover all uses of handle vars, some of them are just9 impossible with the new rules set in patches 1.23b and 1.24, but they should work for10 most of the cases....11
12 All of them but the SetHandle*** ones are inline friendly. I follow the interface13 in official Kattana's handle vars from wc3jass.com, if your handle vars functions14 look different, then you were not using handle vars but another thing...15
16 *******************************************************************************************/17 18 //==========================================================================================19 library HandleVars initializer init
20 21 globals22 private hashtable ht
23 endglobals24
25 // too bad the Handle vars' old functionality forces me to make these things26 // inline-unfriendly27 function SetHandleHandle takes agent subject, string label, agent value returns nothing
28 if(value==null) then
29 call RemoveSavedHandle( ht, GetHandleId(subject), StringHash(label))
30 else31 call SaveAgentHandle( ht, GetHandleId(subject), StringHash(label), value)
32 endif33 endfunction34 35 function SetHandleInt takes agent subject, string label, integer value returns nothing
36 if value==0 then
37 call RemoveSavedInteger(ht, GetHandleId(subject), StringHash(label))
38 else39 call SaveInteger(ht, GetHandleId(subject), StringHash(label), value)
40 endif 41 endfunction42 43 function SetHandleBoolean takes agent subject, string label, boolean value returns nothing
44 if (value == false) then
45 call RemoveSavedBoolean(ht, GetHandleId(subject), StringHash(label))
46 else47 call SaveBoolean(ht, GetHandleId(subject), StringHash(label), value)
48 endif49 endfunction50 51 function SetHandleReal takes agent subject, string label, real value returns nothing
52 if (value == 0.0) then
53 call RemoveSavedReal(ht, GetHandleId(subject), StringHash(label))
54 else55 call SaveReal(ht, GetHandleId(subject), StringHash(label), value)
56 endif57 endfunction58 59 function SetHandleString takes agent subject, string label, string value returns nothing
60 if ((value=="") or (value==null)) then
61 call RemoveSavedString(ht, GetHandleId(subject), StringHash(label))
62 else63 call SaveStr(ht, GetHandleId(subject), StringHash(label), value) //yay for blizz' consistent naming scheme...
64 endif65 endfunction66 67 function GetHandleHandle takes agent subject, string label returns agent
68 debug call BJDebugMsg("[debug] What the heck? Why would you call HandleHandle I guess this was caused by a search and replace mistake")
69 return null
70 endfunction71 72 // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize73 // GetHandleId as non-state changing. But they will be once I fix jasshelper...74 75 function GetHandleInt takes agent subject, string label returns integer
76 return LoadInteger(ht, GetHandleId(subject), StringHash(label))
77 endfunction78 79 function GetHandleBoolean takes agent subject, string label returns boolean
80 return LoadBoolean(ht, GetHandleId(subject), StringHash(label))
81 endfunction82 83 function GetHandleString takes agent subject, string label returns string
84 return LoadStr(ht, GetHandleId(subject), StringHash(label))
85 endfunction86 87 function GetHandleReal takes agent subject, string label returns real
88 return LoadReal(ht, GetHandleId(subject), StringHash(label))
89 endfunction90 91 // got bored so I now use a textmacro...92 //! textmacro FAUX_HANDLE_VARS_GetHandleHandle takes NAME, TYPE93 function SetHandle$NAME$ takes agent subject, string label, $TYPE$ value returns nothing
94 if(value==null) then
95 call RemoveSavedHandle( ht, GetHandleId(subject), StringHash(label))
96 else97 call Save$NAME$Handle( ht, GetHandleId(subject), StringHash(label), value)
98 endif99 endfunction100 101 function GetHandle$NAME$ takes agent subject, string label returns $TYPE$
102 return Load$NAME$Handle( ht, GetHandleId(subject), StringHash(label))
103 endfunction104 //! endtextmacro105 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Player","player")106 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Widget","widget")107 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Destructable","destructable")108 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Item","item")109 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Unit","unit")110 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Ability","ability")111 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Timer","timer")112 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Trigger","trigger")113 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("TriggerCondition","triggercondition")114 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("TriggerAction","triggeraction")115 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("TriggerEvent","event")116 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Force","force")117 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Group","group")118 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Location","location")119 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Rect","rect")120 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("BooleanExpr","boolexpr")121 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Sound","sound")122 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Effect","effect")123 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("UnitPool","unitpool")124 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("ItemPool","itempool")125 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Quest","quest")126 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("QuestItem","questitem")127 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("DefeatCondition","defeatcondition")128 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("TimerDialog","timerdialog")129 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Leaderboard","leaderboard")130 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Multiboard","multiboard")131 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("MultiboardItem","multiboarditem")132 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Trackable","trackable")133 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Dialog","dialog")134 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Button","button")135 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("TextTag","texttag")136 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Lightning","lightning")137 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Image","image")138 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Ubersplat","ubersplat")139 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Region","region")140 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("FogState","fogstate")141 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("FogModifier","fogmodifier")142 //! runtextmacro FAUX_HANDLE_VARS_GetHandleHandle("Hashtable","hashtable")143 144 145 function FlushHandleVars takes agent subject returns nothing
146 call FlushChildHashtable(ht, GetHandleId(subject))
147 endfunction148 function FlushHandleLocals takes agent subject returns nothing
149 call FlushHandleVars(subject)
150 endfunction151 152 153 private function init takes nothing returns nothing
154 set ht=InitHashtable()
155 endfunction156 157 endlibrary158
Faux CSCache
1 2 /*******************************************************************************************3 Faux CSCache AttachVars4 ----------------5 Do not use these functions for new stuff, it is just not the right thing to do...6
7 The intention of Faux CSCache is to be a patch fix for a map's migration to8 patch 1.24 This library might not cover all uses of handle vars, some of them are just9 impossible with the new rules set in patches 1.23b and 1.24, but they should work for10 most of the cases....11
12 *******************************************************************************************/13 14 //==========================================================================================15 library CSCache initializer init requires CSSafeCache
16 17 globals18 private hashtable ht
19 endglobals20
21 22 // too bad the Handle vars' old functionality forces me to make these things23 // inline-unfriendly24 function SetTableObject takes string subject, string label, agent value returns nothing
25 if(value==null) then
26 call RemoveSavedHandle( ht, StringHash(subject), StringHash(label))
27 else28 call SaveAgentHandle( ht, StringHash(subject), StringHash(label), value)
29 endif30 endfunction31 32 33 34 35 function GetTableHandle takes string subject, string label returns agent
36 debug call BJDebugMsg("[debug] What the heck? Why would you call HandleHandle I guess this was caused by a search and replace mistake")
37 return null
38 endfunction39 40 // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize41 // GetHandleId as non-state changing. But they will be once I fix jasshelper...42 43 44 45 // got bored so I now use a textmacro...46 //! textmacro FAUX_HANDLE_VARS_GetTableHandle takes NAME, TYPE47 function SetTable$NAME$ takes string subject, string label, $TYPE$ value returns nothing
48 if(value==null) then
49 call RemoveSavedHandle( ht, StringHash(subject), StringHash(label))
50 else51 call Save$NAME$Handle( ht, StringHash(subject), StringHash(label), value)
52 endif53 endfunction54 55 function GetTable$NAME$ takes string subject, string label returns $TYPE$
56 return Load$NAME$Handle( ht, StringHash(subject), StringHash(label))
57 endfunction58 //! endtextmacro59 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Player","player")60 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Widget","widget")61 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Destructable","destructable")62 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Item","item")63 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Unit","unit")64 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Ability","ability")65 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Timer","timer")66 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Trigger","trigger")67 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("TriggerCondition","triggercondition")68 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("TriggerAction","triggeraction")69 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("TriggerEvent","event")70 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Force","force")71 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Group","group")72 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Location","location")73 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Rect","rect")74 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("BooleanExpr","boolexpr")75 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Sound","sound")76 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Effect","effect")77 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("UnitPool","unitpool")78 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("ItemPool","itempool")79 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Quest","quest")80 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("QuestItem","questitem")81 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("DefeatCondition","defeatcondition")82 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("TimerDialog","timerdialog")83 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Leaderboard","leaderboard")84 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Multiboard","multiboard")85 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("MultiboardItem","multiboarditem")86 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Trackable","trackable")87 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Dialog","dialog")88 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Button","button")89 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("TextTag","texttag")90 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Lightning","lightning")91 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Image","image")92 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Ubersplat","ubersplat")93 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Region","region")94 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("FogState","fogstate")95 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("FogModifier","fogmodifier")96 //! runtextmacro FAUX_HANDLE_VARS_GetTableHandle("Hashtable","hashtable")97 98 function CS_KillTrigger takes trigger t returns nothing
99 // let em leak100 endfunction101 102 // too bad the Handle vars' old functionality forces me to make these things103 // inline-unfriendly104 function AttachObject takes agent subject, string label, agent value returns nothing
105 call SetTableObject( GetAttachmentTable(subject) , label, value)
106 endfunction107 108 109 110 111 function GetAttachedHandle takes agent subject, string label returns agent
112 debug call BJDebugMsg("[debug] What the heck? Why would you call HandleHandle I guess this was caused by a search and replace mistake")
113 return null
114 endfunction115 116 // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize117 // GetHandleId as non-state changing. But they will be once I fix jasshelper...118 119 120 121 // got bored so I now use a textmacro...122 //! textmacro FAUX_HANDLE_VARS_GetAttachedHandle takes NAME, TYPE123 function Attach$NAME$ takes agent subject, string label, $TYPE$ value returns nothing
124 call SetTable$NAME$( GetAttachmentTable(subject), label, value)
125 endfunction126 127 function GetAttached$NAME$ takes agent subject, string label returns $TYPE$
128 return GetTable$NAME$( GetAttachmentTable(subject), label)
129 endfunction130 //! endtextmacro131 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Player","player")132 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Widget","widget")133 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Destructable","destructable")134 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Item","item")135 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Unit","unit")136 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Ability","ability")137 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Timer","timer")138 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Trigger","trigger")139 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("TriggerCondition","triggercondition")140 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("TriggerAction","triggeraction")141 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("TriggerEvent","event")142 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Force","force")143 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Group","group")144 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Location","location")145 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Rect","rect")146 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("BooleanExpr","boolexpr")147 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Sound","sound")148 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Effect","effect")149 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("UnitPool","unitpool")150 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("ItemPool","itempool")151 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Quest","quest")152 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("QuestItem","questitem")153 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("DefeatCondition","defeatcondition")154 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("TimerDialog","timerdialog")155 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Leaderboard","leaderboard")156 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Multiboard","multiboard")157 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("MultiboardItem","multiboarditem")158 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Trackable","trackable")159 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Dialog","dialog")160 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Button","button")161 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("TextTag","texttag")162 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Lightning","lightning")163 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Image","image")164 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Ubersplat","ubersplat")165 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Region","region")166 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("FogState","fogstate")167 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("FogModifier","fogmodifier")168 //! runtextmacro FAUX_HANDLE_VARS_GetAttachedHandle("Hashtable","hashtable")169
170
171 private function init takes nothing returns nothing
172 set ht=InitHashtable()
173 endfunction174 175 endlibrary176 177
Pyrogasm recommendations
For anyone attempting to use the Faux CSCache system:
You will need two additional libraries from Vex's original CasterSystem. They are CSSafeCache and CSData. Their code is below and all 3 libraries are in the attached map to show how they should be implemented.
CSData
1 library CSData initializer init
2 3 //****************************************************************************************************4 // CSData 16.05 // ¯¯¯¯¯¯¯¯¯¯¯6 // CSDatas are like UserData in units and items, they now use a hashtable instead of big arrays,7 // should be faster and safer8 //9 // Notice that for public spells or systems to be distributed you should only use these10 // for private objects (those who the mapper would never have access to) If you are making something11 // for your map you can use them wherever you want.12 //13 // Best to be used in conjunction to CSArrays so you just specify an array id for a handle.14 //15 // DO NOT USE THIS ON THESE HANDLE TYPES: -lightning, -ubersplat, -image, -texttag,16 // -any 'argument' handle (like playerstate, damagetype, etc)17 //18 //****************************************************************************************************19 20 //====================================================================================================21 globals22 private constant integer MAX_HANDLE_ID_COUNT = 408000
23 // values lower than 8191: very fast, but very unsafe.24 // values bigger than 8191: not that fast, the bigger the number is the slower the function gets25 // Most maps don't really need a value bigger than 50000 here, but if you are unsure, leave it26 // as the rather inflated value of 40800027 endglobals28 29 //=================================================================================================30 // a.k.a H2I, changed name to CS_H2I to prevent conflicts with other systems, it then stayed that31 // instead of changing to a private or public function since many outside spells use it.32 //33 function CS_H2I takes handle h returns integer //For compat
34 return GetHandleId(h) //
35 endfunction //
36 37 //==================================================================================================38 globals39 private hashtable ht
40 endglobals41 42 //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.43 function SetCSData takes handle h, integer v returns nothing
44 call SaveInteger(ht , 0, GetHandleId(h) , v)
45 endfunction46 47 function GetCSData takes handle h returns integer
48 return LoadInteger( ht, 0, GetHandleId(h) )
49 endfunction50 51 private function init takes nothing returns nothing
52 set ht = InitHashtable()
53 endfunction54 55 endlibrary
CSSafeCache
1 library CSSafeCache initializer init requires CSData
2 //*************************************************************************************************3 //* *4 //* CSSafeCache 15.3 [url]http://wc3campaigns.net/vexorian[/url] *5 //* ¯¯¯¯¯¯¯ *6 //* CSCache is evil now, use just CSSafeCache when possible as it now contains all functions *7 //* that do not use I2H or similar functions that are considered to cause unstability in the map *8 //* *9 //* CSCache has been deprecated, and is now unusuable since it can't be ported to patch 1.23b *10 //* Migration from CSCache to CSSafeCache+structs should be easy *11 //* *12 //* However, for old compatibility, CSSafeCache needs to stick to using gamecache, which is not *13 //* as good as hashtable (it is slower and may be vulnerable to Sync attacks) I recommend *14 //* switching from CSSafeCache to hashtable or Table *15 //* *16 //*************************************************************************************************17 18 //=================================================================================================19 // CSSafeCache globals:20 //21 globals22 23 gamecache cs_cache = null
24 integer array cs_array1
25 integer array cs_array3
26 integer array cs_array2
27 private integer array cs_freeindexes
28 private integer array cs_pairx
29 private integer array cs_pairy
30 private integer array cs_freepairs
31 32 endglobals33 34 private function init takes nothing returns nothing
35 // CSSafeCache initializer :36 call FlushGameCache(InitGameCache("cscache"))
37 set cs_cache=InitGameCache("cscache")
38 call ExecuteFunc("InitArrayIndexes")
39 call ExecuteFunc("Pool_SetupCharMap")
40 endfunction41 42 43 //=================================================================================================================44 // CS Pairs45 // ¯¯¯¯¯¯¯¯46 // This is a sub system to assist csarrays, you can use them but CSArrays of size 2 have the same functionality47 // although cspairs are be faster their space is limited and will start using gamecache if abused48 //49 function NewPair takes integer x, integer y returns integer
50 local integer i
51
52 if (cs_freepairs[0]==0) then
53 set cs_freepairs[8190]=cs_freepairs[8190]+1
54 set i= cs_freepairs[8190]
55 else56 set i= cs_freepairs[cs_freepairs[0]]
57 set cs_freepairs[0]=cs_freepairs[0]-1
58 endif59 if (i>=8189) then //because we can only recycle up to 8189 (free pairs array uses indexes 0 and 8190 for other purposes)
60 call StoreInteger(cs_cache,"pairx",I2S(i),x)
61 call StoreInteger(cs_cache,"pairy",I2S(i),y)
62 else63 set cs_pairx[i]=x
64 set cs_pairy[i]=y
65 66 endif67 return i68 endfunction69 70 function DestroyPair takes integer id returns nothing
71 if (id>=8189) then
72 call FlushStoredInteger(cs_cache,"pairx",I2S(id))
73 call FlushStoredInteger(cs_cache,"pairy",I2S(id))
74 else75 set cs_freepairs[0]=cs_freepairs[0]+1
76 set cs_freepairs[cs_freepairs[0]] = id
77 endif78 endfunction79 80 function SetPairXY takes integer id, integer x, integer y returns nothing
81 if (id>=8189) then
82 call StoreInteger(cs_cache,"pairx",I2S(id),x)
83 call StoreInteger(cs_cache,"pairy",I2S(id),y)
84 85 else86 set cs_pairx[id]=x
87 set cs_pairy[id]=y
88 endif89 endfunction90 91 function SetPairX takes integer id, integer x returns nothing
92 if (id>=8189) then
93 call StoreInteger(cs_cache,"pairx",I2S(id),x)
94 else95 set cs_pairx[id]=x
96 endif97 endfunction98 99 function SetPairY takes integer id, integer y returns nothing
100 if (id>=8189) then
101 call StoreInteger(cs_cache,"pairy",I2S(id),y)
102 else103 set cs_pairy[id]=y
104 endif105 endfunction106 107 function GetPairX takes integer id returns integer
108 if (id>=8189) then
109 return GetStoredInteger(cs_cache,"pairy",I2S(id))
110 endif111 return cs_pairx[id]
112 endfunction113 function GetPairY takes integer id returns integer
114 if (id>=8189) then
115 return GetStoredInteger(cs_cache,"pairx",I2S(id))
116 endif117 return cs_pairy[id]
118 endfunction119 120 121 122 123 124 //=================================================================================================================125 // CS Dynamic Arrays126 // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯127 // Thanks: Pipedream, Peppar128 //129 // We can now create arrays in game! , also pass them as arguments or return values!130 // a 1 length array is a pointer!131 //132 function Array_TryFree takes nothing returns nothing
133 local integer i
134 local integer N=cs_array1[0]
135 local integer k
136 local boolean cleaned=false
137 138 local integer loc
139 140 local integer q
141 local integer r
142
143 144 145 set i=cs_array1[146]
146 if (i>144) then
147 call TimerStart(GetExpiredTimer(),60.,false,function Array_TryFree)
148 return149 endif150 151 set loc=cs_freeindexes[i]
152 set q=0
153 loop154 exitwhen (loc==0)
155 // we could just have used:156 //set k=GetPairX(loc)157 //set r=GetPairY(loc) But it is slower than direct usage:158 159 if (loc>=8192) then
160 set k=GetStoredInteger(cs_cache,"pairx",I2S(loc))
161 set r=GetStoredInteger(cs_cache,"pairy",I2S(loc))
162 else163 set k=cs_pairx[loc]
164 set r=cs_pairy[loc]
165 endif166 167 if (k+i-1==N) then
168 169 170 //we found one we can remove from the list171 172 set cleaned=true
173 //decrement N174
175 set N=k-2
176 177 //Remove from the list:178 if (q==null) then
179 //That was the first, update the array as well180 set cs_freeindexes[i]=r
181 else182 //Update the next of the previous one183 //We could use : call SetPairY(q,,r) but it is slower184 if (q>=8189) then
185 call StoreInteger(cs_cache,"pairy",I2S(q),r)
186 else187 set cs_pairy[q]=r
188 endif189 190 191 endif192 if (r==null) then
193 //This was the last one, update it in the array as well194 set cs_freeindexes[i+4096]=q
195 endif196
197 call DestroyPair(loc)
198 set loc=q
199 endif200 set q=loc
201 set loc=r
202 endloop203
204 if (cleaned) then
205 set cs_array1[0]=N
206 set cs_array1[146]=1
207 else208 set cs_array1[146]=cs_array1[i+1]
209 endif210 call TimerStart(GetExpiredTimer(),0.2,false,function Array_TryFree)
211 212 endfunction213 214 function InitArrayIndexes2 takes nothing returns nothing
215 local integer i=0
216 loop217 exitwhen (i==8191)
218 set cs_pairx[i]=777
219 set cs_pairy[i]=777
220 set i=i+1
221 endloop222
223 endfunction224 225 226 function InitArrayIndexes takes nothing returns nothing
227 local integer i=0
228 local integer a=1
229 local integer b=1
230 local integer c
231 232 233 //By placing 777 there instead of 0 it is easier to recognize non correctly initialized bugs234 loop235 exitwhen (i== 8191)
236 set cs_array1[i]=777
237 set cs_array2[i]=777
238 set cs_array3[i]=777
239 //set cs_pairx[i]=777240 //set cs_pairy[i]=777241 set i=i+1
242 endloop243 call ExecuteFunc("InitArrayIndexes2")
244 245 246 set cs_freeindexes[0]=0 //The stack for the table indexes.
247 set cs_freepairs[0]=0
248 set cs_freepairs[8190]=0
249 set i=1
250 loop251 set c=a+b
252 set a=b
253 set b=c
254 exitwhen (b>144) //max size is 144
255 set cs_freeindexes[b]=0 //the first of the list
256 set cs_freeindexes[b+4096]=0 //the last of the list
257 loop258 exitwhen (i>b)
259 set cs_array1[i]=b
260 set i=i+1
261 endloop262
263 endloop264 set cs_array1[i]=b //i is 145
265 set cs_array1[146]=1
266 set cs_array1[147]=101 //initial table index is 101
267 set cs_array1[0]=147
268 //index 0: Last used index269 // 1 to 145 : Fibonacci sequence270 // 146 : last check271 // 147 : Table indexes check272
273 //This has a good chance to compress the thing when necesary274 call TimerStart(CreateTimer(),60.,false,function Array_TryFree)
275 276 endfunction277 278 //=============================================================================================279 // Create an array of size, max size is 144, if doinit is true it will put a bunch of zeros280 // in the indexes281 //282 function NewArray takes integer size, boolean doinit returns integer
283 local integer i
284 local integer rsize=cs_array1[size]
285 local integer loc
286 287 set loc=cs_freeindexes[rsize]
288 if (loc!=0) then
289 290 set cs_freeindexes[rsize]= GetPairY(loc)
291 if (cs_freeindexes[rsize]==0) then
292 set cs_freeindexes[4096+rsize]=0
293 endif294 set i=GetPairX(loc)
295 call DestroyPair(loc)
296 297 if (i==0) then
298 //this code was probably a good idea when we used locations for the free indexes list, now we use pairs which should not ever299 //do this unless someone modiffied the pair array incorrectly300
301 call BJDebugMsg("Caster System: Unexpected error (5): corrupt stack, attempt to recover "+I2S(rsize))
302 // recovering involves forgetting about the stack which got corrupted and start again from zero, it will leak303 // and probably get slow due to usage of gamecache but it is better than the problems that a corrupt stack might cause304 set cs_freeindexes[rsize]=0
305 set cs_freeindexes[4096+rsize]=0
306
307
308 return NewArray(size,doinit)
309 endif310 311 else312
313 //sz i i+1 i+2314 //[ ][ ][ ][ ]315
316 set i=cs_array1[0]+2
317 set cs_array1[0]=i+rsize-1
318 319 endif320 321 //It used to store size in the index equal to the array's id322 // but that required the get/set functions to increment 1 in every index323 // calculation. Instead, making size the previous index to the array works324 if (i<=8191) then
325 set cs_array1[i-1]=size
326 elseif (i<=16382) then
327 set cs_array2[i-8192]=size
328 else329 call StoreInteger(cs_cache,I2S(-i),"size",size)
330 endif331 332
333 if (not doinit) then
334 return i335 endif336
337 // 3338 //[i][i+1][i+2]339 340 set size=i+size-1
341 if (size>=16382) then
342 set size=16381
343 endif344 loop345 exitwhen (size<i) or (size<8191)
346 set cs_array2[size-8191]=0
347 set size=size-1
348 endloop349 loop350 exitwhen (size<i)
351 set cs_array1[size]=0
352 set size=size-1
353 endloop354
355 //call DisplayTextToPlayer(GetLocalPlayer(),0,0,I2S(i))356 357 return i358 endfunction359 360 361 //===============================================================================================================362 // Remember to destroy arrays when you no longer need them, else new arrays will get slower after a bunch of 363 // arrays are active364 //365 function DestroyArray takes integer id returns nothing
366 local integer L
367 local integer loc
368 // local string k=I2S(-id)369 local integer lstpace
370 371 if (id<=8191) then
372 set L=cs_array1[cs_array1[id-1]]
373 elseif (id<=16382) then
374 set L=cs_array1[cs_array2[id-8191]]
375 else376 set L=cs_array1[GetStoredInteger(cs_cache,I2S(-id),"size")]
377 //No way you are gonna call DestroyArray without calling378 //NewArray first, so we can use the gamecache variable directly instead379 380 endif381 set lstpace=id+L-1
382 call FlushStoredMission(cs_cache,I2S(-id))
383
384 if (lstpace>16382) then
385
386 if (lstpace==cs_array1[0]) then
387 //We just destroyed the array that happens to be at the end of the heap.388 //Just get it back389 set cs_array1[0]=id-2
390 set cs_array1[146]=1
391 else392 //Add to the last393 set loc=cs_freeindexes[L+4096]
394 if (loc==0) then
395 set loc=NewPair(id,0)
396 set cs_freeindexes[L]=loc
397 set cs_freeindexes[L+4096]=loc
398 else399 set cs_freeindexes[L+4096]= NewPair(id,0)
400 //we could just use: call SetPairY(loc, cs_freeindexes[L+4096] ) //but that's slower401 if (loc>=8189) then
402 call StoreInteger(cs_cache,"pairy",I2S(loc), cs_freeindexes[L+4096] )
403 else404 set cs_pairy[loc]=cs_freeindexes[L+4096]
405 endif406 407 endif408 409 410 endif411 412 elseif (lstpace==cs_array1[0]) then
413 //We just destroyed the array that happens to be at the end of the heap.414 //Just get it back415 set cs_array1[0]=id-2
416 set cs_array1[146]=1
417 else418 set loc=cs_freeindexes[L]
419 set cs_freeindexes[L]=NewPair(id,loc)
420 421 if (loc==0) then
422 set cs_freeindexes[L+4096]=cs_freeindexes[L]
423 endif424 425 endif426 427 endfunction428 429 //================================================================================================================430 // Int Set/Get array usage prototypes.431 //432 // These are the actual functions, the rest are just the result of copy paste, if these functions are updated433 // the other ones should be updated as well (They are just return bugged variations)434 //435 function SetArrayInt takes integer id, integer index, integer val returns nothing
436 set index=id+index
437 if (index<8191) then
438 set cs_array1[index]=val
439 elseif (index<16382) then
440 set cs_array2[index-8191]=val
441 else442 call StoreInteger(cs_cache,I2S(-id),I2S(index),val)
443 endif444 endfunction445 function GetArrayInt takes integer id, integer index returns integer
446 set index=id+index
447 if (index<8191) then
448 return cs_array1[index]
449 elseif (index<16382) then
450 return cs_array2[index-8191]
451 endif452 return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
453 endfunction454 455 456 //================================================================================================================457 // String Set/Get array458 //459 // Due String related return bug issues, these are forced to use gamecache460 //461 function SetArrayString takes integer id, integer index, string val returns nothing
462 call StoreString(cs_cache,I2S(-id),I2S(index),val)
463 endfunction464 function GetArrayString takes integer id, integer index returns string
465 return GetStoredString(cs_cache,I2S(-id),I2S(index))
466 endfunction467 468 //(Boolean is not needed)469 470 //==========================================================================================================================471 // Returns the size of an array (the specified by player one, not the actual size of it) should be useful.472 //473 function GetArraySize takes integer id returns integer
474 if (id<=8191) then
475 return cs_array1[id-1]
476 elseif (id<=16382) then
477 return cs_array2[id-8192]
478 endif479 return GetStoredInteger(cs_cache,I2S(-id),"size")
480 endfunction481 482 483 //===========================================================================================================================484 // Returns an array that is an exact copy of the given array485 //486 function CloneArray takes integer id returns integer
487 local integer sz
488 local integer i
489 local integer sz2
490 local integer x
491 local integer y
492 493 if (id<=8191) then
494 set sz=cs_array1[id-1]
495 elseif (id<=16382) then
496 set sz=cs_array2[id-8192]
497 else498 set sz=GetStoredInteger(cs_cache,I2S(-id),"size")
499 //No way you are gonna call DestroyArray without calling500 //NewArray first, so we can use the gamecache variable directly instead501 502 endif503 504 set i=NewArray(sz,false)
505
506 set sz2=i+sz-1
507 set sz=id+sz-1
508 set x=i
509 set y=id
510 loop511 exitwhen ((y>sz) or (y>=8191) or (x>=8191))
512 set cs_array1[x]=cs_array1[y]
513 set y=y+1
514 set x=x+1
515 endloop516 loop517 exitwhen ((y>sz) or (y>=8191) or (x>=16382))
518 set cs_array2[x-8191]=cs_array1[y]
519 set y=y+1
520 set x=x+1
521 endloop522 loop523 exitwhen ((y>sz) or (y>=8191))
524 call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array1[y])
525 set x=y+1
526 set y=y+1
527 endloop528 //...529 loop530 exitwhen ((y>sz) or (y>=16382) or (x>=8191))
531 set cs_array1[x]=cs_array2[y-8191]
532 set y=y+1
533 set x=x+1
534 endloop535 loop536 exitwhen ((y>sz) or (y>=16382) or (x>=16382))
537 set cs_array2[x-8191]=cs_array2[y-8191]
538 set y=y+1
539 set x=x+1
540 endloop541 loop542 exitwhen ((y>sz) or (y>=16382))
543 call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array2[y-8191])
544 set y=y+1
545 set x=x+1
546 endloop547 //...548 loop549 exitwhen ((y>sz) or (x>=8191))
550 set cs_array1[x]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id))
551 set y=y+1
552 set x=x+1
553 endloop554 loop555 exitwhen ((y>sz) or (x>=16382))
556 set cs_array2[x-8191]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id))
557 set y=y+1
558 set x=x+1
559 endloop560 loop561 exitwhen (y>sz)
562 call StoreInteger(cs_cache,I2S(-i),I2S(x-i),GetStoredInteger(cs_cache,I2S(-id),I2S(y-id)))
563 set y=y+1
564 set x=x+1
565 endloop566
567 return i568 endfunction569 570 //==================================================================================================571 // Attachable vars : Attacheable variables are what most other people call Handle Variables, they572 // allow to relate data with any handle, using a label, and its value, the stuff auto flushes if573 // the value is 0, false, "", or null .574 //575 // Differences between Attacheable variables and "Local Handle Variables" :576 // - The names of the functions577 // - The name of the function group does not cause confusion, it is difficult to say: 578 // "you should set local handle variables to null at the end of a function" since579 // it sounds as if you were talking about the "Local Handle Variables"580 // - And can work together with Tables.581 // 582 // Gamecache stuff are NOT Case Sensitive, don't ever use "" for label (Crashes game!)583 //584 //585 // Although locations and dynamic arrays are faster than gamecache, gamecache still keeps the flexibility586 // Best thing to do in my opinion is to combine these options. By combining you can acquire gamecache587 // flexibility and arrays/locs speed to solve a problem588 //589 590 //============================================================================================================591 // For integers592 //593 function AttachInt takes handle h, string label, integer x returns nothing
594 if x==0 then
595 call FlushStoredInteger(cs_cache,I2S(GetHandleId(h)),label)
596 else597 call StoreInteger(cs_cache,I2S(GetHandleId(h)),label,x)
598 endif599 endfunction600 function GetAttachedInt takes handle h, string label returns integer
601 return GetStoredInteger(cs_cache, I2S(GetHandleId(h)), label)
602 endfunction603 604 //=============================================================================================================605 function AttachReal takes handle h, string label, real x returns nothing
606 if x==0 then
607 call FlushStoredReal(cs_cache,I2S(GetHandleId(h)),label)
608 else609 call StoreReal(cs_cache,I2S(GetHandleId(h)),label,x)
610 endif611 endfunction612 function GetAttachedReal takes handle h, string label returns real
613 return GetStoredReal(cs_cache,I2S(GetHandleId(h)),label)
614 endfunction615 616 //=============================================================================================================617 function AttachBoolean takes handle h, string label, boolean x returns nothing
618 if not x then
619 call FlushStoredBoolean(cs_cache,I2S(GetHandleId(h)),label)
620 else621 call StoreBoolean(cs_cache,I2S(GetHandleId(h)),label,x)
622 endif623 endfunction624 function GetAttachedBoolean takes handle h, string label returns boolean
625 return GetStoredBoolean(cs_cache,I2S(GetHandleId(h)),label)
626 endfunction627 628 //=============================================================================================================629 function AttachString takes handle h, string label, string x returns nothing
630 if ((x=="") or (x==null)) then
631 call FlushStoredString(cs_cache,I2S(GetHandleId(h)),label)
632 else633 call StoreString(cs_cache,I2S(GetHandleId(h)),label,x)
634 endif635 endfunction636 function GetAttachedString takes handle h, string label returns string
637 return GetStoredString(cs_cache,I2S(GetHandleId(h)),label)
638 endfunction639 640 //============================================================================================================641 function CleanAttachedVars takes handle h returns nothing
642 call FlushStoredMission(cs_cache,I2S(GetHandleId(h)))
643 endfunction644 645 //============================================================================================================646 // Left for compat647 function CleanAttachedVars_NoSets takes handle h returns nothing
648 call FlushStoredMission(cs_cache,I2S(GetHandleId(h)))
649 endfunction650 651 652 //=============================================================================================653 // Tables654 //655 // Tables are lame, the real name would be hash tables, they are just abbreviated usage656 // of gamecache natives with the addition that you can also Copy the values of a table to657 // another one, but don't expect it to be automatic, it must use a FieldData object to know658 // which fields and of wich types to copy, Copying a table to another, with a lot of Fields,659 // should surelly be lag friendly.660 //661 // The other thing about tables is that I can say that the Attached variables of a handle work662 // inside a table and GetAttachmentTable which is just return bug and I2S , works to allow you663 // to manipulate a handle's attached variables through a table.664 //665 // NewTable and DestroyTable were created to allow to create tables in the fly, but you can666 // simply use strings for tables, but place the table names should be between "("")" for example667 // "(mytable)" to avoid conflicts with other caster system stuff.668 //669 function NewTableIndex takes nothing returns integer
670 local integer loc=cs_freeindexes[0]
671 local integer i
672 if (loc!=0) then
673 set i=GetPairX(loc)
674 set cs_freeindexes[0]=GetPairY(loc)
675 call DestroyPair(loc)
676 677 return i678 endif679 set i=cs_array1[147]+1
680 set cs_array1[147]=i
681 682 return i683 endfunction684 function NewTable takes nothing returns string
685 local integer loc=cs_freeindexes[0]
686 local integer i
687 if (loc!=0) then
688 set i=GetPairX(loc)
689 set cs_freeindexes[0]=GetPairY(loc)
690 call DestroyPair(loc)
691 692 return I2S(i)
693 endif694 set i=cs_array1[147]+1
695 set cs_array1[147]=i
696 697 return I2S(i)
698 endfunction699 function GetAttachmentTable takes handle h returns string
700 return I2S(GetHandleId(h))
701 endfunction702 703 //============================================================================================================704 function DestroyTable takes string table returns nothing
705 local integer i=S2I(table)
706 local integer n
707 call FlushStoredMission(cs_cache,table)
708 if ((i>100) and (i<1000000)) then //All right, more than 1000000 tables is just wrong.
709 if (i==cs_array1[147]) then
710 set cs_array1[147]=cs_array1[147]-1
711 else712 set cs_freeindexes[0]= NewPair(i,cs_freeindexes[0])
713 endif714 endif715 716 endfunction717 718 //============================================================================================================719 function ClearTable takes string table returns nothing
720 call FlushStoredMission(cs_cache,table)
721 endfunction722 723 724 //============================================================================================================725 function SetTableInt takes string table, string field, integer val returns nothing
726 if (val==0) then
727 call FlushStoredInteger(cs_cache,table,field)
728 else729 call StoreInteger(cs_cache,table,field,val)
730 endif731 endfunction732 function GetTableInt takes string table, string field returns integer
733 return GetStoredInteger(cs_cache,table,field)
734 endfunction735 736 //============================================================================================================737 function SetTableReal takes string table, string field, real val returns nothing
738 if (val==0) then
739 call FlushStoredReal(cs_cache,table,field)
740 else741 call StoreReal(cs_cache,table,field,val)
742 endif743 endfunction744 function GetTableReal takes string table, string field returns real
745 return GetStoredReal(cs_cache,table,field)
746 endfunction747 748 //============================================================================================================749 function SetTableBoolean takes string table, string field, boolean val returns nothing
750 if (not(val)) then
751 call FlushStoredBoolean(cs_cache,table,field)
752 else753 call StoreBoolean(cs_cache,table,field,val)
754 endif755 endfunction756 function GetTableBoolean takes string table, string field returns boolean
757 return GetStoredBoolean(cs_cache,table,field)
758 endfunction759 760 //============================================================================================================761 function SetTableString takes string table, string field, string val returns nothing
762 if (val=="") or (val==null) then
763 call FlushStoredString(cs_cache,table,field)
764 else765 call StoreString(cs_cache,table,field,val)
766 endif767 endfunction768 function GetTableString takes string table, string field returns string
769 return GetStoredString(cs_cache,table,field)
770 endfunction771 772 //============================================================================================================773 // Returns true if the fiel contains a value different from 0, false, null, or "" (depending on the type)774 // it is worthless to use this with boolean, since it would be the same as reading the boolean value775 //776 function HaveSetField takes string table, string field, integer fieldType returns boolean
777 if (fieldType == bj_GAMECACHE_BOOLEAN) then
778 return HaveStoredBoolean(cs_cache,table,field)
779 elseif (fieldType == bj_GAMECACHE_INTEGER) then
780 return HaveStoredInteger(cs_cache,table,field)
781 elseif (fieldType == bj_GAMECACHE_REAL) then
782 return HaveStoredReal(cs_cache,table,field)
783 elseif (fieldType == bj_GAMECACHE_STRING) then
784 return HaveStoredString(cs_cache,table,field)
785 endif786 return false
787 endfunction788 789 //============================================================================================================790 // Allows to copy a table to another one, but it needs a FieldData object to know which fields of which type791 // it is supposed to copy.792 //793 function CopyTable takes integer FieldData, string sourceTable, string destTable returns nothing
794 local integer i=1
795 local string k=I2S(FieldData)
796 local string k2
797 local string k3
798 local integer n=GetStoredInteger(cs_cache,k,"N")
799 local integer t
800 loop801 exitwhen (i>n)
802 set k2=I2S(i)
803 set t=GetStoredInteger(cs_cache,k,k2)
804 set k3=GetStoredString(cs_cache,k,k2)
805 if (t==bj_GAMECACHE_BOOLEAN) then
806 if (HaveStoredBoolean(cs_cache,sourceTable,k3)) then
807 call StoreBoolean(cs_cache,destTable,k3,GetStoredBoolean(cs_cache,sourceTable,k3))
808 else809 call FlushStoredBoolean(cs_cache,destTable,k3)
810 endif811 elseif (t==bj_GAMECACHE_INTEGER) then
812 if (HaveStoredInteger(cs_cache,sourceTable,k3)) then
813 call StoreInteger(cs_cache,destTable,k3,GetStoredInteger(cs_cache,sourceTable,k3))
814 else815 call FlushStoredInteger(cs_cache,destTable,k3)
816 endif817 elseif (t==bj_GAMECACHE_REAL) then
818 if (HaveStoredReal(cs_cache,sourceTable,k3)) then
819 call StoreReal(cs_cache,destTable,k3,GetStoredReal(cs_cache,sourceTable,k3))
820 else821 call FlushStoredReal(cs_cache,destTable,k3)
822 endif823 elseif (t==bj_GAMECACHE_STRING) then
824 if (HaveStoredString(cs_cache,sourceTable,k3)) then
825 call StoreString(cs_cache,destTable,k3,GetStoredString(cs_cache,sourceTable,k3))
826 else827 call FlushStoredString(cs_cache,destTable,k3)
828 endif829 endif830 set i=i+1
831 endloop832 833 834 endfunction835 836 //=============================================================================================837 // FieldData inherits from Table, was just designed to be used by CopyTable.838 //839 function FieldData_Create takes nothing returns integer
840 return NewTableIndex()
841 endfunction842 843 844 //============================================================================================================845 // valueType uses the same integer variables from blizzard.j :846 // bj_GAMECACHE_BOOLEAN, bj_GAMECACHE_INTEGER, bj_GAMECACHE_REAL and bj_GAMECACHE_STRING847 //848 function FieldData_AddField takes integer fielddata, string field, integer valueType returns nothing
849 local string k=I2S(fielddata)
850 local integer n=GetStoredInteger(cs_cache,k,"N")+1
851 local string k2=I2S(n)
852 853 call StoreString(cs_cache,k,k2,field)
854 call StoreInteger(cs_cache,k,k2,valueType)
855 call StoreInteger(cs_cache,k,"N",n)
856 857 endfunction858 859 //=============================================================================================860 // Destroys Field Data861 function FieldData_Destroy takes integer fielddata returns nothing
862 call DestroyTable(I2S(fielddata))
863 endfunction864 865 //=============================================================================================866 // Pools867 //868 // A better name for pools would be sets, but by the time I made them I couldn't think of that869 // name, besides the word set is already a JASS syntax word so it would have been problematic.870 //871 // Another naming failure is that values of a pool are called "items" but that conflicts with872 // the word item that points to wc3 items, Pools can only store integer values, but if you want873 // you can go and use the return bug on them.874 //875 876 function CreatePool takes nothing returns integer
877 local integer i=NewArray(34,false)
878 call SetArrayInt(i,0,0)
879 return i880 endfunction881 882 function ClearPool takes integer poolid returns nothing
883 call SetArrayInt(poolid,0,0) //[0:integer:n]
884 call FlushStoredMission(cs_cache,I2S(-poolid))
885 endfunction886 887 function DestroyPool takes integer poolid returns nothing
888 call DestroyArray(poolid)
889 endfunction890 891 892 function PoolAddItem takes integer poolid, integer value returns nothing
893 local integer n
894 local string k=I2S(-poolid)
895 local string vk="#"+I2S(value)
896 if not HaveStoredInteger(cs_cache,k,vk) then
897 set n=GetArrayInt(poolid,0)+1 //[0:integer:N]
898 call StoreInteger(cs_cache,k,vk,n)
899 if (n>33) then
900 call StoreInteger(cs_cache,k,I2S(n),value)
901 else902 call SetArrayInt(poolid,n,value)
903 endif904 call SetArrayInt(poolid,0,n) //[0:integer:N]
905 endif906 endfunction907 908 909 910 function PoolRemoveItem takes integer poolid, integer value returns nothing
911 local string k=I2S(-poolid)
912 local string vk="#"+I2S(value)
913 914 local integer p=GetStoredInteger(cs_cache,k,vk)
915 local integer n
916 917 if (p!=0) then
918 set n=GetArrayInt(poolid,0) //[0:integer:N]
919 call FlushStoredInteger( cs_cache, k, vk)
920
921 if (n>p) then
922
923 if (n>33) then
924 set vk=I2S(n)
925 set value=GetStoredInteger(cs_cache,k,vk)
926 call FlushStoredInteger(cs_cache,k,vk)
927 else928 set value=GetArrayInt(poolid,n)
929 endif930 call StoreInteger(cs_cache,k,"#"+I2S(value),p)
931 if (p>33) then
932 call StoreInteger(cs_cache,k,I2S(p),value)
933 else934 call SetArrayInt(poolid,p,value)
935 endif936 elseif (p>33) then
937 call FlushStoredInteger(cs_cache,k,I2S(p))
938 endif939 call SetArrayInt( poolid,0,n - 1) //[0:integer:N]
940 endif941 endfunction942 943 //===================================================================================944 function PoolGetItem takes integer poolid, integer itemn returns integer
945 if (itemn>33) then
946 return GetStoredInteger( cs_cache, I2S(-poolid), I2S(itemn))
947 endif948 return GetArrayInt(poolid,itemn)
949 endfunction950 951 //===================================================================================952 function CountItemsInPool takes integer poolid returns integer
953 return GetArrayInt(poolid,0) //[0:integer:N]
954 endfunction955 956 957 //===================================================================================958 // Removed : GetEnumPoolItem , ForPool and ForPool2 they are much worse than just959 // using CountItemsInPool and PoolGetItem to iterate the pool960 //961 962 //===================================================================================963 function GetFirstOfPool takes integer poolid returns integer
964 return GetArrayInt(poolid,1) //[1 is just the first of the pool]
965 endfunction966 967 968 //===================================================================================969 function PoolPickRandomItem takes integer poolid returns integer
970 local integer p=GetRandomInt( 1, GetArrayInt(poolid,0) )
971 if (p>33) then
972 return GetStoredInteger( cs_cache, I2S(-poolid), I2S(p))
973 endif974 return GetArrayInt(poolid,p)
975 endfunction976 977 //===================================================================================978 function GetItemPositionInPool takes integer poolid, integer it returns integer
979 return GetStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it))
980 endfunction981 982 //===================================================================================983 function IsItemInPool takes integer poolid, integer it returns boolean
984 return(HaveStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it)) )
985 endfunction986 987 //===================================================================================988 // This had to be optimized for speed, if it was just a loop using the above functions 989 // that would have been too slow to be worth keeping. That's a bad thing about JASS990 // it is such an slow language that code reusability always has the cost of speed991 //992 function PoolAddPool takes integer sourcepoolid, integer destpoolid returns nothing
993 local integer a=1
994 local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N]
995 local integer dn=GetArrayInt( destpoolid,0) //[0:integer:N]
996 local string sk=I2S(-sourcepoolid)
997 998 local string k=I2S(-destpoolid)
999 local integer v
1000 local string vk
1001 1002 loop1003 exitwhen (a>n)
1004 if (a>33) then
1005 set v=GetStoredInteger(cs_cache,sk,I2S(a))
1006 else1007 set v=GetArrayInt(sourcepoolid,a)
1008 endif1009 set vk="#"+I2S(v)
1010 if not HaveStoredInteger(cs_cache,k,vk) then
1011 set dn=dn+1
1012 call StoreInteger(cs_cache,k,vk,dn)
1013 if (dn>33) then
1014 call StoreInteger(cs_cache,k,I2S(dn),v)
1015 else1016 call SetArrayInt(destpoolid,dn,v)
1017 endif1018 endif1019 set a=a+1
1020 endloop1021 call SetArrayInt(destpoolid,0,dn) //[0:integer:N]
1022 endfunction1023 1024 //=============================================================================================1025 // Oh darn, After making PoolAddPool I don't feel like writting this one1026 // All right I am at least make the get code1027 //1028 function PoolRemovePool takes integer sourcepoolid, integer destpoolid returns nothing
1029 local integer a=1
1030 local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N]
1031 local integer v
1032 local string sk=I2S(-sourcepoolid)
1033 loop1034 exitwhen a>n
1035 if (a>33) then
1036 set v=GetStoredInteger(cs_cache,sk,I2S(a) )
1037 else1038 set v=GetArrayInt(sourcepoolid,a)
1039 endif1040 call PoolRemoveItem( destpoolid, v)
1041 set a=a+1
1042 endloop1043 endfunction1044 1045 //===================================================================================1046 // Adds a tokenized string to a pool,1047 // Example: PoolAddS(udg_p, "1;2;3;4") will add to the udg_p pool : 1,2,3 and 41048 //1049 function PoolAddS takes integer poolid, string s returns nothing
1050 local integer i=0
1051 local integer st
1052 local string c
1053 set s=s+";"
1054 set st=0
1055 loop1056 set c=SubString(s, i, i+1)
1057 exitwhen (c == "") or (c == null)
1058 if (c == ";") then
1059 call PoolAddItem( poolid, S2I(SubString(s, st, i)) )
1060 set st=i+1
1061 endif1062 set i=i+1
1063 endloop1064 endfunction1065 1066 //===================================================================================1067 // Converts a tokenized string into a pool,1068 // Example: S2Pool( "1;2;3;4") will return a pool that has 1,2,3 and 4 inside1069 //1070 function S2Pool takes string s returns integer
1071 local integer spool= CreatePool()
1072 call PoolAddS(spool,s)
1073 return spool1074 endfunction1075 1076 //===================================================================================1077 // Does the opposite of S2Pool, debugging is a good use for this function.1078 //1079 function Pool2S takes integer P returns string
1080 local integer N=CountItemsInPool(P)
1081 local integer i
1082 local string s
1083 if (N>=1) then
1084 set s=I2S(PoolGetItem(P,1) )
1085 set i=2
1086 else1087 return ""
1088 endif1089 loop1090 exitwhen (i>N)
1091 set s=s+";"+I2S(PoolGetItem(P,i))
1092 set i=i+1
1093 endloop1094 return s1095 endfunction1096 1097 //=============================================================================================================1098 // Fixes a lame bug by blizzard related to the custom script section (The condition of the if statement might1099 // actually be true.1100 //1101 function Pool_Percent takes nothing returns string
1102 if ("%"=="") then
1103 return "%%"
1104 endif1105 return "%"
1106 endfunction1107 1108 function Pool_SetupCharMap takes nothing returns nothing
1109 local string cm=".................................!.#$"+Pool_Percent()+"&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~..."
1110 local integer i=0
1111 local string c
1112 if HaveStoredInteger(cs_cache,"charmap_upper","A") then
1113 return1114 endif1115 loop1116 set c=SubString(cm,i,i+1)
1117 exitwhen (c==null) or (c=="")
1118 if (c!=".") then
1119 if c==StringCase(c,true) then
1120 call StoreInteger(cs_cache,"charmap_upper",c,i)
1121 else1122 call StoreInteger(cs_cache,"charmap_lower",c,i)
1123 endif1124
1125 endif1126 set i=i+1
1127 endloop1128 1129 endfunction1130 1131 1132 function Pool_Rawcode2Int takes string s returns integer
1133 local string c
1134 local integer i=0
1135 local integer r=0
1136 loop1137 exitwhen i>3
1138 set c=SubString(s,i,i+1)
1139 set r=r*256
1140 if c==StringCase(c,true) then
1141 set r=r+GetStoredInteger(cs_cache,"charmap_upper",c)
1142 else1143 set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
1144 endif1145
1146 set i=i+1
1147 endloop1148 return r1149 endfunction1150 1151 function PoolAddRawcodes_thread takes nothing returns nothing
1152 //Threaded because I don't want it to halt execution for no reason1153 //1154 local string s=bj_lastPlayedMusic
1155 local integer poolid=bj_groupEnumTypeId
1156 local string c
1157 local integer i=0
1158 local integer st=0
1159 set s=s+";"
1160 loop1161 set c=SubString(s, i, i+1)
1162 exitwhen (c == "") or (c == null)
1163 if c == ";" then
1164 call PoolAddItem(poolid, Pool_Rawcode2Int(SubString(s,st,i) ))
1165 set st=i+1
1166 endif1167 set i=i+1
1168 endloop1169 1170 endfunction1171 1172 //=====================================================================================================================1173 // Adds a string of tokenized rawcodes to a pool1174 // Example: PoolAddRawcodes(udg_p,"A000;A001") will add 'A000' and 'A001' to the pool1175 //1176 // (Saves some lines, but is not as good efficiency wise)1177 //1178 function PoolAddRawcodes takes integer poolid, string s returns nothing
1179 local string b=bj_lastPlayedMusic
1180 set bj_groupEnumTypeId=poolid
1181 set bj_lastPlayedMusic=s
1182 call ExecuteFunc("PoolAddRawcodes_thread")
1183 set bj_lastPlayedMusic=b
1184 endfunction1185 1186 //===================================================================================================================1187 // Converts a tokenized string of rawcodes into a pool,1188 // Example: Rawcodes2Pool( "A000;A001;AHbz;S000") will return a pool that has 'A000,'A001','AHbx' and 'S000' inside1189 //1190 // (Saves some lines, but is not as good efficiency wise)1191 //1192 function Rawcodes2Pool takes string s returns integer
1193 local integer spool= CreatePool()
1194 call PoolAddRawcodes(spool,s)
1195 return spool1196 endfunction1197 1198 //===================================================================================================================1199 // A subproduct of the Pool's Rawcode support is that we can easily have this function so I am including it even if1200 // it has nothing to do with data storage.1201 //1202 // takes "Aloc" and converts it into 'Aloc'1203 // it is different to the Pool_Rawcode2Int function in that it is safe to use it when it is the first CSCache1204 // function ever used. But it is a little slower (wc3mapoptimizer should make it as fast though)1205 //1206 function CS_Rawcode2Int takes string s returns integer
1207 local string c
1208 local integer i=0
1209 local integer r=0
1210 loop1211 exitwhen i>3
1212 set c=SubString(s,i,i+1)
1213 set r=r*256
1214 if c==StringCase(c,true) then
1215 set r=r+GetStoredInteger(cs_cache,"charmap_upper",c)
1216 else1217 set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
1218 endif1219
1220 set i=i+1
1221 endloop1222 return r1223 endfunction1224 1225 1226 endlibrary