commit 75af14c4ddf6cf3cacd56299df0ec779e012883e Author: Torsten Brendgen Date: Fri Apr 24 16:29:57 2026 +0200 Initial commit diff --git a/Adapters/BliZziInterrupts.lua b/Adapters/BliZziInterrupts.lua new file mode 100644 index 0000000..704f0ba --- /dev/null +++ b/Adapters/BliZziInterrupts.lua @@ -0,0 +1,125 @@ +local Bridge = _G.HMGT_Bridge +if not Bridge then return end + +local PREFIX = "BliZziIT" +local HEADER = "B1" +local SOURCE = "BliZzi_Interrupts" + +local Adapter = { + key = SOURCE, +} + +local frame = CreateFrame("Frame") + +local function IsSecret(value) + return type(issecretvalue) == "function" and issecretvalue(value) +end + +local function ParseMessage(message) + if IsSecret(message) then + return nil + end + + local text = tostring(message or "") + if text == "" then + return nil + end + + local parts = { strsplit(";", text) } + if parts[1] ~= HEADER then + return nil + end + + return parts +end + +local function NormalizeSender(sender) + if IsSecret(sender) then + return nil + end + + local text = tostring(sender or "") + if text == "" then + return nil + end + if Ambiguate then + text = Ambiguate(text, "short") + end + return Bridge:NormalizePlayerName(text) +end + +function Adapter:HandleHello(parts, senderName) + local class = tostring(parts[3] or "") + local spellId = tonumber(parts[4]) + local cooldown = tonumber(parts[5]) + if class == "" or not spellId or spellId <= 0 then + Bridge:RememberResult("known", false, "invalid_hello", tostring(senderName or "")) + return + end + Bridge:Count("hello") + Bridge:ApplyKnownSpell(SOURCE, senderName, spellId, class, cooldown) +end + +function Adapter:HandleHelloSync(parts, senderName) + local class = tostring(parts[3] or "") + local specId = tonumber(parts[5]) + if class == "" or not specId or specId <= 0 then + Bridge:RememberResult("spec", false, "invalid_hello_sync", tostring(senderName or "")) + return + end + Bridge:Count("helloSync") + Bridge:ApplySpecInfo(SOURCE, senderName, class, specId) +end + +function Adapter:HandleKick(parts, senderName) + local spellId = tonumber(parts[3]) + local cooldown = tonumber(parts[4]) + if not spellId or spellId <= 0 or not cooldown or cooldown <= 0 then + Bridge:RememberResult("cooldown", false, "invalid_kick", tostring(senderName or "")) + return + end + Bridge:Count("kick") + Bridge:ApplyCooldown(SOURCE, senderName, spellId, cooldown) +end + +function Adapter:OnAddonMessage(prefix, message, channel, sender) + if prefix ~= PREFIX then + return + end + Bridge:Count("received") + + local senderName = NormalizeSender(sender) + if not senderName or senderName == Bridge:NormalizePlayerName(UnitName("player")) then + Bridge:RememberResult("message", false, "ignored_sender", tostring(sender or "")) + return + end + + local parts = ParseMessage(message) + if not parts then + Bridge:RememberResult("message", false, "invalid_message", tostring(senderName or "")) + return + end + + local command = tostring(parts[2] or "") + if command == "HELLO" then + self:HandleHello(parts, senderName) + elseif command == "HELLOSYNC" then + self:HandleHelloSync(parts, senderName) + elseif command == "KICK" then + self:HandleKick(parts, senderName) + end +end + +function Adapter:Register() + if C_ChatInfo and type(C_ChatInfo.RegisterAddonMessagePrefix) == "function" then + pcall(C_ChatInfo.RegisterAddonMessagePrefix, PREFIX) + end + frame:RegisterEvent("CHAT_MSG_ADDON") + frame:RegisterEvent("CHAT_MSG_ADDON_LOGGED") + frame:SetScript("OnEvent", function(_, _, ...) + Adapter:OnAddonMessage(...) + end) +end + +Bridge:RegisterAdapter(Adapter) +Adapter:Register() diff --git a/Core.lua b/Core.lua new file mode 100644 index 0000000..d85707d --- /dev/null +++ b/Core.lua @@ -0,0 +1,145 @@ +local ADDON_NAME = ... +local HMGT = _G.HailMaryGuildTools +if not HMGT then return end + +local Bridge = { + name = ADDON_NAME or "HailMaryGuildTools_Bridge", + adapters = {}, + stats = { + received = 0, + hello = 0, + helloSync = 0, + kick = 0, + appliedKnown = 0, + appliedSpec = 0, + appliedCooldown = 0, + rejected = 0, + }, +} + +_G.HMGT_Bridge = Bridge +HMGT.Bridge = Bridge + +local function SafeText(value) + if type(issecretvalue) == "function" and issecretvalue(value) then + return nil + end + return tostring(value or "") +end + +function Bridge:RegisterAdapter(adapter) + if type(adapter) ~= "table" or not adapter.key then + return false + end + self.adapters[adapter.key] = adapter + return true +end + +function Bridge:Count(key) + self.stats = self.stats or {} + self.stats[key] = (tonumber(self.stats[key]) or 0) + 1 +end + +function Bridge:RememberResult(action, ok, reason, details) + self.lastResult = { + action = action, + ok = ok and true or false, + reason = reason, + details = details, + time = time and time() or nil, + } + + if ok then + if action == "known" then + self:Count("appliedKnown") + elseif action == "spec" then + self:Count("appliedSpec") + elseif action == "cooldown" then + self:Count("appliedCooldown") + end + else + self:Count("rejected") + end +end + +function Bridge:GetStatusLines() + local stats = self.stats or {} + local lines = { + "HMGT Bridge status", + string.format("Adapters: %d", self.adapters and (self.adapters["BliZzi_Interrupts"] and 1 or 0) or 0), + string.format( + "Messages: received=%d hello=%d helloSync=%d kick=%d", + tonumber(stats.received) or 0, + tonumber(stats.hello) or 0, + tonumber(stats.helloSync) or 0, + tonumber(stats.kick) or 0 + ), + string.format( + "Applied: known=%d spec=%d cooldown=%d rejected=%d", + tonumber(stats.appliedKnown) or 0, + tonumber(stats.appliedSpec) or 0, + tonumber(stats.appliedCooldown) or 0, + tonumber(stats.rejected) or 0 + ), + } + + if self.lastResult then + local result = self.lastResult + lines[#lines + 1] = string.format( + "Last: action=%s ok=%s reason=%s details=%s", + tostring(result.action or "?"), + tostring(result.ok), + tostring(result.reason or "-"), + tostring(result.details or "-") + ) + else + lines[#lines + 1] = "Last: no BliZzi message seen yet" + end + + return lines +end + +function Bridge:GetAdapter(key) + return self.adapters[key] +end + +function Bridge:NormalizePlayerName(name) + if HMGT and HMGT.NormalizePlayerName then + return HMGT:NormalizePlayerName(name) + end + return SafeText(name) +end + +function Bridge:ApplyKnownSpell(sourceName, playerName, spellId, class, cooldown) + if HMGT and HMGT.ApplyExternalKnownSpell then + local ok, reason = HMGT:ApplyExternalKnownSpell(sourceName, playerName, spellId, class, cooldown) + self:RememberResult("known", ok, reason, string.format("%s:%s", tostring(playerName), tostring(spellId))) + return ok, reason + end + self:RememberResult("known", false, "hmgt_api_missing") + return false, "hmgt_api_missing" +end + +function Bridge:ApplySpecInfo(sourceName, playerName, class, specId, talentString) + if HMGT and HMGT.ApplyExternalSpecInfo then + local ok, reason = HMGT:ApplyExternalSpecInfo(sourceName, playerName, class, specId, talentString) + self:RememberResult("spec", ok, reason, string.format("%s:%s", tostring(playerName), tostring(specId))) + return ok, reason + end + self:RememberResult("spec", false, "hmgt_api_missing") + return false, "hmgt_api_missing" +end + +function Bridge:ApplyCooldown(sourceName, playerName, spellId, cooldown) + if HMGT and HMGT.ApplyExternalCooldown then + local ok, reason = HMGT:ApplyExternalCooldown(sourceName, playerName, spellId, cooldown) + self:RememberResult("cooldown", ok, reason, string.format("%s:%s:%s", tostring(playerName), tostring(spellId), tostring(cooldown))) + return ok, reason + end + self:RememberResult("cooldown", false, "hmgt_api_missing") + return false, "hmgt_api_missing" +end + +function Bridge:SafeText(value) + return SafeText(value) +end diff --git a/HailMaryGuildTools_Bridge.toc b/HailMaryGuildTools_Bridge.toc new file mode 100644 index 0000000..0f98ffc --- /dev/null +++ b/HailMaryGuildTools_Bridge.toc @@ -0,0 +1,10 @@ +## Interface: 120000,120001,120005 +## IconTexture: Interface\Addons\HailMaryGuildTools\Media\HailMaryIcon.png +## Title: Hail Mary Guild Tools Bridge +## Notes: Compatibility bridge for external cooldown and interrupt addons. +## Author: Hail Mary Guild Tools +## Version: 1.0.0 +## Dependencies: HailMaryGuildTools + +Core.lua +Adapters\BliZziInterrupts.lua diff --git a/Media/HailMaryIcon.png b/Media/HailMaryIcon.png new file mode 100644 index 0000000..438c7ae Binary files /dev/null and b/Media/HailMaryIcon.png differ diff --git a/Media/HailMaryLogo.png b/Media/HailMaryLogo.png new file mode 100644 index 0000000..e1893a8 Binary files /dev/null and b/Media/HailMaryLogo.png differ