from retail

This commit is contained in:
NoM0Re
2025-01-26 03:47:13 +01:00
parent c0c78643e7
commit 4750b095d3
13 changed files with 210 additions and 122 deletions
+22 -10
View File
@@ -408,9 +408,13 @@ local function FindBestMatchData(time, id, triggernum, triggerInfo, matchedUnits
for index, auraData in pairs(unitData) do for index, auraData in pairs(unitData) do
local remCheck = true local remCheck = true
if triggerInfo.remainingFunc and auraData.expirationTime then if triggerInfo.remainingFunc and auraData.expirationTime then
local remaining = auraData.expirationTime - time if auraData.duration == 0 then
remCheck = triggerInfo.remainingFunc(remaining) remCheck = false
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck) else
local remaining = auraData.expirationTime - time
remCheck = triggerInfo.remainingFunc(remaining)
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck)
end
end end
if remCheck then if remCheck then
@@ -444,9 +448,13 @@ local function FindBestMatchDataForUnit(time, id, triggernum, triggerInfo, unit)
for index, auraData in pairs(matchDataByTrigger[id][triggernum][unit]) do for index, auraData in pairs(matchDataByTrigger[id][triggernum][unit]) do
local remCheck = true local remCheck = true
if triggerInfo.remainingFunc and auraData.expirationTime then if triggerInfo.remainingFunc and auraData.expirationTime then
local remaining = auraData.expirationTime - time if auraData.expirationTime == 0 then
remCheck = triggerInfo.remainingFunc(remaining) remCheck = false
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck) else
local remaining = auraData.expirationTime - time
remCheck = triggerInfo.remainingFunc(remaining)
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck)
end
end end
if remCheck then if remCheck then
@@ -1224,9 +1232,13 @@ local function UpdateTriggerState(time, id, triggernum)
for index, auraData in pairs(unitData) do for index, auraData in pairs(unitData) do
local remCheck = true local remCheck = true
if triggerInfo.remainingFunc and auraData.expirationTime then if triggerInfo.remainingFunc and auraData.expirationTime then
local remaining = auraData.expirationTime - time if auraData.expirationTime == 0 then
remCheck = triggerInfo.remainingFunc(remaining) remCheck = false
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck) else
local remaining = auraData.expirationTime - time
remCheck = triggerInfo.remainingFunc(remaining)
nextCheck = calculateNextCheck(triggerInfo.remainingCheck, remaining, auraData.expirationTime, nextCheck)
end
end end
if remCheck then if remCheck then
@@ -2445,7 +2457,7 @@ function BuffTrigger.Add(data)
local effectiveIgnoreInvisible = groupTrigger and trigger.ignoreInvisible local effectiveIgnoreInvisible = groupTrigger and trigger.ignoreInvisible
local effectiveHostility = (groupTrigger or 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 effectiveNameCheck = groupTrigger and trigger.useUnitName and trigger.unitName
local effectiveNpcId = trigger.unit == "nameplate" and trigger.useNpcId and Private.ExecEnv.ParseStringCheck(trigger.npcId) local effectiveNpcId = (trigger.unit == "nameplate" or trigger.unit == "boss") and trigger.useNpcId and Private.ExecEnv.ParseStringCheck(trigger.npcId)
if trigger.unit == "multi" then if trigger.unit == "multi" then
BuffTrigger.InitMultiAura() BuffTrigger.InitMultiAura()
+7 -4
View File
@@ -201,7 +201,7 @@ end
function Private.ExecEnv.CallCustomConditionTest(uid, testFunctionNumber, ...) function Private.ExecEnv.CallCustomConditionTest(uid, testFunctionNumber, ...)
local ok, result = pcall(Private.ExecEnv.conditionHelpers[uid].customTestFunctions[testFunctionNumber], ...) local ok, result = pcall(Private.ExecEnv.conditionHelpers[uid].customTestFunctions[testFunctionNumber], ...)
if not ok then if not ok then
Private.GetErrorHandlerUid(uid, L["Condition Custom Text"]) Private.GetErrorHandlerUid(uid, L["Condition Custom Test"])
elseif (ok) then elseif (ok) then
return result return result
end end
@@ -311,9 +311,9 @@ local function CreateTestForCondition(data, input, allConditionsTemplate, usedSt
remainingTime = "((" .. pausedString .. " and " .. remainingString .. ") or " .. remainingTime .. ")" remainingTime = "((" .. pausedString .. " and " .. remainingString .. ") or " .. remainingTime .. ")"
end end
if (op == "==") then if (op == "==") then
check = stateCheck .. stateVariableCheck .. "abs((" .. remainingTime .. "-" .. value .. ")" .. ") < 0.05" check = stateCheck .. stateVariableCheck .. varString .. "~= 0 and " .. "abs((" .. remainingTime .. "-" .. value .. ")" .. ") < 0.05"
else else
check = stateCheck .. stateVariableCheck .. remainingTime .. op .. value check = stateCheck .. stateVariableCheck .. varString .. "~= 0 and " .. remainingTime .. op .. value
end end
elseif (cType == "elapsedTimer" and value and op) then elseif (cType == "elapsedTimer" and value and op) then
if (op == "==") then if (op == "==") then
@@ -805,7 +805,10 @@ end
function Private.RunConditions(region, uid, hideRegion) function Private.RunConditions(region, uid, hideRegion)
if (checkConditions[uid]) then if (checkConditions[uid]) then
Private.ActivateAuraEnvironmentForRegion(region) Private.ActivateAuraEnvironmentForRegion(region)
checkConditions[uid](region, hideRegion); local ok = pcall(checkConditions[uid], region, hideRegion);
if not ok then
Private.GetErrorHandlerUid(uid, L["Execute Conditions"])
end
Private.ActivateAuraEnvironment() Private.ActivateAuraEnvironment()
end end
end end
+85 -48
View File
@@ -262,7 +262,7 @@ local function singleTest(arg, trigger, name, value, operator, use_exact)
end end
end end
function ConstructTest(trigger, arg, testGroups, preambleGroups) function ConstructTest(trigger, arg, preambleGroups)
local test local test
local preamble local preamble
local name = arg.name; local name = arg.name;
@@ -321,7 +321,7 @@ function ConstructTest(trigger, arg, testGroups, preambleGroups)
end end
end end
if not test or test == "(true)" or arg.testGroup and testGroups[arg.testGroup] then if not test or test == "(true)" then
return nil, preamble return nil, preamble
end end
@@ -356,7 +356,6 @@ function ConstructFunction(prototype, trigger)
local preambles = "\n" local preambles = "\n"
local orConjunctionGroups = {} local orConjunctionGroups = {}
local preambleGroups = {} local preambleGroups = {}
local testGroups = {}
if(prototype.init) then if(prototype.init) then
init = prototype.init(trigger); init = prototype.init(trigger);
else else
@@ -382,7 +381,7 @@ function ConstructFunction(prototype, trigger)
if (arg.store) then if (arg.store) then
tinsert(store, name); tinsert(store, name);
end end
local test, preamble = ConstructTest(trigger, arg, testGroups, preambleGroups); local test, preamble = ConstructTest(trigger, arg, preambleGroups);
if (test) then if (test) then
if(arg.required) then if(arg.required) then
tinsert(required, test); tinsert(required, test);
@@ -846,17 +845,43 @@ local function getGameEventFromComposedEvent(composedEvent)
return separatorPosition == nil and composedEvent or composedEvent:sub(1, separatorPosition - 1) return separatorPosition == nil and composedEvent or composedEvent:sub(1, separatorPosition - 1)
end end
local scannerFrame = CreateFrame("Frame")
scannerFrame.queue = {}
scannerFrame:Hide()
scannerFrame:SetScript("OnUpdate", function(self)
local todo = self.queue
self.queue = {}
for _, event in ipairs(todo) do
event.func(unpack(event.args))
end
-- there's a chance that a joker dispatched an event in in trigger code,
-- so the queue might already be populated
-- in that case, we'll process next frame by declining to hide
if #self.queue == 0 then
self:Hide()
end
end)
function scannerFrame:Queue(func, ...)
tinsert(self.queue, {func = func, args = {...}})
self:Show()
end
function Private.ScanEventsByID(event, id, ...) function Private.ScanEventsByID(event, id, ...)
if loaded_events[event] then if loaded_events[event] then
WeakAuras.ScanEvents(event, id, ...) Private.ScanEvents(event, id, ...)
end end
local eventWithID = event .. ":" .. id local eventWithID = event .. ":" .. id
if loaded_events[eventWithID] then if loaded_events[eventWithID] then
WeakAuras.ScanEvents(eventWithID, id, ...) Private.ScanEvents(eventWithID, id, ...)
end end
end end
function WeakAuras.ScanEvents(event, arg1, arg2, ...) function WeakAuras.ScanEventsByID(event, id, ...)
scannerFrame:Queue(Private.ScanEventsByID, event, id, ...)
end
function Private.ScanEvents(event, arg1, arg2, ...)
local system = getGameEventFromComposedEvent(event) local system = getGameEventFromComposedEvent(event)
Private.StartProfileSystem("generictrigger " .. system) Private.StartProfileSystem("generictrigger " .. system)
local event_list = loaded_events[event]; local event_list = loaded_events[event];
@@ -870,21 +895,25 @@ function WeakAuras.ScanEvents(event, arg1, arg2, ...)
Private.StopProfileSystem("generictrigger " .. system) Private.StopProfileSystem("generictrigger " .. system)
return; return;
end end
WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ...); Private.ScanEventsInternal(event_list, event, arg1, arg2, ...);
elseif (event == "COMBAT_LOG_EVENT_UNFILTERED_CUSTOM") then elseif (event == "COMBAT_LOG_EVENT_UNFILTERED_CUSTOM") then
-- This reverts the COMBAT_LOG_EVENT_UNFILTERED_CUSTOM workaround so that custom triggers that check the event argument will work as expected -- This reverts the COMBAT_LOG_EVENT_UNFILTERED_CUSTOM workaround so that custom triggers that check the event argument will work as expected
if(event == "COMBAT_LOG_EVENT_UNFILTERED_CUSTOM") then if(event == "COMBAT_LOG_EVENT_UNFILTERED_CUSTOM") then
event = "COMBAT_LOG_EVENT_UNFILTERED"; event = "COMBAT_LOG_EVENT_UNFILTERED";
end end
WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ...); Private.ScanEventsInternal(event_list, event, arg1, arg2, ...);
else else
WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ...); Private.ScanEventsInternal(event_list, event, arg1, arg2, ...);
end end
Private.StopProfileSystem("generictrigger " .. system) Private.StopProfileSystem("generictrigger " .. system)
end end
function WeakAuras.ScanUnitEvents(event, unit, ...) function WeakAuras.ScanEvents(event, arg1, arg2, ...)
scannerFrame:Queue(Private.ScanEvents, event, arg1, arg2, ...)
end
function Private.ScanUnitEvents(event, unit, ...)
Private.StartProfileSystem("generictrigger " .. event .. " " .. unit) Private.StartProfileSystem("generictrigger " .. event .. " " .. unit)
local unit_list = loaded_unit_events[unit] local unit_list = loaded_unit_events[unit]
if unit_list then if unit_list then
@@ -916,7 +945,11 @@ function WeakAuras.ScanUnitEvents(event, unit, ...)
Private.StopProfileSystem("generictrigger " .. event .. " " .. unit) Private.StopProfileSystem("generictrigger " .. event .. " " .. unit)
end end
function WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ... ) function WeakAuras.ScanUnitEvents(event, unit, ...)
scannerFrame:Queue(Private.ScanUnitEvents, event, unit, ...)
end
function Private.ScanEventsInternal(event_list, event, arg1, arg2, ... )
for id, triggers in pairs(event_list) do for id, triggers in pairs(event_list) do
Private.StartProfileAura(id); Private.StartProfileAura(id);
Private.ActivateAuraEnvironment(id); Private.ActivateAuraEnvironment(id);
@@ -940,6 +973,10 @@ function WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ... )
end end
end end
function WeakAuras.ScanEventsInternal(event_list, event, arg1, arg2, ... )
scannerFrame:Queue(Private.ScanEventsInternal, event_list, event, arg1, arg2, ...)
end
do do
local function RunTriggerFuncForDelay(id, triggernum, data, event, ...) local function RunTriggerFuncForDelay(id, triggernum, data, event, ...)
Private.StartProfileAura(id) Private.StartProfileAura(id)
@@ -1141,12 +1178,12 @@ function HandleEvent(frame, event, arg1, arg2, ...)
if not(WeakAuras.IsPaused()) then if not(WeakAuras.IsPaused()) then
if(event == "COMBAT_LOG_EVENT_UNFILTERED") then if(event == "COMBAT_LOG_EVENT_UNFILTERED") then
WeakAuras.ScanEvents(event, arg1, arg2, ...); Private.ScanEvents(event, arg1, arg2, ...);
-- This triggers the scanning of "hacked" COMBAT_LOG_EVENT_UNFILTERED events that were renamed in order to circumvent -- This triggers the scanning of "hacked" COMBAT_LOG_EVENT_UNFILTERED events that were renamed in order to circumvent
-- the "proper" COMBAT_LOG_EVENT_UNFILTERED checks -- the "proper" COMBAT_LOG_EVENT_UNFILTERED checks
WeakAuras.ScanEvents("COMBAT_LOG_EVENT_UNFILTERED_CUSTOM", arg1, arg2, ...); Private.ScanEvents("COMBAT_LOG_EVENT_UNFILTERED_CUSTOM", arg1, arg2, ...);
else else
WeakAuras.ScanEvents(event, arg1, arg2, ...); Private.ScanEvents(event, arg1, arg2, ...);
end end
end end
if (event == "PLAYER_ENTERING_WORLD") then if (event == "PLAYER_ENTERING_WORLD") then
@@ -1173,7 +1210,7 @@ function HandleUnitEvent(frame, event, unit, ...)
Private.StartProfileSystem("generictrigger " .. event .. " " .. unit); Private.StartProfileSystem("generictrigger " .. event .. " " .. unit);
if not(WeakAuras.IsPaused()) then if not(WeakAuras.IsPaused()) then
if (UnitIsUnit(unit, frame.unit)) then if (UnitIsUnit(unit, frame.unit)) then
WeakAuras.ScanUnitEvents(event, frame.unit, ...); Private.ScanUnitEvents(event, frame.unit, ...);
end end
end end
Private.StopProfileSystem("generictrigger " .. event .. " " .. unit); Private.StopProfileSystem("generictrigger " .. event .. " " .. unit);
@@ -1462,11 +1499,11 @@ function GenericTrigger.LoadDisplays(toLoad, loadEvent, ...)
-- Replay events that lead to loading, if we weren't already registered for them -- Replay events that lead to loading, if we weren't already registered for them
if (eventsToRegister[loadEvent]) then if (eventsToRegister[loadEvent]) then
WeakAuras.ScanEvents(loadEvent, ...); Private.ScanEvents(loadEvent, ...);
end end
local loadUnit = ... local loadUnit = ...
if loadUnit and unitEventsToRegister[loadUnit] and unitEventsToRegister[loadUnit][loadEvent] then if loadUnit and unitEventsToRegister[loadUnit] and unitEventsToRegister[loadUnit][loadEvent] then
WeakAuras.ScanUnitEvents(loadEvent, ...); Private.ScanUnitEvents(loadEvent, ...);
end end
wipe(eventsToRegister); wipe(eventsToRegister);
@@ -1871,7 +1908,7 @@ do
if not(updating) then if not(updating) then
update_frame:SetScript("OnUpdate", function(self, elapsed) update_frame:SetScript("OnUpdate", function(self, elapsed)
if not(WeakAuras.IsPaused()) then if not(WeakAuras.IsPaused()) then
WeakAuras.ScanEvents("FRAME_UPDATE", elapsed); Private.ScanEvents("FRAME_UPDATE", elapsed);
end end
end); end);
updating = true; updating = true;
@@ -1961,7 +1998,7 @@ do
elseif(hand == "ranged") then elseif(hand == "ranged") then
lastSwingRange, swingDurationRange = nil, nil; lastSwingRange, swingDurationRange = nil, nil;
end end
WeakAuras.ScanEvents("SWING_TIMER_END"); Private.ScanEvents("SWING_TIMER_END");
end end
local function swingTimerCLEUCheck(ts, event, sourceGUID, _, _, destGUID, _, _, ...) local function swingTimerCLEUCheck(ts, event, sourceGUID, _, _, destGUID, _, _, ...)
@@ -2005,7 +2042,7 @@ do
offTimer = timer:ScheduleTimer(swingEnd, offSpeed, "off"); offTimer = timer:ScheduleTimer(swingEnd, offSpeed, "off");
end end
end end
WeakAuras.ScanEvents(event); Private.ScanEvents(event);
end end
elseif (destGUID == selfGUID and (select(1, ...) == "PARRY" or select(4, ...) == "PARRY")) then elseif (destGUID == selfGUID and (select(1, ...) == "PARRY" or select(4, ...) == "PARRY")) then
if (lastSwingMain) then if (lastSwingMain) then
@@ -2014,12 +2051,12 @@ do
timer:CancelTimer(mainTimer); timer:CancelTimer(mainTimer);
mainTimer = timer:ScheduleTimer(swingEnd, timeLeft - 0.4 * swingDurationMain, "main"); mainTimer = timer:ScheduleTimer(swingEnd, timeLeft - 0.4 * swingDurationMain, "main");
mainSwingOffset = 0.4 * swingDurationMain mainSwingOffset = 0.4 * swingDurationMain
WeakAuras.ScanEvents("SWING_TIMER_CHANGE"); Private.ScanEvents("SWING_TIMER_CHANGE");
elseif (timeLeft > 0.2 * swingDurationMain) then elseif (timeLeft > 0.2 * swingDurationMain) then
timer:CancelTimer(mainTimer); timer:CancelTimer(mainTimer);
mainTimer = timer:ScheduleTimer(swingEnd, timeLeft - 0.2 * swingDurationMain, "main"); mainTimer = timer:ScheduleTimer(swingEnd, timeLeft - 0.2 * swingDurationMain, "main");
mainSwingOffset = 0.2 * swingDurationMain mainSwingOffset = 0.2 * swingDurationMain
WeakAuras.ScanEvents("SWING_TIMER_CHANGE"); Private.ScanEvents("SWING_TIMER_CHANGE");
end end
end end
end end
@@ -2039,7 +2076,7 @@ do
local timeLeft = (lastSwingMain + swingDurationMain - GetTime()) * multiplier local timeLeft = (lastSwingMain + swingDurationMain - GetTime()) * multiplier
swingDurationMain = mainSpeedNew swingDurationMain = mainSpeedNew
mainTimer = timer:ScheduleTimer(swingEnd, timeLeft, "main") mainTimer = timer:ScheduleTimer(swingEnd, timeLeft, "main")
WeakAuras.ScanEvents("SWING_TIMER_CHANGE") Private.ScanEvents("SWING_TIMER_CHANGE")
end end
end end
if lastSwingOff then if lastSwingOff then
@@ -2049,7 +2086,7 @@ do
local timeLeft = (lastSwingOff + swingDurationOff - GetTime()) * multiplier local timeLeft = (lastSwingOff + swingDurationOff - GetTime()) * multiplier
swingDurationOff = offSpeedNew swingDurationOff = offSpeedNew
offTimer = timer:ScheduleTimer(swingEnd, timeLeft, "off") offTimer = timer:ScheduleTimer(swingEnd, timeLeft, "off")
WeakAuras.ScanEvents("SWING_TIMER_CHANGE") Private.ScanEvents("SWING_TIMER_CHANGE")
end end
end end
mainSpeed, offSpeed = mainSpeedNew, offSpeedNew mainSpeed, offSpeed = mainSpeedNew, offSpeedNew
@@ -2072,7 +2109,7 @@ do
event = "SWING_TIMER_START"; event = "SWING_TIMER_START";
end end
mainTimer = timer:ScheduleTimer(swingEnd, mainSpeed, "main"); mainTimer = timer:ScheduleTimer(swingEnd, mainSpeed, "main");
WeakAuras.ScanEvents(event); Private.ScanEvents(event);
elseif Private.reset_ranged_swing_spells[spell] then elseif Private.reset_ranged_swing_spells[spell] then
local event; local event;
local currentTime = GetTime(); local currentTime = GetTime();
@@ -2086,14 +2123,14 @@ do
lastSwingRange = currentTime; lastSwingRange = currentTime;
swingDurationRange = speed; swingDurationRange = speed;
rangeTimer = timer:ScheduleTimer(swingEnd, speed, "ranged"); rangeTimer = timer:ScheduleTimer(swingEnd, speed, "ranged");
WeakAuras.ScanEvents(event); Private.ScanEvents(event);
end end
elseif event == "UNIT_SPELLCAST_START" then elseif event == "UNIT_SPELLCAST_START" then
-- pause swing timer -- pause swing timer
casting = true casting = true
lastSwingMain, swingDurationMain, mainSwingOffset = nil, nil, nil lastSwingMain, swingDurationMain, mainSwingOffset = nil, nil, nil
lastSwingOff, swingDurationOff = nil, nil lastSwingOff, swingDurationOff = nil, nil
WeakAuras.ScanEvents("SWING_TIMER_END") Private.ScanEvents("SWING_TIMER_END")
end end
Private.StopProfileSystem("generictrigger swing"); Private.StopProfileSystem("generictrigger swing");
end end
@@ -2187,7 +2224,7 @@ do
gcdEndCheck = 0; gcdEndCheck = 0;
end end
if(event and not WeakAuras.IsPaused()) then if(event and not WeakAuras.IsPaused()) then
WeakAuras.ScanEvents(event); Private.ScanEvents(event);
end end
end end
@@ -2371,7 +2408,7 @@ do
gcdSpellName = name; gcdSpellName = name;
gcdSpellIcon = icon; gcdSpellIcon = icon;
if not WeakAuras.IsPaused() then if not WeakAuras.IsPaused() then
WeakAuras.ScanEvents("GCD_UPDATE") Private.ScanEvents("GCD_UPDATE")
end end
end end
end end
@@ -2482,7 +2519,7 @@ do
runeCdHandles[id] = nil; runeCdHandles[id] = nil;
runeCdDurs[id] = nil; runeCdDurs[id] = nil;
runeCdExps[id] = nil; runeCdExps[id] = nil;
WeakAuras.ScanEvents("RUNE_COOLDOWN_READY", id); Private.ScanEvents("RUNE_COOLDOWN_READY", id);
end end
local function ItemCooldownFinished(id) local function ItemCooldownFinished(id)
@@ -2521,7 +2558,7 @@ do
runeCdDurs[id] = duration; runeCdDurs[id] = duration;
runeCdExps[id] = endTime; runeCdExps[id] = endTime;
runeCdHandles[id] = timer:ScheduleTimer(RuneCooldownFinished, endTime - time, id); runeCdHandles[id] = timer:ScheduleTimer(RuneCooldownFinished, endTime - time, id);
WeakAuras.ScanEvents("RUNE_COOLDOWN_STARTED", id); Private.ScanEvents("RUNE_COOLDOWN_STARTED", id);
elseif(runeCdExps[id] ~= endTime) then elseif(runeCdExps[id] ~= endTime) then
-- Cooldown is now different -- Cooldown is now different
if(runeCdHandles[id]) then if(runeCdHandles[id]) then
@@ -2530,7 +2567,7 @@ do
runeCdDurs[id] = duration; runeCdDurs[id] = duration;
runeCdExps[id] = endTime; runeCdExps[id] = endTime;
runeCdHandles[id] = timer:ScheduleTimer(RuneCooldownFinished, endTime - time, id); runeCdHandles[id] = timer:ScheduleTimer(RuneCooldownFinished, endTime - time, id);
WeakAuras.ScanEvents("RUNE_COOLDOWN_CHANGED", id); Private.ScanEvents("RUNE_COOLDOWN_CHANGED", id);
end end
elseif(startTime > 0 and duration > 0) then elseif(startTime > 0 and duration > 0) then
-- GCD, do nothing -- GCD, do nothing
@@ -3098,7 +3135,7 @@ function WeakAuras.WatchUnitChange(unit)
handleEvent[event](unit, eventsToSend) handleEvent[event](unit, eventsToSend)
-- send events -- send events
for event, unit in pairs(eventsToSend) do for event, unit in pairs(eventsToSend) do
WeakAuras.ScanEvents(event, unit) Private.ScanEvents(event, unit)
end end
Private.StopProfileSystem("generictrigger unit change"); Private.StopProfileSystem("generictrigger unit change");
@@ -3269,14 +3306,14 @@ do
end end
rw_icon = GetInventoryItemTexture("player", rw) rw_icon = GetInventoryItemTexture("player", rw)
end end
WeakAuras.ScanEvents("TENCH_UPDATE"); Private.ScanEvents("TENCH_UPDATE");
Private.StopProfileSystem("generictrigger temporary enchant"); Private.StopProfileSystem("generictrigger temporary enchant");
end end
tenchFrame:SetScript("OnEvent", function(_, unit, ...) tenchFrame:SetScript("OnEvent", function(_, unit, ...)
if unit and unit ~= "player" then return end if unit and unit ~= "player" then return end
Private.StartProfileSystem("generictrigger temporary enchant"); Private.StartProfileSystem("generictrigger temporary enchant");
timer:ScheduleTimer(tenchUpdate, 0.1); timer:ScheduleTimer(tenchUpdate, 0.1)
Private.StopProfileSystem("generictrigger temporary enchant"); Private.StopProfileSystem("generictrigger temporary enchant");
end); end);
@@ -3308,7 +3345,7 @@ do
petFrame:SetScript("OnEvent", function(_, event, unit) petFrame:SetScript("OnEvent", function(_, event, unit)
if unit ~= "player" then return end if unit ~= "player" then return end
Private.StartProfileSystem("generictrigger pet update") Private.StartProfileSystem("generictrigger pet update")
WeakAuras.ScanEvents("PET_UPDATE", "pet") Private.ScanEvents("PET_UPDATE", "pet")
Private.StopProfileSystem("generictrigger pet update") Private.StopProfileSystem("generictrigger pet update")
end) end)
end end
@@ -3380,7 +3417,7 @@ do
or (newTargetGUID ~= nil and targetGUID ~= newTargetGUID) or (newTargetGUID ~= nil and targetGUID ~= newTargetGUID)
then then
nameplateTargets[unit] = newTargetGUID or true nameplateTargets[unit] = newTargetGUID or true
WeakAuras.ScanEvents("WA_UNIT_TARGET_NAME_PLATE", unit) Private.ScanEvents("WA_UNIT_TARGET_NAME_PLATE", unit)
end end
end end
throttle_update = tick_throttle throttle_update = tick_throttle
@@ -3411,7 +3448,7 @@ do
elapsed = elapsed + elaps elapsed = elapsed + elaps
if(isMounted ~= IsMounted()) then if(isMounted ~= IsMounted()) then
isMounted = IsMounted(); isMounted = IsMounted();
WeakAuras.ScanEvents("MOUNTED_UPDATE"); Private.ScanEvents("MOUNTED_UPDATE");
mountedFrame:SetScript("OnUpdate", nil); mountedFrame:SetScript("OnUpdate", nil);
end end
if(elapsed > delay) then if(elapsed > delay) then
@@ -3442,7 +3479,7 @@ do
local speed = GetUnitSpeed("player") local speed = GetUnitSpeed("player")
if speed ~= playerMovingFrame.speed then if speed ~= playerMovingFrame.speed then
playerMovingFrame.speed = speed playerMovingFrame.speed = speed
WeakAuras.ScanEvents("PLAYER_MOVE_SPEED_UPDATE") Private.ScanEvents("PLAYER_MOVE_SPEED_UPDATE")
end end
Private.StopProfileSystem("generictrigger player moving"); Private.StopProfileSystem("generictrigger player moving");
end end
@@ -3480,14 +3517,14 @@ do
Private.StartProfileSystem("nameplatetrigger") Private.StartProfileSystem("nameplatetrigger")
local name = gsub(self.nameText:GetText() or "", FSPAT, "") local name = gsub(self.nameText:GetText() or "", FSPAT, "")
visibleNameplates[self] = name visibleNameplates[self] = name
WeakAuras.ScanEvents("NP_SHOW", self, name) Private.ScanEvents("NP_SHOW", self, name)
Private.StopProfileSystem("nameplatetrigger") Private.StopProfileSystem("nameplatetrigger")
end end
local function nameplateHide(self) local function nameplateHide(self)
Private.StartProfileSystem("nameplatetrigger") Private.StartProfileSystem("nameplatetrigger")
visibleNameplates[self] = nil visibleNameplates[self] = nil
WeakAuras.ScanEvents("NP_HIDE", self, gsub(self.nameText:GetText() or "", FSPAT, "")) Private.ScanEvents("NP_HIDE", self, gsub(self.nameText:GetText() or "", FSPAT, ""))
Private.StopProfileSystem("nameplatetrigger") Private.StopProfileSystem("nameplatetrigger")
end end
@@ -3549,8 +3586,8 @@ function WeakAuras.RegisterItemCountWatch()
itemCountWatchFrame:SetScript("OnEvent", function(_, _, unit) itemCountWatchFrame:SetScript("OnEvent", function(_, _, unit)
if unit ~= "player" then return end if unit ~= "player" then return end
Private.StartProfileSystem("generictrigger item count"); Private.StartProfileSystem("generictrigger item count");
timer:ScheduleTimer(WeakAuras.ScanEvents, 0.2, "ITEM_COUNT_UPDATE"); timer:ScheduleTimer(Private.ScanEvents, 0.2, "ITEM_COUNT_UPDATE");
timer:ScheduleTimer(WeakAuras.ScanEvents, 0.5, "ITEM_COUNT_UPDATE"); timer:ScheduleTimer(Private.ScanEvents, 0.5, "ITEM_COUNT_UPDATE");
Private.StopProfileSystem("generictrigger item count"); Private.StopProfileSystem("generictrigger item count");
end); end);
end end
@@ -3616,7 +3653,7 @@ do
local function doScan(fireTime, event) local function doScan(fireTime, event)
scheduled_scans[event][fireTime] = nil; scheduled_scans[event][fireTime] = nil;
WeakAuras.ScanEvents(event); Private.ScanEvents(event);
end end
function Private.ExecEnv.ScheduleScan(fireTime, event) function Private.ExecEnv.ScheduleScan(fireTime, event)
event = event or "COOLDOWN_REMAINING_CHECK" event = event or "COOLDOWN_REMAINING_CHECK"
@@ -3632,7 +3669,7 @@ do
local function doCastScan(firetime, unit) local function doCastScan(firetime, unit)
scheduled_scans[unit][firetime] = nil; scheduled_scans[unit][firetime] = nil;
WeakAuras.ScanEvents("CAST_REMAINING_CHECK_" .. string.lower(unit), unit); Private.ScanEvents("CAST_REMAINING_CHECK_" .. string.lower(unit), unit);
end end
function Private.ExecEnv.ScheduleCastCheck(fireTime, unit) function Private.ExecEnv.ScheduleCastCheck(fireTime, unit)
@@ -3820,10 +3857,10 @@ function GenericTrigger.SetToolTip(trigger, state)
local prototype = GenericTrigger.GetPrototype(trigger) local prototype = GenericTrigger.GetPrototype(trigger)
if prototype then if prototype then
if prototype.hasSpellID then if prototype.hasSpellID then
GameTooltip:SetSpellByID(trigger.spellName); GameTooltip:SetSpellByID(trigger.spellName or 0);
return true return true
elseif prototype.hasItemID then elseif prototype.hasItemID then
GameTooltip:SetHyperlink("item:"..trigger.itemName..":0:0:0:0:0:0:0") GameTooltip:SetHyperlink("item:"..(trigger.itemName or 0)..":0:0:0:0:0:0:0")
return true return true
end end
end end
+20
View File
@@ -1703,6 +1703,26 @@ function Private.Modernize(data, oldSnapshot)
fixData(data.load, loadFix) fixData(data.load, loadFix)
end]] end]]
if data.internalVersion < 79 then
if data.triggers then
for _, triggerData in ipairs(data.triggers) do
local trigger = triggerData.trigger
if trigger and trigger.type == "unit" and trigger.event == "Unit Characteristics" then
if trigger.use_ignoreDead then
if trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" then
trigger.use_dead = false
else
-- since this option was previously only available for group units,
-- nil it out if the unit isn't group to avoid surprises from vestigial data
trigger.use_dead = nil
end
end
trigger.use_ignoreDead = nil
end
end
end
end
data.internalVersion = max(data.internalVersion or 0, WeakAuras.InternalVersion()) data.internalVersion = max(data.internalVersion or 0, WeakAuras.InternalVersion())
end end
+40 -33
View File
@@ -1592,6 +1592,15 @@ Private.event_prototypes = {
test = "true", test = "true",
init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''" init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''"
}, },
{
name = "dead",
display = L["Dead"],
type = "tristate",
width = WeakAuras.doubleWidth,
init = "UnitIsDeadOrGhost(unit)",
store = true,
conditionType = "bool",
},
{ {
name = "ignoreSelf", name = "ignoreSelf",
display = L["Ignore Self"], display = L["Ignore Self"],
@@ -1602,16 +1611,6 @@ Private.event_prototypes = {
end, end,
init = "not UnitIsUnit(\"player\", unit)" init = "not UnitIsUnit(\"player\", unit)"
}, },
{
name = "ignoreDead",
display = L["Ignore Dead"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsDeadOrGhost(unit)"
},
{ {
name = "ignoreDisconnected", name = "ignoreDisconnected",
display = L["Ignore Disconnected"], display = L["Ignore Disconnected"],
@@ -2895,7 +2894,6 @@ Private.event_prototypes = {
preambleAdd = "spellChecker:AddExact(%q)" preambleAdd = "spellChecker:AddExact(%q)"
}, },
test = "spellChecker:Check(spellId)", test = "spellChecker:Check(spellId)",
testGroup = "spell",
conditionType = "number", conditionType = "number",
type = "spell", type = "spell",
showExactOption = false, showExactOption = false,
@@ -2918,7 +2916,6 @@ Private.event_prototypes = {
preambleAdd = "spellChecker:AddName(%q)" preambleAdd = "spellChecker:AddName(%q)"
}, },
test = "spellChecker:Check(spellId)", test = "spellChecker:Check(spellId)",
testGroup = "spell",
conditionType = "string" conditionType = "string"
}, },
{ {
@@ -5380,7 +5377,8 @@ Private.event_prototypes = {
progressType = "timed" progressType = "timed"
}, },
-- fixing later -- fixing later
--[[["Spell Cast Succeeded"] = { --[[
["Spell Cast Succeeded"] = {
type = "event", type = "event",
events = function(trigger) events = function(trigger)
local result = {} local result = {}
@@ -5391,7 +5389,6 @@ Private.event_prototypes = {
name = L["Spell Cast Succeeded"], name = L["Spell Cast Succeeded"],
statesParameter = "unit", statesParameter = "unit",
args = { args = {
{},
{ {
name = "unit", name = "unit",
init = "arg", init = "arg",
@@ -5406,39 +5403,49 @@ Private.event_prototypes = {
end end
}, },
{ {
name = "spellName", },
type = "string", { -- castGUID
init = "arg",
test = "true",
store = true,
hidden = true
}, },
{ {
name = "rank", name = "spellNames",
type = "string", display = L["Name(s)"],
init = "arg", type = "spell",
test = "true", multiEntry = {
store = true, operator = "preamble",
hidden = true preambleAdd = "spellChecker:AddName(%q)"
},
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
preambleGroup = "spell",
test = "spellChecker:Check(spellId)",
noValidation = true,
}, },
{ {
name = "spellId", name = "spellId",
display = L["Spell Id"], display = L["Exact Spell ID(s)"],
type = "string", type = "spell",
init = "arg",
store = true, store = true,
conditionType = "number" multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddExact(%q)"
},
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
preambleGroup = "spell",
test = "spellChecker:Check(spellId)",
conditionType = "number",
noProgressSource = true
}, },
{ {
name = "icon", name = "icon",
hidden = true, hidden = true,
init = "select(3, GetSpellInfo(spellId))", init = "GetSpellIcon(spellId or 0)",
store = true, store = true,
test = "true" test = "true"
}, },
{ {
name = "name", name = "name",
hidden = true, hidden = true,
init = "GetSpellInfo(spellId)", init = "GetSpellInfo(spellId or 0)",
store = true, store = true,
test = "true" test = "true"
}, },
@@ -5447,7 +5454,8 @@ Private.event_prototypes = {
delayEvents = true, delayEvents = true,
timedrequired = true, timedrequired = true,
progressType = "timed" progressType = "timed"
},]] },
]]
["Ready Check"] = { ["Ready Check"] = {
type = "event", type = "event",
events = { events = {
@@ -6188,7 +6196,6 @@ Private.event_prototypes = {
operator = "preamble", operator = "preamble",
preambleAdd = "spellChecker:AddName(%q)" preambleAdd = "spellChecker:AddName(%q)"
}, },
testGroup = "spell",
test = "spellChecker:CheckName(spell)", test = "spellChecker:CheckName(spell)",
noValidation = true, noValidation = true,
}, },
+16 -8
View File
@@ -1,6 +1,6 @@
local AddonName, Private = ... local AddonName, Private = ...
local internalVersion = 78 local internalVersion = 79
-- Lua APIs -- Lua APIs
local insert = table.insert local insert = table.insert
@@ -2205,14 +2205,22 @@ function Private.AddMany(tbl, takeSnapshots)
copies[data.uid] = CopyTable(data) copies[data.uid] = CopyTable(data)
coroutine.yield(200, "addmany prepare snapshot") coroutine.yield(200, "addmany prepare snapshot")
end end
Private.Threads:Add("snapshot", coroutine.create(function() if #order > 0 then
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."]) Private.Threads:Add("snapshot", coroutine.create(function()
for uid, data in pairs(copies) do 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."])
Private.SetMigrationSnapshot(uid, data) for uid, data in pairs(copies) do
coroutine.yield(200, "snapshot") Private.SetMigrationSnapshot(uid, data)
coroutine.yield(200, "snapshot")
end
prettyPrint(L["Rollback snapshot is complete. Thank you for your patience!"])
end), 'normal')
else
if next(WeakAuras.LoadFromArchive("Repository", "migration").stores) ~= nil then
timer:ScheduleTimer(function()
prettyPrint(L["WeakAuras has detected empty settings. If this is unexpected, ask for assitance on https://discord.gg/weakauras."])
end, 1)
end end
prettyPrint(L["Rollback snapshot is complete. Thank you for your patience!"]) end
end), 'normal')
end end
local groups = {} local groups = {}
+3 -3
View File
@@ -844,14 +844,14 @@ local function GetBuffTriggerOptions(data, triggernum)
name = L["Filter by Npc ID"], name = L["Filter by Npc ID"],
order = 69.31, order = 69.31,
hidden = function() return hidden = function() return
not (trigger.type == "aura2" and trigger.unit == "nameplate") not (trigger.type == "aura2" and (trigger.unit == "nameplate" or trigger.unit == "boss"))
end end
}, },
npcId = { npcId = {
type = "input", type = "input",
width = WeakAuras.normalWidth, width = WeakAuras.normalWidth,
name = L["Npc ID"], name = L["Npc ID"],
hidden = function() return not (trigger.type == "aura2" and trigger.unit == "nameplate" and trigger.useNpcId) end, hidden = function() return not (trigger.type == "aura2" and (trigger.unit == "nameplate" or trigger.unit == "boss") and trigger.useNpcId) end,
order = 69.32, order = 69.32,
desc = L["Supports multiple entries, separated by commas"] desc = L["Supports multiple entries, separated by commas"]
}, },
@@ -860,7 +860,7 @@ local function GetBuffTriggerOptions(data, triggernum)
name = "", name = "",
order = 69.33, order = 69.33,
width = WeakAuras.normalWidth, width = WeakAuras.normalWidth,
hidden = function() return not (trigger.type == "aura2" and trigger.unit == "nameplate" and not trigger.useNpcId) end hidden = function() return not (trigger.type == "aura2" and (trigger.unit == "nameplate" or trigger.unit == "boss") and not trigger.useNpcId) end
}, },
ignoreSelf = { ignoreSelf = {
+1 -1
View File
@@ -1232,7 +1232,7 @@ local function PositionOptions(id, data, _, hideWidthHeight, disableSelfPoint, g
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
local positionOptions = { local positionOptions = {
__title = L["Position Settings"], __title = L["Position and Size Settings"],
__order = metaOrder, __order = metaOrder,
__collapsed = true, __collapsed = true,
width = { width = {
-2
View File
@@ -401,8 +401,6 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA
conditions[i].changes[j].value = {}; conditions[i].changes[j].value = {};
end end
conditions[i].changes[j].value[property] = v; conditions[i].changes[j].value[property] = v;
WeakAuras.Add(data)
WeakAuras.ClearAndUpdateOptions(data.id) WeakAuras.ClearAndUpdateOptions(data.id)
end end
end end
+6 -3
View File
@@ -636,7 +636,7 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum
hidden = disabled or hidden, hidden = disabled or hidden,
image = function() image = function()
local value = getValue(trigger, "use_"..realname, realname, multiEntry, entryNumber) local value = getValue(trigger, "use_"..realname, realname, multiEntry, entryNumber)
if value then if type(value) == "number" or type(value) == "string" then
if(arg.type == "aura") then if(arg.type == "aura") then
local icon = spellCache.GetIcon(value); local icon = spellCache.GetIcon(value);
return icon and tostring(icon) or "", 18, 18; return icon and tostring(icon) or "", 18, 18;
@@ -653,6 +653,9 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum
end, end,
disabled = function() disabled = function()
local value = getValue(trigger, nil, realname, multiEntry, entryNumber) local value = getValue(trigger, nil, realname, multiEntry, entryNumber)
if type(value) ~= "number" and type(value) ~= "string" then
return true
end
return not ((arg.type == "aura" and value and spellCache.GetIcon(value)) or (arg.type == "spell" and value and GetSpellInfo(value)) or (arg.type == "item" and value and GetItemIcon(value))) return not ((arg.type == "aura" and value and spellCache.GetIcon(value)) or (arg.type == "spell" and value and GetSpellInfo(value)) or (arg.type == "item" and value and GetItemIcon(value)))
end end
}; };
@@ -690,7 +693,7 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum
end end
elseif(arg.type == "spell") then elseif(arg.type == "spell") then
local useExactSpellId = (arg.showExactOption and getValue(trigger, nil, "use_exact_"..realname, multiEntry, entryNumber)) local useExactSpellId = (arg.showExactOption and getValue(trigger, nil, "use_exact_"..realname, multiEntry, entryNumber))
if value and value ~= "" then if value and value ~= "" and (type(value) == "number" or type(value) == "string") then
local spellID = WeakAuras.SafeToNumber(value) local spellID = WeakAuras.SafeToNumber(value)
if spellID then if spellID then
local spellName = GetSpellInfo(WeakAuras.SafeToNumber(value)) local spellName = GetSpellInfo(WeakAuras.SafeToNumber(value))
@@ -878,7 +881,7 @@ function OptionsPrivate.ConstructOptions(prototype, data, startorder, triggernum
values = WeakAuras[arg.values]; values = WeakAuras[arg.values];
end end
end end
local sortOrder = arg.sorted and OptionsPrivate.Private.SortOrderForValues(values) or nil local sortOrder = arg.sorted and (arg.sortOrder or OptionsPrivate.Private.SortOrderForValues(values)) or nil
options[name..suffix] = { options[name..suffix] = {
type = "select", type = "select",
width = WeakAuras.normalWidth, width = WeakAuras.normalWidth,
@@ -152,7 +152,7 @@ local function ConstructIconPicker(frame)
else else
self.givenPath = {}; self.givenPath = {};
for child in OptionsPrivate.Private.TraverseLeafsOrAura(baseObject) do for child in OptionsPrivate.Private.TraverseLeafsOrAura(baseObject) do
if(child) then if child and paths[child.id] then
local value = valueFromPath(child, paths[child.id]) local value = valueFromPath(child, paths[child.id])
self.givenPath[child.id] = value or ""; self.givenPath[child.id] = value or "";
end end
+8 -8
View File
@@ -182,15 +182,15 @@ local function recurseUpdate(data, chunk)
end end
end end
local function RecurseDiff(ours, theirs, ignoredForDiffChecking) local function RecurseDiff(ours, theirs, ignored)
local diff, seen, same = {}, {}, true local diff, seen, same = {}, {}, true
for key, ourVal in pairs(ours) do for key, ourVal in pairs(ours) do
if not (type(ignoredForDiffChecking) == "table" and ignoredForDiffChecking[key] == true) then local ignoredVal = ignored and ignored[key]
if not ignoredVal or type(ignoredVal) == "table" then
seen[key] = true seen[key] = true
local theirVal = theirs[key] local theirVal = theirs[key]
if type(ourVal) == "table" and type(theirVal) == "table" then if type(ourVal) == "table" and type(theirVal) == "table" then
local diffVal = RecurseDiff(ourVal, theirVal, local diffVal = RecurseDiff(ourVal, theirVal, type(ignoredVal) == "table" and ignoredVal or nil)
type(ignoredForDiffChecking) == table and ignoredForDiffChecking[key] or nil)
if diffVal then if diffVal then
diff[key] = diffVal diff[key] = diffVal
same = false same = false
@@ -207,7 +207,7 @@ local function RecurseDiff(ours, theirs, ignoredForDiffChecking)
end end
end end
for key, theirVal in pairs(theirs) do for key, theirVal in pairs(theirs) do
if not seen[key] and not (type(ignoredForDiffChecking) == "table" and ignoredForDiffChecking[key] == true) then if not seen[key] and not (type(ignored) == "table" and ignored[key] == true) then
diff[key] = theirVal diff[key] = theirVal
same = false same = false
end end
@@ -243,13 +243,13 @@ local function DebugPrintDiff(diff, id, uid)
end end
local function Diff(ours, theirs) local function Diff(ours, theirs)
local ignoredForDiffChecking = WeakAuras.Mixin({}, OptionsPrivate.Private.internal_fields, local ignored = WeakAuras.Mixin({}, OptionsPrivate.Private.internal_fields,
OptionsPrivate.Private.non_transmissable_fields) OptionsPrivate.Private.non_transmissable_fields)
-- generates a diff which WeakAuras.Update can use -- generates a diff which WeakAuras.Update can use
local debug = false local debug = false
if not ours or not theirs then return end if not ours or not theirs then return end
local diff = RecurseDiff(ours, theirs, ignoredForDiffChecking) local diff = RecurseDiff(ours, theirs, ignored)
if diff then if diff then
if debug then if debug then
DebugPrintDiff(diff, theirs.id, theirs.uid) DebugPrintDiff(diff, theirs.id, theirs.uid)
+1 -1
View File
@@ -545,7 +545,7 @@ local function OnRename(event, uid, oldid, newid)
end end
OptionsPrivate.StopGrouping() OptionsPrivate.StopGrouping()
OptionsPrivate.SortDisplayButtons() OptionsPrivate.SortDisplayButtons(nil, true)
frame:OnRename(uid, oldid, newid) frame:OnRename(uid, oldid, newid)