Refactor Heimdall modules to improve structure and clarity, including AchievementSniffer, BonkDetector, Bully, Commander, and Config.

This commit is contained in:
2025-05-18 12:27:00 +02:00
parent 0057ac3a5c
commit b16cf762ac
6 changed files with 2774 additions and 2799 deletions

View File

@@ -36,30 +36,30 @@ local function init()
---@field Memoize fun(f: function): function ---@field Memoize fun(f: function): function
---@field GetLocaleForChannel fun(channel: string): string ---@field GetLocaleForChannel fun(channel: string): string
---@field WhoQueryService WhoQueryService ---@field WhoQueryService WhoQueryService
---@field Whoer InitTable|{ShouldNotifyForZone: fun(zone: string): boolean} ---@field AchievementSniffer AchievementSniffer
---@field AchievementSniffer InitTable
---@field AgentTracker AgentTracker ---@field AgentTracker AgentTracker
---@field BonkDetector InitTable ---@field BonkDetector BonkDetector
---@field Bully InitTable ---@field Bully Bully
---@field CombatAlerter InitTable ---@field CombatAlerter CombatAlerter
---@field Commander InitTable ---@field Commander Commander
---@field Config InitTable ---@field Config Config
---@field Configurator InitTable ---@field Configurator Configurator
---@field DeathReporter InitTable ---@field DeathReporter DeathReporter
---@field Dueler InitTable ---@field Dueler Dueler
---@field Echoer InitTable ---@field Echoer Echoer
---@field Emoter InitTable ---@field Emoter Emoter
---@field Inviter InitTable ---@field Inviter Inviter
---@field Macroer InitTable ---@field Macroer Macroer
---@field Messenger InitTable ---@field Messenger Messenger
---@field MinimapTagger InitTable ---@field MinimapTagger MinimapTagger
---@field Network InitTable ---@field Network Network
---@field NetworkMessenger InitTable ---@field NetworkMessenger NetworkMessenger
---@field Noter InitTable ---@field Noter Noter
---@field Sniffer InitTable ---@field Sniffer Sniffer
---@field Spotter InitTable ---@field Spotter Spotter
---@field StinkyCache InitTable ---@field StinkyCache StinkyCache
---@field StinkyTracker StinkyTracker ---@field StinkyTracker StinkyTracker
---@field Whoer Whoer
--- Config --- --- Config ---
---@class HeimdallConfig ---@class HeimdallConfig
@@ -119,19 +119,6 @@ local function init()
---@field debug boolean ---@field debug boolean
---@field interval number ---@field interval number
---@class HeimdallInviterConfig
---@field enabled boolean
---@field debug boolean
---@field channels string[]
---@field keyword string
---@field allAssist boolean
---@field agentsAssist boolean
---@field throttle number
---@field kickOffline boolean
---@field cleanupInterval number
---@field afkThreshold number
---@field listeningChannel table<string, boolean>
---@class HeimdallDuelerConfig ---@class HeimdallDuelerConfig
---@field enabled boolean ---@field enabled boolean
---@field debug boolean ---@field debug boolean
@@ -149,25 +136,12 @@ local function init()
---@field channels string[] ---@field channels string[]
---@field prefix string ---@field prefix string
---@class HeimdallMacroerConfig
---@field enabled boolean
---@field debug boolean
---@field priority string[]
---@class HeimdallStinkyTrackerConfig ---@class HeimdallStinkyTrackerConfig
---@field enabled boolean ---@field enabled boolean
---@field debug boolean ---@field debug boolean
---@field ignoredTimeout number ---@field ignoredTimeout number
---@field channels string[] ---@field channels string[]
---@class HeimdallSnifferConfig
---@field enabled boolean
---@field debug boolean
---@field channels string[]
---@field throttle number
---@field zoneOverride string?
---@field stinky boolean
---@class HeimdallMinimapTaggerConfig ---@class HeimdallMinimapTaggerConfig
---@field enabled boolean ---@field enabled boolean
---@field debug boolean ---@field debug boolean

View File

