Faux HandleVars & CSCache

Scripts

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:

Code (jass) Select
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:
Code (jass) Select
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
Code (jass) Select
1
2
/*******************************************************************************************
3
 Faux Handle Vars
4
 ----------------
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 to
8
  patch 1.24 This library might not cover all uses of handle vars, some of them are just
9
  impossible with the new rules set in patches 1.23b and 1.24, but they should work for
10
  most of the cases....
11
12
    All of them but the SetHandle*** ones are inline friendly. I follow the interface
13
  in official Kattana's handle vars from wc3jass.com, if your handle vars functions
14
  look different, then you were not using handle vars but another thing...
15
16
*******************************************************************************************/
17
18
//==========================================================================================
19
library HandleVars initializer init
20
21
 globals
22
    private hashtable ht
23
 endglobals
24
 
25
    // too bad the Handle vars' old functionality forces me to make these things
26
    // inline-unfriendly
27
    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
        else
31
            call SaveAgentHandle( ht, GetHandleId(subject), StringHash(label), value)
32
        endif
33
    endfunction
34
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
        else
39
            call SaveInteger(ht, GetHandleId(subject), StringHash(label), value)
40
        endif        
41
    endfunction
42
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
        else
47
            call SaveBoolean(ht, GetHandleId(subject), StringHash(label), value)
48
        endif
49
    endfunction
50
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
        else
55
            call SaveReal(ht, GetHandleId(subject), StringHash(label), value)
56
        endif
57
    endfunction
58
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
        else
63
            call SaveStr(ht, GetHandleId(subject), StringHash(label), value) //yay for blizz' consistent naming scheme...
64
        endif
65
    endfunction
66
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
    endfunction
71
72
    // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize
73
    // 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
    endfunction
78
79
    function GetHandleBoolean takes agent subject, string label returns boolean
80
        return LoadBoolean(ht, GetHandleId(subject), StringHash(label))
81
    endfunction
82
83
    function GetHandleString takes agent subject, string label returns string
84
        return LoadStr(ht, GetHandleId(subject), StringHash(label))
85
    endfunction
86
87
    function GetHandleReal takes agent subject, string label returns real
88
        return LoadReal(ht, GetHandleId(subject), StringHash(label))
89
    endfunction
90
91
    // got bored so I now use a textmacro...
92
    //! textmacro FAUX_HANDLE_VARS_GetHandleHandle takes NAME, TYPE
93
         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
             else
97
                call Save$NAME$Handle( ht, GetHandleId(subject), StringHash(label), value)
98
             endif
99
         endfunction
100
101
         function GetHandle$NAME$ takes agent subject, string label returns $TYPE$
102
             return Load$NAME$Handle( ht, GetHandleId(subject), StringHash(label))
103
         endfunction
104
    //! endtextmacro
105
    //! 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
    endfunction
148
    function FlushHandleLocals takes agent subject returns nothing
149
        call FlushHandleVars(subject)
150
    endfunction
151
152
153
    private function init takes nothing returns nothing
154
        set ht=InitHashtable()
155
    endfunction
156
157
endlibrary
158


Faux CSCache
Code (jass) Select
1
2
/*******************************************************************************************
3
 Faux CSCache AttachVars
4
 ----------------
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 to
8
  patch 1.24 This library might not cover all uses of handle vars, some of them are just
9
  impossible with the new rules set in patches 1.23b and 1.24, but they should work for
10
  most of the cases....
11
12
*******************************************************************************************/
13
14
//==========================================================================================
15
library CSCache initializer init requires CSSafeCache
16
17
 globals
18
    private hashtable ht
19
 endglobals
20
 
21
22
    // too bad the Handle vars' old functionality forces me to make these things
23
    // inline-unfriendly
24
    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
        else
28
            call SaveAgentHandle( ht, StringHash(subject), StringHash(label), value)
29
        endif
30
    endfunction
31
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
    endfunction
39
40
    // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize
41
    // 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, TYPE
47
         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
             else
51
                call Save$NAME$Handle( ht, StringHash(subject), StringHash(label), value)
52
             endif
53
         endfunction
54
55
         function GetTable$NAME$ takes string subject, string label returns $TYPE$
56
             return Load$NAME$Handle( ht, StringHash(subject), StringHash(label))
57
         endfunction
58
    //! endtextmacro
59
    //! 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 leak
100
    endfunction
101
102
    // too bad the Handle vars' old functionality forces me to make these things
103
    // inline-unfriendly
104
    function AttachObject takes agent subject,  string label, agent value returns nothing
