Repository navigation
Expand file tree
/
Copy pathCore.lua
More file actions
383 lines (352 loc) · 11.5 KB
/
Copy pathCore.lua
File metadata and controls
383 lines (352 loc) · 11.5 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
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
local addonName, ns = ...
ns.addonName = addonName
ns.version = "0.2.11"
ns.PRINT_PREFIX = "|cff5dade2[ProfessionMaster]|r "
local frame = CreateFrame("Frame")
ns.eventFrame = frame
--- Forever (Camelot) vs Mainline/Midnight (standard). Detect before Data/*.lua runs.
local function DetectClientFlavor()
if WOW_PROJECT_CAMELOT and WOW_PROJECT_ID == WOW_PROJECT_CAMELOT then
ns.isForever = true
elseif WOW_PROJECT_MAINLINE and WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
ns.isForever = false
else
local iface = select(4, GetBuildInfo())
ns.isForever = type(iface) == "number" and iface > 16000 and iface < 20000
end
ns.isMainline = not ns.isForever
ns.clientFlavor = ns.isForever and "forever" or "mainline"
end
DetectClientFlavor()
function ns.ApplyClientFlavor()
local key = ns.isForever and "forever" or "mainline"
local professions = ns.ProfessionsByFlavor and ns.ProfessionsByFlavor[key]
if not professions then
return
end
ns.Professions = professions
ns.ProfessionLabel = {}
ns.ProfessionNameToKey = {}
ns.CraftNotifyProfessions = {}
for _, p in ipairs(professions) do
ns.ProfessionLabel[p.key] = p.label
ns.ProfessionNameToKey[p.label] = p.key
if p.kind == "craft" or p.kind == "secondary" then
ns.CraftNotifyProfessions[p.key] = true
end
end
end
function ns.Print(...)
print(ns.PRINT_PREFIX .. string.format(...))
end
function ns.SafeString(value, fallback)
if value == nil then
return fallback or "?"
end
if type(issecretvalue) == "function" and issecretvalue(value) then
return fallback or "?"
end
return tostring(value)
end
function ns.SurnameSeparator()
local consts = Constants and Constants.CharacterNameSeparatorConsts
if consts and consts.CHARACTERNAME_SURNAME_SEPARATOR then
return consts.CHARACTERNAME_SURNAME_SEPARATOR
end
return " "
end
function ns.HasRegionalUniqueNames()
return type(RegionalUniqueNamesEnabled) == "function" and RegionalUniqueNamesEnabled()
end
function ns.UsesSurnameNames()
return ns.isForever or ns.HasRegionalUniqueNames()
end
--- On Forever, UnitName returns (first, surname). On Mainline, (name, realm).
function ns.GetUnitNameParts(unit)
unit = unit or "player"
local first, second
if UnitNameUnmodified then
first, second = UnitNameUnmodified(unit)
else
first, second = UnitName(unit)
end
first = ns.SafeString(first, nil)
if not first or first == "?" then
first = ns.SafeString(UnitName(unit), "Player")
end
if not ns.UsesSurnameNames() then
return first, nil
end
local surname
if second and second ~= "" and not (type(issecretvalue) == "function" and issecretvalue(second)) then
surname = tostring(second)
end
if (not surname or surname == "") and NameUtil and NameUtil.SplitPlayerNameIntoParts then
local a, b = NameUtil.SplitPlayerNameIntoParts(first)
if a and b and b ~= "" then
first, surname = a, b
end
elseif (not surname or surname == "") then
local sep = ns.SurnameSeparator()
if sep == " " then
local a, b = string.match(first, "^(%S+)%s+(.+)$")
if a and b and b ~= "" then
first, surname = a, b
end
elseif sep and sep ~= "" and sep ~= "-" then
local pos = string.find(first, sep, 1, true)
if pos and pos > 1 then
first, surname = string.sub(first, 1, pos - 1), string.sub(first, pos + #sep)
end
end
end
return first, surname
end
function ns.ComposeFullName(firstName, surname)
firstName = ns.SafeString(firstName, "Player")
if not surname or surname == "" then
return firstName
end
surname = ns.SafeString(surname, "")
if surname == "" or surname == "?" then
return firstName
end
if NameUtil and NameUtil.GetFullNameWithoutRealm then
local composed = NameUtil.GetFullNameWithoutRealm(firstName, surname)
if composed and composed ~= "" then
return ns.SafeString(composed, firstName .. ns.SurnameSeparator() .. surname)
end
end
return firstName .. ns.SurnameSeparator() .. surname
end
function ns.PlayerFullName()
local first, surname = ns.GetUnitNameParts("player")
if ns.UsesSurnameNames() then
return ns.ComposeFullName(first, surname), first, surname
end
return first, first, nil
end
function ns.CharKey(name, realm)
if not name then
name = select(1, ns.PlayerFullName())
end
realm = realm or GetNormalizedRealmName() or GetRealmName() or "Unknown"
name = ns.SafeString(name, "Player")
realm = ns.SafeString(realm, "Realm"):gsub("%s+", "")
return name .. "-" .. realm
end
function ns.PlayerKey()
return ns.CharKey()
end
function ns.MigrateCharKey(oldKey, newKey)
if not oldKey or not newKey or oldKey == newKey or not ns.db then
return false
end
local chars = ns.db.chars
if chars and chars[oldKey] then
if not chars[newKey] then
chars[newKey] = chars[oldKey]
else
local dest = chars[newKey]
local src = chars[oldKey]
if src.professions then
dest.professions = dest.professions or {}
for k, v in pairs(src.professions) do
if dest.professions[k] == nil then
dest.professions[k] = v
end
end
end
if src.recipes then
dest.recipes = dest.recipes or {}
for k, v in pairs(src.recipes) do
dest.recipes[k] = dest.recipes[k] or v
end
end
end
chars[oldKey] = nil
end
local prefs = ns.db.charPrefs
if prefs and prefs[oldKey] then
prefs[newKey] = prefs[newKey] or prefs[oldKey]
prefs[oldKey] = nil
end
return true
end
--- Per-character prefs (notify professions, hidden recipes). Seeded once from the
--- old account-wide settings so existing choices carry over to each character.
function ns.CharPrefs(charKey)
charKey = charKey or ns.PlayerKey()
if not ns.db or not charKey then
return { notifyProfessions = {}, hiddenRecipes = {} }
end
ns.db.charPrefs = ns.db.charPrefs or {}
local p = ns.db.charPrefs[charKey]
if not p then
local s = ns.db.settings or {}
p = {
notifyProfessions = ns.DeepCopy(s.notifyProfessions or {}),
hiddenRecipes = ns.DeepCopy(s.hiddenRecipes or {}),
}
ns.db.charPrefs[charKey] = p
end
p.notifyProfessions = p.notifyProfessions or {}
p.hiddenRecipes = p.hiddenRecipes or {}
return p
end
function ns.DeepCopy(src)
if type(src) ~= "table" then
return src
end
local out = {}
for k, v in pairs(src) do
out[k] = ns.DeepCopy(v)
end
return out
end
local function MergeDefaults(dest, src)
for k, v in pairs(src) do
if type(v) == "table" then
if type(dest[k]) ~= "table" then
dest[k] = {}
end
MergeDefaults(dest[k], v)
elseif dest[k] == nil then
dest[k] = v
end
end
end
local pendingRescan = false
local function ScheduleRescan()
if pendingRescan then
return
end
pendingRescan = true
C_Timer.After(0.35, function()
pendingRescan = false
if ns.Inventory then
ns.Inventory:Refresh()
end
if ns.SkillUp then
ns.SkillUp:Refresh()
end
if ns.UI and ns.UI.RefreshIfShown then
ns.UI:RefreshIfShown()
end
end)
end
ns.ScheduleRescan = ScheduleRescan
local function OnEvent(self, event, ...)
if event == "ADDON_LOADED" then
local loaded = ...
if loaded ~= addonName then
return
end
ProfessionMasterDB = ProfessionMasterDB or {}
MergeDefaults(ProfessionMasterDB, ns.defaults)
ns.db = ProfessionMasterDB
if ns.RecipeDB then
if ns.RecipeDB.LoadPersistedLiveRecipes then
ns.RecipeDB:LoadPersistedLiveRecipes()
end
ns.RecipeDB:BuildIndexes()
end
local n = ns.RecipeCount or 0
if n == 0 then
if ns.isForever then
ns.Print("WARNING: recipe catalog empty (TOC load order?). Skill-up toasts disabled until fixed.")
else
ns.Print("No cached recipes yet — open each profession or /pm scan to harvest.")
end
else
ns.Print("Loaded %d catalog recipes (%s).", n, ns.clientFlavor or "?")
end
self:UnregisterEvent("ADDON_LOADED")
return
end
if event == "PLAYER_LOGIN" then
if ns.CharDB then
ns.CharDB:ScanPlayer()
end
if ns.MinimapButton then
ns.MinimapButton:Init()
end
if ns.Notify then
ns.Notify:Init()
end
if ns.Gathering then
ns.Gathering:HookTooltips()
end
ScheduleRescan()
-- Surname + skill APIs / bags often aren't ready at login; re-scan so
-- professions don't land under a short CharKey or get wiped to empty.
C_Timer.After(1.0, function()
if ns.CharDB then
ns.CharDB:ScanPlayer()
end
ScheduleRescan()
end)
C_Timer.After(3.0, function()
if ns.CharDB then
ns.CharDB:ScanPlayer()
end
ScheduleRescan()
end)
return
end
if event == "TRADE_SKILL_LIST_UPDATE"
or event == "TRADE_SKILL_DATA_SOURCE_CHANGED"
or event == "TRADE_SKILL_SHOW"
or event == "SKILL_LINES_CHANGED" then
if ns.CharDB then
ns.CharDB:ScanPlayer()
C_Timer.After(0.1, function()
if ns.CharDB then
local n = ns.CharDB:HarvestOpenTradeSkill()
if n > 0 then
ns.Print("Cached +%d recipes from open profession.", n)
end
end
if ns.UI and ns.UI.RefreshIfShown then
ns.UI:RefreshIfShown()
end
ScheduleRescan()
end)
end
return
end
if event == "BAG_UPDATE"
or event == "PLAYERBANKSLOTS_CHANGED"
or event == "BANKFRAME_OPENED"
or event == "BANKFRAME_CLOSED"
or event == "PLAYER_INTERACTION_MANAGER_FRAME_SHOW"
or event == "PLAYER_INTERACTION_MANAGER_FRAME_HIDE"
or event == "CHAT_MSG_SKILL" then
ScheduleRescan()
return
end
if event == "PLAYER_REGEN_ENABLED" then
if ns.Craft and ns.Craft.FlushPending then
ns.Craft:FlushPending()
end
end
end
frame:SetScript("OnEvent", OnEvent)
frame:RegisterEvent("ADDON_LOADED")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("BAG_UPDATE")
frame:RegisterEvent("PLAYERBANKSLOTS_CHANGED")
frame:RegisterEvent("BANKFRAME_OPENED")
frame:RegisterEvent("BANKFRAME_CLOSED")
frame:RegisterEvent("SKILL_LINES_CHANGED")
frame:RegisterEvent("CHAT_MSG_SKILL")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
C_Timer.After(0, function()
frame:RegisterEvent("TRADE_SKILL_LIST_UPDATE")
frame:RegisterEvent("TRADE_SKILL_DATA_SOURCE_CHANGED")
frame:RegisterEvent("TRADE_SKILL_SHOW")
pcall(function()
frame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_SHOW")
frame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_HIDE")
end)
end)