diff --git a/WeakAuras/AuraEnvironment.lua b/WeakAuras/AuraEnvironment.lua index 23819d8..181be93 100644 --- a/WeakAuras/AuraEnvironment.lua +++ b/WeakAuras/AuraEnvironment.lua @@ -598,19 +598,24 @@ local function firstLine(string) end local function CreateFunctionCache(exec_env) - local cache = {} - cache.Load = function(self, string) - if self[string] then - return self[string] + local cache = { + funcs = setmetatable({}, {__mode = "v"}) + } + cache.Load = function(self, string, silent) + if self.funcs[string] then + return self.funcs[string] else local loadedFunction, errorString = loadstring(string, firstLine(string)) if errorString then - print(errorString) - else + if not silent then + print(errorString) + end + return nil, errorString + elseif loadedFunction then setfenv(loadedFunction, exec_env) local success, func = pcall(assert(loadedFunction)) if success then - self[string] = func + self.funcs[string] = func return func end end @@ -626,8 +631,8 @@ function WeakAuras.LoadFunction(string) return function_cache_custom:Load(string) end -function Private.LoadFunction(string) - return function_cache_builtin:Load(string) +function Private.LoadFunction(string, silent) + return function_cache_builtin:Load(string, silent) end function Private.GetSanitizedGlobal(key) diff --git a/WeakAuras/BuffTrigger2.lua b/WeakAuras/BuffTrigger2.lua index 1f4448e..c870728 100644 --- a/WeakAuras/BuffTrigger2.lua +++ b/WeakAuras/BuffTrigger2.lua @@ -2443,7 +2443,7 @@ function BuffTrigger.Add(data) local effectiveIgnoreDead = groupTrigger and trigger.ignoreDead local effectiveIgnoreDisconnected = groupTrigger and trigger.ignoreDisconnected local effectiveIgnoreInvisible = groupTrigger and trigger.ignoreInvisible - local effectiveHostility = trigger.unit == "nameplate" and trigger.useHostility and trigger.hostility + local effectiveHostility = (groupTrigger or trigger.unit == "nameplate") and trigger.useHostility and trigger.hostility local effectiveNameCheck = groupTrigger and trigger.useUnitName and trigger.unitName local effectiveNpcId = trigger.unit == "nameplate" and trigger.useNpcId and Private.ExecEnv.ParseStringCheck(trigger.npcId) @@ -3465,7 +3465,8 @@ function BuffTrigger.InitMultiAura() end function BuffTrigger.HandleMultiEvent(frame, event, ...) - Private.StartProfileSystem("bufftrigger2 - multi") + local system = "bufftrigger2 - multi - " .. event + Private.StartProfileSystem(system) if event == "COMBAT_LOG_EVENT_UNFILTERED" then CombatLog(...) elseif event == "UNIT_TARGET" then @@ -3498,7 +3499,7 @@ function BuffTrigger.HandleMultiEvent(frame, event, ...) end wipe(matchDataMulti) end - Private.StopProfileSystem("bufftrigger2 - multi") + Private.StopProfileSystem(system) end function BuffTrigger.GetTriggerDescription(data, triggernum, namestable) diff --git a/WeakAuras/Conditions.lua b/WeakAuras/Conditions.lua index 1f20cfb..edc6479 100644 --- a/WeakAuras/Conditions.lua +++ b/WeakAuras/Conditions.lua @@ -52,6 +52,9 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path elseif vType == "progressSource" then if type(value) == "table" then local progressSource = Private.AddProgressSourceMetaData(data, value) + if not progressSource then + return "{}" + end local trigger = progressSource[1] or -1 local progressType = progressSource[2] or "auto" local property = progressSource[3] diff --git a/WeakAuras/DiscordList.lua b/WeakAuras/DiscordList.lua new file mode 100644 index 0000000..907ccf9 --- /dev/null +++ b/WeakAuras/DiscordList.lua @@ -0,0 +1,64 @@ +if not WeakAuras.IsLibsOK() then return end + +local AddonName, Private = ... + +Private.DiscordList = { + [=[007bb]=], + [=[AcidWeb]=], + [=[aelen]=], + [=[Aishuu]=], + [=[Ariani Continuity]=], + [=[Azortharion]=], + [=[BadBrain]=], + [=[Bart]=], + [=[Boneshock]=], + [=[Boxthor]=], + [=[Burlis]=], + [=[Causese]=], + [=[Chab]=], + [=[cheswick]=], + [=[Darian]=], + [=[Desik]=], + [=[DjinnFish]=], + [=[exality]=], + [=[Fatpala]=], + [=[Fels]=], + [=[Fenchurch]=], + [=[Guffin]=], + [=[Ifor]=], + [=[Ironi]=], + [=[Jiberish]=], + [=[Jods]=], + [=[kanegasi]=], + [=[Koxy]=], + [=[Listefano]=], + [=[Luckyone]=], + [=[Luxthos]=], + [=[m33shoq]=], + [=[maddin]=], + [=[Max rdv 2026 pour TBC cla]=], + [=[MetalMusicMan]=], + [=[Murph]=], + [=[Mynze]=], + [=[Nona]=], + [=[NostraDumAzz]=], + [=[Ocelots]=], + [=[Oi]=], + [=[Ora]=], + [=[phoenix7700]=], + [=[Pseiko]=], + [=[Reloe]=], + [=[Shwinsta]=], + [=[Slurp]=], + [=[Spaten]=], + [=[Tollo]=], + [=[update]=], + [=[vozochris]=], + [=[Wizeowel]=], + [=[Xepheris]=], + [=[Мектран]=], +} +Private.DiscordListCJ = { +} +Private.DiscordListK = { +} diff --git a/WeakAuras/GenericTrigger.lua b/WeakAuras/GenericTrigger.lua index 31e4f7f..6c1546a 100644 --- a/WeakAuras/GenericTrigger.lua +++ b/WeakAuras/GenericTrigger.lua @@ -703,6 +703,9 @@ local function RunTriggerFunc(allStates, data, id, triggernum, event, arg1, arg2 elseif (data.statesParameter == "unit") then if arg1 then if Private.multiUnitUnits[data.trigger.unit] then + if data.trigger.unit == "group" and IsInRaid() and Private.multiUnitUnits.party[arg1] then + return + end unitForUnitTrigger = arg1 cloneIdForUnitTrigger = arg1 else @@ -1149,8 +1152,8 @@ function HandleEvent(frame, event, arg1, arg2, ...) if (event == "PLAYER_ENTERING_WORLD") then timer:ScheduleTimer(function() HandleEvent(frame, "WA_DELAYED_PLAYER_ENTERING_WORLD"); - Private.StartProfileSystem("generictrigger WA_DELAYED_PLAYER_ENTERING_WORLD"); Private.ScanForLoads(nil, "WA_DELAYED_PLAYER_ENTERING_WORLD") + Private.StartProfileSystem("generictrigger WA_DELAYED_PLAYER_ENTERING_WORLD"); Private.CheckCooldownReady(); Private.StopProfileSystem("generictrigger WA_DELAYED_PLAYER_ENTERING_WORLD"); Private.PreShowModels() @@ -1843,7 +1846,7 @@ function GenericTrigger.Add(data, region) end if warnAboutCLEUEvents then - Private.AuraWarnings.UpdateWarning(data.uid, "spammy_event_warning", "warning", + Private.AuraWarnings.UpdateWarning(data.uid, "spammy_event_warning", "error", L["COMBAT_LOG_EVENT_UNFILTERED with no filter can trigger frame drops in raid environment. Find more information:\nhttps://github.com/WeakAuras/WeakAuras2/wiki/Deprecated-CLEU"]) else Private.AuraWarnings.UpdateWarning(data.uid, "spammy_event_warning") @@ -2199,19 +2202,21 @@ do end, Schedule = function(self, expirationTime, id) if (not self.expirationTime[id] or expirationTime < self.expirationTime[id]) and expirationTime > 0 then - if self.handles[id] then - timer:CancelTimer(self.handles[id]) - self.handles[id] = nil - self.expirationTime[id] = nil - end - + self:Cancel(id) local duration = expirationTime - GetTime() if duration > 0 then self.handles[id] = timer:ScheduleTimer(self.Recheck, duration, self, id) self.expirationTime[id] = expirationTime end end - end + end, + Cancel = function(self, id) + if self.handles[id] then + timer:CancelTimer(self.handles[id]) + self.handles[id] = nil + self.expirationTime[id] = nil + end + end, } local function FetchSpellCooldown(self, id) @@ -2226,6 +2231,7 @@ do local nowReady = false local time = GetTime() if self.expirationTime[id] and self.expirationTime[id] <= time and self.expirationTime[id] ~= 0 then + self.readyTime[id] = self.expirationTime[id] self.duration[id] = 0 self.expirationTime[id] = 0 changed = true diff --git a/WeakAuras/Media/Fira LICENSE b/WeakAuras/Media/Fira License.txt similarity index 97% rename from WeakAuras/Media/Fira LICENSE rename to WeakAuras/Media/Fira License.txt index d444ea9..d6d88ac 100644 --- a/WeakAuras/Media/Fira LICENSE +++ b/WeakAuras/Media/Fira License.txt @@ -1,5 +1,4 @@ -Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. -with Reserved Font Name < Fira >, +Digitized data copyright 2012-2018: The Mozilla Foundation, Telefonica S.A., Carrois Corporate GbR and bBox Type GmbH. This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: @@ -19,7 +18,7 @@ with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, +fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The diff --git a/WeakAuras/Media/Fonts/FiraSans-Black.ttf b/WeakAuras/Media/Fonts/FiraSans-Black.ttf deleted file mode 100644 index 113cd3b..0000000 Binary files a/WeakAuras/Media/Fonts/FiraSans-Black.ttf and /dev/null differ diff --git a/WeakAuras/Media/Fonts/FiraSans-Heavy.ttf b/WeakAuras/Media/Fonts/FiraSans-Heavy.ttf new file mode 100644 index 0000000..718f5b3 Binary files /dev/null and b/WeakAuras/Media/Fonts/FiraSans-Heavy.ttf differ diff --git a/WeakAuras/Media/Fonts/FiraSans-Medium.ttf b/WeakAuras/Media/Fonts/FiraSans-Medium.ttf index 001ebe7..fc45d5d 100644 Binary files a/WeakAuras/Media/Fonts/FiraSans-Medium.ttf and b/WeakAuras/Media/Fonts/FiraSans-Medium.ttf differ diff --git a/WeakAuras/Media/Fonts/FiraSansCondensed-Black.ttf b/WeakAuras/Media/Fonts/FiraSansCondensed-Black.ttf deleted file mode 100644 index 06e2a3e..0000000 Binary files a/WeakAuras/Media/Fonts/FiraSansCondensed-Black.ttf and /dev/null differ diff --git a/WeakAuras/Media/Fonts/FiraSansCondensed-Heavy.ttf b/WeakAuras/Media/Fonts/FiraSansCondensed-Heavy.ttf new file mode 100644 index 0000000..eed4423 Binary files /dev/null and b/WeakAuras/Media/Fonts/FiraSansCondensed-Heavy.ttf differ diff --git a/WeakAuras/Media/Fonts/FiraSansCondensed-Medium.ttf b/WeakAuras/Media/Fonts/FiraSansCondensed-Medium.ttf index 534c970..593b55a 100644 Binary files a/WeakAuras/Media/Fonts/FiraSansCondensed-Medium.ttf and b/WeakAuras/Media/Fonts/FiraSansCondensed-Medium.ttf differ diff --git a/WeakAuras/Media/Fonts/PTSansNarrow-Bold.ttf b/WeakAuras/Media/Fonts/PTSansNarrow-Bold.ttf index 960a20a..a12d0c6 100644 Binary files a/WeakAuras/Media/Fonts/PTSansNarrow-Bold.ttf and b/WeakAuras/Media/Fonts/PTSansNarrow-Bold.ttf differ diff --git a/WeakAuras/Media/Fonts/PTSansNarrow-Regular.ttf b/WeakAuras/Media/Fonts/PTSansNarrow-Regular.ttf index 5e83fc8..65e9dec 100644 Binary files a/WeakAuras/Media/Fonts/PTSansNarrow-Regular.ttf and b/WeakAuras/Media/Fonts/PTSansNarrow-Regular.ttf differ diff --git a/WeakAuras/Media/PT Sans License.txt b/WeakAuras/Media/PT Sans License.txt new file mode 100644 index 0000000..1b8be86 --- /dev/null +++ b/WeakAuras/Media/PT Sans License.txt @@ -0,0 +1,95 @@ +Copyright (c) 2018, Paratype Inc (https://paratype.com), +Copyright (c) 2018, Paratype Ltd, +with Reserved Font Name "PT Sans". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/WeakAuras/Media/Textures/waheart.tga b/WeakAuras/Media/Textures/waheart.tga new file mode 100644 index 0000000..959e861 Binary files /dev/null and b/WeakAuras/Media/Textures/waheart.tga differ diff --git a/WeakAuras/Modernize.lua b/WeakAuras/Modernize.lua index 40e13e1..11021d1 100644 --- a/WeakAuras/Modernize.lua +++ b/WeakAuras/Modernize.lua @@ -1533,6 +1533,176 @@ function Private.Modernize(data, oldSnapshot) end end + if data.internalVersion < 76 then + local function removeHoles(t) + local keys = {} + for key in pairs(t) do + table.insert(keys, key) + end + if #keys ~= #t then + table.sort(keys) + local newTable = {} + for i, key in ipairs(keys) do + newTable[i] = t[key] + end + return newTable + else + return t + end + end + local trigger_migration = { + ["Spell Cast Succeeded"] = { + "spellId", + }, + ["Unit Characteristics"] = { + "level", + }, + ["Power"] = { + "power", + "percentpower", + "deficit", + "maxpower", + }, + ["Combat Log"] = { + "spellId", + "spellName", + }, + ["Health"] = { + "health", + "percenthealth", + "deficit", + "maxhealth", + }, + ["Location"] = { + "zone", + "subzone", + }, + ["Threat Situation"] = { + "threatpct", + "rawthreatpct", + "threatvalue", + }, + ["Character Stats"] = { + "strength", + "agility", + "stamina", + "intellect", + "spirit", + "attackpower", + "spellpower", + "rangedattackpower", + "criticalrating", + "criticalpercent", + "hitrating", + "hitpercent", + "hasterating", + "hastepercent", + "expertiserating", + "expertisebonus", + "armorpenrating", + "armorpenpercent", + "spellpenpercent", + "resiliencerating", + "resiliencepercent", + "expertisebonus", + "expertiserating", + "resistancefire", + "resistancenature", + "resistancefrost", + "resistanceshadow", + "resistancearcane", + "movespeedpercent", + "dodgerating", + "dodgepercent", + "parryrating", + "parrypercent", + "blockpercent", + "blockvalue", + "armorrating", + "armorpercent", + }, + ["Cast"] = { + "spellNames", + "spellIds", + }, + } + for _, triggerData in ipairs(data.triggers) do + local trigger = triggerData.trigger + local fieldsToMigrate = trigger_migration[trigger.event] + if fieldsToMigrate then + for _, field in ipairs(fieldsToMigrate) do + if type(trigger[field]) == "table" then + trigger[field] = removeHoles(trigger[field]) + end + end + end + end + end + + --[[if data.internalVersion < 77 then + -- fix data broken by wago export + local triggerFix = { + talent = { + multi = true + }, + herotalent = { + multi = true + }, + form = { + multi = true + }, + specId = { + multi = true + }, + actualSpec = true, + arena_spec = true + } + local loadFix = { + talent = { + multi = true + }, + talent2 = { + multi = true + }, + talent3 = { + multi = true + }, + herotalent = { + multi = true + }, + class_and_spec = { + multi = true + } + } + local function fixData(data, fields) + for k, v in pairs(fields) do + if v == true and type(data[k]) == "table" then + -- fix field k + local tofix = {} + for key in pairs(data[k]) do + if type(key) == "string" then + table.insert(tofix, key) + end + end + for _, oldkey in ipairs(tofix) do + local newkey = tonumber(oldkey) + if newkey then + data[k][newkey] = data[k][oldkey] + end + data[k][oldkey] = nil + end + elseif type(v) == "table" and type(data[k]) == "table" then + -- recurse + fixData(data[k], fields[k]) + end + end + end + for _, triggerData in ipairs(data.triggers) do + fixData(triggerData.trigger, triggerFix) + end + fixData(data.load, loadFix) + end]] + data.internalVersion = max(data.internalVersion or 0, WeakAuras.InternalVersion()) end diff --git a/WeakAuras/Prototypes.lua b/WeakAuras/Prototypes.lua index cf43d06..c805467 100644 --- a/WeakAuras/Prototypes.lua +++ b/WeakAuras/Prototypes.lua @@ -711,8 +711,8 @@ end function WeakAuras.ValidateNumericOrPercent(info, val) if val ~= nil and val ~= "" then - local percent = string.match(val, "(%d+)%%") - local number = percent and tonumber(percent) or tonumber(val) + local index = val:find("%% *$") + local number = index and tonumber(val:sub(1, index-1)) or tonumber(val) if(not number or number >= 2^31) then return false; end @@ -965,6 +965,15 @@ Private.load_prototype = { optional = true, events = {"VEHICLE_UPDATE", "UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE"} }, + { -- broken, fix later COMPANION_UPDATE fires too early for an check, needs some custom stuff + name = "mounted", + display = L["Mounted"], + type = "tristate", + init = "arg", + width = WeakAuras.normalWidth, + optional = true, + --events = {"PLAYER_MOUNT_DISPLAY_CHANGED"} + }, { name ="playerTitle", display = L["Player"], @@ -3810,7 +3819,13 @@ Private.event_prototypes = { test = "true", conditionType = "bool", conditionTest = function(state, needle) - return state and state.show and (UnitExists('target') and IsItemInRange(state.itemname, 'target')) == (needle == 1) + if not state or not state.show or not UnitExists('target') then + return false + end + if InCombatLockdown() and not UnitCanAttack('player', 'target') then + return false + end + return IsItemInRange(state.itemname, 'target') == (needle == 1) end, conditionEvents = { "PLAYER_TARGET_CHANGED", @@ -4419,7 +4434,7 @@ Private.event_prototypes = { return { "SPELL_COOLDOWN_CHANGED:" .. spellName } end, force_events = "SPELL_UPDATE_USABLE", - name = L["Action Usable"], + name = L["Spell Usable"], statesParameter = "one", loadFunc = function(trigger) trigger.spellName = trigger.spellName or 0; diff --git a/WeakAuras/RegionTypes/DynamicGroup.lua b/WeakAuras/RegionTypes/DynamicGroup.lua index 3e66f6b..f99bfcb 100644 --- a/WeakAuras/RegionTypes/DynamicGroup.lua +++ b/WeakAuras/RegionTypes/DynamicGroup.lua @@ -449,7 +449,7 @@ local centeredIndexerStart = { if maxIndex >= 3 then return maxIndex - maxIndex % 2 else - return maxIndex + return maxIndex > 0 and maxIndex or nil end end, -- Center -> Right -> Left, e.g: 3 1 2 4 @@ -457,7 +457,7 @@ local centeredIndexerStart = { if maxIndex % 2 == 1 then return maxIndex else - return maxIndex - 1 + return maxIndex > 0 and maxIndex - 1 or nil end end } diff --git a/WeakAuras/RegionTypes/RegionPrototype.lua b/WeakAuras/RegionTypes/RegionPrototype.lua index 96b650c..ba197a6 100644 --- a/WeakAuras/RegionTypes/RegionPrototype.lua +++ b/WeakAuras/RegionTypes/RegionPrototype.lua @@ -344,8 +344,9 @@ local function SetProgressSource(self, progressSource) self:UpdateProgress() end local function SetAdjustedMin(self, adjustedMin) - local percent = string.match(adjustedMin, "(%d+)%%") - if percent then + local index = adjustedMin:find("%% *$") + if index then + local percent = adjustedMin:sub(1, index-1) self.adjustedMinRelPercent = tonumber(percent) / 100 self.adjustedMin = nil else @@ -355,8 +356,9 @@ local function SetAdjustedMin(self, adjustedMin) self:UpdateProgress() end local function SetAdjustedMax(self, adjustedMax) - local percent = string.match(adjustedMax, "(%d+)%%") - if percent then + local index = adjustedMax:find("%% *$") + if index then + local percent = adjustedMax:sub(1, index-1) self.adjustedMaxRelPercent = tonumber(percent) / 100 else self.adjustedMax = tonumber(adjustedMax) diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 2577853..8b86f8f 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -2377,8 +2377,8 @@ end -- register options font LSM:Register("font", "Fira Mono Medium", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraMono-Medium.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) -- Other Fira fonts -LSM:Register("font", "Fira Sans Black", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSans-Black.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) -LSM:Register("font", "Fira Sans Condensed Black", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSansCondensed-Black.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) +LSM:Register("font", "Fira Sans Black", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSans-Heavy.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) +LSM:Register("font", "Fira Sans Condensed Black", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSansCondensed-Heavy.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) LSM:Register("font", "Fira Sans Condensed Medium", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSansCondensed-Medium.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) LSM:Register("font", "Fira Sans Medium", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\FiraSans-Medium.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) LSM:Register("font", "PT Sans Narrow Regular", "Interface\\Addons\\WeakAuras\\Media\\Fonts\\PTSansNarrow-Regular.ttf", LSM.LOCALE_BIT_western + LSM.LOCALE_BIT_ruRU) @@ -2606,7 +2606,8 @@ Private.update_categories = { "url", "desc", "version", - "semver" + "semver", + "wagoID", -- i don't *love* that we're so closely tied to wago, but eh }, default = true, label = L["Meta Data"], diff --git a/WeakAuras/WeakAuras.lua b/WeakAuras/WeakAuras.lua index 4c55c2e..99b1a3b 100644 --- a/WeakAuras/WeakAuras.lua +++ b/WeakAuras/WeakAuras.lua @@ -1,6 +1,6 @@ local AddonName, Private = ... -local internalVersion = 75 +local internalVersion = 78 -- Lua APIs local insert = table.insert @@ -183,6 +183,8 @@ function SlashCmdList.WEAKAURAS(input) WeakAuras.PrintProfile(); elseif msg == "pcancel" then WeakAuras.CancelScheduledProfile() + elseif msg == "pshow" or msg == "profiling" then + WeakAuras.RealTimeProfilingWindow:Toggle() elseif msg == "minimap" then Private.ToggleMinimap(); elseif msg == "help" then @@ -1075,21 +1077,20 @@ function Private.LoginMessage() return loginMessage end -function Private.Login(initialTime, takeNewSnapshots) +function Private.Login(takeNewSnapshots) local loginThread = coroutine.create(function() Private.Pause(); - + coroutine.yield(100) if db.history then local histRepo = WeakAuras.LoadFromArchive("Repository", "history") local migrationRepo = WeakAuras.LoadFromArchive("Repository", "migration") for uid, hist in pairs(db.history) do local histStore = histRepo:Set(uid, hist.data) local migrationStore = migrationRepo:Set(uid, hist.migration) - coroutine.yield() + coroutine.yield(1000, "login move old history") end -- history is now in archive so we can shrink WeakAurasSaved db.history = nil - coroutine.yield(); end local toAdd = {}; @@ -1103,14 +1104,15 @@ function Private.Login(initialTime, takeNewSnapshots) tinsert(toAdd, data); end - coroutine.yield(); + coroutine.yield(8000); Private.AddMany(toAdd, takeNewSnapshots); - coroutine.yield(); + coroutine.yield(1000); Private.RegisterLoadEvents(); + coroutine.yield(10000); Private.Resume(); - coroutine.yield(); + coroutine.yield(100); local nextCallback = loginQueue[1]; while nextCallback do @@ -1120,7 +1122,7 @@ function Private.Login(initialTime, takeNewSnapshots) else nextCallback() end - coroutine.yield(); + coroutine.yield(1000, "login post login callbacks"); nextCallback = loginQueue[1]; end @@ -1129,31 +1131,12 @@ function Private.Login(initialTime, takeNewSnapshots) for _, region in pairs(Private.regions) do if (region.region and region.region.RunDelayedActions) then region.region:RunDelayedActions(); - coroutine.yield() + coroutine.yield(500, "login delayed region actions"); end end end) - if initialTime then - local startTime = debugprofilestop() - local finishTime = debugprofilestop() - local ok, msg - -- hard limit seems to be 19 seconds. We'll do 15 for now. - while coroutine.status(loginThread) ~= 'dead' and finishTime - startTime < 15000 do - ok, msg = coroutine.resume(loginThread) - finishTime = debugprofilestop() - end - if coroutine.status(loginThread) ~= 'dead' then - Private.dynFrame:AddAction('login', loginThread) - end - if not ok then - loginMessage = L["WeakAuras has encountered an error during the login process. Please report this issue at https://github.com/WeakAuras/Weakauras2/issues/new."] - .. "\nMessage:" .. msg - geterrorhandler()(msg .. '\n' .. debugstack(loginThread)) - end - else - Private.dynFrame:AddAction('login', loginThread) - end + Private.Threads:Immediate('login', loginThread, 15000, 1000) end local WeakAurasFrame = CreateFrame("Frame", "WeakAurasFrame", UIParent); @@ -1194,7 +1177,8 @@ loadedFrame:SetScript("OnEvent", function(self, event, addon) if db.lastArchiveClear == nil then db.lastArchiveClear = time(); - elseif db.lastArchiveClear < time() - 86400 then + elseif db.lastArchiveClear < time() - 2505600 --[[29 days]] then + db.lastArchiveClear = time(); Private.CleanArchive(db.historyCutoff, db.migrationCutoff); end db.minimap = db.minimap or { hide = false }; @@ -1216,8 +1200,7 @@ loadedFrame:SetScript("OnEvent", function(self, event, addon) dbIsValid = true end if dbIsValid then - -- run login thread for up to 15 seconds, then defer to dynFrame - Private.Login(15000, takeNewSnapshots) + Private.Login(takeNewSnapshots) else -- db isn't valid. Request permission to run repair tool before logging in StaticPopup_Show("WEAKAURAS_CONFIRM_REPAIR", nil, nil, {reason = "downgrade"}) @@ -1412,12 +1395,15 @@ local function scanForLoadsImpl(toCheck, event, arg1, ...) local vehicleUi = UnitHasVehicleUI("player") or false local raidMemberType = 0 + if UnitIsPartyLeader("player") then raidMemberType = raidMemberType + 1 + elseif UnitIsRaidOfficer("player") then raidMemberType = raidMemberType + 2 end + local mounted = IsMounted() local size, difficulty, instanceType = GetInstanceTypeAndSize() local group = Private.ExecEnv.GroupType() local groupSize = GetNumGroupMembers() @@ -1433,8 +1419,8 @@ local function scanForLoadsImpl(toCheck, event, arg1, ...) if (data and not data.controlledChildren) then local loadFunc = loadFuncs[id]; local loadOpt = loadFuncsForOptions[id]; - shouldBeLoaded = loadFunc and loadFunc("ScanForLoads_Auras", inCombat, alive, pvp, vehicle, vehicleUi, player, realm, class, race, faction, playerLevel, raidRole, group, groupSize, raidMemberType, zone, zoneId, subzone, size, difficulty); - couldBeLoaded = loadOpt and loadOpt("ScanForLoads_Auras", inCombat, alive, pvp, vehicle, vehicleUi, player, realm, class, race, faction, playerLevel, raidRole, group, groupSize, raidMemberType, zone, zoneId, subzone, size, difficulty); + shouldBeLoaded = loadFunc and loadFunc("ScanForLoads_Auras", inCombat, alive, pvp, vehicle, vehicleUi, mounted, player, realm, class, race, faction, playerLevel, raidRole, group, groupSize, raidMemberType, zone, zoneId, subzone, size, difficulty); + couldBeLoaded = loadOpt and loadOpt("ScanForLoads_Auras", inCombat, alive, pvp, vehicle, vehicleUi, mounted, player, realm, class, race, faction, playerLevel, raidRole, group, groupSize, raidMemberType, zone, zoneId, subzone, size, difficulty); if(shouldBeLoaded and not loaded[id]) then changed = changed + 1; @@ -1983,20 +1969,20 @@ function Private.NeedToRepairDatabase() return db.dbVersion and db.dbVersion > WeakAuras.InternalVersion() end -local function RepairDatabase(loginAfter) +local function RepairDatabase() local coro = coroutine.create(function() Private.SetImporting(true) -- set db version to current code version db.dbVersion = WeakAuras.InternalVersion() -- reinstall snapshots from history local newDB = WeakAuras.Mixin({}, db.displays) - coroutine.yield() + coroutine.yield(1000) for id, data in pairs(db.displays) do local snapshot = Private.GetMigrationSnapshot(data.uid) if snapshot then newDB[id] = nil newDB[snapshot.id] = snapshot - coroutine.yield() + coroutine.yield(1000, "repair get snapshot") end end db.displays = newDB @@ -2004,7 +1990,7 @@ local function RepairDatabase(loginAfter) -- finally, login Private.Login() end) - Private.dynFrame:AddAction("repair", coro) + Private.Threads:Add("repair", coro, 'urgent') end StaticPopupDialogs["WEAKAURAS_CONFIRM_REPAIR"] = { @@ -2165,9 +2151,9 @@ local function loadOrder(tbl, idtable) if not(loaded[data.parent]) then local dependsOut = CopyTable(depends) dependsOut[data.parent] = true - coroutine.yield() + coroutine.yield(100, "sort deps") load(data.parent, dependsOut) - coroutine.yield() + coroutine.yield(100, "sort deps") end end else @@ -2175,15 +2161,15 @@ local function loadOrder(tbl, idtable) end end if not(loaded[id]) then - coroutine.yield(); + coroutine.yield(100, "sort deps"); loaded[id] = true; tinsert(order, idtable[id]) end end - for id, data in pairs(idtable) do + for id in pairs(idtable) do load(id, {}); - coroutine.yield() + coroutine.yield(100, "sort deps") end return order end @@ -2207,17 +2193,26 @@ function Private.AddMany(tbl, takeSnapshots) end local order = loadOrder(tbl, idtable) - coroutine.yield() + coroutine.yield(5000) local oldSnapshots = {} + local copies = {} if takeSnapshots then for _, data in ipairs(order) do if Private.ModernizeNeedsOldSnapshot(data) then oldSnapshots[data.uid] = Private.GetMigrationSnapshot(data.uid) end - Private.SetMigrationSnapshot(data.uid, data) - coroutine.yield() + copies[data.uid] = CopyTable(data) + coroutine.yield(200, "addmany prepare snapshot") end + Private.Threads:Add("snapshot", coroutine.create(function() + prettyPrint(L["WeakAuras is creating a rollback snapshot of your auras. This snapshot will allow you to revert to the current state of your auras if something goes wrong. This process may cause your framerate to drop until it is complete."]) + for uid, data in pairs(copies) do + Private.SetMigrationSnapshot(uid, data) + coroutine.yield(200, "snapshot") + end + prettyPrint(L["Rollback snapshot is complete. Thank you for your patience!"]) + end), 'normal') end local groups = {} @@ -2238,7 +2233,7 @@ function Private.AddMany(tbl, takeSnapshots) elseif data.regionType == "dynamicgroup" or data.regionType == "group" then groups[data] = true end - coroutine.yield() + coroutine.yield(1000, "addmany modernize") end end @@ -2254,13 +2249,14 @@ function Private.AddMany(tbl, takeSnapshots) end end end - coroutine.yield() + coroutine.yield(2000, "addmany add") end for id in pairs(anchorTargets) do local data = idtable[id] if data and not bads[data.id] and (data.parent == nil or idtable[data.parent].regionType ~= "dynamicgroup") then Private.EnsureRegion(id) + coroutine.yield(100, "addmany ensure anchor") end end @@ -2274,7 +2270,7 @@ function Private.AddMany(tbl, takeSnapshots) WeakAuras.Add(data) end end - coroutine.yield(); + coroutine.yield(1000, "addmany reload dynamic group"); end end @@ -3839,78 +3835,128 @@ function WeakAuras.EnsureString(input) end -- Handle coroutines -local dynFrame = {}; +local threads = { + frame = CreateFrame("Frame"), + size = 0, + ---@type table + prios = {}, + pools = { + urgent = {}, + normal = {}, + background = {}, + instant = {}, + }, +}; do - -- Internal data - dynFrame.frame = CreateFrame("Frame"); - dynFrame.update = {}; - dynFrame.size = 0; + local validPriorities = { + urgent = true, + normal = true, + background = true, + instant = true, + } -- Add an action to be resumed via OnUpdate - function dynFrame.AddAction(self, name, func) - if not name then - name = string.format("NIL", dynFrame.size+1); + function threads:Add(name, thread, prio) + if not prio or not validPriorities[prio] then + prio = "normal" end + if type(thread) == "function" then + thread = coroutine.create(thread) + end + if not self.prios[name] then + self.prios[name] = prio + self.pools[prio][name] = { + thread = thread, + sequence = {} + } + self.size = self.size + 1 + self.frame:Show() + end + end - if not dynFrame.update[name] then - dynFrame.update[name] = func; - dynFrame.size = dynFrame.size + 1 - dynFrame.frame:Show(); + function threads:SetPriority(name, prio) + local oldPrio = self.prios[name] + if oldPrio and oldPrio ~= prio then + self.pools[prio][name] = self.pools[oldPrio][name] + self.pools[oldPrio][name] = nil + self.prios[name] = prio end end -- Remove an action from OnUpdate - function dynFrame.RemoveAction(self, name) - if dynFrame.update[name] then - dynFrame.update[name] = nil; - dynFrame.size = dynFrame.size - 1 - if dynFrame.size == 0 then - dynFrame.frame:Hide(); + function threads:Remove(name) + local prio = self.prios[name] + if prio then + local pool = self.pools[prio] + pool[name] = nil + self.prios[name] = nil + self.size = self.size - 1 + if self.size == 0 then + self.frame:Hide() end end end - -- Setup frame - dynFrame.frame:Hide(); - dynFrame.frame:SetScript("OnUpdate", function(self, elapsed) - -- Start timing - local start = debugprofilestop(); - local hasData = true; - - -- Resume as often as possible (Limit to 16ms per frame -> 60 FPS) - while (debugprofilestop() - start < 16 and hasData) do - -- Stop loop without data - hasData = false; - - -- Resume all coroutines - for name, func in pairs(dynFrame.update) do - -- Loop has data - hasData = true; - - -- Resume or remove - if coroutine.status(func) ~= "dead" then - local ok, msg = coroutine.resume(func) - if not ok then - geterrorhandler()(msg .. '\n' .. debugstack(func)) - end + local function runThreadPool(pool, finish, defaultEstimate) + local start = debugprofilestop() + if finish <= start then return end + local estimates = {} + local ok, val1, val2 + local continue = false + repeat + continue = false + for name, threadData in pairs(pool) do + local estimate = estimates[name] or defaultEstimate + if debugprofilestop() + estimate > finish then + break else - dynFrame:RemoveAction(name); + continue = true + ok, val1, val2 = coroutine.resume(threadData.thread) + if not ok then + geterrorhandler()(val1 .. '\n' .. debugstack(threadData.thread)) + end + if coroutine.status(threadData.thread) ~= "dead" then + estimates[name] = type(val1) == "number" and val1 or defaultEstimate + local sequence = val2 or "" + threadData.sequence[sequence] = (threadData.sequence[sequence] or 0) + 1 + else + threads:Remove(name) + end end end + until not continue + end + + function threads:Immediate(name, func, limit, defaultEstimate) + self:Add(name, func, "instant") + runThreadPool(self.pools.instant, debugprofilestop() + limit, defaultEstimate or 1000) + if coroutine.status(func) ~= "dead" then + self:SetPriority(name, "urgent") + else + self:Remove(name) end + end + + -- Setup frame + threads.frame:Hide(); + threads.frame:SetScript("OnUpdate", function() + local start = debugprofilestop(); + runThreadPool(threads.pools.urgent, start + 15000, 1000) + runThreadPool(threads.pools.normal, start + 20, 1) + runThreadPool(threads.pools.background, start + 2, 0.5) end); - dynFrame.frame:RegisterEvent("PLAYER_REGEN_ENABLED") - dynFrame.frame:RegisterEvent("PLAYER_REGEN_DISABLED") - dynFrame.frame:SetScript("OnEvent", function(self, event) + threads.frame:RegisterEvent("PLAYER_REGEN_ENABLED") + threads.frame:RegisterEvent("PLAYER_REGEN_DISABLED") + threads.frame:SetScript("OnEvent", function(self, event) if event == "PLAYER_REGEN_ENABLED" and self:IsShown() then self:Hide() - elseif event == "PLAYER_REGEN_DISABLED" and not self:IsShown() and dynFrame.size > 0 then + elseif event == "PLAYER_REGEN_DISABLED" and not self:IsShown() and threads.size > 0 then self:Show() end end) end -Private.dynFrame = dynFrame; +Private.Threads = threads; function WeakAuras.RegisterTriggerSystem(types, triggerSystem) for _, v in ipairs(types) do diff --git a/WeakAuras/WeakAuras.toc b/WeakAuras/WeakAuras.toc index 498509a..511ebca 100644 --- a/WeakAuras/WeakAuras.toc +++ b/WeakAuras/WeakAuras.toc @@ -72,3 +72,6 @@ SubRegionTypes\Border.lua SubRegionTypes\Glow.lua SubRegionTypes\Tick.lua SubRegionTypes\Model.lua + +#Misc +DiscordList.lua \ No newline at end of file diff --git a/WeakAurasOptions/Cache.lua b/WeakAurasOptions/Cache.lua index b3edab5..8bd4f9a 100644 --- a/WeakAurasOptions/Cache.lua +++ b/WeakAurasOptions/Cache.lua @@ -29,6 +29,7 @@ function spellCache.Build() wipe(cache) local co = coroutine.create(function() + metaData.rebuilding = true local id = 0 local misses = 0 @@ -47,7 +48,7 @@ function spellCache.Build() misses = misses + 1 end - coroutine.yield() + coroutine.yield(0.01, "spells") end for _, category in pairs(GetCategoryList()) do @@ -59,8 +60,9 @@ function spellCache.Build() cache[name].achievements = cache[name].achievements or {} cache[name].achievements[id] = iconID end + coroutine.yield(0.1, "achievements") end - coroutine.yield() + coroutine.yield(0.1, "categories") end -- Updates the icon cache with whatever icons WeakAuras core has actually used. @@ -74,8 +76,9 @@ function spellCache.Build() end metaData.needsRebuild = false + metaData.rebuilding = false end) - OptionsPrivate.Private.dynFrame:AddAction("spellCache", co) + OptionsPrivate.Private.Threads:Add("spellCache", co, 'background') end function spellCache.GetIcon(name) @@ -97,6 +100,8 @@ function spellCache.GetIcon(name) end end end + elseif metaData.rebuilding then + OptionsPrivate.Private.Threads:SetPriority('spellCache', 'normal') end bestIcon[name] = bestMatch and icons.spells[bestMatch]; @@ -121,6 +126,8 @@ function spellCache.AddIcon(name, id, icon) cache[name].spells[id] = icon end end + elseif metaData.rebuilding then + OptionsPrivate.Private.Threads:SetPriority('spellCache', 'normal') else error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.") end diff --git a/WeakAurasOptions/CommonOptions.lua b/WeakAurasOptions/CommonOptions.lua index 012a29e..d990e44 100644 --- a/WeakAurasOptions/CommonOptions.lua +++ b/WeakAurasOptions/CommonOptions.lua @@ -1060,6 +1060,7 @@ local function ProgressOptions(data) local options = { __title = L["Progress Settings"], __order = 98, + __collapsed = true } options.progressSource = { @@ -1233,6 +1234,7 @@ local function PositionOptions(id, data, _, hideWidthHeight, disableSelfPoint, g local positionOptions = { __title = L["Position Settings"], __order = metaOrder, + __collapsed = true, width = { type = "range", control = "WeakAurasSpinBox", @@ -1645,14 +1647,11 @@ local function AddCodeOption(args, data, name, prefix, url, order, hiddenFunc, p code = "return " .. code; - local loadedFunction, errorString = loadstring(code); + local loadedFunction, errorString = OptionsPrivate.Private.LoadFunction(code, true); if not errorString then if options.validator then - local ok, validate = xpcall(loadedFunction, function(err) errorString = err end) - if ok then - errorString = options.validator(validate) - end + errorString = options.validator(loadedFunction) end end return errorString and "|cFFFF0000"..errorString or ""; diff --git a/WeakAurasOptions/ConditionOptions.lua b/WeakAurasOptions/ConditionOptions.lua index 8aa052f..7f406e2 100644 --- a/WeakAurasOptions/ConditionOptions.lua +++ b/WeakAurasOptions/ConditionOptions.lua @@ -659,7 +659,7 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA local v = conditions[i].changes[j].value local progressSource = OptionsPrivate.Private.AddProgressSourceMetaData(data, v) -- Auto progress, Manual Progress or the progress source has a total property - if progressSource[2] == "auto" or progressSource[1] == 0 or progressSource[4] ~= nil then + if progressSource and (progressSource[2] == "auto" or progressSource[1] == 0 or progressSource[4] ~= nil) then return true end return false @@ -670,7 +670,7 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA local function hiddenManual() local v = conditions[i].changes[j].value local progressSource = OptionsPrivate.Private.AddProgressSourceMetaData(data, v) - if progressSource[1] == 0 then + if progressSource and progressSource[1] == 0 then return false end return true diff --git a/WeakAurasOptions/DisplayOptions.lua b/WeakAurasOptions/DisplayOptions.lua index 1b8dda3..3656eb7 100644 --- a/WeakAurasOptions/DisplayOptions.lua +++ b/WeakAurasOptions/DisplayOptions.lua @@ -101,6 +101,7 @@ function OptionsPrivate.GetDisplayOptions(data) subIndex[subRegionType] = subIndex[subRegionType] and subIndex[subRegionType] + 1 or 1 local options, common = OptionsPrivate.Private.subRegionOptions[subRegionType].create(data, subRegionData, index, subIndex[subRegionType]) options.__order = 200 + index + options.__collapsed = true regionOption["sub." .. index .. "." .. subRegionType] = options commonOption[subRegionType] = common end diff --git a/WeakAurasOptions/LoadOptions.lua b/WeakAurasOptions/LoadOptions.lua index e27e3eb..fd626db 100644 --- a/WeakAurasOptions/LoadOptions.lua +++ b/WeakAurasOptions/LoadOptions.lua @@ -17,14 +17,9 @@ local ValidateNumeric = WeakAuras.ValidateNumeric; local spellCache = WeakAuras.spellCache; local function CorrectSpellName(input) - local inputId = tonumber(input); + local inputId = tonumber(input) if(inputId) then - local name = GetSpellInfo(inputId); - if(name) then - return inputId; - else - return nil; - end + return inputId elseif(input) then local link; if(input:sub(1,1) == "\124") then @@ -35,6 +30,16 @@ local function CorrectSpellName(input) if(link) and link ~= "" then local itemId = link:match("spell:(%d+)"); return tonumber(itemId); + else + local spells = spellCache.GetSpellsMatching(input) + if type(spells) == "table" then + for id in pairs(spells) do + if id and tonumber(id) and id > 0 and IsSpellKnown(tonumber(id)) then + return id + end + end + return next(spells) + end end end end @@ -48,8 +53,6 @@ local function CorrectItemName(input) if(link) then local itemId = link:match("item:(%d+)"); return tonumber(itemId); - else - return nil; end end end @@ -694,6 +697,7 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum if spellName then return ("%s (%s)"):format(spellID, spellName) .. "\0" .. value end + return ("%s (%s)"):format(spellID, L["Unknown Spell"]) .. "\0" .. value elseif not useExactSpellId and not arg.noValidation then local spellName = GetSpellInfo(value) if spellName then @@ -946,6 +950,7 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum v = arg.multiConvertKey(trigger, v) end if v then + trigger[realname] = trigger[realname] or {} trigger[realname].multi = trigger[realname].multi or {}; if (calledFromSetAll or arg.multiTristate) then trigger[realname].multi[v] = calledFromSetAll; diff --git a/WeakAurasOptions/OptionsFrames/OptionsFrame.lua b/WeakAurasOptions/OptionsFrames/OptionsFrame.lua index 38da717..3866924 100644 --- a/WeakAurasOptions/OptionsFrames/OptionsFrame.lua +++ b/WeakAurasOptions/OptionsFrames/OptionsFrame.lua @@ -13,6 +13,7 @@ local GetScreenWidth, GetScreenHeight, CreateFrame, GetAddOnInfo, UnitName local AceGUI = LibStub("AceGUI-3.0") local AceConfigDialog = LibStub("AceConfigDialog-3.0") local AceConfigRegistry = LibStub("AceConfigRegistry-3.0") +local SharedMedia = LibStub("LibSharedMedia-3.0") local WeakAuras = WeakAuras local L = WeakAuras.L @@ -344,15 +345,33 @@ function OptionsPrivate.CreateFrame() tipPopupTitle:SetJustifyV("TOP") local tipPopupLabel = tipPopup:CreateFontString(nil, "BACKGROUND", "GameFontWhite") + local fontPath = SharedMedia:Fetch("font", "Fira Sans Medium") + if (fontPath) then + tipPopupLabel:SetFont(fontPath, 12) + end tipPopupLabel:SetPoint("TOPLEFT", tipPopupTitle, "BOTTOMLEFT", 0, -6) tipPopupLabel:SetPoint("TOPRIGHT", tipPopupTitle, "BOTTOMRIGHT", 0, -6) tipPopupLabel:SetJustifyH("LEFT") tipPopupLabel:SetJustifyV("TOP") + local tipPopupLabelCJ = tipPopup:CreateFontString(nil, "BACKGROUND", "GameFontWhite") + tipPopupLabelCJ:SetFont("Fonts\\ARKai_T.ttf", 12) + tipPopupLabelCJ:SetPoint("TOPLEFT", tipPopupLabel, "BOTTOMLEFT", 0, 0) + tipPopupLabelCJ:SetPoint("TOPRIGHT", tipPopupLabel, "BOTTOMRIGHT", 0, 0) + tipPopupLabelCJ:SetJustifyH("LEFT") + tipPopupLabelCJ:SetJustifyV("TOP") + + local tipPopupLabelK = tipPopup:CreateFontString(nil, "BACKGROUND", "GameFontWhite") + tipPopupLabelK:SetFont("Fonts\\K_Pagetext.TTF", 12) + tipPopupLabelK:SetPoint("TOPLEFT", tipPopupLabelCJ, "BOTTOMLEFT", 0, 0) + tipPopupLabelK:SetPoint("TOPRIGHT", tipPopupLabelCJ, "BOTTOMRIGHT", 0, 0) + tipPopupLabelK:SetJustifyH("LEFT") + tipPopupLabelK:SetJustifyV("TOP") + local urlWidget = CreateFrame("EditBox", nil, tipPopup, "WA_InputBoxTemplate") urlWidget:SetFont(STANDARD_TEXT_FONT, 12) - urlWidget:SetPoint("TOPLEFT", tipPopupLabel, "BOTTOMLEFT", 6, 0) - urlWidget:SetPoint("TOPRIGHT", tipPopupLabel, "BOTTOMRIGHT", 0, 0) + urlWidget:SetPoint("TOPLEFT", tipPopupLabelK, "BOTTOMLEFT", 6, 0) + urlWidget:SetPoint("TOPRIGHT", tipPopupLabelK, "BOTTOMRIGHT", 0, 0) urlWidget:SetScript("OnChar", function() urlWidget:SetText(urlWidget.text); urlWidget:HighlightText(); end); urlWidget:SetScript("OnMouseUp", function() urlWidget:HighlightText(); end); urlWidget:SetScript("OnEscapePressed", function() tipPopup:Hide() end) @@ -365,7 +384,8 @@ function OptionsPrivate.CreateFrame() tipPopupCtrlC:SetJustifyV("TOP") tipPopupCtrlC:SetText(L["Press Ctrl+C to copy the URL"]) - local function ToggleTip(referenceWidget, url, title, description, rightAligned) + local function ToggleTip(referenceWidget, url, title, description, descriptionCJ, descriptionK, rightAligned, width) + width = width or 400 if tipPopup:IsVisible() and urlWidget.text == url then tipPopup:Hide() return @@ -374,64 +394,117 @@ function OptionsPrivate.CreateFrame() urlWidget:SetText(url) tipPopupTitle:SetText(title) tipPopupLabel:SetText(description) + tipPopupLabelCJ:SetText(descriptionCJ) + tipPopupLabelK:SetText(descriptionK) urlWidget:HighlightText() - tipPopup:SetWidth(400) - tipPopup:SetHeight(26 + tipPopupTitle:GetHeight() + tipPopupLabel:GetHeight() + urlWidget:GetHeight() + tipPopupCtrlC:GetHeight()) - tipPopup:ClearAllPoints(); if rightAligned then tipPopup:SetPoint("BOTTOMRIGHT", referenceWidget, "TOPRIGHT", 6, 4) else tipPopup:SetPoint("BOTTOMLEFT", referenceWidget, "TOPLEFT", -6, 4) end + + tipPopup:SetWidth(width) tipPopup:Show() + tipPopup:SetHeight(26 + tipPopupTitle:GetHeight() + tipPopupLabel:GetHeight() + tipPopupLabelCJ:GetHeight() + tipPopupLabelK:GetHeight() + + urlWidget:GetHeight() + tipPopupCtrlC:GetHeight()) + -- This does somehow fix an issue where the first popup after a game restart doesn't show up. + -- This isn't reproducable after a simple ui reload, so no idea what goes wrong, but with this line here, + -- it seems to work. + tipPopupLabel:GetRect() + tipPopupLabelCJ:GetRect() + tipPopupLabelK:GetRect() end OptionsPrivate.ToggleTip = ToggleTip - local addFooter = function(title, texture, url, description, rightAligned) + local addFooter = function(title, texture, url, description, descriptionCJ, descriptionK, rightAligned, width) local button = AceGUI:Create("WeakAurasToolbarButton") button:SetText(title) button:SetTexture(texture) button:SetCallback("OnClick", function() - ToggleTip(button.frame, url, title, description, rightAligned) + ToggleTip(button.frame, url, title, description, descriptionCJ, descriptionK, rightAligned, width) end) button.frame:Show() return button.frame end + local function lineWrapDiscordList(list) + local patreonLines = {} + local lineLength = 0 + local currentLine = {} + for _, patreon in ipairs(list) do + if lineLength + #patreon + 2 * #currentLine > 130 then + tinsert(patreonLines, table.concat(currentLine, ", ") .. ", ") + currentLine = {} + tinsert(currentLine, patreon) + lineLength = #patreon + else + lineLength = lineLength + #patreon + tinsert(currentLine, patreon) + end + end + if #currentLine > 0 then + tinsert(patreonLines, table.concat(currentLine, ", ")) + end + return table.concat(patreonLines, "\n") + end + + local thanksList = L["We thank"] .. "\n" + .. L["All maintainers of the libraries we use, especially:"] .. "\n" + .. "• " .. L["Ace: Funkeh, Nevcairiel"] .. "\n" + .. "• " .. L["LibCompress: Galmok"] .. "\n" + .. "• " .. L["LibCustomGlow: Dooez"] .. "\n" + .. "• " .. L["LibDeflate: Yoursafety"] .. "\n" + .. "• " .. L["LibDispel: Simpy"] .. "\n" + .. "• " .. L["LibSerialize: Sanjo"] .. "\n" + .. "• " .. L["LibSpecialization: Funkeh"] .. "\n" + .. "• " .. L["Our translators (too many to name)"] .. "\n" + .. "• " .. L["And our Patreons, Discord Regulars and Subscribers, and Friends of the Addon:"] .. "\n" + + thanksList = thanksList .. lineWrapDiscordList(OptionsPrivate.Private.DiscordList) + + local thanksListCJ = lineWrapDiscordList(OptionsPrivate.Private.DiscordListCJ) + local thanksListK = lineWrapDiscordList(OptionsPrivate.Private.DiscordListK) + + local discordButton = addFooter(L["Join Discord"], [[Interface\AddOns\WeakAuras\Media\Textures\discord.tga]], "https://discord.gg/UXSc7nt", - L["Chat with WeakAuras experts on our Discord server."]) + L["Chat with WeakAuras experts on our Discord server."]) discordButton:SetParent(tipFrame) discordButton:SetPoint("LEFT", tipFrame, "LEFT") local documentationButton = addFooter(L["Documentation"], [[Interface\AddOns\WeakAuras\Media\Textures\GitHub.tga]], "https://github.com/WeakAuras/WeakAuras2/wiki", - L["Check out our wiki for a large collection of examples and snippets."]) + L["Check out our wiki for a large collection of examples and snippets."]) documentationButton:SetParent(tipFrame) documentationButton:SetPoint("LEFT", discordButton, "RIGHT", 10, 0) + local thanksButton = addFooter(L["Thanks"], [[Interface\AddOns\WeakAuras\Media\Textures\waheart.tga]], + "https://www.patreon.com/WeakAuras", thanksList, thanksListCJ, thanksListK, nil, 800) + thanksButton:SetParent(tipFrame) + thanksButton:SetPoint("LEFT", documentationButton, "RIGHT", 10, 0) + local awesomeWotlkButton if not WeakAuras.isAwesomeEnabled() then - awesomeWotlkButton = addFooter("Awesome WotLK", [[Interface\AddOns\WeakAuras\Media\Textures\GitHub.tga]], "https://github.com/FrostAtom/awesome_wotlk", - L["Unlock Nameplate anchoring and units in WeakAuras with awesome_wotlk client patch!"]) + awesomeWotlkButton = addFooter("Awesome WotLK", [[Interface\AddOns\WeakAuras\Media\Textures\GitHub.tga]], "https://github.com/FrostAtom/awesome_wotlk/releases", + L["Unlock nameplate anchoring & units in WeakAuras with the awesome_wotlk client patch"]) awesomeWotlkButton:SetParent(tipFrame) - awesomeWotlkButton:SetPoint("LEFT", documentationButton, "RIGHT", 10, 0) + awesomeWotlkButton:SetPoint("LEFT", thanksButton, "RIGHT", 10, 0) end - local reportbugButton = addFooter(L["Found a Bug?"], [[Interface\AddOns\WeakAuras\Media\Textures\bug_report.tga]], "https://github.com/Bunny67/WeakAuras-WotLK/issues/new?assignees=&labels=bug&template=bug_report.md&title=", - L["Report bugs on our issue tracker."], true) + local reportbugButton = addFooter(L["Found a Bug?"], [[Interface\AddOns\WeakAuras\Media\Textures\bug_report.tga]], "https://github.com/NoM0Re/WeakAuras-WotLK/issues", + L["Report bugs on our issue tracker."], nil, nil, true) reportbugButton:SetParent(tipFrame) reportbugButton:SetPoint("RIGHT", tipFrame, "RIGHT") - local wagoButton = addFooter(L["Find Auras"], [[Interface\AddOns\WeakAuras\Media\Textures\wago.tga]], "https://wago.io", - L["Browse Wago, the largest collection of auras."], true) + local wagoButton = addFooter(L["Find Auras"], [[Interface\AddOns\WeakAuras\Media\Textures\wago.tga]], "https://wago.io/search/imports/wow/all?q=3.3.5", + L["Browse Wago, the largest collection of auras."], nil, nil, true) wagoButton:SetParent(tipFrame) wagoButton:SetPoint("RIGHT", reportbugButton, "LEFT", -10, 0) local companionButton if not OptionsPrivate.Private.CompanionData.slugs then companionButton = addFooter(L["Update Auras"], [[Interface\AddOns\WeakAuras\Media\Textures\wagoupdate_refresh.tga]], "https://weakauras.wtf", - L["Keep your Wago imports up to date with the Companion App."]) + L["Keep your Wago imports up to date with the Companion App."]) companionButton:SetParent(tipFrame) companionButton:SetPoint("RIGHT", wagoButton, "LEFT", -10, 0) end diff --git a/WeakAurasOptions/OptionsFrames/TextEditor.lua b/WeakAurasOptions/OptionsFrames/TextEditor.lua index 634fb20..ccf294c 100644 --- a/WeakAurasOptions/OptionsFrames/TextEditor.lua +++ b/WeakAurasOptions/OptionsFrames/TextEditor.lua @@ -3,7 +3,6 @@ local AddonName, OptionsPrivate = ... -- Lua APIs local pairs, type, ipairs = pairs, type, ipairs -local loadstring = loadstring local gsub = gsub -- WoW APIs @@ -182,6 +181,7 @@ local function ConstructTextEditor(frame) -- The indention lib overrides GetText, but for the line number -- display we ned the original, so save it here. local originalGetText = editor.editBox.GetText + local originalSetText = editor.editBox.SetText set_scheme() IndentationLib.enable(editor.editBox, color_scheme, WeakAurasSaved.editor_tab_spaces) @@ -517,7 +517,7 @@ local function ConstructTextEditor(frame) if self.timeMachine[self.timeMachinePos + 1] then self.timeMachinePos = self.timeMachinePos + 1 self.skipOnTextChanged = true - self:SetText(self.timeMachine[self.timeMachinePos][1]) + originalSetText(self, self.timeMachine[self.timeMachinePos][1]) self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2]) end elseif IsControlKeyDown() and key == "Y" then @@ -525,7 +525,7 @@ local function ConstructTextEditor(frame) if self.timeMachine[self.timeMachinePos - 1] then self.timeMachinePos = self.timeMachinePos - 1 self.skipOnTextChanged = true - self:SetText(self.timeMachine[self.timeMachinePos][1]) + originalSetText(self, self.timeMachine[self.timeMachinePos][1]) self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2]) end end @@ -705,15 +705,12 @@ local function ConstructTextEditor(frame) else local func, errorString if (enclose) then - func, errorString = loadstring("return function() " .. str .. "\n end") + func, errorString = OptionsPrivate.Private.LoadFunction("return function() " .. str .. "\n end", true) else - func, errorString = loadstring("return " .. str) + func, errorString = OptionsPrivate.Private.LoadFunction("return " .. str, true) end if not errorString and validator then - local ok, validate = xpcall(func, function(err) errorString = err end) - if ok then - errorString = validator(validate) - end + errorString = validator(func) end if errorString then if self.url then diff --git a/WeakAurasOptions/OptionsFrames/Update.lua b/WeakAurasOptions/OptionsFrames/Update.lua index 3fb07c9..47e6517 100644 --- a/WeakAurasOptions/OptionsFrames/Update.lua +++ b/WeakAurasOptions/OptionsFrames/Update.lua @@ -739,6 +739,7 @@ local function BuildUidMap(data, children, type) for _, childUid in ipairs(children) do self:EnsureUniqueIdOfUnmatched(childUid, IncProgress) end + coroutine.yield(0.1, "ensure unique uids") end uidMap.InsertUnmatchedPhase1 = function(self, otherUidMap, otherUid, IncProgress) @@ -777,10 +778,10 @@ local function BuildUidMap(data, children, type) end else IncProgress() - coroutine.yield() + coroutine.yield(0.1) end end - coroutine.yield() + coroutine.yield(0.1) end for uid, otherList in pairs(matchToInsert) do @@ -800,8 +801,9 @@ local function BuildUidMap(data, children, type) otherUidMap:SetUIDMatch(otherUid, otherUid) -- Uids are the same! self:SetUIDMatch(otherUid, otherUid) IncProgress() - coroutine.yield() + coroutine.yield(0.1) end + coroutine.yield(0.1) end if otherList.after then @@ -815,11 +817,12 @@ local function BuildUidMap(data, children, type) otherUidMap:SetUIDMatch(otherUid, otherUid) -- Uids are the same! self:SetUIDMatch(otherUid, otherUid) IncProgress() - coroutine.yield() + coroutine.yield(0.1) end + coroutine.yield(0.1) end end - coroutine.yield() + coroutine.yield(0.1) end for _, otherUid in ipairs(waitingForMatch) do @@ -839,7 +842,7 @@ local function BuildUidMap(data, children, type) otherUidMap:SetUIDMatch(otherUid, otherUid) -- Uids are the same! self:SetUIDMatch(otherUid, otherUid) IncProgress() - coroutine.yield() + coroutine.yield(0.1) end return #waitingForMatch > 0 @@ -1621,7 +1624,7 @@ local methods = { end end, Import = function(self) - OptionsPrivate.Private.dynFrame:AddAction("import", coroutine.create(function() + OptionsPrivate.Private.Threads:Add("import", coroutine.create(function() self:ImportImpl() end)) end, @@ -1634,27 +1637,34 @@ local methods = { self.closeButton:Disable() self.viewCodeButton:Disable() OptionsPrivate.Private.SetImporting(true) - + coroutine.yield(10, "init") -- Adjust UI self:ReleaseChildren() self:AddBasicInformationWidgets(pendingData.data, pendingData.sender) self:AddProgressWidgets() + local copies = {} local pendingPickData if userChoices.mode == "import" then + coroutine.yield(0.1, "start import") self:InitializeProgress(2 * (#pendingData.children + 1)) EnsureUniqueUid(pendingData.data) + coroutine.yield(0.1, "ensure unique uids") for i, child in ipairs(pendingData.children) do EnsureUniqueUid(child) + coroutine.yield(0.1, "ensure unique uids") end + coroutine.yield(1, "build uid map") local uidMap = BuildUidMap(pendingData.data, pendingData.children, "new") local phase2Order = {} + coroutine.yield(1, "start phase 1") self:ImportPhase1(uidMap, uidMap:GetRootUID(), phase2Order) - self:ImportPhase2(uidMap, phase2Order) + coroutine.yield(1, "start phase 2") + self:ImportPhase2(uidMap, phase2Order, copies) pendingPickData = { id = uidMap:GetIdFor(uidMap:GetRootUID()) @@ -1662,9 +1672,10 @@ local methods = { if #pendingData.children > 0 then pendingPickData.tabToShow = "group" end - + coroutine.yield(1, "update ui") OptionsPrivate.SortDisplayButtons() elseif userChoices.mode == "update" then + coroutine.yield(0.1, "start update") local onePhaseProgress = matchInfo.oldUidMap:GetTotalCount() + matchInfo.newUidMap:GetTotalCount() local IncProgress = function() self:IncProgress() end @@ -1677,9 +1688,9 @@ local methods = { -- On update, we won't match A_new to A_old, because A_old is outside the matched parent group -- Thus on import A_new needs to get its own uid -- On next import, the auras uids won't match either, there's not much we can do about that. + coroutine.yield(0.1, "ensure unique uids") matchInfo.newUidMap:EnsureUniqueIdOfUnmatched(nil, IncProgress) self:SetMinimumProgress(1 * onePhaseProgress) - coroutine.yield() local removeOldGroups = matchInfo.activeCategories.arrangement and userChoices.activeCategories.arrangement if userChoices.activeCategories.oldchildren or removeOldGroups then @@ -1709,6 +1720,7 @@ local methods = { if not userChoices.activeCategories.oldchildren then -- Keep old children matchInfo.newUidMap:InsertUnmatchedFrom(matchInfo.oldUidMap, IncProgress) + coroutine.yield(0.1, "keep old children done") end self:SetMinimumProgress(4 * onePhaseProgress) @@ -1775,17 +1787,26 @@ local methods = { end end + coroutine.yield(10, "prep done") local phase2Order = {} self:UpdatePhase1(structureUidMap, structureUidMap:GetRootUID(), GetPhase1Data, phase2Order) self:SetMinimumProgress(16 * onePhaseProgress) + coroutine.yield(10, " phase 1 done") + self:UpdatePhase2(structureUidMap, GetPhase2Data, phase2Order, copies) - self:UpdatePhase2(structureUidMap, GetPhase2Data, phase2Order) self:SetMinimumProgress(26 * onePhaseProgress) + coroutine.yield(10, " phase 2 done") + + local renameTries = 0 while(self:RenameAuras(targetNames)) do -- Try renaming again and again... + renameTries = renameTries + 1 + if renameTries % 10 == 0 then + coroutine.yield(0.1, "renaming auras") + end end self:SetMaxProgress() - coroutine.yield() + coroutine.yield(0.1, "renaming auras done") pendingPickData = { id = OptionsPrivate.Private.GetDataByUID(matchInfo.oldUidMap:GetRootUID()).id @@ -1796,7 +1817,7 @@ local methods = { OptionsPrivate.SortDisplayButtons() end - + coroutine.yield(0.1, "winding down") OptionsPrivate.Private.SetImporting(false) self.viewCodeButton:Enable() self.importButton:Enable() @@ -1809,6 +1830,12 @@ local methods = { OptionsPrivate.ClearPicks() WeakAuras.PickDisplay(pendingPickData.id, pendingPickData.tabToShow) end + OptionsPrivate.Private.Threads:Add("history_update", coroutine.create(function() + for _, copy in ipairs(copies) do + OptionsPrivate.Private.SetHistory(copy.uid, copy.data, copy.source) + coroutine.yield() + end + end), "background") end, -- This ensures that the id that we are adding is either -- same for existing uids @@ -1930,7 +1957,7 @@ local methods = { end end self:IncProgress() - coroutine.yield() + coroutine.yield(0.1, "remove unmatched old") return false end, RemoveUnmatchedNew = function(self, uidMap, uid, otherMap, removeAuras, removeGroups) @@ -1966,7 +1993,7 @@ local methods = { end end self:IncProgress() - coroutine.yield() + coroutine.yield(0.1, "remove unmatched new") return false end, UpdatePhase1 = function(self, structureUidMap, uid, GetPhase1Data, phase2Order) @@ -1980,7 +2007,7 @@ local methods = { WeakAuras.Add(data) WeakAuras.NewDisplayButton(data, true) self:IncProgress10() - coroutine.yield() + coroutine.yield(1, "adding phase 1 data") local children = structureUidMap:GetChildren(uid) local parentIsDynamicGroup = data.regionType == "dynamicgroup" @@ -1990,14 +2017,14 @@ local methods = { structureUidMap:SetParentIsDynamicGroup(childUid, parentIsDynamicGroup) end end, - UpdatePhase2 = function(self, structureUidMap, GetPhase2Data, phase2Order) + UpdatePhase2 = function(self, structureUidMap, GetPhase2Data, phase2Order, copies) for i = #phase2Order, 1, -1 do local uid = phase2Order[i] local data = GetPhase2Data(uid) data.preferToUpdate = true data.authorMode = nil WeakAuras.Add(data) - OptionsPrivate.Private.SetHistory(data.uid, data, "import") + table.insert(copies, {uid = uid, data = CopyTable(data), source = "update"}) local button = OptionsPrivate.GetDisplayButton(data.id) button:SetData(data) if (data.parent) then @@ -2051,14 +2078,14 @@ local methods = { uidMap:SetParentIsDynamicGroup(childUid, parentIsDynamicGroup) end end, - ImportPhase2 = function(self, uidMap, phase2Order) + ImportPhase2 = function(self, uidMap, phase2Order, copies) for i = #phase2Order, 1, -1 do local uid = phase2Order[i] local data = uidMap:GetPhase2Data(uid) data.preferToUpdate = false data.authorMode = nil WeakAuras.Add(data) - OptionsPrivate.Private.SetHistory(data.uid, data, "import") + table.insert(copies, {uid = uid, data = CopyTable(data), source = "import"}) local button = OptionsPrivate.GetDisplayButton(data.id) button:SetData(data) diff --git a/WeakAurasOptions/VersionCheck.lua b/WeakAurasOptions/VersionCheck.lua new file mode 100644 index 0000000..50c86d7 --- /dev/null +++ b/WeakAurasOptions/VersionCheck.lua @@ -0,0 +1,23 @@ +---@type string +local AddonName = ... +---@class Private +local Private = select(2, ...) + +local L = WeakAuras.L + +local optionsVersion = "@project-version@" +--@debug@ +optionsVersion = "Dev" +--@end-debug@ + +if optionsVersion ~= WeakAuras.versionString then + local message = string.format(L["The WeakAuras Options Addon version %s doesn't match the WeakAuras version %s. If you updated the addon while the game was running, try restarting World of Warcraft. Otherwise try reinstalling WeakAuras"], + optionsVersion, WeakAuras.versionString) + ---@diagnostic disable-next-line: duplicate-set-field + WeakAuras.IsLibsOk = function() return false end + ---@diagnostic disable-next-line: duplicate-set-field + WeakAuras.ToggleOptions = function() + WeakAuras.prettyPrint(message) + end + +end diff --git a/WeakAurasOptions/WeakAurasOptions.lua b/WeakAurasOptions/WeakAurasOptions.lua index d965491..59abb2f 100644 --- a/WeakAurasOptions/WeakAurasOptions.lua +++ b/WeakAurasOptions/WeakAurasOptions.lua @@ -567,45 +567,46 @@ local function OptionsFrame() end end -function WeakAuras.ToggleOptions(msg, Private) - if not Private then - return - end - if not OptionsPrivate.Private then - OptionsPrivate.Private = Private - Private.OptionsFrame = OptionsFrame - for _, fn in ipairs(OptionsPrivate.registerRegions) do - fn() +if not WeakAuras.ToggleOptions then + function WeakAuras.ToggleOptions(msg, Private) + if not Private then + return + end + if not OptionsPrivate.Private then + OptionsPrivate.Private = Private + Private.OptionsFrame = OptionsFrame + for _, fn in ipairs(OptionsPrivate.registerRegions) do + fn() + end + OptionsPrivate.Private.callbacks:RegisterCallback("AuraWarningsUpdated", function(event, uid) + local id = OptionsPrivate.Private.UIDtoID(uid) + if displayButtons[id] then + -- The button does not yet exists if a new aura is created + displayButtons[id]:UpdateWarning() + end + local data = Private.GetDataByUID(uid) + if data and data.parent then + local button = OptionsPrivate.GetDisplayButton(data.parent); + if button then + button:UpdateParentWarning() + end + end + end) + + OptionsPrivate.Private.callbacks:RegisterCallback("ScanForLoads", AfterScanForLoads) + OptionsPrivate.Private.callbacks:RegisterCallback("AboutToDelete", OnAboutToDelete) + OptionsPrivate.Private.callbacks:RegisterCallback("Rename", OnRename) + OptionsPrivate.Private.OpenUpdate = OptionsPrivate.OpenUpdate end - OptionsPrivate.Private.callbacks:RegisterCallback("AuraWarningsUpdated", function(event, uid) - local id = OptionsPrivate.Private.UIDtoID(uid) - if displayButtons[id] then - -- The button does not yet exists if a new aura is created - displayButtons[id]:UpdateWarning() - end - local data = Private.GetDataByUID(uid) - if data and data.parent then - local button = OptionsPrivate.GetDisplayButton(data.parent); - if button then - button:UpdateParentWarning() - end - end - end) - - OptionsPrivate.Private.callbacks:RegisterCallback("ScanForLoads", AfterScanForLoads) - OptionsPrivate.Private.callbacks:RegisterCallback("AboutToDelete", OnAboutToDelete) - OptionsPrivate.Private.callbacks:RegisterCallback("Rename", OnRename) - OptionsPrivate.Private.OpenUpdate = OptionsPrivate.OpenUpdate - end - - if(frame and frame:IsVisible()) then - WeakAuras.HideOptions(); - elseif (InCombatLockdown()) then - WeakAuras.prettyPrint(L["Options will open after combat ends."]) - reopenAfterCombat = true; - else - WeakAuras.ShowOptions(msg); + if(frame and frame:IsVisible()) then + WeakAuras.HideOptions(); + elseif (InCombatLockdown()) then + WeakAuras.prettyPrint(L["Options will open after combat ends."]) + reopenAfterCombat = true; + else + WeakAuras.ShowOptions(msg); + end end end @@ -722,9 +723,11 @@ local function LayoutDisplayButtons(msg) for id, button in pairs(displayButtons) do if OptionsPrivate.Private.loaded[id] then button:PriorityShow(1); + coroutine.yield() end end OptionsPrivate.Private.OptionsFrame().loadedButton:RecheckVisibility() + coroutine.yield() end OptionsPrivate.Private.ResumeAllDynamicGroups(suspended) @@ -757,11 +760,11 @@ local function LayoutDisplayButtons(msg) end local co2 = coroutine.create(func2); - OptionsPrivate.Private.dynFrame:AddAction("LayoutDisplayButtons2", co2); + OptionsPrivate.Private.Threads:Add("LayoutDisplayButtons2", co2); end local co1 = coroutine.create(func1); - OptionsPrivate.Private.dynFrame:AddAction("LayoutDisplayButtons1", co1); + OptionsPrivate.Private.Threads:Add("LayoutDisplayButtons1", co1); end function OptionsPrivate.DeleteAuras(auras, parents) @@ -809,7 +812,7 @@ function OptionsPrivate.DeleteAuras(auras, parents) end local co1 = coroutine.create(func1) - OptionsPrivate.Private.dynFrame:AddAction("Deleting Auras", co1) + OptionsPrivate.Private.Threads:Add("Deleting Auras", co1) end function WeakAuras.ShowOptions(msg) @@ -1566,7 +1569,7 @@ function OptionsPrivate.Drop(mainAura, target, action, area) end local co1 = coroutine.create(func1) - OptionsPrivate.Private.dynFrame:AddAction("Dropping Auras", co1) + OptionsPrivate.Private.Threads:Add("Dropping Auras", co1) end function OptionsPrivate.StartDrag(mainAura) diff --git a/WeakAurasOptions/WeakAurasOptions.toc b/WeakAurasOptions/WeakAurasOptions.toc index f762a63..ab47efc 100644 --- a/WeakAurasOptions/WeakAurasOptions.toc +++ b/WeakAurasOptions/WeakAurasOptions.toc @@ -17,6 +17,7 @@ embeds.xml locales.xml +VersionCheck.lua ForAllIndentsAndPurposes.lua RegionOptions\AuraBar.lua