from retail

This commit is contained in:
NoM0Re
2025-01-25 23:37:36 +01:00
parent 4a326118da
commit 667a2f3f50
34 changed files with 788 additions and 242 deletions
+14 -9
View File
@@ -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)
+4 -3
View File
@@ -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)
+3
View File
@@ -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]
+64
View File
@@ -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 = {
}
+15 -9
View File
@@ -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
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+95
View File
@@ -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.
Binary file not shown.
+170
View File
@@ -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
+19 -4
View File
@@ -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;
+2 -2
View File
@@ -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
}
+6 -4
View File
@@ -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)
+4 -3
View File
@@ -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"],
+143 -97
View File
@@ -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<string, threadPriority>
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
+3
View File
@@ -72,3 +72,6 @@ SubRegionTypes\Border.lua
SubRegionTypes\Glow.lua
SubRegionTypes\Tick.lua
SubRegionTypes\Model.lua
#Misc
DiscordList.lua
+10 -3
View File
@@ -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
+4 -5
View File
@@ -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 "";
+2 -2
View File
@@ -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
+1
View File
@@ -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
+14 -9
View File
@@ -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;
+91 -18
View File
@@ -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
@@ -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
+48 -21
View File
@@ -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)
+23
View File
@@ -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
+44 -41
View File
@@ -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)
+1
View File
@@ -17,6 +17,7 @@
embeds.xml
locales.xml
VersionCheck.lua
ForAllIndentsAndPurposes.lua
RegionOptions\AuraBar.lua