@@ -74,220 +74,221 @@ local Achievements = {
12448, 12448,
} }
---@diagnostic disable-next-line: missing-fields ---@class AchievementSniffer
shared.AchievementSniffer = {} shared.AchievementSniffer = {
function shared.AchievementSniffer.Init() Init = function()
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Module initialized", ModuleName))
end
local guidMap = {}
---@class AchievementData
---@field id number
---@field date string
---@field completed boolean
---@class Heimdall_Achievements
---@field players table<string, table<number, AchievementData>>
---@field alreadySeen table<string, boolean>
---@field rescan boolean
if not Heimdall_Achievements then Heimdall_Achievements = {} end
if not Heimdall_Achievements.players then Heimdall_Achievements.players = {} end
if not Heimdall_Achievements.alreadySeen then Heimdall_Achievements.alreadySeen = {} end
--local framePool = {}
--for i = 1, 40 do
-- local frame = CreateFrame("Frame", "HeimdallAchievementSnifferNameplate" .. i, UIParent)
-- local texture = frame:CreateTexture(nil, "ARTWORK")
-- texture:SetAllPoints(frame)
-- texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
-- frame.texture = texture
-- frame:Hide()
-- table.insert(framePool, frame)
--end
---@param name string
---@return boolean
local function ShouldInspect(name)
local should = false
if not Heimdall_Achievements.players[name] then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Player %s does not have prior achievement data", ModuleName, name))
end
should = true
end
if Heimdall_Achievements.alreadySeen[name] then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Player %s has already been seen", ModuleName, name))
end
-- Save some memory
Heimdall_Achievements.players[name] = nil
should = false
end
if Heimdall_Data.config.achievementSniffer.rescan then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Rescan is enabled", ModuleName))
end
should = true
end
return should
end
-- It's not working well AT ALL
-- I don't know how to do it better
-- It simply just does not work...
--local function UpdateFrames()
-- for i, frame in ipairs(framePool) do
-- local unit = "nameplate" .. i
-- if not UnitExists(unit) then
-- --if Heimdall_Data.config.achievementSniffer.debug then
-- -- print(string.format("[%s] Unit %s does not exist, hiding frame", ModuleName, unit))
-- --end
-- frame:Hide()
-- else
-- --local unitFrame = _G[string.format("ElvUI_NamePlate%dHealthBar", i)]
-- local unitFrame = _G[string.format("NamePlate%d", i)]
-- if unitFrame == nil then
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Unit frame for %s not found", ModuleName, unit))
-- end
-- frame:Hide()
-- else
-- local unitName = UnitName(unit)
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Unit frame found for %s (%s)", ModuleName, unit, unitName))
-- end
-- frame:Show()
-- frame:SetSize(32, 32)
-- frame:SetFrameStrata("HIGH")
-- frame:SetFrameLevel(100)
-- frame:SetScale(Heimdall_Data.config.achievementSniffer.iconScale)
-- frame.texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
-- frame:SetPoint("CENTER", unitFrame, "CENTER",
-- Heimdall_Data.config.achievementSniffer.offsetX,
-- Heimdall_Data.config.achievementSniffer.offsetY)
-- frame:SetParent(unitFrame)
-- frame:SetAlpha(1)
-- local exists = ShouldInspect(unitName)
-- if exists then
-- frame.texture:SetVertexColor(1, 0, 0, 1)
-- else
-- frame.texture:SetVertexColor(0, 1, 0, 1)
-- end
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Frame updated for %s", ModuleName, unitName))
-- end
-- end
-- end
-- end
--end
---@param unit string
local function TryInspect(unit)
local targetPlayer = UnitIsPlayer(unit)
if not targetPlayer then return end
local targetName = UnitName(unit)
local targetGuid = UnitGUID(unit)
guidMap[targetGuid] = targetName
if not ShouldInspect(targetName) then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Not inspecting player: %s", ModuleName, targetName))
end
return
end
local canInspect = CheckInteractDistance(unit, 1)
if canInspect then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Inspecting player: %s", ModuleName, targetName))
end
SetAchievementComparisonUnit(unit)
else
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Cannot inspect player (too far?): %s", ModuleName, targetName))
end
end
end
---@param name string
local function Scan(name)
if Heimdall_Data.config.achievementSniffer.debug then if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Scanning achievements for %s", ModuleName, name)) print(string.format("[%s] Module initialized", ModuleName))
end end
Heimdall_Achievements.players[name] = {} local guidMap = {}
for i, aid in ipairs(Achievements) do
local completed, month, day, year = GetAchievementComparisonInfo(aid)
if completed then
---@type string
local yearstr = "" .. year
if year < 100 then yearstr = "20" .. year end
local date = string.format("%04d-%02d-%02d", yearstr, month, day) ---@class AchievementData
---@field id number
---@field date string
---@field completed boolean
local data = { ---@class Heimdall_Achievements
id = aid, ---@field players table<string, table<number, AchievementData>>
date = date, ---@field alreadySeen table<string, boolean>
completed = completed, ---@field rescan boolean
} if not Heimdall_Achievements then Heimdall_Achievements = {} end
if not Heimdall_Achievements.players then Heimdall_Achievements.players = {} end
if not Heimdall_Achievements.alreadySeen then Heimdall_Achievements.alreadySeen = {} end
--local framePool = {}
--for i = 1, 40 do
-- local frame = CreateFrame("Frame", "HeimdallAchievementSnifferNameplate" .. i, UIParent)
-- local texture = frame:CreateTexture(nil, "ARTWORK")
-- texture:SetAllPoints(frame)
-- texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
-- frame.texture = texture
-- frame:Hide()
-- table.insert(framePool, frame)
--end
---@param name string
---@return boolean
local function ShouldInspect(name)
local should = false
if not Heimdall_Achievements.players[name] then
if Heimdall_Data.config.achievementSniffer.debug then if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Achievement %d completed on %s", ModuleName, aid, date)) print(string.format("[%s] Player %s does not have prior achievement data", ModuleName, name))
end
should = true
end
if Heimdall_Achievements.alreadySeen[name] then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Player %s has already been seen", ModuleName, name))
end
-- Save some memory
Heimdall_Achievements.players[name] = nil
should = false
end
if Heimdall_Data.config.achievementSniffer.rescan then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Rescan is enabled", ModuleName))
end
should = true
end
return should
end
-- It's not working well AT ALL
-- I don't know how to do it better
-- It simply just does not work...
--local function UpdateFrames()
-- for i, frame in ipairs(framePool) do
-- local unit = "nameplate" .. i
-- if not UnitExists(unit) then
-- --if Heimdall_Data.config.achievementSniffer.debug then
-- -- print(string.format("[%s] Unit %s does not exist, hiding frame", ModuleName, unit))
-- --end
-- frame:Hide()
-- else
-- --local unitFrame = _G[string.format("ElvUI_NamePlate%dHealthBar", i)]
-- local unitFrame = _G[string.format("NamePlate%d", i)]
-- if unitFrame == nil then
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Unit frame for %s not found", ModuleName, unit))
-- end
-- frame:Hide()
-- else
-- local unitName = UnitName(unit)
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Unit frame found for %s (%s)", ModuleName, unit, unitName))
-- end
-- frame:Show()
-- frame:SetSize(32, 32)
-- frame:SetFrameStrata("HIGH")
-- frame:SetFrameLevel(100)
-- frame:SetScale(Heimdall_Data.config.achievementSniffer.iconScale)
-- frame.texture:SetTexture(TextureRoot .. Heimdall_Data.config.achievementSniffer.texture)
-- frame:SetPoint("CENTER", unitFrame, "CENTER",
-- Heimdall_Data.config.achievementSniffer.offsetX,
-- Heimdall_Data.config.achievementSniffer.offsetY)
-- frame:SetParent(unitFrame)
-- frame:SetAlpha(1)
-- local exists = ShouldInspect(unitName)
-- if exists then
-- frame.texture:SetVertexColor(1, 0, 0, 1)
-- else
-- frame.texture:SetVertexColor(0, 1, 0, 1)
-- end
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Frame updated for %s", ModuleName, unitName))
-- end
-- end
-- end
-- end
--end
---@param unit string
local function TryInspect(unit)
local targetPlayer = UnitIsPlayer(unit)
if not targetPlayer then return end
local targetName = UnitName(unit)
local targetGuid = UnitGUID(unit)
guidMap[targetGuid] = targetName
if not ShouldInspect(targetName) then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Not inspecting player: %s", ModuleName, targetName))
end
return
end
local canInspect = CheckInteractDistance(unit, 1)
if canInspect then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Inspecting player: %s", ModuleName, targetName))
end
SetAchievementComparisonUnit(unit)
else
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Cannot inspect player (too far?): %s", ModuleName, targetName))
end end
Heimdall_Achievements.players[name][aid] = data
end end
end end
--UpdateFrames()
end
local nameplateFrame = CreateFrame("Frame") ---@param name string
nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED") local function Scan(name)
nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
nameplateFrame:SetScript("OnEvent", function(self, event, unit)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Event triggered: %s for unit: %s", ModuleName, event, unit))
end
if event == "NAME_PLATE_UNIT_ADDED" then TryInspect(unit) end
--UpdateFrames()
end)
local inspectFrame = CreateFrame("Frame")
inspectFrame:RegisterEvent("INSPECT_ACHIEVEMENT_READY")
inspectFrame:SetScript("OnEvent", function(self, event, guid)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
local name = guidMap[guid]
if not name then
if Heimdall_Data.config.achievementSniffer.debug then if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] No name found for guid: %s", ModuleName, guid)) print(string.format("[%s] Scanning achievements for %s", ModuleName, name))
end end
return Heimdall_Achievements.players[name] = {}
end for i, aid in ipairs(Achievements) do
if Heimdall_Data.config.achievementSniffer.debug then local completed, month, day, year = GetAchievementComparisonInfo(aid)
print(string.format("[%s] Event triggered: %s for player: %s", ModuleName, event, name)) if completed then
end ---@type string
Scan(name) local yearstr = "" .. year
end) if year < 100 then yearstr = "20" .. year end
local function Tick() local date = string.format("%04d-%02d-%02d", yearstr, month, day)
C_Timer.NewTimer(Heimdall_Data.config.achievementSniffer.scanInterval, Tick)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
if Heimdall_Data.config.achievementSniffer.debug then local data = {
print(string.format("[%s] Scanning achievements for everyone on screen", ModuleName)) id = aid,
end date = date,
for i = 1, 40 do completed = completed,
local unit = "nameplate" .. i }
if UnitExists(unit) then if Heimdall_Data.config.achievementSniffer.debug then
TryInspect(unit) print(string.format("[%s] Achievement %d completed on %s", ModuleName, aid, date))
--else end
-- if Heimdall_Data.config.achievementSniffer.debug then Heimdall_Achievements.players[name][aid] = data
-- print(string.format("[%s] Unit %s does not exist, nothing to inspect", ModuleName, unit)) end
-- end
end end
--UpdateFrames()
end end
--UpdateFrames()
end
Tick()
print("[Heimdall] AchievementSniffer loaded") local nameplateFrame = CreateFrame("Frame")
end nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
nameplateFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
nameplateFrame:SetScript("OnEvent", function(self, event, unit)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Event triggered: %s for unit: %s", ModuleName, event, unit))
end
if event == "NAME_PLATE_UNIT_ADDED" then TryInspect(unit) end
--UpdateFrames()
end)
local inspectFrame = CreateFrame("Frame")
inspectFrame:RegisterEvent("INSPECT_ACHIEVEMENT_READY")
inspectFrame:SetScript("OnEvent", function(self, event, guid)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
local name = guidMap[guid]
if not name then
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] No name found for guid: %s", ModuleName, guid))
end
return
end
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Event triggered: %s for player: %s", ModuleName, event, name))
end
Scan(name)
end)
local function Tick()
C_Timer.NewTimer(Heimdall_Data.config.achievementSniffer.scanInterval, Tick)
if not Heimdall_Data.config.achievementSniffer.enabled then return end
if Heimdall_Data.config.achievementSniffer.debug then
print(string.format("[%s] Scanning achievements for everyone on screen", ModuleName))
end
for i = 1, 40 do
local unit = "nameplate" .. i
if UnitExists(unit) then
TryInspect(unit)
--else
-- if Heimdall_Data.config.achievementSniffer.debug then
-- print(string.format("[%s] Unit %s does not exist, nothing to inspect", ModuleName, unit))
-- end
end
end
--UpdateFrames()
end
Tick()
print("[Heimdall] AchievementSniffer loaded")
end,
}

