mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-22 15:46:59 +00:00
v1.0.5
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
MTH_CONST = MTH_CONST or {}
|
||||
MTH_CONST.version = MTH_CONST.version or "1.0.4"
|
||||
MTH_CONST.version = MTH_CONST.version or "1.0.5"
|
||||
|
||||
MTH_CONST.WEAPON_TYPES = {
|
||||
BOWS = "Bows",
|
||||
|
||||
@@ -526,6 +526,7 @@ local function MTH_FEED_CoreDropItemOnUnitHook(unit)
|
||||
end
|
||||
|
||||
if target == "pet" and CursorHasItem and CursorHasItem() then
|
||||
MTH_FEED_EnsureTrackerFrame()
|
||||
local itemId, itemName, itemLink, itemIcon = MTH_FEED_GetCursorItemSnapshot()
|
||||
local pet = MTH_FEED_GetCurrentPetContext()
|
||||
if not itemId then
|
||||
@@ -608,7 +609,6 @@ function MTH_FEED_DebugStatus()
|
||||
end
|
||||
|
||||
function MTH_FEED_ReinstallCoreTracking()
|
||||
MTH_FEED_EnsureTrackerFrame()
|
||||
local ok = MTH_FEED_InstallCoreHooks()
|
||||
return ok and true or false
|
||||
end
|
||||
@@ -624,8 +624,12 @@ local function MTH_FEED_EnsureBootstrapFrame()
|
||||
frame:RegisterEvent("VARIABLES_LOADED")
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:SetScript("OnEvent", function()
|
||||
frame:SetScript("OnEvent", function(self)
|
||||
MTH_FEED_ReinstallCoreTracking()
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
end)
|
||||
MTH_FEED_BootstrapFrame = frame
|
||||
return frame
|
||||
@@ -1542,6 +1546,5 @@ function MTH_FEED_DebugDumpCurrentPet(limit)
|
||||
return true
|
||||
end
|
||||
|
||||
MTH_FEED_EnsureTrackerFrame()
|
||||
MTH_FEED_InstallCoreHooks()
|
||||
MTH_FEED_EnsureBootstrapFrame()
|
||||
|
||||
+50
-44
@@ -1,5 +1,5 @@
|
||||
MTH = MTH or {
|
||||
version = "1.0.4",
|
||||
version = "1.0.5",
|
||||
name = "MetaHunt",
|
||||
modules = {},
|
||||
config = {},
|
||||
@@ -424,9 +424,37 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
local resolvedName = MTH_NormalizeModuleName(name)
|
||||
local candidates = MTH_ModuleNameCandidates(name)
|
||||
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.moduleStates) ~= "table" then
|
||||
MTH_CharSavedVariables.moduleStates = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.modules) ~= "table" then
|
||||
MTH_CharSavedVariables.modules = {}
|
||||
end
|
||||
|
||||
if type(MTH_SavedVariables) ~= "table" then
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " no-savedvars fallback-default=" .. tostring(defaultEnabled and true or false))
|
||||
return defaultEnabled and true or false
|
||||
MTH_SavedVariables = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.moduleStates) ~= "table" then
|
||||
MTH_SavedVariables.moduleStates = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.modules) ~= "table" then
|
||||
MTH_SavedVariables.modules = {}
|
||||
end
|
||||
|
||||
if type(MTH_CharSavedVariables.moduleStates) == "table"
|
||||
then
|
||||
for i = 1, table.getn(candidates) do
|
||||
local key = candidates[i]
|
||||
if MTH_CharSavedVariables.moduleStates[key] ~= nil then
|
||||
local resolved = MTH_CharSavedVariables.moduleStates[key] and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from char.moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type(MTH_SavedVariables.moduleStates) == "table" then
|
||||
@@ -435,25 +463,11 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
if MTH_SavedVariables.moduleStates[key] ~= nil then
|
||||
local resolved = MTH_SavedVariables.moduleStates[key] and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
|
||||
MTH_SavedVariables.moduleStates[resolvedName] = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.moduleStates) == "table"
|
||||
then
|
||||
for i = 1, table.getn(candidates) do
|
||||
local key = candidates[i]
|
||||
if MTH_CharSavedVariables.moduleStates[key] ~= nil then
|
||||
local resolved = MTH_CharSavedVariables.moduleStates[key] and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from char.moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
|
||||
if type(MTH_SavedVariables.moduleStates) ~= "table" then
|
||||
MTH_SavedVariables.moduleStates = {}
|
||||
end
|
||||
MTH_SavedVariables.moduleStates[resolvedName] = resolved
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
end
|
||||
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
@@ -465,9 +479,11 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
if type(MTH_SavedVariables.modules[key]) == "table" and MTH_SavedVariables.modules[key].enabled ~= nil then
|
||||
local resolved = MTH_SavedVariables.modules[key].enabled and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from modules." .. tostring(key) .. ".enabled=" .. tostring(resolved))
|
||||
if type(MTH_SavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_SavedVariables.modules[resolvedName] = MTH_SavedVariables.modules[key]
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
end
|
||||
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
@@ -478,16 +494,11 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
if type(MTH_SavedVariables[key]) == "table" and MTH_SavedVariables[key].enabled ~= nil then
|
||||
local resolved = MTH_SavedVariables[key].enabled and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from legacy-top-level." .. tostring(key) .. ".enabled=" .. tostring(resolved))
|
||||
if type(MTH_SavedVariables.modules) ~= "table" then
|
||||
MTH_SavedVariables.modules = {}
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_SavedVariables.modules[resolvedName] = MTH_SavedVariables[key]
|
||||
end
|
||||
if type(MTH_SavedVariables.moduleStates) ~= "table" then
|
||||
MTH_SavedVariables.moduleStates = {}
|
||||
end
|
||||
MTH_SavedVariables.moduleStates[resolvedName] = resolved
|
||||
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
@@ -506,27 +517,22 @@ local function MTH_SetPersistedModuleEnabled(name, enabled)
|
||||
if type(MTH_SavedVariables) ~= "table" then
|
||||
MTH_SavedVariables = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.moduleStates) ~= "table" then
|
||||
MTH_SavedVariables.moduleStates = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.modules) ~= "table" then
|
||||
MTH_SavedVariables.modules = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.modules[name]) ~= "table" then
|
||||
MTH_SavedVariables.modules[name] = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.moduleStates) ~= "table" then
|
||||
MTH_CharSavedVariables.moduleStates = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.modules) ~= "table" then
|
||||
MTH_CharSavedVariables.modules = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.modules[name]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[name] = {}
|
||||
end
|
||||
|
||||
enabled = enabled and true or false
|
||||
MTH_SavedVariables.moduleStates[name] = enabled
|
||||
MTH_SavedVariables.modules[name].enabled = enabled
|
||||
MTH_SavedVariables[name] = MTH_SavedVariables.modules[name]
|
||||
MTH_CharSavedVariables.moduleStates[name] = enabled
|
||||
MTH_CharSavedVariables.modules[name].enabled = enabled
|
||||
MTH_ModuleStateDebug("write " .. tostring(name) .. " enabled=" .. tostring(enabled))
|
||||
end
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ end
|
||||
local MTH_PT_ApplyScan
|
||||
local MTH_PT_AbilityHasPositiveRanks
|
||||
local MTH_PT_PromoteUnrankedKnownAliases
|
||||
local MTH_PT_BootstrapFrame = nil
|
||||
|
||||
local MTH_PT_VERBOSE_SCAN_LOGS = false
|
||||
|
||||
@@ -846,6 +847,38 @@ function MTH_PT_InitService()
|
||||
end)
|
||||
end
|
||||
|
||||
function MTH_PT_InitBootstrap()
|
||||
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate("trainscan-bootstrap") then
|
||||
return
|
||||
end
|
||||
if MTH_PetTrainingFrame or MTH_PT_BootstrapFrame then
|
||||
return
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
frame:RegisterEvent("PET_TRAINING_SHOW")
|
||||
frame:RegisterEvent("CRAFT_SHOW")
|
||||
frame:SetScript("OnEvent", function(self, evt)
|
||||
evt = evt or event
|
||||
if evt ~= "PET_TRAINING_SHOW" and evt ~= "CRAFT_SHOW" then
|
||||
return
|
||||
end
|
||||
MTH_PT_InitService()
|
||||
if type(MTH_PT_OnEvent) == "function" then
|
||||
MTH_PT_OnEvent(MTH_PetTrainingFrame, evt)
|
||||
end
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
MTH_PT_BootstrapFrame = nil
|
||||
end)
|
||||
MTH_PT_BootstrapFrame = frame
|
||||
end
|
||||
|
||||
function MTH_PT_ShutdownService(_reason)
|
||||
if not MTH_PetTrainingFrame then
|
||||
return
|
||||
@@ -929,3 +962,4 @@ end
|
||||
|
||||
MTH_TR_InitService = MTH_PT_InitService
|
||||
MTH_TR_ShutdownService = MTH_PT_ShutdownService
|
||||
MTH_TR_InitBootstrap = MTH_PT_InitBootstrap
|
||||
|
||||
@@ -7,6 +7,7 @@ local MTH_PS_LastScanAt = 0
|
||||
local MTH_PS_VERBOSE_LOGS = false
|
||||
local MTH_PS_ForceScanUntil = 0
|
||||
local MTH_PS_ForceScanBudget = 0
|
||||
local MTH_PS_EventThrottle = {}
|
||||
|
||||
local function MTH_PS_ClearForceWindow()
|
||||
MTH_PS_ForceScanUntil = 0
|
||||
@@ -26,9 +27,25 @@ end
|
||||
local function MTH_PS_IsFollowupEventTrigger(trigger)
|
||||
local t = tostring(trigger or "")
|
||||
return t == "event:UNIT_PET"
|
||||
or t == "UNIT_PET"
|
||||
or t == "event:PET_BAR_UPDATE"
|
||||
or t == "PET_BAR_UPDATE"
|
||||
or t == "event:SPELLS_CHANGED"
|
||||
or t == "SPELLS_CHANGED"
|
||||
or t == "event:LEARNED_SPELL_IN_TAB"
|
||||
or t == "LEARNED_SPELL_IN_TAB"
|
||||
end
|
||||
|
||||
local function MTH_PS_ShouldHandleEvent(evt, minIntervalSeconds)
|
||||
local now = tonumber(GetTime and GetTime() or time()) or 0
|
||||
local key = tostring(evt or "")
|
||||
local minInterval = tonumber(minIntervalSeconds) or 0
|
||||
local last = tonumber(MTH_PS_EventThrottle[key] or 0) or 0
|
||||
if minInterval > 0 and (now - last) < minInterval then
|
||||
return false
|
||||
end
|
||||
MTH_PS_EventThrottle[key] = now
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_PS_IsPriorityTrigger(trigger)
|
||||
@@ -237,7 +254,19 @@ local function MTH_PS_OnEvent(_, evt, eventArg1)
|
||||
end
|
||||
|
||||
if evt == "PLAYER_ENTERING_WORLD" or evt == "UNIT_PET" or evt == "PET_BAR_UPDATE" or evt == "SPELLS_CHANGED" or evt == "LEARNED_SPELL_IN_TAB" then
|
||||
MTH_PSP_RequestScan("event:" .. tostring(evt), 1)
|
||||
local minInterval = 1
|
||||
if evt == "PET_BAR_UPDATE" then
|
||||
minInterval = 2
|
||||
elseif evt == "SPELLS_CHANGED" then
|
||||
minInterval = 2.5
|
||||
elseif evt == "LEARNED_SPELL_IN_TAB" then
|
||||
minInterval = 0.75
|
||||
elseif evt == "UNIT_PET" then
|
||||
minInterval = 0.5
|
||||
end
|
||||
if MTH_PS_ShouldHandleEvent(evt, minInterval) then
|
||||
MTH_PSP_RequestScan(evt, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ local MTH_PETS_TRACE_RUNAWAY = false
|
||||
MTH_PETS_TRACE_CONSISTENCY = false
|
||||
|
||||
local MTH_StableFrame = nil
|
||||
local MTH_ST_BootstrapFrame = nil
|
||||
local MTH_ST_LastAutoScanAt = 0
|
||||
local MTH_ST_LastUnitPetHadPet = false
|
||||
local MTH_PETS_LastTameAttempt = nil
|
||||
@@ -15,6 +16,8 @@ local MTH_PETS_LiveState = nil
|
||||
local MTH_PETS_LiveStateSeq = 0
|
||||
local MTH_PETS_LiveStateSubscribers = {}
|
||||
local MTH_PETS_LiveStateEventName = "MTH_PET_LIVE_STATE_CHANGED"
|
||||
local MTH_PETS_EventThrottle = {}
|
||||
local MTH_PETS_TRACE_TAME = false
|
||||
|
||||
MTH_PETS_CoreOriginal_PetRename = MTH_PETS_CoreOriginal_PetRename or nil
|
||||
|
||||
@@ -61,6 +64,17 @@ local function MTH_PETS_RequestPetSpellScan(reason)
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_PETS_ShouldHandleThrottledEvent(key, minIntervalSeconds)
|
||||
local now = (type(GetTime) == "function" and GetTime()) or (type(time) == "function" and time()) or 0
|
||||
local threshold = tonumber(minIntervalSeconds) or 0
|
||||
local last = tonumber(MTH_PETS_EventThrottle[key] or 0) or 0
|
||||
if threshold > 0 and (now - last) < threshold then
|
||||
return false
|
||||
end
|
||||
MTH_PETS_EventThrottle[key] = now
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_PETS_CopyLiveState(state)
|
||||
if type(state) ~= "table" then
|
||||
return nil
|
||||
@@ -146,7 +160,10 @@ local function MTH_PETS_NotifyLiveSubscribers(state, source)
|
||||
end
|
||||
|
||||
function MTH_PETS_EmitLiveState(source, force)
|
||||
local emittedSource = tostring(source or "stablemaster")
|
||||
local emittedSource = source or "stablemaster"
|
||||
if type(emittedSource) ~= "string" then
|
||||
emittedSource = tostring(emittedSource)
|
||||
end
|
||||
local nextState = MTH_PETS_BuildLiveState(emittedSource)
|
||||
local changed = force and true or (not MTH_PETS_AreLiveStatesEqual(MTH_PETS_LiveState, nextState))
|
||||
if not changed then
|
||||
@@ -2784,35 +2801,45 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
local pets = MTH_PETS_GetRootStore()
|
||||
MTH_PETS_MaybePromptStableVisit(pets)
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:PLAYER_ENTERING_WORLD", true)
|
||||
MTH_PETS_EmitLiveState("PLAYER_ENTERING_WORLD", true)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "SPELLCAST_CHANNEL_START" then
|
||||
MTH_PETS_RecordTameAttempt("event:" .. tostring(evt), eventArg1)
|
||||
MTH_PETS_RecordTameAttempt(evt, eventArg1)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "SPELLCAST_STOP" or evt == "SPELLCAST_CHANNEL_STOP" or evt == "SPELLCAST_FAILED" or evt == "SPELLCAST_INTERRUPTED" then
|
||||
MTH_PETS_LogTame("Spell terminal evt=" .. tostring(evt) .. " spell='" .. tostring(eventArg1 or "") .. "' pending=" .. tostring(type(MTH_PETS_LastTameAttempt) == "table"))
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Spell terminal evt=" .. tostring(evt) .. " spell='" .. tostring(eventArg1 or "") .. "' pending=" .. tostring(type(MTH_PETS_LastTameAttempt) == "table"))
|
||||
end
|
||||
local terminalIsTame = MTH_PETS_IsTameBeastSpellName(eventArg1)
|
||||
if not terminalIsTame and type(MTH_PETS_LastTameAttempt) == "table" then
|
||||
terminalIsTame = true
|
||||
MTH_PETS_LogTame("Treating terminal event as tame because pending attempt exists")
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Treating terminal event as tame because pending attempt exists")
|
||||
end
|
||||
end
|
||||
if not terminalIsTame then
|
||||
local fallbackName, fallbackSource = MTH_PETS_GetCurrentPlayerCastOrChannelName()
|
||||
if fallbackName and MTH_PETS_IsTameBeastSpellName(fallbackName) then
|
||||
terminalIsTame = true
|
||||
MTH_PETS_LogTame("Resolved terminal spell via " .. tostring(fallbackSource) .. " => '" .. tostring(fallbackName) .. "'")
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Resolved terminal spell via " .. tostring(fallbackSource) .. " => '" .. tostring(fallbackName) .. "'")
|
||||
end
|
||||
end
|
||||
end
|
||||
if terminalIsTame then
|
||||
if evt == "SPELLCAST_FAILED" or evt == "SPELLCAST_INTERRUPTED" then
|
||||
MTH_PETS_LogTame("Tame ended with failure/interruption; clearing pending attempt")
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Tame ended with failure/interruption; clearing pending attempt")
|
||||
end
|
||||
MTH_PETS_LastTameAttempt = nil
|
||||
elseif evt == "SPELLCAST_CHANNEL_STOP" or evt == "SPELLCAST_STOP" then
|
||||
MTH_PETS_LogTame("Tame channel ended; awaiting UNIT_PET to confirm acquire")
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Tame channel ended; awaiting UNIT_PET to confirm acquire")
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
@@ -2822,14 +2849,17 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
if eventArg1 ~= "player" then
|
||||
return
|
||||
end
|
||||
MTH_PETS_HandleUnitPetTransition("event:UNIT_PET")
|
||||
MTH_PETS_EmitLiveState("event:UNIT_PET")
|
||||
MTH_PETS_HandleUnitPetTransition("UNIT_PET")
|
||||
MTH_PETS_EmitLiveState("UNIT_PET")
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "PET_BAR_UPDATE" then
|
||||
if not MTH_PETS_ShouldHandleThrottledEvent("PET_BAR_UPDATE", 0.5) then
|
||||
return
|
||||
end
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:PET_BAR_UPDATE")
|
||||
MTH_PETS_EmitLiveState("PET_BAR_UPDATE")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -2837,14 +2867,20 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
if eventArg1 and eventArg1 ~= "pet" then
|
||||
return
|
||||
end
|
||||
if not MTH_PETS_ShouldHandleThrottledEvent("UNIT_HAPPINESS", 0.75) then
|
||||
return
|
||||
end
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:UNIT_HAPPINESS")
|
||||
MTH_PETS_EmitLiveState("UNIT_HAPPINESS")
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "CHAT_MSG_COMBAT_XP_GAIN" or evt == "PLAYER_XP_UPDATE" then
|
||||
if not MTH_PETS_ShouldHandleThrottledEvent("XP_UPDATE", 1.5) then
|
||||
return
|
||||
end
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:" .. tostring(evt))
|
||||
MTH_PETS_EmitLiveState(evt)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -2852,28 +2888,28 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
local matchedRunaway = MTH_PETS_IsRunawaySystemMessage(eventArg1)
|
||||
MTH_PETS_TraceRunawayEvent(evt, eventArg1, matchedRunaway)
|
||||
if matchedRunaway then
|
||||
MTH_PETS_RecordPetRunaway("event:" .. tostring(evt), eventArg1)
|
||||
MTH_PETS_RecordPetRunaway(evt, eventArg1)
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:" .. tostring(evt))
|
||||
MTH_PETS_EmitLiveState(evt)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "PET_STABLE_SHOW" then
|
||||
MTH_ST_RunScanThrottled("event:" .. tostring(evt), 1)
|
||||
MTH_ST_RunScanThrottled(evt, 1)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "PET_STABLE_UPDATE" then
|
||||
MTH_ST_Scan("event:PET_STABLE_UPDATE")
|
||||
MTH_ST_Scan(evt)
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:PET_STABLE_UPDATE")
|
||||
MTH_PETS_EmitLiveState(evt)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "PET_STABLE_CLOSED" then
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_EmitLiveState("event:PET_STABLE_CLOSED")
|
||||
MTH_PETS_EmitLiveState(evt)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -2912,6 +2948,37 @@ function MTH_ST_InitService()
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ST_InitBootstrap()
|
||||
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate("stablescan-bootstrap") then
|
||||
return
|
||||
end
|
||||
if MTH_StableFrame or MTH_ST_BootstrapFrame then
|
||||
return
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
frame:RegisterEvent("PET_STABLE_SHOW")
|
||||
frame:SetScript("OnEvent", function(self, evt)
|
||||
evt = evt or event
|
||||
if evt ~= "PET_STABLE_SHOW" then
|
||||
return
|
||||
end
|
||||
MTH_ST_InitService()
|
||||
if type(MTH_ST_Scan) == "function" then
|
||||
MTH_ST_Scan("bootstrap:PET_STABLE_SHOW")
|
||||
end
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
MTH_ST_BootstrapFrame = nil
|
||||
end)
|
||||
MTH_ST_BootstrapFrame = frame
|
||||
end
|
||||
|
||||
function MTH_ST_ShutdownService(_reason)
|
||||
if not MTH_StableFrame then
|
||||
return
|
||||
|
||||
+51
-6
@@ -129,6 +129,49 @@ local function MTH_CommandOptions()
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_FormatAgeSeconds(seconds)
|
||||
local value = tonumber(seconds) or 0
|
||||
if value < 0 then value = 0 end
|
||||
if value < 60 then
|
||||
return tostring(math.floor(value)) .. "s"
|
||||
end
|
||||
if value < 3600 then
|
||||
return tostring(math.floor(value / 60)) .. "m"
|
||||
end
|
||||
if value < 86400 then
|
||||
return tostring(math.floor(value / 3600)) .. "h"
|
||||
end
|
||||
return tostring(math.floor(value / 86400)) .. "d"
|
||||
end
|
||||
|
||||
local function MTH_CommandPeers()
|
||||
if not (MTH and MTH.VersionCheck and type(MTH.VersionCheck.GetTrackedPeers) == "function") then
|
||||
MTH:Print("Peer tracker is not available yet")
|
||||
return
|
||||
end
|
||||
|
||||
local peers = MTH.VersionCheck:GetTrackedPeers()
|
||||
local count = table.getn(peers)
|
||||
if count <= 0 then
|
||||
MTH:Print("No MetaHunt broadcasters seen yet on LFT")
|
||||
return
|
||||
end
|
||||
|
||||
MTH:Print("MetaHunt broadcasters seen on LFT: " .. tostring(count))
|
||||
local now = (type(time) == "function" and time()) or (type(GetTime) == "function" and math.floor(GetTime())) or 0
|
||||
local maxRows = math.min(count, 20)
|
||||
for i = 1, maxRows do
|
||||
local peer = peers[i]
|
||||
if type(peer) == "table" then
|
||||
local age = MTH_FormatAgeSeconds((now or 0) - (tonumber(peer.lastSeenAt) or 0))
|
||||
MTH:Print("- " .. tostring(peer.name or "?") .. " v" .. tostring(peer.versionText or "?") .. " (seen " .. tostring(age) .. " ago)")
|
||||
end
|
||||
end
|
||||
if count > maxRows then
|
||||
MTH:Print("... and " .. tostring(count - maxRows) .. " more")
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_CommandPetSpellScanFallback()
|
||||
local getSpellName = (type(getglobal) == "function" and getglobal("GetSpellName")) or (_G and _G["GetSpellName"])
|
||||
local getSpellTexture = (type(getglobal) == "function" and getglobal("GetSpellTexture")) or (_G and _G["GetSpellTexture"])
|
||||
@@ -245,6 +288,8 @@ function SlashCmdList.MTH(msg, editbox)
|
||||
MTH_CommandOptions()
|
||||
elseif lowerMsg == "book" or lowerMsg == "hunterbook" then
|
||||
MTH_CommandBook()
|
||||
elseif lowerMsg == "peers" or lowerMsg == "who" then
|
||||
MTH_CommandPeers()
|
||||
elseif lowerMsg == "err" then
|
||||
if MTH_DebugFrame and type(MTH_DebugFrame.Toggle) == "function" then
|
||||
MTH_DebugFrame:Toggle()
|
||||
@@ -259,13 +304,13 @@ end
|
||||
|
||||
-- Initialize on load
|
||||
MTH:InitSavedVariables()
|
||||
if type(MTH_ST_InitService) == "function" then
|
||||
MTH_ST_InitService()
|
||||
if type(MTH_ST_InitBootstrap) == "function" then
|
||||
MTH_ST_InitBootstrap()
|
||||
end
|
||||
if type(MTH_TR_InitService) == "function" then
|
||||
MTH_TR_InitService()
|
||||
elseif type(MTH_PT_InitService) == "function" then
|
||||
MTH_PT_InitService()
|
||||
if type(MTH_TR_InitBootstrap) == "function" then
|
||||
MTH_TR_InitBootstrap()
|
||||
elseif type(MTH_PT_InitBootstrap) == "function" then
|
||||
MTH_PT_InitBootstrap()
|
||||
end
|
||||
if type(MTH_PS_InitService) == "function" then
|
||||
MTH_PS_InitService()
|
||||
|
||||
+93
-41
@@ -2,7 +2,7 @@ MTH_Map = {
|
||||
enabled = true,
|
||||
showWorld = true,
|
||||
showMinimap = true,
|
||||
activeSource = "beasts",
|
||||
activeSource = "focus",
|
||||
providers = {},
|
||||
nodesByZone = {},
|
||||
worldPins = {},
|
||||
@@ -21,6 +21,10 @@ MTH_Map = {
|
||||
lastWorldReason = "n/a",
|
||||
lastMiniReason = "n/a",
|
||||
nodeRevision = 0,
|
||||
minimapForceRefreshInterval = 1.0,
|
||||
verboseMiniReasons = false,
|
||||
minimapTickActive = 0.20,
|
||||
minimapTickIdle = 0.75,
|
||||
}
|
||||
|
||||
local MTH_MAP_MINIMAP_ZOOM = {
|
||||
@@ -468,7 +472,18 @@ local function MTH_Map_ClearPendingZoneOpen()
|
||||
MTH_Map.pendingZoneOpenNextAttemptAt = 0
|
||||
end
|
||||
|
||||
function MTH_Map:EnsureInitialized()
|
||||
if self.controller then
|
||||
return true
|
||||
end
|
||||
self:Init()
|
||||
return self.controller ~= nil
|
||||
end
|
||||
|
||||
function MTH_Map:SetSource(key)
|
||||
if not self:EnsureInitialized() then
|
||||
return false
|
||||
end
|
||||
if not self.providers[key] then
|
||||
return false
|
||||
end
|
||||
@@ -672,6 +687,9 @@ function MTH_Map:SetEnabled(enabled)
|
||||
if not self.enabled then
|
||||
self:HideAllPins()
|
||||
else
|
||||
if not self:EnsureInitialized() then
|
||||
return
|
||||
end
|
||||
self:UpdateWorldMap()
|
||||
self:UpdateMinimap()
|
||||
end
|
||||
@@ -682,6 +700,9 @@ function MTH_Map:SetWorldEnabled(enabled)
|
||||
if not self.showWorld then
|
||||
self:HideWorldPins()
|
||||
else
|
||||
if not self:EnsureInitialized() then
|
||||
return
|
||||
end
|
||||
self:UpdateWorldMap()
|
||||
end
|
||||
end
|
||||
@@ -691,6 +712,9 @@ function MTH_Map:SetMinimapEnabled(enabled)
|
||||
if not self.showMinimap then
|
||||
self:HideMinimapPins()
|
||||
else
|
||||
if not self:EnsureInitialized() then
|
||||
return
|
||||
end
|
||||
self:UpdateMinimap()
|
||||
end
|
||||
end
|
||||
@@ -952,22 +976,21 @@ function MTH_Map:UpdateMinimap()
|
||||
end
|
||||
|
||||
local mapId = self:GetCurrentMapID()
|
||||
if not mapId or not self.nodesByZone[mapId] then
|
||||
local nodes = mapId and self.nodesByZone[mapId] or nil
|
||||
if not mapId or not nodes then
|
||||
self.lastMiniReason = "no-mapid-or-nodes"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
end
|
||||
|
||||
local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"])
|
||||
local mapSize = minimapSizes and minimapSizes[mapId]
|
||||
if not mapSize then
|
||||
self.lastMiniReason = "missing-minimap-size"
|
||||
if table.getn(nodes) <= 0 then
|
||||
self.lastMiniReason = "no-nodes-in-zone"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
end
|
||||
|
||||
local now = GetTime() or 0
|
||||
local xPlayer, yPlayer = GetPlayerMapPosition("player")
|
||||
if not xPlayer or not yPlayer or (xPlayer == 0 and yPlayer == 0) then
|
||||
self.lastMiniReason = "player-position-unavailable"
|
||||
@@ -980,10 +1003,33 @@ function MTH_Map:UpdateMinimap()
|
||||
yPlayer = yPlayer * 100
|
||||
|
||||
local zoom = Minimap:GetZoom()
|
||||
local miniState = self._lastMiniState
|
||||
if miniState
|
||||
and miniState.mapId == mapId
|
||||
and miniState.zoom == zoom
|
||||
and miniState.nodeRevision == (self.nodeRevision or 0)
|
||||
then
|
||||
local dx = math.abs((xPlayer or 0) - (miniState.xPlayer or 0))
|
||||
local dy = math.abs((yPlayer or 0) - (miniState.yPlayer or 0))
|
||||
if dx < 0.05 and dy < 0.05 and now < (miniState.nextForceAt or 0) then
|
||||
self.lastMiniReason = self.verboseMiniReasons and "throttled-small-move" or "throttle"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"])
|
||||
local mapSize = minimapSizes and minimapSizes[mapId]
|
||||
if not mapSize then
|
||||
self.lastMiniReason = self.verboseMiniReasons and "missing-minimap-size" or "missing-size"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
end
|
||||
|
||||
local indoor = MTH_Map_MinimapIndoorState()
|
||||
local zoomSet = MTH_MAP_MINIMAP_ZOOM[indoor]
|
||||
if not zoomSet then
|
||||
self.lastMiniReason = "missing-zoomset"
|
||||
self.lastMiniReason = self.verboseMiniReasons and "missing-zoomset" or "missing-zoomset"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
@@ -991,7 +1037,7 @@ function MTH_Map:UpdateMinimap()
|
||||
|
||||
local mapZoom = zoomSet[zoom]
|
||||
if not mapZoom then
|
||||
self.lastMiniReason = "missing-mapzoom"
|
||||
self.lastMiniReason = self.verboseMiniReasons and "missing-mapzoom" or "missing-zoom"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
@@ -1000,33 +1046,16 @@ function MTH_Map:UpdateMinimap()
|
||||
local mapWidth = mapSize[1]
|
||||
local mapHeight = mapSize[2]
|
||||
if not mapWidth or not mapHeight or mapWidth == 0 or mapHeight == 0 then
|
||||
self.lastMiniReason = "invalid-map-size"
|
||||
self.lastMiniReason = self.verboseMiniReasons and "invalid-map-size" or "invalid-size"
|
||||
self._lastMiniState = nil
|
||||
self:HideMinimapPins()
|
||||
return
|
||||
end
|
||||
|
||||
local miniState = self._lastMiniState
|
||||
if miniState
|
||||
and miniState.mapId == mapId
|
||||
and miniState.zoom == zoom
|
||||
and miniState.indoor == indoor
|
||||
and miniState.nodeRevision == (self.nodeRevision or 0)
|
||||
then
|
||||
local dx = math.abs((xPlayer or 0) - (miniState.xPlayer or 0))
|
||||
local dy = math.abs((yPlayer or 0) - (miniState.yPlayer or 0))
|
||||
if dx < 0.05 and dy < 0.05 then
|
||||
self.lastMiniReason = "throttled-small-move"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local xScale = mapZoom / mapWidth
|
||||
local yScale = mapZoom / mapHeight
|
||||
local xDraw = Minimap:GetWidth() / xScale / 100
|
||||
local yDraw = Minimap:GetHeight() / yScale / 100
|
||||
|
||||
local nodes = self.nodesByZone[mapId]
|
||||
local shown = 0
|
||||
|
||||
for i = 1, table.getn(nodes) do
|
||||
@@ -1057,16 +1086,21 @@ function MTH_Map:UpdateMinimap()
|
||||
if self.minimapPins[i] then self.minimapPins[i]:Hide() end
|
||||
end
|
||||
|
||||
self._lastMiniState = {
|
||||
mapId = mapId,
|
||||
zoom = zoom,
|
||||
indoor = indoor,
|
||||
xPlayer = xPlayer,
|
||||
yPlayer = yPlayer,
|
||||
nodeRevision = self.nodeRevision or 0,
|
||||
}
|
||||
local lastState = self._lastMiniState or {}
|
||||
lastState.mapId = mapId
|
||||
lastState.zoom = zoom
|
||||
lastState.indoor = indoor
|
||||
lastState.xPlayer = xPlayer
|
||||
lastState.yPlayer = yPlayer
|
||||
lastState.nodeRevision = self.nodeRevision or 0
|
||||
lastState.nextForceAt = now + (tonumber(self.minimapForceRefreshInterval) or 1.0)
|
||||
self._lastMiniState = lastState
|
||||
|
||||
self.lastMiniReason = "ok(map=" .. tostring(mapId) .. ",shown=" .. tostring(shown) .. ")"
|
||||
if self.verboseMiniReasons then
|
||||
self.lastMiniReason = "ok(map=" .. tostring(mapId) .. ",shown=" .. tostring(shown) .. ")"
|
||||
else
|
||||
self.lastMiniReason = "ok"
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_Map:RegisterDefaultProviders()
|
||||
@@ -1202,9 +1236,12 @@ function MTH_Map:RegisterDefaultProviders()
|
||||
end
|
||||
|
||||
function MTH_Map:Init()
|
||||
if self.controller then
|
||||
return
|
||||
end
|
||||
self:BuildZoneLookup()
|
||||
self:RegisterDefaultProviders()
|
||||
self:RebuildNodes()
|
||||
self.nodesByZone = self.nodesByZone or {}
|
||||
|
||||
if not self.controller then
|
||||
self.controller = CreateFrame("Frame", "MTHMapController", UIParent)
|
||||
@@ -1230,7 +1267,6 @@ function MTH_Map:Init()
|
||||
if not frame then return end
|
||||
local now = GetTime() or 0
|
||||
if (frame._mthTick or 0) > now then return end
|
||||
frame._mthTick = now + 0.12
|
||||
|
||||
if MTH_Map.pendingZoneOpenId and MTH_Map.pendingZoneOpenAttempts and MTH_Map.pendingZoneOpenAttempts > 0 then
|
||||
if (MTH_Map.pendingZoneOpenNextAttemptAt or 0) <= now then
|
||||
@@ -1259,12 +1295,28 @@ function MTH_Map:Init()
|
||||
end
|
||||
|
||||
if MTH_Map.enabled and MTH_Map.showMinimap then
|
||||
MTH_Map:UpdateMinimap()
|
||||
local mapId = MTH_Map:GetCurrentMapID()
|
||||
if not mapId and (frame._mthMapRecoverAt or 0) <= now then
|
||||
frame._mthMapRecoverAt = now + 2.0
|
||||
if SetMapToCurrentZone and (not WorldMapFrame or not WorldMapFrame:IsShown()) then
|
||||
SetMapToCurrentZone()
|
||||
mapId = MTH_Map:GetCurrentMapID()
|
||||
end
|
||||
end
|
||||
local nodes = mapId and MTH_Map.nodesByZone and MTH_Map.nodesByZone[mapId] or nil
|
||||
local hasNodes = nodes and table.getn(nodes) > 0
|
||||
frame._mthTick = now + (hasNodes and (tonumber(MTH_Map.minimapTickActive) or 0.20) or (tonumber(MTH_Map.minimapTickIdle) or 0.75))
|
||||
if hasNodes then
|
||||
MTH_Map:UpdateMinimap()
|
||||
elseif (frame._mthNoNodeTick or 0) <= now then
|
||||
frame._mthNoNodeTick = now + 1.0
|
||||
MTH_Map:UpdateMinimap()
|
||||
end
|
||||
else
|
||||
frame._mthTick = now + (tonumber(MTH_Map.minimapTickIdle) or 0.75)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
MTH_Map_Log("Map system initialized")
|
||||
end
|
||||
|
||||
MTH_Map:Init()
|
||||
|
||||
@@ -169,10 +169,14 @@ end
|
||||
|
||||
local loader = CreateFrame("Frame", "MTH_MinimapButtonLoader")
|
||||
loader:RegisterEvent("ADDON_LOADED")
|
||||
loader:SetScript("OnEvent", function(_, eventName, addonName)
|
||||
loader:SetScript("OnEvent", function(self, eventName, addonName)
|
||||
eventName = eventName or event
|
||||
addonName = addonName or arg1
|
||||
if eventName == "ADDON_LOADED" and addonName == "MetaHunt" then
|
||||
MTH_MinimapButton:Initialize()
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -44,6 +44,8 @@ local MTH_AB_STATE = {
|
||||
},
|
||||
}
|
||||
|
||||
local MTH_AB_TRANSIENT_STORE = {}
|
||||
|
||||
local function MTH_AB_SetCheckedNoClick(check, checked)
|
||||
if not check then return end
|
||||
MTH_AB_STATE.syncing = true
|
||||
@@ -60,8 +62,7 @@ local function MTH_AB_GetStore()
|
||||
if engine and engine.EnsureDefaults then
|
||||
return engine:EnsureDefaults()
|
||||
end
|
||||
MTH_AutoBuy_Saved = MTH_AutoBuy_Saved or {}
|
||||
return MTH_AutoBuy_Saved
|
||||
return MTH_AB_TRANSIENT_STORE
|
||||
end
|
||||
|
||||
local function MTH_AB_NormalizeRule(rule)
|
||||
|
||||
@@ -98,11 +98,20 @@ local function MTH_CHRON_CopyTable(source)
|
||||
end
|
||||
|
||||
local function MTH_CHRON_GetProfile()
|
||||
if not (MTH and MTH.GetModuleSavedVariables) then
|
||||
if not (MTH and MTH.GetModuleCharSavedVariables) then
|
||||
return MTH_CHRON_CopyTable(MTH_CHRON_DEFAULTS)
|
||||
end
|
||||
|
||||
local store = MTH:GetModuleSavedVariables("chronometer")
|
||||
local store = MTH:GetModuleCharSavedVariables("chronometer")
|
||||
if type(store) ~= "table" then
|
||||
return MTH_CHRON_CopyTable(MTH_CHRON_DEFAULTS)
|
||||
end
|
||||
if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then
|
||||
local accountStore = MTH:GetModuleSavedVariables("chronometer")
|
||||
if type(accountStore) == "table" and type(accountStore.profile) == "table" then
|
||||
store.profile = MTH_CHRON_CopyTable(accountStore.profile)
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table" then
|
||||
store.profile = {}
|
||||
end
|
||||
|
||||
@@ -1114,10 +1114,26 @@ function MTH_SetupGeneralOptions()
|
||||
|
||||
local tooltipsSection = ensureSection("MetaHuntGeneralTooltipsBox", "Tooltips", topY, 356, "right")
|
||||
if tooltipsSection then
|
||||
local tooltipsStore = MTH and MTH.GetModuleSavedVariables and MTH:GetModuleSavedVariables("tooltips")
|
||||
local tooltipsStore = MTH and MTH.GetModuleCharSavedVariables and MTH:GetModuleCharSavedVariables("tooltips")
|
||||
if type(tooltipsStore) ~= "table" then
|
||||
tooltipsStore = {}
|
||||
end
|
||||
if MTH and MTH.GetModuleSavedVariables and next(tooltipsStore) == nil then
|
||||
local accountStore = MTH:GetModuleSavedVariables("tooltips")
|
||||
if type(accountStore) == "table" and next(accountStore) ~= nil then
|
||||
for key, value in pairs(accountStore) do
|
||||
if type(value) == "table" then
|
||||
local copied = {}
|
||||
for subKey, subValue in pairs(value) do
|
||||
copied[subKey] = subValue
|
||||
end
|
||||
tooltipsStore[key] = copied
|
||||
else
|
||||
tooltipsStore[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if tooltipsStore.beastTooltips == nil then
|
||||
tooltipsStore.beastTooltips = true
|
||||
end
|
||||
|
||||
+163
-5
@@ -8,6 +8,8 @@ VC.nextPublishAt = nil
|
||||
VC.joinAt = nil
|
||||
VC.notified = false
|
||||
VC._invalidVersionWarned = false
|
||||
VC.maxPersistedPeers = 200
|
||||
VC.seenPeers = VC.seenPeers or {}
|
||||
|
||||
local function VC_GetTimeNow()
|
||||
if type(time) == "function" then
|
||||
@@ -63,6 +65,158 @@ local function VC_IsOurChannel(name)
|
||||
return type(name) == "string" and string.lower(name) == string.lower(VC.channelName)
|
||||
end
|
||||
|
||||
local function VC_ShouldPersistPeers()
|
||||
if type(UnitName) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local playerName = UnitName("player")
|
||||
if type(playerName) ~= "string" or playerName == "" then
|
||||
return false
|
||||
end
|
||||
return string.find(playerName, "^Meta") ~= nil
|
||||
end
|
||||
|
||||
local function VC_EnsurePersistenceStore()
|
||||
if not VC_ShouldPersistPeers() then
|
||||
return nil
|
||||
end
|
||||
if type(MTH_SavedVariables) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
if type(MTH_SavedVariables.versionCheck) ~= "table" then
|
||||
MTH_SavedVariables.versionCheck = {}
|
||||
end
|
||||
local store = MTH_SavedVariables.versionCheck
|
||||
if type(store.seenPeers) ~= "table" then
|
||||
store.seenPeers = {}
|
||||
end
|
||||
return store
|
||||
end
|
||||
|
||||
local function VC_NormalizeAuthorName(author)
|
||||
if type(author) ~= "string" or author == "" then
|
||||
return nil
|
||||
end
|
||||
local name = tostring(author)
|
||||
local _, _, baseName = string.find(name, "^([^%-]+)")
|
||||
if baseName and baseName ~= "" then
|
||||
name = baseName
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
function VC:VersionNumberToString(versionNumber)
|
||||
local n = tonumber(versionNumber)
|
||||
if not n or n <= 0 then
|
||||
return "?"
|
||||
end
|
||||
local major = math.floor(n / 1000000)
|
||||
local remMajor = n - (major * 1000000)
|
||||
local minor = math.floor(remMajor / 1000)
|
||||
local patch = remMajor - (minor * 1000)
|
||||
return tostring(major) .. "." .. tostring(minor) .. "." .. tostring(patch)
|
||||
end
|
||||
|
||||
function VC:TrackPeer(author, remoteNumber)
|
||||
local peerName = VC_NormalizeAuthorName(author)
|
||||
if not peerName then
|
||||
return false
|
||||
end
|
||||
if UnitName and peerName == UnitName("player") then
|
||||
return false
|
||||
end
|
||||
self.seenPeers = self.seenPeers or {}
|
||||
self.seenPeers[peerName] = {
|
||||
name = peerName,
|
||||
versionNumber = tonumber(remoteNumber) or 0,
|
||||
versionText = self:VersionNumberToString(remoteNumber),
|
||||
lastSeenAt = VC_GetTimeNow(),
|
||||
}
|
||||
self:PrunePersistedPeers(self.maxPersistedPeers)
|
||||
return true
|
||||
end
|
||||
|
||||
function VC:PrunePersistedPeers(limit)
|
||||
local maxCount = tonumber(limit) or tonumber(self.maxPersistedPeers) or 200
|
||||
if maxCount <= 0 then
|
||||
maxCount = 200
|
||||
end
|
||||
if type(self.seenPeers) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local names = {}
|
||||
for name, peer in pairs(self.seenPeers) do
|
||||
if type(name) == "string" and type(peer) == "table" then
|
||||
table.insert(names, name)
|
||||
end
|
||||
end
|
||||
if table.getn(names) <= maxCount then
|
||||
return
|
||||
end
|
||||
|
||||
table.sort(names, function(a, b)
|
||||
local pa = self.seenPeers[a] or {}
|
||||
local pb = self.seenPeers[b] or {}
|
||||
local ta = tonumber(pa.lastSeenAt) or 0
|
||||
local tb = tonumber(pb.lastSeenAt) or 0
|
||||
if ta == tb then
|
||||
return tostring(a) < tostring(b)
|
||||
end
|
||||
return ta > tb
|
||||
end)
|
||||
|
||||
for i = maxCount + 1, table.getn(names) do
|
||||
self.seenPeers[names[i]] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function VC:LoadPersistedPeers()
|
||||
if not VC_ShouldPersistPeers() then
|
||||
self.seenPeers = {}
|
||||
if type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.versionCheck) == "table"
|
||||
and type(MTH_SavedVariables.versionCheck.seenPeers) == "table" then
|
||||
MTH_SavedVariables.versionCheck.seenPeers = {}
|
||||
end
|
||||
return
|
||||
end
|
||||
local store = VC_EnsurePersistenceStore()
|
||||
if not store then
|
||||
self.seenPeers = self.seenPeers or {}
|
||||
return
|
||||
end
|
||||
if type(store.seenPeers) ~= "table" then
|
||||
store.seenPeers = {}
|
||||
end
|
||||
self.seenPeers = store.seenPeers
|
||||
self:PrunePersistedPeers(self.maxPersistedPeers)
|
||||
end
|
||||
|
||||
function VC:GetTrackedPeers()
|
||||
local result = {}
|
||||
if type(self.seenPeers) ~= "table" then
|
||||
return result
|
||||
end
|
||||
for _, peer in pairs(self.seenPeers) do
|
||||
if type(peer) == "table" and peer.name then
|
||||
table.insert(result, {
|
||||
name = tostring(peer.name),
|
||||
versionNumber = tonumber(peer.versionNumber) or 0,
|
||||
versionText = tostring(peer.versionText or self:VersionNumberToString(peer.versionNumber)),
|
||||
lastSeenAt = tonumber(peer.lastSeenAt) or 0,
|
||||
})
|
||||
end
|
||||
end
|
||||
table.sort(result, function(a, b)
|
||||
if (a.lastSeenAt or 0) == (b.lastSeenAt or 0) then
|
||||
return tostring(a.name or "") < tostring(b.name or "")
|
||||
end
|
||||
return (a.lastSeenAt or 0) > (b.lastSeenAt or 0)
|
||||
end)
|
||||
return result
|
||||
end
|
||||
|
||||
function VC:ResetPublishDelay()
|
||||
self.nextPublishAt = VC_GetTimeNow() + math.random(10, 20)
|
||||
end
|
||||
@@ -96,13 +250,11 @@ function VC:TryPublish()
|
||||
end
|
||||
|
||||
function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
if self.notified then
|
||||
return
|
||||
end
|
||||
if not message or message == "" then
|
||||
return
|
||||
end
|
||||
if author and UnitName and author == UnitName("player") then
|
||||
local normalizedAuthor = VC_NormalizeAuthorName(author)
|
||||
if normalizedAuthor and UnitName and normalizedAuthor == UnitName("player") then
|
||||
return
|
||||
end
|
||||
local channelName = string.gsub(tostring(channelLabel or ""), "^%d+%.%s*", "")
|
||||
@@ -121,6 +273,12 @@ function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
if not remoteNumber or remoteNumber <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
self:TrackPeer(normalizedAuthor or author, remoteNumber)
|
||||
|
||||
if self.notified then
|
||||
return
|
||||
end
|
||||
local localVersionNumber = self:GetLocalVersionNumber()
|
||||
if not localVersionNumber or localVersionNumber <= 0 then
|
||||
return
|
||||
@@ -136,7 +294,6 @@ function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
end
|
||||
|
||||
if VC.frame then
|
||||
VC.frame:UnregisterEvent("CHAT_MSG_CHANNEL")
|
||||
VC.frame:SetScript("OnUpdate", nil)
|
||||
end
|
||||
end
|
||||
@@ -149,6 +306,7 @@ if not VC.frame then
|
||||
frame:RegisterEvent("CHAT_MSG_CHANNEL")
|
||||
frame:SetScript("OnEvent", function()
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
VC:LoadPersistedPeers()
|
||||
VC.joinAt = GetTime() + 6
|
||||
VC:ResetPublishDelay()
|
||||
elseif event == "CHAT_MSG_CHANNEL" then
|
||||
|
||||
Reference in New Issue
Block a user