nop
nop

Reputation: 6361

Preventing AUTOFOLLOW_END and AUTOFOLLOW_BEGIN Spam in WoW Addon

I'm working on a simple multiboxing helper addon for 3.3.5 (Wrath of the Lich King). My addon involves maintaining a trusted list of characters called teamList. Since there's no direct API function available to check if one character is following another, I've implemented this functionality using AceComm, allowing my WoW instances to communicate with each other.

The issue I'm facing is related to the auto-follow feature in the game. When I start following one of my characters and then re-follow the same target without breaking the follow, the game triggers the AUTOFOLLOW_END event and then immediately follows it up with the AUTOFOLLOW_BEGIN event. Consequently, if I spam AltF repeatedly in ISBoxer to follow the same character again, it results in the game spamming the "Follow Broken" message.

How can I prevent this behavior and ensure that the "Follow Broken" message is not displayed when re-following the same character within a short timeframe?

Team.lua

local AddonName = ...
local DMA = LibStub("AceAddon-3.0"):GetAddon(AddonName)
local Team = DMA:NewModule("Team", "AceEvent-3.0", "AceConsole-3.0")

-- get a reference to the Communication module
local Communication = DMA:GetModule("Communication")

-- constants
local SLASH_TEAMFOLLOW1 = "teamfollow"
local SLASH_TEAMFOLLOW2 = "tf"

-- variables
local selectedCharacter = nil
local masterCharacter = nil

local currentlyFollowing = nil

local teamList = {}

-- options
local options = {
    name = "Team",
    type = "group",
    args = {
        header = {
            type = "header",
            name = "Multiboxing Team Management",
            order = 0,
        },
        description = {
            type = "description",
            name = "Manage your multiboxing team members and designate a master character.",
            fontSize = "medium",
            order = 1,
        },
        teamControlGroup = {
            type = "group",
            name = "Team Controls",
            inline = true,
            order = 2,
            args = {
                newCharacterName = {
                    type = "input",
                    name = "Add New Character",
                    desc = "Enter the name of a new character to add to your team.",
                    set = function(_, val) Team:AddCharacter(val) end,
                    order = 1,
                },
                teamDropdown = {
                    type = "select",
                    name = "Select Team Member",
                    desc = "Choose a member of your team to manage.",
                    values = function() return Team:GetTeamListOptions() end,
                    get = function() return selectedCharacter end,
                    set = function(_, val) selectedCharacter = val end,
                    order = 2,
                },
                setMaster = {
                    type = "select",
                    name = "Set Master",
                    desc = "Select the master character of your multiboxing team.",
                    values = function() return Team:GetTeamListOptions() end,
                    get = function() return masterCharacter end,
                    set = function(_, val) masterCharacter = val end,
                    order = 3,
                },
                removeCharacter = {
                    type = "execute",
                    name = "Remove Character",
                    desc = "Remove the selected character from the team.",
                    func = function() Team:RemoveCharacter() end,
                    order = 4,
                }
            }
        }
    }
}

function Team:OnInitialize()
    LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("DMA_Team_Options", options)
    self.optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("DMA_Team_Options", "Team", AddonName)
end

function Team:OnEnable()
    Communication:RegisterMessageHandler(function(message, distribution, sender)
        self:HandleMessage(message, distribution, sender)
    end)

    self:RegisterEvent("AUTOFOLLOW_BEGIN")
    self:RegisterEvent("AUTOFOLLOW_END")

    self:RegisterChatCommand(SLASH_TEAMFOLLOW1, "TeamFollowCommand")
    self:RegisterChatCommand(SLASH_TEAMFOLLOW2, "TeamFollowCommand")
end

function Team:GetTeamListOptions()
    local values = {}
    for key, _ in pairs(teamList) do
        values[key] = key
    end
    return values
end

function Team:AddCharacter(name)
    if name and name ~= "" and not teamList[name] then
        teamList[name] = name
        -- Update the dropdown menu
        LibStub("AceConfigRegistry-3.0"):NotifyChange("DMA_Team_Options")
    end
end

function Team:RemoveCharacter()
    if selectedCharacter then
        teamList[selectedCharacter] = nil
        selectedCharacter = nil
        -- Update the dropdown menu
        LibStub("AceConfigRegistry-3.0"):NotifyChange("DMA_Team_Options")
    end
end

function Team:IsInTeam(name)
    return teamList[name] ~= nil
end

-- Event handler for when auto-follow begins
function Team:AUTOFOLLOW_BEGIN(event, name)
    if self:IsInTeam(name) then
        currentlyFollowing = name -- Store the name of the character being followed
        -- Send a message that the current player (UnitName("player")) is following 'name'
        Communication:SendMessage("FollowStart", "WHISPER", name)
    end
end

-- Event handler for when auto-follow ends
function Team:AUTOFOLLOW_END()
    if currentlyFollowing then
        Communication:SendMessage("FollowStop:" .. UnitName("player"), "WHISPER", currentlyFollowing)
        currentlyFollowing = nil -- Reset the variable as you are no longer following
    end
end

-- Handle incoming communication messages
function Team:HandleMessage(message, distribution, sender)
    -- Message format is "command:additionalInfo" (like "FollowStart:playerName")
    local command, info = strsplit(":", message, 2)

    if command == "FollowStart" then
        print(sender .. " has started following.")
    elseif command == "FollowStop" then
        print(sender .. " has stopped following.")
        RaidNotice_AddMessage(RaidWarningFrame, sender .. " has stopped following - follow link broken!", ChatTypeInfo["RAID_WARNING"])
    elseif command == "FollowMe" then
        if Team:IsInTeam(sender) then
            FollowUnit(sender)
        end
    end
end

-- Slash command to instruct all team members to follow you
function Team:TeamFollowCommand()
    for member, _ in pairs(teamList) do
        -- Check if the member is not the current player
        if member ~= UnitName("player") then
            -- Send a message to each team member to start following this player
            Communication:SendMessage("FollowMe", "WHISPER", member)
        end
    end
end

Communication.lua

local AddonName = ...
local DMA = LibStub("AceAddon-3.0"):GetAddon(AddonName)
local Communication = DMA:NewModule("Communication", "AceEvent-3.0", "AceConsole-3.0", "AceComm-3.0")

local COMM_CHANNEL = "DMATeamChannel"

function Communication:OnInitialize()
    self.messageHandlers = {}
    self:RegisterComm(COMM_CHANNEL)
end

function Communication:RegisterMessageHandler(handlerFunc)
    table.insert(self.messageHandlers, handlerFunc)
end

function Communication:OnCommReceived(prefix, message, distribution, sender)
    if prefix ~= COMM_CHANNEL then return end

    for _, handler in ipairs(self.messageHandlers) do
        handler(message, distribution, sender)
    end
end

function Communication:SendMessage(message, distribution, target)
    self:SendCommMessage(COMM_CHANNEL, message, distribution, target)
end

Upvotes: 1

Views: 55

Answers (0)

Related Questions