View File

@@ -1,5 +1,6 @@
local _, shared = ... local _, shared = ...
---@cast shared HeimdallShared ---@cast shared HeimdallShared
local ModuleName = "BonkDetector"
---@class HeimdallBonkDetectorConfig ---@class HeimdallBonkDetectorConfig
---@field enabled boolean ---@field enabled boolean
@@ -7,8 +8,7 @@ local _, shared = ...
---@field channels string[] ---@field channels string[]
---@field throttle number ---@field throttle number
local ModuleName = "BonkDetector" ---@class BonkDetector
shared.BonkDetector = { shared.BonkDetector = {
---@return nil ---@return nil
Init = function() Init = function()

View File

@@ -1,12 +1,12 @@
local _, shared = ... local _, shared = ...
---@cast shared HeimdallShared ---@cast shared HeimdallShared
local ModuleName = "Bully"
---@class HeimdallBullyConfig ---@class HeimdallBullyConfig
---@field enabled boolean ---@field enabled boolean
---@field debug boolean ---@field debug boolean
local ModuleName = "Bully" ---@class Bully
shared.Bully = { shared.Bully = {
---@return nil ---@return nil
Init = function() Init = function()

View File

@@ -1,394 +1,389 @@
local _, shared = ... local _, shared = ...
---@cast shared HeimdallShared ---@cast shared HeimdallShared
local ModuleName = "Commander"
---@class HeimdallCommanderConfig
---@field enabled boolean ---@class HeimdallCommanderConfig
---@field debug boolean ---@field enabled boolean
---@field channels string[] ---@field debug boolean
---@field commander string ---@field channels string[]
---@field commands table<string, boolean> ---@field commander string
---@field commands table<string, boolean>
local ModuleName = "Commander"
local helpMessages = {
local helpMessages = { ru = {
ru = { "1) who - пишет вам никнеймы текущих врагов и локу.",
"1) who - пишет вам никнеймы текущих врагов и локу.", "2) classes - покажет классы врагов и число.",
"2) classes - покажет классы врагов и число.", "3) howmany - общее число врагов (дурик 4 . огри 2 ) ",
"3) howmany - общее число врагов (дурик 4 . огри 2 ) ", "4) + - атоинвайт в сбор пати и сброса кд.",
"4) + - атоинвайт в сбор пати и сброса кд.", "5) ++ -автоинвайт в пати аликов (если нужен рефрак)",
"5) ++ -автоинвайт в пати аликов (если нужен рефрак)", "6 ) note Никнейм текст - добавление заметки.",
"6 ) note Никнейм текст - добавление заметки.", "7) note Никнейм - посмотреть последние заметки.",
"7) note Никнейм - посмотреть последние заметки.", "8) note Никнейм 5 - посмотреть конкретную заметку.",
"8) note Никнейм 5 - посмотреть конкретную заметку.", "9) note Никнейм 1..5 - посмотреть заметки от 1 до 5",
"9) note Никнейм 1..5 - посмотреть заметки от 1 до 5", "10) note Никнейм delete 1 - удалить заметку номер 1",
"10) note Никнейм delete 1 - удалить заметку номер 1", "11) note Никнейм delete 1..5 - удалить заметки 1 до 5",
"11) note Никнейм delete 1..5 - удалить заметки 1 до 5", },
}, en = {
en = { "1) who - reports currently tracked stinkies in orgrimmar and durotar",
"1) who - reports currently tracked stinkies in orgrimmar and durotar", "2) classes - reports stinkies grouped by class",
"2) classes - reports stinkies grouped by class", "3) howmany - reports stinkies grouped by zone",
"3) howmany - reports stinkies grouped by zone", "4) + - automatically invites to group with duel rogue for cd reset",
"4) + - automatically invites to group with duel rogue for cd reset", "5) ++ - automatically invites to alliance group",
"5) ++ - automatically invites to alliance group", "6) note <name> <note> - adds a note for the specified character.",
"6) note <name> <note> - adds a note for the specified character.", "7) note <name> - lists the last N notes for the character.",
"7) note <name> - lists the last N notes for the character.", "8) note <name> i - lists the i-th note for the character.",
"8) note <name> i - lists the i-th note for the character.", "9) note <name> i..j - lists notes from i to j for the character.",
"9) note <name> i..j - lists notes from i to j for the character.", "10) note <name> delete i - deletes the i-th note for the character.",
"10) note <name> delete i - deletes the i-th note for the character.", "11) note <name> delete i..j - deletes notes from i to j for the character.",
"11) note <name> delete i..j - deletes notes from i to j for the character.", },
}, }
}
---@class Commander
---@class Commander shared.Commander = {
shared.Commander = { Init = function()
Init = function() ---@param text string
---@param text string ---@param size number
---@param size number ---@return string[]
---@return string[] local function Partition(text, size)
local function Partition(text, size) local words = {}
local words = {} for word in text:gmatch("[^,]+") do
for word in text:gmatch("[^,]+") do words[#words + 1] = word
words[#words + 1] = word end
end
local ret = {}
local ret = {} local currentChunk = ""
local currentChunk = ""
for _, word in ipairs(words) do
for _, word in ipairs(words) do if #currentChunk + #word + 1 <= size then
if #currentChunk + #word + 1 <= size then currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word)
currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word) else
else if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
if #currentChunk > 0 then ret[#ret + 1] = currentChunk end currentChunk = word
currentChunk = word end
end end
end
if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
if #currentChunk > 0 then ret[#ret + 1] = currentChunk end
return ret
return ret end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function Count(arr)
local function Count(arr) local ret = {}
local ret = {} for _, player in pairs(arr) do
for _, player in pairs(arr) do if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end
if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end end
end local text = {}
local text = {} for zone, count in pairs(ret) do
for zone, count in pairs(ret) do text[#text + 1] = string.format("%s: %d", zone, count)
text[#text + 1] = string.format("%s: %d", zone, count) end
end return text
return text end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function CountPartitioned(arr)
local function CountPartitioned(arr) local count = Count(arr)
local count = Count(arr) local text = {}
local text = {} ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do
for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do text[#text + 1] = line
text[#text + 1] = line end
end return text
return text end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function Who(arr)
local function Who(arr) local ret = {}
local ret = {} for _, player in pairs(arr) do
for _, player in pairs(arr) do if shared.Whoer.ShouldNotifyForZone(player.zone) then
if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[#ret + 1] = string.format(
ret[#ret + 1] = string.format( "%s/%s (%s) %s",
"%s/%s (%s) %s", player.name,
player.name, player.class,
player.class, player.zone,
player.zone, player.stinky and "(!!!!)" or ""
player.stinky and "(!!!!)" or "" )
) end
end end
end if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Command result: %s", ModuleName, strjoin(", ", unpack(ret))))
print(string.format("[%s] Command result: %s", ModuleName, strjoin(", ", unpack(ret)))) end
end return ret
return ret end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function WhoPartitioned(arr)
local function WhoPartitioned(arr) local who = Who(arr)
local who = Who(arr) local text = {}
local text = {} ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do
for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do text[#text + 1] = "who: " .. line
text[#text + 1] = "who: " .. line end
end return text
return text end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function CountClass(arr)
local function CountClass(arr) local ret = {}
local ret = {} for _, player in pairs(arr) do
for _, player in pairs(arr) do if shared.Whoer.ShouldNotifyForZone(player.zone) then
if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.class] = (ret[player.class] or 0) + 1
ret[player.class] = (ret[player.class] or 0) + 1 end
end end
end local text = {}
local text = {} for class, count in pairs(ret) do
for class, count in pairs(ret) do text[#text + 1] = string.format("%s: %d", class, count)
text[#text + 1] = string.format("%s: %d", class, count) end
end if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text))))
print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text)))) end
end return text
return text end
end ---@param arr table<string, Player>
---@param arr table<string, Player> ---@return string[]
---@return string[] local function CountClassPartitioned(arr)
local function CountClassPartitioned(arr) local countClass = CountClass(arr)
local countClass = CountClass(arr) local text = {}
local text = {} ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do
for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do text[#text + 1] = line
text[#text + 1] = line end
end return text
return text end
end local function CountClassPartitionedStinkies()
local function CountClassPartitionedStinkies() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName))
print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName)) end
end local res = CountClassPartitioned(HeimdallStinkies)
local res = CountClassPartitioned(HeimdallStinkies) if #res == 0 then return { "No stinkies found" } end
if #res == 0 then return { "No stinkies found" } end return res
return res end
end local function WhoPartitionedStinkies()
local function WhoPartitionedStinkies() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName))
print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName)) shared.dumpTable(HeimdallStinkies)
shared.dumpTable(HeimdallStinkies) end
end local res = WhoPartitioned(HeimdallStinkies)
local res = WhoPartitioned(HeimdallStinkies) if #res == 0 then return { "No stinkies found" } end
if #res == 0 then return { "No stinkies found" } end return res
return res end
end local function CountPartitionedStinkies()
local function CountPartitionedStinkies() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: CountPartitionedStinkies", ModuleName))
print(string.format("[%s] Executing: CountPartitionedStinkies", ModuleName)) end
end local res = CountPartitioned(HeimdallStinkies)
local res = CountPartitioned(HeimdallStinkies) if #res == 0 then return { "No stinkies found" } end
if #res == 0 then return { "No stinkies found" } end return res
return res end
end local function HelpRu()
local function HelpRu() if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end return helpMessages.ru
return helpMessages.ru end
end local function HelpEn()
local function HelpEn() if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end return helpMessages.en
return helpMessages.en end
end local groupInviteFrame = CreateFrame("Frame")
local groupInviteFrame = CreateFrame("Frame") groupInviteFrame:SetScript("OnEvent", function(self, event, ...)
groupInviteFrame:SetScript("OnEvent", function(self, event, ...) if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end AcceptGroup()
AcceptGroup() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST")
groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") C_Timer.NewTimer(0.1, function()
C_Timer.NewTimer(0.1, function() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Click event triggered", ModuleName))
print(string.format("[%s] Click event triggered", ModuleName)) end
end _G["StaticPopup1Button1"]:Click()
_G["StaticPopup1Button1"]:Click() end, 1)
end, 1) end)
end) local function JoinGroup()
local function JoinGroup() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] JoinGroup command received", ModuleName))
print(string.format("[%s] JoinGroup command received", ModuleName)) end
end groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST")
groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST") C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1)
C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1) return { "+" }
return { "+" } end
end local function LeaveGroup()
local function LeaveGroup() if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] LeaveGroup command received", ModuleName))
print(string.format("[%s] LeaveGroup command received", ModuleName)) end
end LeaveParty()
LeaveParty() return {}
return {} end
end ---@param target string
---@param target string local function FollowTarget(target)
local function FollowTarget(target) if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Following target: %s", ModuleName, target))
print(string.format("[%s] Following target: %s", ModuleName, target)) end
end if not target then return end
if not target then return end FollowUnit(target)
FollowUnit(target) return {}
return {} end
end
---@param args string[]
---@param args string[] local function MacroTarget(args)
local function MacroTarget(args) if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) end
end if #args < 2 or #args % 2 ~= 0 then
if #args < 2 or #args % 2 ~= 0 then if #args < 2 or #args % 2 ~= 0 then
if #args < 2 or #args % 2 ~= 0 then if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName))
print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName)) end
end return {}
return {} end
end end
end table.remove(args, 1)
table.remove(args, 1)
for i = 1, #args do
for i = 1, #args do local stinky = strtrim(args[i])
local stinky = strtrim(args[i]) local name = stinky:match("([^/]+)")
local name = stinky:match("([^/]+)") local class = stinky:match("/([^ $]+)")
local class = stinky:match("/([^ $]+)") if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class)))
print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class))) end
end shared.StinkyTracker.Track({
shared.StinkyTracker.Track({ name = name,
name = name, class = class or "unknown",
class = class or "unknown", seenAt = GetTime(),
seenAt = GetTime(), hostile = true,
hostile = true, })
}) if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class)))
print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class))) end
end end
end return {}
return {} end
end
---@param args string[]
---@param args string[] local function IgnoreMacroTarget(args)
local function IgnoreMacroTarget(args) if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack
---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args))))
print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) end
end if #args < 1 then
if #args < 1 then if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName))
print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName)) end
end return {}
return {} end
end table.remove(args, 1)
table.remove(args, 1)
for i = 1, #args do
for i = 1, #args do local stinky = strtrim(args[i])
local stinky = strtrim(args[i]) local name = stinky:match("([^/]+)")
local name = stinky:match("([^/]+)") if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring stinky: %s", ModuleName, name))
print(string.format("[%s] Ignoring stinky: %s", ModuleName, name)) end
end shared.StinkyTracker.Ignore(name)
shared.StinkyTracker.Ignore(name) end
end return {}
return {} end
end
---@class Command
---@class Command ---@field keywordRe string
---@field keywordRe string ---@field commanderOnly boolean
---@field commanderOnly boolean ---@field callback fun(...: any): string[]
---@field callback fun(...: any): string[]
local commands = {
local commands = { { keywordRe = "^who$", commanderOnly = false, callback = WhoPartitionedStinkies },
{ keywordRe = "^who$", commanderOnly = false, callback = WhoPartitionedStinkies }, { keywordRe = "^howmany$", commanderOnly = false, callback = CountPartitionedStinkies },
{ keywordRe = "^howmany$", commanderOnly = false, callback = CountPartitionedStinkies }, { keywordRe = "^classes$", commanderOnly = false, callback = CountClassPartitionedStinkies },
{ keywordRe = "^classes$", commanderOnly = false, callback = CountClassPartitionedStinkies }, { keywordRe = "^help$", commanderOnly = false, callback = HelpRu },
{ keywordRe = "^help$", commanderOnly = false, callback = HelpRu }, { keywordRe = "^helpen$", commanderOnly = false, callback = HelpEn },
{ keywordRe = "^helpen$", commanderOnly = false, callback = HelpEn }, { keywordRe = "^joingroup$", commanderOnly = false, callback = JoinGroup },
{ keywordRe = "^joingroup$", commanderOnly = false, callback = JoinGroup }, { keywordRe = "^leavegroup$", commanderOnly = false, callback = LeaveGroup },
{ keywordRe = "^leavegroup$", commanderOnly = false, callback = LeaveGroup }, { keywordRe = "^follow$", commanderOnly = false, callback = FollowTarget },
{ keywordRe = "^follow$", commanderOnly = false, callback = FollowTarget }, { keywordRe = "^macro", commanderOnly = false, callback = MacroTarget },
{ keywordRe = "^macro", commanderOnly = false, callback = MacroTarget }, { keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget },
{ keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget }, }
}
local commanderChannelFrame = CreateFrame("Frame")
local commanderChannelFrame = CreateFrame("Frame") commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL")
commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL") commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...) --if Heimdall_Data.config.commander.debug then
--if Heimdall_Data.config.commander.debug then -- print(string.format("[%s] Event received", ModuleName))
-- print(string.format("[%s] Event received", ModuleName)) -- shared.dumpTable(Heimdall_Data.config.commander)
-- shared.dumpTable(Heimdall_Data.config.commander) --end
--end if not Heimdall_Data.config.commander.enabled then
if not Heimdall_Data.config.commander.enabled then --if Heimdall_Data.config.commander.debug then
--if Heimdall_Data.config.commander.debug then -- print(string.format("[%s] Module disabled, ignoring event", ModuleName))
-- print(string.format("[%s] Module disabled, ignoring event", ModuleName)) --end
--end return
return end
end local channelId = select(6, ...)
local channelId = select(6, ...) local _, channelname = GetChannelName(channelId)
local _, channelname = GetChannelName(channelId) local ok = false
local ok = false for _, channel in pairs(Heimdall_Data.config.commander.channels) do
for _, channel in pairs(Heimdall_Data.config.commander.channels) do if channel == channelname then
if channel == channelname then ok = true
ok = true break
break end
end end
end if not ok then
if not ok then if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(
print( string.format(
string.format( "[%s] Channel name '%s' does not match any of the channels '%s'",
"[%s] Channel name '%s' does not match any of the channels '%s'", ModuleName,
ModuleName, channelname,
channelname, table.concat(Heimdall_Data.config.commander.channels, ", ")
table.concat(Heimdall_Data.config.commander.channels, ", ") )
) )
) end
end return
return end
end
sender = string.match(sender, "^[^-]+")
sender = string.match(sender, "^[^-]+") if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(string.format("[%s] Message from: %s", ModuleName, sender))
print(string.format("[%s] Message from: %s", ModuleName, sender)) shared.dumpTable(Heimdall_Data.config.commander)
shared.dumpTable(Heimdall_Data.config.commander) end
end
for _, command in ipairs(commands) do
for _, command in ipairs(commands) do local enabled = Heimdall_Data.config.commander.commands[command.keywordRe] == true or false
local enabled = Heimdall_Data.config.commander.commands[command.keywordRe] == true or false if Heimdall_Data.config.commander.debug then
if Heimdall_Data.config.commander.debug then print(
print( string.format("[%s] Command match: %s = %s", ModuleName, command.keywordRe, tostring(enabled))
string.format("[%s] Command match: %s = %s", ModuleName, command.keywordRe, tostring(enabled)) )
) end
end if
if enabled
enabled and (
and ( not command.commanderOnly
not command.commanderOnly -- if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring command, sender %s not commander %s", ModuleName, sender, Heimdall_Data.config.commander.commander)) end
-- if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring command, sender %s not commander %s", ModuleName, sender, Heimdall_Data.config.commander.commander)) end
or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander)
)
then
if msg:match(command.keywordRe) then
or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander) ---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field
) local messages = command.callback({ strsplit(",", msg) })
then if Heimdall_Data.config.commander.debug then
if msg:match(command.keywordRe) then ---@diagnostic disable-next-line: param-type-mismatch
---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field print(
local messages = command.callback({ strsplit(",", msg) }) string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages)))
if Heimdall_Data.config.commander.debug then )
---@diagnostic disable-next-line: param-type-mismatch end
print( for _, message in ipairs(messages) do
string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages))) ---@type Message
) local returnmsg = {
end channel = "C",
for _, message in ipairs(messages) do data = channelname,
---@type Message message = message,
local returnmsg = { }
channel = "C", if Heimdall_Data.config.commander.debug then
data = channelname, print(string.format("[%s] Queuing message", ModuleName))
message = message, shared.dumpTable(msg)
} end
if Heimdall_Data.config.commander.debug then --table.insert(shared.messenger.queue, msg)
print(string.format("[%s] Queuing message", ModuleName)) table.insert(shared.networkMessenger.queue, returnmsg)
shared.dumpTable(msg) end
end end
--table.insert(shared.messenger.queue, msg) end
table.insert(shared.networkMessenger.queue, returnmsg) end
end end)
end
end print("[Heimdall] Commander module loaded")
end end,
end)
print("[Heimdall] Commander module loaded")
end,
}

File diff suppressed because it is too large Load Diff