FrameworkZ 10.8.3
Provides a framework for Project Zomboid with various systems.
Loading...
Searching...
No Matches
Utilities.lua
Go to the documentation of this file.
3local unpack = unpack
5--! \brief Utility module for FrameworkZ. Contains utility functions and classes.
6--! \class FrameworkZ.Utility
7FrameworkZ.Utilities = {}
8FrameworkZ.Utilities.__index = FrameworkZ.Utilities
9FrameworkZ.Utilities = FrameworkZ.Foundation:NewModule(FrameworkZ.Utilities, "Utilities")
10
11function FrameworkZ.Utilities:Pack(...)
12 return {n = select("#", ...), ...}
13end
15function FrameworkZ.Utilities:Unpack(t)
16 return unpack(t, 1, t.n)
17end
19--! \brief Copies a table.
20--! \param originalTable \table The table to copy.
21--! \param tableCopies \table (Internal) The table of copies used internally by the function.
22--! \return \table The copied table.
23function FrameworkZ.Utilities:CopyTable(originalTable, tableCopies, shouldCopyMetatable)
24 tableCopies = tableCopies or {}
25
26 local originalType = type(originalTable)
27 local copy
29 if originalType == "table" then
30 if tableCopies[originalTable] then
31 copy = tableCopies[originalTable]
32 else
33 copy = {}
34 tableCopies[originalTable] = copy
35
36 for originalKey, originalValue in pairs(originalTable) do
37 copy[self:CopyTable(originalKey, tableCopies)] = self:CopyTable(originalValue, tableCopies)
38 end
40 local mt = getmetatable(originalTable)
42 if mt and type(mt) == "table" then
43 setmetatable(copy, self:CopyTable(mt, tableCopies))
44 end
45 end
46 else -- number, string, boolean, etc
47 copy = originalTable
48 end
50 return copy
51end
52
53function FrameworkZ.Utilities:MergeTables(t1, t2)
54 for k, v in pairs(t2) do
55 if type(v) == "table" and type(t1[k]) == "table" then
56 self:MergeTables(t1[k], v)
57 else
58 t1[k] = v
59 end
60 end
61
62 -- Handle metatable merging
63 local mt1 = getmetatable(t1)
64 local mt2 = getmetatable(t2)
65
66 if mt2 then
67 if mt1 then
68 -- Both tables have metatables, merge them recursively
69 if type(mt1) == "table" and type(mt2) == "table" then
70 self:MergeTables(mt1, mt2)
71 else
72 -- If metatables aren't tables, use t2's metatable
73 setmetatable(t1, mt2)
74 end
75 else
76 -- Only t2 has a metatable, apply it to t1
77 setmetatable(t1, mt2)
78 end
79 end
80
81 return t1
82end
84function FrameworkZ.Utilities:DumpTable(tbl)
85 if type(tbl) == 'table' then
86 local s = '{ '
87 for k,v in pairs(tbl) do
88 if type(k) ~= 'number' then k = '"'..k..'"' end
89 s = s .. '['..k..'] = ' .. self:DumpTable(v) .. ','
90 end
91 return s .. '} '
92 else
93 return tostring(tbl)
94 end
95end
96
97function FrameworkZ.Utilities:PrintTable(tbl)
98 print(self:DumpTable(tbl))
99end
100
101function FrameworkZ.Utilities:TableIsEmpty(t)
102 if type(t) ~= "table" then
103 return false
104 end
105
106 local isEmpty = true
107
108 for _, _ in pairs(t) do
109 isEmpty = false
110 break
111 end
112
113 return isEmpty
114end
115
116function FrameworkZ.Utilities:TableContainsKey(t, key)
117 if t then
118 for k, _ in pairs(t) do
119 if k == key then
120 return true
121 end
122 end
123 end
124
125 return false
126end
127
128function FrameworkZ.Utilities:TableContainsValue(t, value)
129 if t then
130 for _, v in pairs(t) do
131 if v == value then
132 return true
133 end
134 end
135 end
136
137 return false
138end
139
140function FrameworkZ.Utilities:RemoveContextDuplicates(worldObjects)
141 local newObjects = {}
142
143 for _, v1 in ipairs(worldObjects) do
144 local isInList = false
145
146 for _2, v2 in ipairs(newObjects) do
147 if v2 == v1 then
148 isInList = true
149 break
150 end
151 end
152
153 if not isInList then
154 table.insert(newObjects, v1)
155 end
156 end
157
158 return newObjects
159end
160
161function FrameworkZ.Utilities:__GenOrderedIndex( t )
162 local orderedIndex = {}
163
164 for key in pairs(t) do
165 table.insert(orderedIndex, key)
166 end
167
168 table.sort(orderedIndex)
169
170 return orderedIndex
171end
172
173function FrameworkZ.Utilities:OrderedNext(t, state)
174 local key = nil
175
176 if state == nil then
177 t.__orderedIndex = self:__GenOrderedIndex(t)
178 key = t.__orderedIndex[1]
179 else
180 for i = 1, #t.__orderedIndex do
181 if t.__orderedIndex[i] == state then
182 key = t.__orderedIndex[i + 1]
183 end
184 end
185 end
186
187 if key then
188 return key, t[key]
189 end
190
191 t.__orderedIndex = nil
192
193 return
194end
195
196function FrameworkZ.Utilities:OrderedPairs(t)
197 return self.OrderedNext, t, nil
198end
199
200--! \brief Word wraps text to a specified length.
201--! \param text \string The text to word wrap.
202--! \param maxLength \int The maximum length of a line (default: 28).
203--! \param eolDelimiter \string (Optional) The end of line delimiter. Returns a \table of lines if not supplied.
204--! \return \mixed The word wrapped text as a \string or a \table of lines of text if no eolDelimiter was supplied as an argument.
205function FrameworkZ.Utilities:WordWrapText(text, maxLength, eolDelimiter)
206 local maxLineLength = maxLength or 28
207 local lines = {}
208 local line = ""
209 local lineLength = 0
210 local words = {}
211
212 for word in string.gmatch(text, "%S+") do
213 table.insert(words, word)
214 end
215
216 for i = 1, #words do
217 local word = words[i]
218 local wordLength = string.len(word)
219
220 if lineLength + wordLength <= maxLineLength then
221 line = line .. " " .. word
222 lineLength = lineLength + wordLength
223 else
224 table.insert(lines, line)
225 line = word
226 lineLength = wordLength
227 end
228 end
229
230 table.insert(lines, line)
231
232 if eolDelimiter then
233 local delimitedText = ""
234
235 for i = 1, #lines do
236 delimitedText = delimitedText .. lines[i] .. (i ~= #lines and eolDelimiter or "")
237 end
238
239 return delimitedText
240 end
241
242 return lines
243end
244
245function FrameworkZ.Utilities:GetRandomNumber(min, max, keepLeadingZeros)
246 if min > max then
247 min, max = max, min
248 end
249
250 local maxDigits = math.max(#tostring(min), #tostring(max))
251
252 return keepLeadingZeros and string.format("%0" .. maxDigits .. "d", ZombRandBetween(min, max)) or ZombRandBetween(min, max)
253end
254
255FrameworkZ.Utilities.Directions = {
256 { dx = 1, dy = 0, wallFlag = IsoFlagType.collideW, doorFlag = IsoFlagType.doorW, windowFlag = IsoFlagType.windowW },
257 { dx = -1, dy = 0, wallFlag = IsoFlagType.collideW, doorFlag = IsoFlagType.doorW, windowFlag = IsoFlagType.windowW },
258 { dx = 0, dy = 1, wallFlag = IsoFlagType.collideN, doorFlag = IsoFlagType.doorN, windowFlag = IsoFlagType.windowN },
259 { dx = 0, dy = -1, wallFlag = IsoFlagType.collideN, doorFlag = IsoFlagType.doorN, windowFlag = IsoFlagType.windowN },
260}
261
262function FrameworkZ.Utilities:IsExterior(square)
263 return not square or square:getRoom() == nil
264end
265
266function FrameworkZ.Utilities:IsTrulyInterior(square)
267 if not square then return false end
268 local room = square:getRoom()
269 if not room then return false end
270
271 local seen = {}
272 local queue = { square }
273 seen[square] = true
274
275 while #queue > 0 do
276 local currentSquare = table.remove(queue, 1)
277
278 for _, dir in ipairs(self.Directions) do
279 local nx, ny, nz = currentSquare:getX() + dir.dx, currentSquare:getY() + dir.dy, currentSquare:getZ()
280 local nextSquare = getCell():getGridSquare(nx, ny, nz)
281
282 if nextSquare and not seen[nextSquare] then
283 local blocked = nextSquare:Is(dir.wallFlag) or nextSquare:Is(dir.doorFlag) or nextSquare:Is(dir.windowFlag)
284
285 if not blocked then
286 if not nextSquare:getRoom() then
287 return false
288 end
289
290 if nextSquare:getRoom() == room then
291 seen[nextSquare] = true
292 table.insert(queue, nextSquare)
293 end
294 end
295 end
296 end
297 end
298
299 return true
300end
301
302function FrameworkZ.Utilities:IsSemiExterior(square)
303 if not square or not square:getRoom() then return false end
304 return not FrameworkZ.Utilities:IsTrulyInterior(square)
305end
306
307function FrameworkZ.Utilities:GetPrettyDuration(timeInSeconds)
308 local seconds = math.floor(tonumber(timeInSeconds) or 0)
309 local days = math.floor(seconds / 86400)
310 seconds = seconds % 86400
311 local hours = math.floor(seconds / 3600)
312 seconds = seconds % 3600
313 local minutes = math.floor(seconds / 60)
314 seconds = seconds % 60
315
316 local parts = {}
317
318 if days > 0 then
319 table.insert(parts, days .. (days == 1 and " day" or " days"))
320 if hours > 0 then
321 table.insert(parts, hours .. (hours == 1 and " hour" or " hours"))
322 end
323 elseif hours > 0 then
324 table.insert(parts, hours .. (hours == 1 and " hour" or " hours"))
325 if minutes > 0 then
326 table.insert(parts, minutes .. (minutes == 1 and " minute" or " minutes"))
327 end
328 elseif minutes > 0 then
329 table.insert(parts, minutes .. (minutes == 1 and " minute" or " minutes"))
330 if seconds > 0 then
331 table.insert(parts, seconds .. (seconds == 1 and " second" or " seconds"))
332 end
333 else
334 table.insert(parts, seconds .. (seconds == 1 and " second" or " seconds"))
335 end
336
337 return table.concat(parts, " and ")
338end
339
340--! \brief Trims a string to a maximum length, optionally adding ellipsis.
341--! \param str \string The string to trim.
342--! \param maxLength \int The maximum allowed length.
343--! \param addEllipsis \boolean (Optional) If true, appends "..." if trimmed.
344--! \return \string The trimmed string.
345function FrameworkZ.Utilities:TrimString(str, maxLength, addEllipsis)
346 if type(str) ~= "string" or type(maxLength) ~= "number" then
347 return str
348 end
349
350 if #str <= maxLength then
351 return str
352 end
353
354 if addEllipsis then
355 local ellipsis = "..."
356 if maxLength > #ellipsis then
357 local trimmed = string.sub(str, 1, maxLength - #ellipsis)
358 trimmed = trimmed:match("^(.-)%s*$")
359 return trimmed .. ellipsis
360 else
361 return string.sub(str, 1, maxLength)
362 end
363 else
364 return string.sub(str, 1, maxLength)
365 end
366end
void type()
void t1()
void local dx()
void local wordLength()
void local unpack()
void local select()
void local mt()
void local isEmpty()
void local mt1()
void local mt2()
void local IsoFlagType()
void copy()
void for i()
void local word()
void tbl()
void key()
void value()
Utility module for FrameworkZ. Contains utility functions and classes.
Definition Utilities.lua:62