diff --git a/AutoInvite.lua b/AutoInvite.lua index 9a5f61f..bcdd83e 100644 --- a/AutoInvite.lua +++ b/AutoInvite.lua @@ -35,37 +35,39 @@ end ------------------------------------------------ --- Event handlers ------------------------------------------------ + +--Main callback fired on chat message AutoInvite.callback = function(_, messageType, from, message) if not AutoInvite.enabled or not AutoInvite.listening then return end - --TODO: Switch to queue-based with timeouts so don't send out too many invites + --TODO: Move this to the actual invite send so not per-message if GetGroupSize() >= AutoInvite.cfg.maxSize then echo("Group full. Disabling AutoInvite") AutoInvite.stopListening() end if string.lower(message) == AutoInvite.cfg.watchStr and from ~= nil and from ~= "" then - if (messageType >= CHAT_CHANNEL_GUILD_1 and messageType <= CHAT_CHANNEL_OFFICER_5) then - from = AutoInvite.guildLookup(messageType, from) - if from == "" then return end + if (messageType >= CHAT_CHANNEL_GUILD_1 and messageType <= CHAT_CHANNEL_OFFICER_5) or messageType == CHAT_CHANNEL_WHISPER then + from = AutoInvite.accountNameLookup(messageType, from) + if from == "" or from == nil then return end end - - --TODO: Add friends list lookup from = from:gsub("%^.+", "") echo("Sending invite to " .. from) - GroupInvite(from) - GroupInviteByName(from) + AutoInvite:invitePlayer(from) end --d("Checking message '" .. string.lower(message) .."' ?= '" .. AutoInvite.cfg.watchStr .."'") end -AutoInvite.playerLeave = function() - if AutoInvite.enabled and AutoInvite.cfg.restart and GetGroupSize() < AutoInvite.cfg.maxSize then - echo("Now space in group. Restarted listening.") +-- +AutoInvite.playerLeave = function(_, unitTag, connectStatus) + if AutoInvite.enabled and AutoInvite.cfg.restart then + if not AutoInvite.listening then + echo("Now space in group. Restarted listening.") + end AutoInvite.startListening() end @@ -86,24 +88,35 @@ end function AutoInvite.disbandEvent() if AutoInvite.enabled and AutoInvite.cfg.restart then - echo("Group disbanded. Restarted listening.") - AutoInvite.startListening() + --Group size checks in the listening function + AutoInvite.startListening(true) end end --- tick function: called every 15s +-- tick function: called every 1s function AutoInvite.tick() - AutoInvite.kickCheck() + local self = AutoInvite + self.kickCheck() + + if self.listening then + if GetGroupSize() >= self.cfg.maxSize then + self.stopListening() + else + self:checkSentInvites() + self:processQueue() + end + end end ------------------------------------------------ ---- Main interface +--- Event control ------------------------------------------------ AutoInvite.disable = function() AutoInvite.enabled = false AutoInvite.stopListening() - EVENT_MANAGER:UnregisterForUpdate("AutoInviteKickCheck") + EVENT_MANAGER:UnregisterForUpdate(AutoInvite.AddonId) EVENT_MANAGER:UnregisterForEvent(AutoInvite.AddonId, EVENT_GROUP_DISBANDED) + EVENT_MANAGER:UnregisterForEvent(AutoInvite.AddonId, EVENT_GROUP_INVITE_RESPONSE) end AutoInvite.stopListening = function() @@ -111,22 +124,27 @@ AutoInvite.stopListening = function() AutoInvite.listening = false end -AutoInvite.startListening = function() +--@param restart: (boolean) - true if restarted listening due to space open up +--currently only used for different print strings +AutoInvite.startListening = function(restart) if not AutoInvite.enabled then AutoInvite.enabled = true AutoInvite.checkOffline() - EVENT_MANAGER:RegisterForUpdate("AutoInviteKickCheck", 1000, AutoInvite.tick) - EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_DISBANDED) + EVENT_MANAGER:RegisterForUpdate(AutoInvite.AddonId, 1000, AutoInvite.tick) + EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_DISBANDED, AutoInvite.disbandEvent) + EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_INVITE_RESPONSE, AutoInvite.inviteResponse) end if not AutoInvite.listening and GetGroupSize() < AutoInvite.cfg.maxSize then --Add handler EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_CHAT_MESSAGE_CHANNEL, AutoInvite.callback) AutoInvite.listening = true + if restart ~= nil then + echo("Now space in group. AutoInvite restarted listening on '" .. AutoInvite.cfg.watchStr .. "'") + else + echo("AutoInvite listening on string '" .. AutoInvite.cfg.watchStr .. "'") + end end - - --First check. When option, will have to check option for disable - echo("AutoInvite listening on string '" .. AutoInvite.cfg.watchStr .. "'") end ------------------------------------------------ @@ -149,6 +167,10 @@ AutoInvite.init = function() AutoInvite.cfg = ZO_SavedVars:NewAccountWide("AutoInviteSettings", 1.0, "config", def) EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_MEMBER_LEFT, AutoInvite.playerLeave) EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_MEMBER_CONNECTED_STATUS, AutoInvite.offlineEvent) + + --Make sure Offline is updated after player zones (is offline for a bit + EVENT_MANAGER:RegisterForEvent("AutoInviteInit", EVENT_PLAYER_ACTIVATED, AutoInvite.checkOffline) + AutoInvite.listening = false AutoInvite.enabled = false AutoInviteUI.init() diff --git a/lua/guild.lua b/lua/guild.lua index 38d77d6..6032f8a 100644 --- a/lua/guild.lua +++ b/lua/guild.lua @@ -22,39 +22,68 @@ local function echo(msg) CHAT_SYSTEM.primaryContainer.currentBuffer:AddMessage(" AutoInvite = AutoInvite or {} -AutoInvite.guildLookup = function(channel, acctName) - local guildId = 0 - if channel == CHAT_CHANNEL_GUILD_1 or channel == CHAT_CHANNEL_OFFICER_1 then guildId = GetGuildId(1) end - if channel == CHAT_CHANNEL_GUILD_2 or channel == CHAT_CHANNEL_OFFICER_2 then guildId = GetGuildId(2) end - if channel == CHAT_CHANNEL_GUILD_3 or channel == CHAT_CHANNEL_OFFICER_3 then guildId = GetGuildId(3) end - if channel == CHAT_CHANNEL_GUILD_4 or channel == CHAT_CHANNEL_OFFICER_4 then guildId = GetGuildId(4) end - if channel == CHAT_CHANNEL_GUILD_5 or channel == CHAT_CHANNEL_OFFICER_5 then guildId = GetGuildId(5) end +function AutoInvite.executeNameLookup(hasChar, charName, zone) + if not hasChar then + echo("Could not find player name for " .. acctName .. ". Please manually invite.") + return "" + end + + charName = charName:gsub("%^.+", "") + + if AutoInvite.cfg.cyrCheck then + dbg("In Cyrodiil? " .. b(AutoInvite.isCyrodiil()) .. " / Zone: " .. zone) + + if AutoInvite.isCyrodiil() and zone ~= "Cyrodiil" then + echo("Player " .. charName .. " is not in Cyrodiil but in " .. zone) + echo("Blocking invite to prevent crashes.") + return "" + end + end - if guildId == 0 then d("Error - couldn't invite on channel: " .. channel) end + return charName +end +function AutoInvite.guildLookup(guildId, acctName) local aName for i=1,GetNumGuildMembers(guildId) do aName = GetGuildMemberInfo(guildId,i) if aName == acctName then - local hasChar, charName, zone = GetGuildMemberCharacterInfo(guildId,i) - if not hasChar then - echo("Could not find player name for " .. acctName .. ". Please manually invite.") - return "" - end + return AutoInvite.executeNameLookup(GetGuildMemberCharacterInfo(guildId,i)) + end + end +end - charName = charName:gsub("%^.+", "") +function AutoInvite.friendLookup(acctName) + for i=1,GetNumFriends() do + local aName = GetFriendInfo(i) + if aName == acctName then + return AutoInvite.executeNameLookup(GetFriendCharacterInfo(i)) + end + end + return nil +end - if AutoInvite.cfg.cyrCheck then - dbg("In Cyrodiil? " .. b(AutoInvite.isCyrodiil()) .. " / Zone: " .. zone) +function AutoInvite.accountNameLookup(channel, acctName) + local guildId = 0 + if channel == CHAT_CHANNEL_GUILD_1 or channel == CHAT_CHANNEL_OFFICER_1 then guildId = GetGuildId(1) end + if channel == CHAT_CHANNEL_GUILD_2 or channel == CHAT_CHANNEL_OFFICER_2 then guildId = GetGuildId(2) end + if channel == CHAT_CHANNEL_GUILD_3 or channel == CHAT_CHANNEL_OFFICER_3 then guildId = GetGuildId(3) end + if channel == CHAT_CHANNEL_GUILD_4 or channel == CHAT_CHANNEL_OFFICER_4 then guildId = GetGuildId(4) end + if channel == CHAT_CHANNEL_GUILD_5 or channel == CHAT_CHANNEL_OFFICER_5 then guildId = GetGuildId(5) end - if AutoInvite.isCyrodiil() and zone ~= "Cyrodiil" then - echo("Player " .. charName .. " is not in Cyrodiil but in " .. zone) - echo("Blocking invite to prevent crashes.") - return "" - end - end + if guildId > 0 then + AutoInvite.guildLookup(guildId, acctName) + else + --Came in on whisper channel, so try friends then move to all guilds + local charName = AutoInvite.friendLookup(acctName) + if charName then return charName end - return charName + for i=1,5 do + guildId = GetGuildId(i) + charName = AutoInvite.guildLookup(guildId, acctName) + if charName then return charName end end + + d("Error - couldn't invite on channel: " .. channel) end end \ No newline at end of file diff --git a/lua/kick.lua b/lua/kick.lua index 83421da..39a9ec5 100644 --- a/lua/kick.lua +++ b/lua/kick.lua @@ -16,6 +16,10 @@ -- along with this program. If not, see <http://www.gnu.org/licenses/>. AutoInvite = AutoInvite or {} +local function b(v) if v then return "T" else return "F" end end +local function nn(val) if val == nil then return "NIL" else return val end end +local function dbg(msg) if AutoInvite.debug then d("|c999999" .. msg) end end +local function echo(msg) CHAT_SYSTEM.primaryContainer.currentBuffer:AddMessage("|CFFFF00"..msg) end AutoInvite.kickTable = {} function AutoInvite.checkOffline() diff --git a/lua/queue.lua b/lua/queue.lua index 90b0319..f33aa97 100644 --- a/lua/queue.lua +++ b/lua/queue.lua @@ -16,6 +16,10 @@ -- along with this program. If not, see <http://www.gnu.org/licenses/>. AutoInvite = AutoInvite or {} +local function b(v) if v then return "T" else return "F" end end +local function nn(val) if val == nil then return "NIL" else return val end end +local function dbg(msg) if AutoInvite.debug then d("|c999999" .. msg) end end +local function echo(msg) CHAT_SYSTEM.primaryContainer.currentBuffer:AddMessage("|CFFFF00"..msg) end -- FIFO invite queue local queue = { @@ -29,9 +33,10 @@ function queue:size() end function queue:push(val) + AI_SmallGroupListing:updateSingle(val) local back = self.back self.vals[back] = val - queue.back = back + 1 + self.back = back + 1 end function queue:pop() @@ -65,9 +70,14 @@ function AutoInvite:processQueue() self.sentInvites = self.sentInvites + 1 self.sentInvite[name] = now GroupInviteByName(name) + AI_SmallGroupListing:updateSingle(name) end end +function AutoInvite:IsInviteSent(name) + return AutoInvite.sentInvite[name] +end + function AutoInvite:checkSentInvites() local now = GetTimeStamp() @@ -89,16 +99,70 @@ function AutoInvite:resetQueues() queue:reset() end +function AutoInvite:IsInQueue(name) + for i = queue.front, queue.back do + if queue.vals[i] == name then + return i + end + end + return nil +end + +function AutoInvite.__getQueue() + return queue.vals +end function AutoInvite:resetGroup() self:resetQueues() for i=1,GetGroupSize() do local tag = GetGroupUnitTagByIndex(i) local name = GetUnitName(tag) - table.insert(self.toInvite, name) + queue:push(name) GroupDisband() GroupLeave() --for group leader bug end + self:processQueue() +end + +local responseCodes = { + [GROUP_INVITE_RESPONSE_ACCEPTED] = "accept", + [GROUP_INVITE_RESPONSE_ALREADY_GROUPED] = "inGroup", + [GROUP_INVITE_RESPONSE_CONSIDERING_OTHER] = "hasInv", + [GROUP_INVITE_RESPONSE_DECLINED] = "decline", + [GROUP_INVITE_RESPONSE_GROUP_FULL] = "full", + [GROUP_INVITE_RESPONSE_IGNORED] = "ignored", + [GROUP_INVITE_RESPONSE_INVITED] = "invited?", + [GROUP_INVITE_RESPONSE_ONLY_LEADER_CAN_INVITE] = "notLead", + [GROUP_INVITE_RESPONSE_OTHER_ALLIANCE] = "otherAlly", + [GROUP_INVITE_RESPONSE_PLAYER_NOT_FOUND] = "noPlayer", + [GROUP_INVITE_RESPONSE_SELF_INVITE] = "self", +} + +local responseCodeInGroup = { + [GROUP_INVITE_RESPONSE_ACCEPTED] = true, + [GROUP_INVITE_RESPONSE_ALREADY_GROUPED] = true, --Maybe + [GROUP_INVITE_RESPONSE_CONSIDERING_OTHER] = true, --Maybe + [GROUP_INVITE_RESPONSE_DECLINED] = false, + [GROUP_INVITE_RESPONSE_GROUP_FULL] = false, + [GROUP_INVITE_RESPONSE_IGNORED] = false, + [GROUP_INVITE_RESPONSE_INVITED] = true, --Maybe + [GROUP_INVITE_RESPONSE_ONLY_LEADER_CAN_INVITE] = true, + [GROUP_INVITE_RESPONSE_OTHER_ALLIANCE] = false, + [GROUP_INVITE_RESPONSE_PLAYER_NOT_FOUND] = false, + [GROUP_INVITE_RESPONSE_SELF_INVITE] = true, +} + +function AutoInvite.inviteResponse(_, name, responseCode) + dbg("Invite response: " .. name .. " : (" .. responseCode .. ") " .. nn(responseCodes[responseCode])) + if AutoInvite.sentInvite[name] ~= nil then + --TODO: Build in a retry invite for some options + AutoInvite.sentInvite[name] = nil + AutoInvite.sentInvites = math.max(AutoInvite.sentInvites - 1, 0) + + if not responseCodeInGroup[responseCode] then + AI_SmallGroupListing:removeSingle(name) + end + end end --Interface to queue