105
        call SetTableObject( GetAttachmentTable(subject) , label, value)
106
    endfunction
107
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
    endfunction
115
116
    // these are inline friendly, ok, maybe they aren't because jasshelper does not recognize
117
    // 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, TYPE
123
         function Attach$NAME$ takes agent subject,  string label, $TYPE$ value returns nothing
124
             call SetTable$NAME$( GetAttachmentTable(subject), label, value)
125
         endfunction
126
127
         function GetAttached$NAME$ takes agent subject, string label returns $TYPE$
128
             return GetTable$NAME$( GetAttachmentTable(subject), label)
129
         endfunction
130
    //! endtextmacro
131
    //! 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
    endfunction
174
175
endlibrary
176
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
Code (jass) Select
1
library CSData initializer init
2
3
    //****************************************************************************************************
4
    // CSData 16.0
5
    // ¯¯¯¯¯¯¯¯¯¯¯
6
    // CSDatas are like UserData in units and items, they now use a hashtable instead of big arrays,
7
    // should be faster and safer
8
    //
9
    // Notice that for public spells or systems to be distributed you should only use these
10
    // for private objects (those who the mapper would never have access to) If you are making something
11
    // 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
    globals
22
        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 gets
25
        // Most maps don't really need a value bigger than 50000 here, but if you are unsure, leave it
26
        // as the rather inflated value of 408000
27
    endglobals
28
29
    //=================================================================================================
30
    // a.k.a H2I, changed name to CS_H2I to prevent conflicts with other systems, it then stayed that
31
    // 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
    globals
39
        private hashtable ht
40
    endglobals
41
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
    endfunction
46
47
    function GetCSData takes handle h returns integer
48
        return LoadInteger( ht, 0, GetHandleId(h) )
49
    endfunction
50
51
    private function init takes nothing returns nothing
52
        set ht = InitHashtable()
53
    endfunction
54
55
endlibrary


CSSafeCache
Code (jass) Select
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
    globals
22
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
    endglobals
33
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
    endfunction
41
42
43
    //=================================================================================================================
44
    // CS Pairs
45
    // ¯¯¯¯¯¯¯¯
46
    // This is a sub system to assist csarrays, you can use them but CSArrays of size 2 have the same functionality
47
    // although cspairs are be faster their space is limited and will start using gamecache if abused
48
    //
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
       else
56
           set i= cs_freepairs[cs_freepairs[0]]
57
           set cs_freepairs[0]=cs_freepairs[0]-1
58
       endif
59
       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
       else
63
           set cs_pairx[i]=x
64
           set cs_pairy[i]=y
65
66
       endif
67
     return i
68
    endfunction
69
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
        else
75
            set cs_freepairs[0]=cs_freepairs[0]+1
76
            set cs_freepairs[cs_freepairs[0]] = id
77
        endif
78
    endfunction
79
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
        else
86
            set cs_pairx[id]=x
87
            set cs_pairy[id]=y
88
        endif
89
    endfunction
90
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
        else
95
            set cs_pairx[id]=x
96
        endif
97
    endfunction
98
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
        else
103
            set cs_pairy[id]=y
104
        endif
105
    endfunction
106
107
    function GetPairX takes integer id returns integer
108
        if (id>=8189) then
109
            return GetStoredInteger(cs_cache,"pairy",I2S(id))
110
        endif
111
     return cs_pairx[id]
112
    endfunction
113
    function GetPairY takes integer id returns integer
114
        if (id>=8189) then
115
            return GetStoredInteger(cs_cache,"pairx",I2S(id))
116
        endif
117
     return cs_pairy[id]
118
    endfunction
119
120
121
122
123
124
    //=================================================================================================================
125
    // CS Dynamic Arrays
126
    // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
127
    // Thanks: Pipedream, Peppar
128
    //
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
                return
149
            endif
150
151
            set loc=cs_freeindexes[i]
152
            set q=0
153
            loop
154
                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
    	    else
163
    	        set k=cs_pairx[loc]
164
    		set r=cs_pairy[loc]
165
    	    endif
166
167
                if (k+i-1==N) then
168
169
170
                    //we found one we can remove from the list
171
172
                    set cleaned=true
173
                    //decrement N
174
                    
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 well
180
                        set cs_freeindexes[i]=r
181
                    else
182
                        //Update the next of the previous one
183
                        //We could use : call SetPairY(q,,r) but it is slower
184
    		    if (q>=8189) then
185
    		        call StoreInteger(cs_cache,"pairy",I2S(q),r)
