-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathbase.lua
More file actions
348 lines (262 loc) · 11.8 KB
/
base.lua
File metadata and controls
348 lines (262 loc) · 11.8 KB
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
local BaseRecordStore = class("BaseRecordStore")
BaseRecordStore.defaultData =
{
general = {
currentGeneratedNum = 0
},
permanentRecords = {},
generatedRecords = {},
recordLinks = {},
unlinkedRecordsToCheck = {}
}
function BaseRecordStore:__init(storeType)
self.data = tableHelper.deepCopy(self.defaultData)
self.storeType = storeType
end
function BaseRecordStore:HasEntry()
return self.hasEntry
end
function BaseRecordStore:EnsureDataStructure()
for key, value in pairs(self.defaultData) do
if self.data[key] == nil then
self.data[key] = tableHelper.deepCopy(value)
end
end
end
function BaseRecordStore:GetCurrentGeneratedNum()
return self.data.general.currentGeneratedNum
end
function BaseRecordStore:SetCurrentGeneratedNum(currentGeneratedNum)
self.data.general.currentGeneratedNum = currentGeneratedNum
self:QuicksaveToDrive()
end
function BaseRecordStore:IncrementGeneratedNum()
self:SetCurrentGeneratedNum(self:GetCurrentGeneratedNum() + 1)
return self:GetCurrentGeneratedNum()
end
function BaseRecordStore:GenerateRecordId()
return config.generatedRecordIdPrefix .. "_" .. self.storeType .. "_" .. self:IncrementGeneratedNum()
end
-- Go through all the generated records that were at some point tracked as having no links remaining
-- and delete them if they still have no links
function BaseRecordStore:DeleteUnlinkedRecords()
if type(self.data.unlinkedRecordsToCheck) == "table" then
for arrayIndex, recordId in pairs(self.data.unlinkedRecordsToCheck) do
if not self:HasLinks(recordId) then
self:DeleteGeneratedRecord(recordId)
end
self.data.unlinkedRecordsToCheck[arrayIndex] = nil
end
end
end
function BaseRecordStore:DeleteGeneratedRecord(recordId)
if self.data.generatedRecords[recordId] == nil then
tes3mp.LogMessage(enumerations.log.WARN, "Tried deleting " .. self.storeType .. " record " .. recordId ..
" which doesn't exist!")
return
end
tes3mp.LogMessage(enumerations.log.WARN, "Deleting generated " .. self.storeType .. " record " .. recordId)
-- Is this an enchantable record? If so, we should remove any links to it
-- from its associated generated enchantment record if there is one
if tableHelper.containsValue(config.enchantableRecordTypes, self.storeType) then
local enchantmentId = self.data.generatedRecords[recordId].enchantmentId
if enchantmentId ~= nil and logicHandler.IsGeneratedRecord(enchantmentId) then
local enchantmentStore = RecordStores["enchantment"]
enchantmentStore:RemoveLinkToRecord(enchantmentId, recordId, self.storeType)
enchantmentStore:QuicksaveToDrive()
end
end
self.data.generatedRecords[recordId] = nil
if self.data.recordLinks[recordId] ~= nil then
self.data.recordLinks[recordId] = nil
end
self:QuicksaveToDrive()
end
-- Check whether there are any links remaining to a certain generated record
function BaseRecordStore:HasLinks(recordId)
local recordLinks = self.data.recordLinks
if recordLinks[recordId] == nil then
return false
elseif (recordLinks[recordId].cells ~= nil and not tableHelper.isEmpty(recordLinks[recordId].cells)) or
(recordLinks[recordId].players ~= nil and not tableHelper.isEmpty(recordLinks[recordId].players)) then
return true
-- Is this an enchantment record? If so, check for links to other records for enchantable items
elseif self.storeType == "enchantment" then
for _, enchantableType in pairs(config.enchantableRecordTypes) do
if recordLinks[recordId].records ~= nil and recordLinks[recordId].records[enchantableType] ~= nil and not
tableHelper.isEmpty(recordLinks[recordId].records[enchantableType]) then
return true
end
end
end
return false
end
-- Add a link between a record and another record from a different record store,
-- i.e. for enchantments being used by other items
function BaseRecordStore:AddLinkToRecord(recordId, otherRecordId, otherStoreType)
local recordLinks = self.data.recordLinks
if recordLinks[recordId] == nil then recordLinks[recordId] = {} end
if recordLinks[recordId].records == nil then recordLinks[recordId].records = {} end
if recordLinks[recordId].records[otherStoreType] == nil then recordLinks[recordId].records[otherStoreType] = {} end
if not tableHelper.containsValue(recordLinks[recordId].records[otherStoreType], otherRecordId) then
table.insert(recordLinks[recordId].records[otherStoreType], otherRecordId)
end
end
function BaseRecordStore:RemoveLinkToRecord(recordId, otherRecordId, otherStoreType)
local recordLinks = self.data.recordLinks
if recordLinks[recordId] ~= nil and recordLinks[recordId].records ~= nil and
recordLinks[recordId].records[otherStoreType] ~= nil then
local linkIndex = tableHelper.getIndexByValue(recordLinks[recordId].records[otherStoreType], otherRecordId)
if linkIndex ~= nil then
recordLinks[recordId].records[otherStoreType][linkIndex] = nil
end
if not self:HasLinks(recordId) then
table.insert(self.data.unlinkedRecordsToCheck, recordId)
end
end
end
-- Add a link between a record and a cell it is found in
function BaseRecordStore:AddLinkToCell(recordId, cell)
local cellDescription = cell.description
local recordLinks = self.data.recordLinks
if recordLinks[recordId] == nil then recordLinks[recordId] = {} end
if recordLinks[recordId].cells == nil then recordLinks[recordId].cells = {} end
if not tableHelper.containsValue(recordLinks[recordId].cells, cellDescription) then
table.insert(recordLinks[recordId].cells, cellDescription)
end
end
function BaseRecordStore:RemoveLinkToCell(recordId, cell)
local cellDescription = cell.description
local recordLinks = self.data.recordLinks
if recordLinks[recordId] ~= nil and recordLinks[recordId].cells ~= nil then
local linkIndex = tableHelper.getIndexByValue(recordLinks[recordId].cells, cellDescription)
if linkIndex ~= nil then
recordLinks[recordId].cells[linkIndex] = nil
end
if not self:HasLinks(recordId) then
table.insert(self.data.unlinkedRecordsToCheck, recordId)
end
end
end
-- Add a link between a record and a player in whose inventory or spellbook it is found
function BaseRecordStore:AddLinkToPlayer(recordId, player)
local accountName = player.accountName
local recordLinks = self.data.recordLinks
if recordLinks[recordId] == nil then recordLinks[recordId] = {} end
if recordLinks[recordId].players == nil then recordLinks[recordId].players = {} end
if not tableHelper.containsValue(recordLinks[recordId].players, accountName) then
table.insert(recordLinks[recordId].players, accountName)
end
end
function BaseRecordStore:RemoveLinkToPlayer(recordId, player)
local accountName = player.accountName
local recordLinks = self.data.recordLinks
if recordLinks[recordId] == nil then recordLinks[recordId] = {} end
if recordLinks[recordId].players == nil then recordLinks[recordId].players = {} end
local linkIndex = tableHelper.getIndexByValue(recordLinks[recordId].players, accountName)
if linkIndex ~= nil then
recordLinks[recordId].players[linkIndex] = nil
end
if not self:HasLinks(recordId) then
table.insert(self.data.unlinkedRecordsToCheck, recordId)
end
end
function BaseRecordStore:LoadGeneratedRecords(pid, recordList, idArray, forEveryone)
if type(recordList) ~= "table" then return end
if type(idArray) ~= "table" then return end
local validIdArray = {}
-- If these are enchantable records, track generated enchantment records used by them
-- and send them beforehand
local isEnchantable = false
local enchantmentIdArray
if tableHelper.containsValue(config.enchantableRecordTypes, self.storeType) then
isEnchantable = true
enchantmentIdArray = {}
end
for _, recordId in pairs(idArray) do
if recordList[recordId] ~= nil and not tableHelper.containsValue(Players[pid].generatedRecordsReceived, recordId) then
table.insert(Players[pid].generatedRecordsReceived, recordId)
table.insert(validIdArray, recordId)
if isEnchantable then
local record = recordList[recordId]
local shouldLoadEnchantment = record ~= nil and record.enchantmentId ~= nil and
logicHandler.IsGeneratedRecord(record.enchantmentId) and not
tableHelper.containsValue(Players[pid].generatedRecordsReceived, record.enchantmentId)
if shouldLoadEnchantment then
table.insert(enchantmentIdArray, record.enchantmentId)
end
end
end
end
-- Load the associated generated enchantment records first
if isEnchantable and not tableHelper.isEmpty(enchantmentIdArray) then
local enchantmentStore = RecordStores["enchantment"]
enchantmentStore:LoadRecords(pid, enchantmentStore.data.generatedRecords, enchantmentIdArray, forEveryone)
end
-- Load our own valid generated records
self:LoadRecords(pid, recordList, validIdArray, forEveryone)
end
function BaseRecordStore:LoadRecords(pid, recordList, idArray, forEveryone)
if type(recordList) ~= "table" then return end
if type(idArray) ~= "table" then return end
tes3mp.ClearRecords()
tes3mp.SetRecordType(enumerations.recordType[string.upper(self.storeType)])
local recordCount = 0
for _, recordId in pairs(idArray) do
local record = recordList[recordId]
if record ~= nil then
packetBuilder.AddRecordByType(recordId, record, self.storeType)
recordCount = recordCount + 1
if recordCount >= 3000 then
tes3mp.SendRecordDynamic(pid, forEveryone, false)
tes3mp.ClearRecords()
tes3mp.SetRecordType(enumerations.recordType[string.upper(self.storeType)])
recordCount = 0
end
end
end
if recordCount > 0 then
tes3mp.SendRecordDynamic(pid, forEveryone, false)
end
end
-- Check if a record is a perfect match for any of the records whose IDs
-- are contained in an ID array, with optional parameters that allow starting
-- from the end of the idArray and performing a limited number of checks
function BaseRecordStore:GetMatchingRecordId(comparedRecord, recordList, idArray, ignoredKeys, useReverseOrder, maximumChecks)
if idArray == nil then
return nil
end
local initialValue, finalValue, increment
if useReverseOrder then
initialValue = #idArray
increment = -1
finalValue = 1
if maximumChecks ~= nil then
finalValue = math.max(finalValue, initialValue - maximumChecks + 1)
end
else
initialValue = 1
increment = 1
finalValue = #idArray
if maximumChecks ~= nil then
finalValue = math.min(finalValue, maximumChecks)
end
end
for arrayIndex = initialValue, finalValue, increment do
local recordId = idArray[arrayIndex]
local record = recordList[recordId]
if record ~= nil and tableHelper.isEqualTo(comparedRecord, record, ignoredKeys) then
return recordId
end
end
return nil
end
function BaseRecordStore:SaveGeneratedRecords(recordTable)
for recordId, record in pairs(recordTable) do
self.data.generatedRecords[recordId] = tableHelper.deepCopy(record)
-- Retain the quantity in the input table (when applicable) so we can check it
-- elsewhere, but remove it from here
self.data.generatedRecords[recordId].quantity = nil
end
end
return BaseRecordStore