from retail
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 = {
|
||||
}
|
||||
@@ -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.
@@ -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.
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -72,3 +72,6 @@ SubRegionTypes\Border.lua
|
||||
SubRegionTypes\Glow.lua
|
||||
SubRegionTypes\Tick.lua
|
||||
SubRegionTypes\Model.lua
|
||||
|
||||
#Misc
|
||||
DiscordList.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
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
embeds.xml
|
||||
locales.xml
|
||||
|
||||
VersionCheck.lua
|
||||
ForAllIndentsAndPurposes.lua
|
||||
|
||||
RegionOptions\AuraBar.lua
|
||||
|
||||
Reference in New Issue
Block a user