186
                        else
187
    			set cs_pairy[q]=r
188
    		    endif
189
190
191
                    endif
192
                    if (r==null) then
193
                        //This was the last one, update it in the array as well
194
                        set cs_freeindexes[i+4096]=q
195
                    endif
196
                    
197
                    call DestroyPair(loc)
198
                    set loc=q
199
                endif
200
                set q=loc
201
                set loc=r
202
            endloop
203
           
204
            if (cleaned) then
205
                set cs_array1[0]=N
206
                set cs_array1[146]=1
207
            else
208
                set cs_array1[146]=cs_array1[i+1]
209
            endif
210
     call TimerStart(GetExpiredTimer(),0.2,false,function Array_TryFree)
211
212
    endfunction
213
214
    function InitArrayIndexes2 takes nothing returns nothing
215
     local integer i=0
216
        loop
217
            exitwhen (i==8191)
218
            set cs_pairx[i]=777
219
            set cs_pairy[i]=777
220
            set i=i+1
221
        endloop
222
     
223
    endfunction
224
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 bugs
234
        loop
235
            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]=777
240
            //set cs_pairy[i]=777
241
            set i=i+1
242
        endloop
243
        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
        loop
251
            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
            loop
258
                exitwhen (i>b)
259
                set cs_array1[i]=b
260
                set i=i+1
261
            endloop
262
            
263
        endloop
264
        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 index
269
        // 1 to 145 : Fibonacci sequence
270
        // 146 : last check
271
        // 147 : Table indexes check
272
       
273
        //This has a good chance to compress the thing when necesary
274
        call TimerStart(CreateTimer(),60.,false,function Array_TryFree)
275
276
    endfunction
277
278
    //=============================================================================================
279
    // Create an array of size, max size is 144, if doinit is true it will put a bunch of zeros
280
    // in the indexes
281
    //
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
            endif
294
            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 ever
299
                //do this unless someone modiffied the pair array incorrectly
300
            
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 leak
303
                // and probably get slow due to usage of gamecache but it is better than the problems that a corrupt stack might cause
304
                set cs_freeindexes[rsize]=0
305
                set cs_freeindexes[4096+rsize]=0
306
                
307
                
308
                return NewArray(size,doinit)
309
            endif
310
311
        else
312
            
313
            //sz  i   i+1   i+2
314
            //[ ][   ][    ][   ]
315
        
316
            set i=cs_array1[0]+2
317
            set cs_array1[0]=i+rsize-1
318
319
        endif
320
321
        //It used to store size in the index equal to the array's id
322
        // but that required the get/set functions to increment 1 in every index
323
        // calculation. Instead, making size the previous index to the array works
324
        if (i<=8191) then
325
            set cs_array1[i-1]=size
326
        elseif (i<=16382) then
327
            set cs_array2[i-8192]=size
328
        else
329
            call StoreInteger(cs_cache,I2S(-i),"size",size)
330
        endif
331
332
       
333
        if (not doinit) then
334
            return i
335
        endif
336
        
337
        //    3
338
        //[i][i+1][i+2]
339
340
        set size=i+size-1
341
        if (size>=16382) then
342
            set size=16381
343
        endif
344
        loop
345
            exitwhen (size<i) or (size<8191)
346
            set cs_array2[size-8191]=0
347
            set size=size-1
348
        endloop
349
        loop
350
            exitwhen (size<i)
351
            set cs_array1[size]=0
352
            set size=size-1
353
        endloop
354
        
355
        //call DisplayTextToPlayer(GetLocalPlayer(),0,0,I2S(i))
356
357
     return i
358
    endfunction
359
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 active
364
    //
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
        else
376
            set L=cs_array1[GetStoredInteger(cs_cache,I2S(-id),"size")]
377
            //No way you are gonna call DestroyArray without calling
378
           //NewArray first, so we can use the gamecache variable directly instead
379
380
        endif
381
        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 back
389
               set cs_array1[0]=id-2
390
               set cs_array1[146]=1
391
           else
392
               //Add to the last
393
               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
               else
399
                   set cs_freeindexes[L+4096]=  NewPair(id,0)
400
                   //we could just use: call SetPairY(loc, cs_freeindexes[L+4096] ) //but that's slower
401
                   if (loc>=8189) then
402
    	           call StoreInteger(cs_cache,"pairy",I2S(loc), cs_freeindexes[L+4096] )
403
                   else
404
                       set cs_pairy[loc]=cs_freeindexes[L+4096]	            
