Back to Home

ESO Lua File v101041

libraries/utility/zo_objectpool.lua

[◄ back to folders ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
--[[
A generic pool to contain "active" and "free" objects. Active objects
are typically objects which:
1. Have a relatively high construction cost
2. Are not lightweight enough to create many of them at once
3. Tend to be reused as dynamic elements of a larger container.
The pool should "rapidly" reach a high-water mark of contained objects
which should flow between active and free states on a regular basis.
Ideal uses of the ZO_ObjectPool would be to contain objects such as:
1. Scrolling combat text
2. Tracked quests
3. Buff icons
The pools are not intended to be used to track a dynamic set of
contained objects whose membership grows to a predetermined size.
As such, do NOT use the pool to track:
1. Chat filters
2. Inventory slots
3. Action buttons (unless creating something like AutoBar)
A common usage pattern is instantiating templated controls. To facilitate this
without bloating your own code you should use ZO_ObjectPool_CreateControl which has
been written here as a convenience. It creates a control named "template"..id where
id is an arbitrary value that will not conflict with other generated id's.
If your system depends on having well-known names for controls, you should not use the
convenience function.
--]]
ZO_ObjectPool = ZO_InitializingObject:Subclass()
function ZO_ObjectPool:Initialize(factoryFunctionOrObjectClass, resetFunction)
    assert(factoryFunctionOrObjectClass ~= nil)
    self.m_Active = {}
    self.m_Free = {}
    self:SetFactory(factoryFunctionOrObjectClass)
    
    self.m_NextFree = 1 -- Just in case the user would like the pool to generate object keys.
    self.m_NextControlId = 0 -- Just in case the user would like the pool to generate id-based control suffixes
end
-- Define the primary factory behavior
function ZO_ObjectPool:SetFactory(factoryFunctionOrObjectClass)
    if type(factoryFunctionOrObjectClass) == "function" then
        self.m_Factory = factoryFunctionOrObjectClass -- Signature: function(ZO_ObjectPool, objectKey)
    else
        self.m_Factory = function(pool, objectKey) return factoryFunctionOrObjectClass:New(pool, objectKey) end
    end
end
-- Define the primary reset behavior
function ZO_ObjectPool:SetResetFunction(resetFunction)
    self.m_Reset = resetFunction -- Signature: function(objectBeingReset, ZO_ObjectPool)
end
function ZO_ObjectPool:GetNextFree()
    local freeKey, object = next(self.m_Free)
    if freeKey == nil or object == nil then
        local nextPotentialFree = self.m_NextFree
        self.m_NextFree = self.m_NextFree + 1
        return nextPotentialFree, nil
    end
    return freeKey, object
end
function ZO_ObjectPool:GetNextControlId()
    self.m_NextControlId = self.m_NextControlId + 1
    return self.m_NextControlId
end
function ZO_ObjectPool:GetTotalObjectCount()
end
function ZO_ObjectPool:GetActiveObjectCount()
    return NonContiguousCount(self.m_Active)
end
function ZO_ObjectPool:HasActiveObjects()
    return next(self.m_Active) ~= nil
end
function ZO_ObjectPool:GetActiveObjects()
    return self.m_Active
end
function ZO_ObjectPool:GetActiveObject(objectKey)
    return self.m_Active[objectKey]
end
function ZO_ObjectPool:ActiveObjectIterator(filterFunctions)
    return ZO_FilteredNonContiguousTableIterator(self.m_Active, filterFunctions)
end
function ZO_ObjectPool:GetFreeObjectCount()
    return NonContiguousCount(self.m_Free)
end
function ZO_ObjectPool:ActiveAndFreeObjectIterator(filterFunctions)
    local objects = {}
    ZO_CombineNonContiguousTables(objects, self.m_Active, self.m_Free)
    return ZO_FilteredNonContiguousTableIterator(objects, filterFunctions)
end
    self.customAcquireBehavior = customAcquireBehavior -- Signature: function(objectBeingAcquired, objectKey)
end
-- Optional supplementary behavior that can be run after the factory has created the object
-- Often used in conjunction with extension pool classes (e.g.: ZO_ControlPool) when you want all the default factory behavior, plus something extra
    self.customFactoryBehavior = customFactoryBehavior -- Signature: function(objectBeingCreated, objectKey, ZO_ObjectPool)
end
-- Optional supplementary behavior that can be run after the primary reset function has been run on the object
-- Often used in conjunction with extension pool classes (e.g.: ZO_ControlPool) when you want all the default reset behavior, plus something extra
    self.customResetBehavior = customResetBehavior -- Signature: function(objectBeingReset)
end
function ZO_ObjectPool:AcquireObject(objectKey)
    -- If the object referred to by this key is already
    -- active there is very little work to do...just return it.
    local object = objectKey and self.m_Active[objectKey] or nil
    if object then
        return object, objectKey
    end
    
    -- If we know the key that we want, use that object first, otherwise just return the first object from the free pool
    -- A nil objectKey means that the caller doesn't care about tracking unique keys for these objects, or that the keys
    -- the system uses can't directly be used to look up the data. Just manage them with pool-generated id's
    if objectKey == nil then
        objectKey, object = self:GetNextFree()
    else
        object = self.m_Free[objectKey]
    end
    --
    -- If the object is valid it was reclaimed from the free list, otherwise it needs to be created.
    -- Creation uses the m_Factory member which receives this pool as its only argument.
    -- Either way, after this, object must be non-nil
    --
    if object then
        self.m_Free[objectKey] = nil
    else        
        object = self:CreateObject(objectKey)
    end
           
    self.m_Active[objectKey] = object
    if self.customAcquireBehavior then
        self.customAcquireBehavior(object, objectKey)
    end
        
    return object, objectKey
end
function ZO_ObjectPool:CreateObject(objectKey)
    local object = self:m_Factory(objectKey)
    if self.customFactoryBehavior then
        self.customFactoryBehavior(object, objectKey, self)
    end
    return object
end
function ZO_ObjectPool:ReleaseObject(objectKey)
    local object = self.m_Active[objectKey]
    
    if object then
        self:ResetObject(object)
        
        self.m_Active[objectKey] = nil
        self.m_Free[objectKey] = object
    end
end
function ZO_ObjectPool:ReleaseAllObjects()
    for k, v in pairs(self.m_Active) do
        self:ResetObject(v)
        
        self.m_Free[k] = v
    end
    
    ZO_ClearTable(self.m_Active)
end
function ZO_ObjectPool:ResetObject(object)
    if self.m_Reset then
        self.m_Reset(object, self)
    end
    if self.customResetBehavior then
        self.customResetBehavior(object)
    end
end
function ZO_ObjectPool:DestroyFreeObject(objectKey, destroyFunction)
    local object = self.m_Free[objectKey]
    destroyFunction(object)
    self.m_Free[objectKey] = nil
end
function ZO_ObjectPool:DestroyAllFreeObjects(destroyFunction)
    for _, object in pairs(self.m_Free) do
        destroyFunction(object)
    end
    ZO_ClearTable(self.m_Free)
end
function ZO_ObjectPool_CreateControl(templateName, objectPool, parentControl)
    return CreateControlFromVirtual(templateName, parentControl, templateName, objectPool:GetNextControlId())
end
function ZO_ObjectPool_CreateNamedControl(name, templateName, objectPool, parentControl)
    return CreateControlFromVirtual(name, parentControl, templateName, objectPool:GetNextControlId())
end
    object:Reset()
end
    control:SetHidden(true)
end