405
                   endif
406
407
               endif
408
409
410
           endif
411
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 back
415
               set cs_array1[0]=id-2
416
               set cs_array1[146]=1
417
       else
418
           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
           endif
424
425
       endif
426
427
    endfunction
428
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 updated
433
    // 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
        else
442
            call StoreInteger(cs_cache,I2S(-id),I2S(index),val)
443
        endif
444
    endfunction
445
    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
        endif
452
     return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
453
    endfunction
454
455
456
    //================================================================================================================
457
    // String Set/Get array
458
    //
459
    // Due String related return bug issues, these are forced to use gamecache
460
    //
461
    function SetArrayString takes integer id, integer index, string val returns nothing
462
        call StoreString(cs_cache,I2S(-id),I2S(index),val)
463
    endfunction
464
    function GetArrayString takes integer id, integer index returns string
465
     return GetStoredString(cs_cache,I2S(-id),I2S(index))
466
    endfunction
467
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
        endif
479
     return GetStoredInteger(cs_cache,I2S(-id),"size")
480
    endfunction
481
482
483
    //===========================================================================================================================
484
    // Returns an array that is an exact copy of the given array
485
    //
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
        else
498
            set sz=GetStoredInteger(cs_cache,I2S(-id),"size")
499
            //No way you are gonna call DestroyArray without calling
500
           //NewArray first, so we can use the gamecache variable directly instead
501
502
        endif
503
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
        loop
511
            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
        endloop
516
        loop
517
            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
        endloop
522
        loop
523
            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
        endloop
528
        //...
529
        loop
530
            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
        endloop
535
        loop
536
            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
        endloop
541
        loop
542
            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
        endloop
547
        //...
548
        loop
549
            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
        endloop
554
        loop
555
            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
        endloop
560
        loop
561
            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
        endloop
566
        
567
     return i
568
    endfunction
569
570
    //==================================================================================================
571
    // Attachable vars : Attacheable variables are what most other people call Handle Variables, they
572
    // allow to relate data with any handle, using a label, and its value, the stuff auto flushes if
573
    // the value is 0, false, "", or null .
574
    //
575
    // Differences between Attacheable variables and "Local Handle Variables" :
576
    // - The names of the functions
577
    // - 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" since
579
    //   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 flexibility
586
    // Best thing to do in my opinion is to combine these options. By combining you can acquire gamecache
587
    // flexibility and arrays/locs speed to solve a problem
588
    //
589
590
    //============================================================================================================
591
    // For integers
592
    //
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
        else
597
            call StoreInteger(cs_cache,I2S(GetHandleId(h)),label,x)
598
        endif
599
    endfunction
600
    function GetAttachedInt takes handle h, string label returns integer
601
        return GetStoredInteger(cs_cache, I2S(GetHandleId(h)), label)
602
    endfunction
603
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
        else
609
            call StoreReal(cs_cache,I2S(GetHandleId(h)),label,x)
610
        endif
611
    endfunction
612
    function GetAttachedReal takes handle h, string label returns real
613
        return GetStoredReal(cs_cache,I2S(GetHandleId(h)),label)
614
    endfunction
615
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
        else
621
            call StoreBoolean(cs_cache,I2S(GetHandleId(h)),label,x)
622
        endif
623
    endfunction
624
    function GetAttachedBoolean takes handle h, string label returns boolean
625
        return GetStoredBoolean(cs_cache,I2S(GetHandleId(h)),label)
626
    endfunction
627
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
        else
633
            call StoreString(cs_cache,I2S(GetHandleId(h)),label,x)
634
        endif
635
    endfunction
636
    function GetAttachedString takes handle h, string label returns string
637
        return GetStoredString(cs_cache,I2S(GetHandleId(h)),label)
638
    endfunction
639
640
    //============================================================================================================
641
    function CleanAttachedVars takes handle h returns nothing
642
        call FlushStoredMission(cs_cache,I2S(GetHandleId(h)))
643
    endfunction
644
645
    //============================================================================================================
646
    // Left for compat
647
    function CleanAttachedVars_NoSets takes handle h returns nothing
648
        call FlushStoredMission(cs_cache,I2S(GetHandleId(h)))
649
    endfunction
650
651
652
    //=============================================================================================
653
    // Tables
654
    //
655
    // Tables are lame, the real name would be hash tables, they are just abbreviated usage
656
    // of gamecache natives with the addition that you can also Copy the values of a table to
657
    // another one, but don't expect it to be automatic, it must use a FieldData object to know
658
    // 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 work
662
    // inside a table and GetAttachmentTable which is just return bug and I2S , works to allow you
663
    // 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 can
666
    // simply use strings for tables, but place the table names should be between "("")" for example
667
    // "(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 i
678
        endif
679
        set i=cs_array1[147]+1
680
        set cs_array1[147]=i
681
682
     return i
683
    endfunction
684
    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
        endif
694
        set i=cs_array1[147]+1
695
        set cs_array1[147]=i
696
697
     return I2S(i)
698
    endfunction
699
    function GetAttachmentTable takes handle h returns string
700
        return I2S(GetHandleId(h))
701
    endfunction
702
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
             else
712
                 set cs_freeindexes[0]=  NewPair(i,cs_freeindexes[0])
713
             endif
714
         endif
715
716
    endfunction
717
718
    //============================================================================================================
719
    function ClearTable takes string table returns nothing
720
         call FlushStoredMission(cs_cache,table)
721
    endfunction
722
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
        else
729
            call StoreInteger(cs_cache,table,field,val)
730
        endif
731
    endfunction
732
    function GetTableInt takes string table, string field returns integer
733
        return GetStoredInteger(cs_cache,table,field)
734
    endfunction
735
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
        else
741
            call StoreReal(cs_cache,table,field,val)
742
        endif
743
    endfunction
744
    function GetTableReal takes string table, string field returns real
745
        return GetStoredReal(cs_cache,table,field)
746
    endfunction
747
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
        else
753
            call StoreBoolean(cs_cache,table,field,val)
754
        endif
755
    endfunction
756
    function GetTableBoolean takes string table, string field returns boolean
757
        return GetStoredBoolean(cs_cache,table,field)
758
    endfunction
759
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
        else
765
            call StoreString(cs_cache,table,field,val)
766
        endif
767
    endfunction
768
    function GetTableString takes string table, string field returns string
769
        return GetStoredString(cs_cache,table,field)
770
    endfunction
771
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 value
775
    //
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
        endif
786
     return false
787
    endfunction
788
789
    //============================================================================================================
790
    // Allows to copy a table to another one, but it needs a FieldData object to know which fields of which type
791
    // 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
        loop
801
            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
                else
809
                    call FlushStoredBoolean(cs_cache,destTable,k3)
810
                endif
811
            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
                else
815
                    call FlushStoredInteger(cs_cache,destTable,k3)
816
                endif
817
            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
                else
821
                    call FlushStoredReal(cs_cache,destTable,k3)
822
                endif
823
            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
                else
827
                    call FlushStoredString(cs_cache,destTable,k3)
828
                endif
829
            endif
830
            set i=i+1
831
        endloop
832
833
834
    endfunction
835
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
    endfunction
842
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_STRING
847
    //
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
    endfunction
858
859
    //=============================================================================================
860
    // Destroys Field Data
861
    function FieldData_Destroy takes integer fielddata returns nothing
862
        call DestroyTable(I2S(fielddata))
863
    endfunction
864
865
    //=============================================================================================
866
    // Pools
867
    //
868
    // A better name for pools would be sets, but by the time I made them I couldn't think of that
869
    // 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 with
872
    // the word item that points to wc3 items, Pools can only store integer values, but if you want
873
    // 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 i
880
    endfunction
881
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
    endfunction
886
887
    function DestroyPool takes integer poolid returns nothing
888
        call DestroyArray(poolid)
889
    endfunction
890
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
            else
902
                call SetArrayInt(poolid,n,value)
903
            endif
904
            call SetArrayInt(poolid,0,n) //[0:integer:N]
905
        endif
906
    endfunction
907
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
                else
928
                    set value=GetArrayInt(poolid,n)
929
                endif
930
                call StoreInteger(cs_cache,k,"#"+I2S(value),p)
931
                if (p>33) then
932
                    call StoreInteger(cs_cache,k,I2S(p),value)
933
                else
934
                    call SetArrayInt(poolid,p,value)
935
                endif
936
            elseif (p>33) then
937
                call FlushStoredInteger(cs_cache,k,I2S(p))
938
            endif
939
            call SetArrayInt( poolid,0,n - 1) //[0:integer:N]
940
        endif
941
    endfunction
942
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
        endif
948
     return GetArrayInt(poolid,itemn)
949
    endfunction
950
951
    //===================================================================================
952
    function CountItemsInPool takes integer poolid returns integer
953
     return GetArrayInt(poolid,0) //[0:integer:N]
954
    endfunction
955
956
957
    //===================================================================================
958
    // Removed : GetEnumPoolItem , ForPool and ForPool2 they are much worse than just
959
    // using CountItemsInPool and PoolGetItem to iterate the pool
960
    //
961
962
    //===================================================================================
963
    function GetFirstOfPool takes integer poolid returns integer
964
        return GetArrayInt(poolid,1) //[1 is just the first of the pool]
965
    endfunction
966
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
        endif
974
     return GetArrayInt(poolid,p)
975
    endfunction
976
977
    //===================================================================================
978
    function GetItemPositionInPool takes integer poolid, integer it returns integer
979
        return GetStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it))
980
    endfunction
981
982
    //===================================================================================
983
    function IsItemInPool takes integer poolid, integer it returns boolean
984
        return(HaveStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it)) )
985
    endfunction
986
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 JASS
990
    // it is such an slow language that code reusability always has the cost of speed
991
    //
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
        loop
1003
            exitwhen (a>n)
1004
            if (a>33) then
1005
                set v=GetStoredInteger(cs_cache,sk,I2S(a))
1006
            else
1007
                set v=GetArrayInt(sourcepoolid,a)
1008
            endif
1009
            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
                else
1016
                    call SetArrayInt(destpoolid,dn,v)
1017
                endif
1018
            endif
1019
            set a=a+1
1020
        endloop
1021
        call SetArrayInt(destpoolid,0,dn) //[0:integer:N]
1022
    endfunction
1023
1024
    //=============================================================================================
1025
    // Oh darn, After making PoolAddPool I don't feel like writting this one
1026
    // All right I am at least make the get code
1027
    //
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
        loop
1034
            exitwhen a>n
1035
            if (a>33) then
1036
                set v=GetStoredInteger(cs_cache,sk,I2S(a) )
1037
            else
1038
                set v=GetArrayInt(sourcepoolid,a)
1039
            endif
1040
            call PoolRemoveItem( destpoolid, v)
1041
            set a=a+1
1042
        endloop
1043
    endfunction
1044
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 4
1048
    //
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
        loop
1056
            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
            endif
1062
            set i=i+1
1063
        endloop
1064
    endfunction
1065
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 inside
1069
    //
1070
    function S2Pool takes string s returns integer
1071
     local integer spool= CreatePool()
1072
        call PoolAddS(spool,s)
1073
     return spool
1074
    endfunction
1075
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
        else
1087
            return ""
1088
        endif
1089
        loop
1090
            exitwhen (i>N)
1091
            set s=s+";"+I2S(PoolGetItem(P,i))
1092
            set i=i+1
1093
        endloop
1094
    return s
1095
    endfunction
1096
1097
    //=============================================================================================================
1098
    // Fixes a lame bug by blizzard related to the custom script section (The condition of the if statement might
1099
    // actually be true.
1100
    //
1101
    function Pool_Percent takes nothing returns string
1102
       if ("%"=="") then
1103
           return "%%"
1104
       endif
1105
     return "%"
1106
    endfunction
1107
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
            return
1114
        endif
1115
        loop
1116
            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
                else
1122
                    call StoreInteger(cs_cache,"charmap_lower",c,i)
1123
                endif
1124
                
1125
            endif
1126
            set i=i+1
1127
        endloop
1128
1129
    endfunction
1130
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
        loop
1137
            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
            else
1143
                set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
1144
            endif
1145
            
1146
            set i=i+1
1147
        endloop
1148
     return r
1149
    endfunction
1150
1151
    function PoolAddRawcodes_thread takes nothing returns nothing
1152
    //Threaded because I don't want it to halt execution for no reason
1153
    //
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
        loop
1161
            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
            endif
1167
            set i=i+1
1168
        endloop
1169
1170
    endfunction
1171
1172
    //=====================================================================================================================
1173
    // Adds a string of tokenized rawcodes to a pool
1174
    //  Example: PoolAddRawcodes(udg_p,"A000;A001")  will add 'A000' and 'A001' to the pool
1175
    //
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
    endfunction
1185
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' inside
1189
    //
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 spool
1196
    endfunction
1197
1198
    //===================================================================================================================
1199
    // A subproduct of the Pool's Rawcode support is that we can easily have this function so I am including it even if
1200
    // 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 CSCache
1204
    // 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
        loop
1211
            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
            else
1217
                set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
1218
            endif
1219
            
1220
            set i=i+1
1221
        endloop
1222
     return r
1223
    endfunction
1224
1225
1226
endlibrary
  • Faux CSCache With Everything.w3x (51.27 KB)