Quantcast

BattleNetTools and PlayerManager updated.

F16Gaming [08-20-12 - 11:15]
BattleNetTools and PlayerManager updated.

BattleNetTools.GetToon* now takes a second argument, startIndex.
BattleNetTools.GetToon* now returns a second value, index.
Updated all modules according to changes in BattleNetTools.
PlayerManager and ChatManager now properly supports BattleNet friends
(different realm than player).
Filename
BattleNetTools.lua
ChatManager.lua
CommandManager.lua
PlayerManager.lua
SummonManager.lua
locales/enUS.lua
locales/svSE.lua
diff --git a/BattleNetTools.lua b/BattleNetTools.lua
index f4caaea..d2a4063 100644
--- a/BattleNetTools.lua
+++ b/BattleNetTools.lua
@@ -19,6 +19,7 @@

 -- Upvalues
 local select = select
+local tinsert = table.insert
 local tonumber = tonumber

 -- API Upvalues
@@ -143,30 +144,50 @@ function BNT:GetFriendById(id)
 	return ParseBNFriendResult(BNGetFriendInfoByID(id))
 end

-function BNT:GetFriendByName(name)
+function BNT:GetFriendByName(name, startIndex)
 	local n = BNGetNumFriends()
 	if n <= 0 then return nil end
-	for i = 1, n do
+	for i = startIndex or 1, n do
 		local friend = ParseBNFriendResult(BNGetFriendInfo(i))
 		if (friend.ToonName or ""):lower() == name:lower() then
-			return friend
+			return friend, i
 		end
 	end
 	return nil
 end

+function BNT:GetAllFriendsByName(name)
+	local result = {}
+	local friend, lastIndex
+	repeat
+		friend, lastIndex = self:GetFriendByName(name, (lastIndex or 0) + 1)
+		if friend then tinsert(result, friend) end
+	until friend == nil
+	return result
+end
+
 function BNT:GetToon(id)
 	return ParseBNToonResult(BNGetToonInfo(id))
 end

-function BNT:GetToonByName(name)
+function BNT:GetToonByName(name, startIndex)
 	local numF = BNGetNumFriends()
 	if numF <= 0 then return nil end
-	for i = 1, numF do
+	for i = startIndex or 1, numF do
 		for t = 1, BNGetNumFriendToons(i) do
 			local toon = ParseBNToonResult(BNGetFriendToonInfo(i, t))
-			if (toon.Name or ""):lower() == name:lower() then return toon end
+			if (toon.Name or ""):lower() == name:lower() then return toon, i end
 		end
 	end
 	return nil
 end
+
+function BNT:GetAllToonsByName(name)
+	local result = {}
+	local toon, lastIndex
+	repeat
+		toon, lastIndex = self:GetToonByName(name, (lastIndex or 0) + 1)
+		if toon then tinsert(result, toon) end
+	until toon == nil
+	return result
+end
diff --git a/ChatManager.lua b/ChatManager.lua
index 0a0bb08..b39dc76 100644
--- a/ChatManager.lua
+++ b/ChatManager.lua
@@ -68,6 +68,7 @@ local PM = C.PlayerManager
 local L = C.LocaleManager
 local GT = C.GroupTools
 local AC = C.AddonComm
+local BNT = C.BattleNetTools
 local CCM = C.CommandManager
 local CES = C.Extensions.String

@@ -211,8 +212,19 @@ function CM:HandleMessage(msg, sender, channel, target, sourceChannel, isBN, pID
 			table.insert(t, args[i])
 		end
 	end
-	local player = PM:GetOrCreatePlayer(sender)
-	local result, arg, errArg = CCM:HandleCommand(cmd, t, sourceChannel, player)
+	local realm = GetRealmName()
+	local bnetInfo
+	if isBN then
+		local toon = BNT:GetToon(pID)
+		if toon then
+			realm = toon.Realm
+		end
+		bnetInfo = {
+			PresenceID = pID
+		}
+	end
+	local player = PM:GetOrCreatePlayer(sender, realm)
+	local result, arg, errArg = CCM:HandleCommand(cmd, t, sourceChannel, player, bnetInfo)
 	if isBN then
 		target = pID
 		sender = pID
diff --git a/CommandManager.lua b/CommandManager.lua
index 8ce386f..94671ea 100644
--- a/CommandManager.lua
+++ b/CommandManager.lua
@@ -167,10 +167,11 @@ end
 -- @param args Table with arguments for the command.
 -- @param isChat Is the command called from chat?
 -- @param player Player object of the calling player (if chat)
+-- @param bnetInfo Information about the B.Net sender (if called from B.Net chat)
 -- @return If successfull, returns result, otherwise false.
 -- @return Error message if not successful, otherwise nil.
 --
-function CM:HandleCommand(command, args, isChat, player)
+function CM:HandleCommand(command, args, isChat, player, bnetInfo)
 	command = tostring(command):lower()
 	local cmd = self:GetCommand(command)
 	if cmd then
@@ -181,7 +182,7 @@ function CM:HandleCommand(command, args, isChat, player)
 				return false, "CM_ERR_NOACCESS", {player.Info.Name, cmd.Access, PM:GetAccess(player)}
 			end
 		end
-		return cmd.Call(args, player, isChat)
+		return cmd.Call(args, player, isChat, bnetInfo)
 	else
 		return false, "CM_ERR_NOTREGGED", {tostring(command)}
 	end
@@ -205,7 +206,7 @@ function CM:GetHelp(cmd)
 end


-CM:Register({"__DEFAULT__"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"__DEFAULT__"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat then
 		return "CM_DEFAULT_CHAT"
 	end
@@ -214,7 +215,7 @@ CM:Register({"__DEFAULT__"}, PM.Access.Local, function(args, sender, isChat)
 	return "CM_DEFAULT_END"
 end, "CM_DEFAULT_HELP")

-CM:Register({"help", "h"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"help", "h"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		if isChat then
 			return "CM_DEFAULT_CHAT"
@@ -224,7 +225,7 @@ CM:Register({"help", "h"}, PM.Access.Groups.User.Level, function(args, sender, i
 	return CM:GetHelp(tostring(args[1]):lower())
 end, "CM_HELP_HELP")

-CM:Register({"commands", "cmds", "cmdlist", "listcmds", "listcommands", "commandlist"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"commands", "cmds", "cmdlist", "listcmds", "listcommands", "commandlist"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	local all
 	if #args > 0 then
 		all = args[1] == "all"
@@ -233,11 +234,11 @@ CM:Register({"commands", "cmds", "cmdlist", "listcmds", "listcommands", "command
 	return "RAW_TABLE_OUTPUT", CES:Fit(cmds, 240, ", ") -- Max length is 255, "[Command] " takes up 10. This leaves us with 5 characters grace.
 end, "CM_COMMANDS_HELP")

-CM:Register({"version", "ver", "v"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"version", "ver", "v"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	return "CM_VERSION", {C.Version}
 end, "CM_VERSION_HELP")

-CM:Register({"set", "s"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"set", "s"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_SET_USAGE"
 	end
@@ -405,7 +406,7 @@ CM:Register({"set", "s"}, PM.Access.Groups.Admin.Level, function(args, sender, i
 	return false, "CM_SET_USAGE"
 end, "CM_SET_HELP")

-CM:Register({"locale", "loc"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"locale", "loc"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat then return false, "CM_ERR_NOCHAT" end
 	if #args <= 0 then
 		return "CM_LOCALE_CURRENT", {L.Settings.LOCALE}
@@ -432,7 +433,7 @@ CM:Register({"locale", "loc"}, PM.Access.Local, function(args, sender, isChat)
 	return false, "CM_LOCALE_USAGE"
 end, "CM_LOCALE_HELP")

-CM:Register({"mylocale", "ml"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"mylocale", "ml"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
@@ -451,7 +452,7 @@ CM:Register({"mylocale", "ml"}, PM.Access.Groups.User.Level, function(args, send
 	end
 end, "CM_MYLOCALE_HELP")

-CM:Register({"lock", "lockdown"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"lock", "lockdown"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if type(args[1]) == "string" then
 		return PM:SetLocked(PM:GetOrCreatePlayer(args[1]), true)
 	else
@@ -459,7 +460,7 @@ CM:Register({"lock", "lockdown"}, PM.Access.Groups.Admin.Level, function(args, s
 	end
 end, "CM_LOCK_HELP")

-CM:Register({"unlock", "open"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"unlock", "open"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if type(args[1]) == "string" then
 		return PM:SetLocked(PM:GetOrCreatePlayer(args[1]), false)
 	else
@@ -467,7 +468,7 @@ CM:Register({"unlock", "open"}, PM.Access.Groups.Admin.Level, function(args, sen
 	end
 end, "CM_UNLOCK_HELP")

-CM:Register({"getaccess"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"getaccess"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if type(args[1]) == "string" then
 		local player = PM:GetOrCreatePlayer(args[1])
 		return "CM_GETACCESS_STRING", {player.Info.Name, PM.Access.Groups[player.Info.Group].Level, player.Info.Group}
@@ -476,7 +477,7 @@ CM:Register({"getaccess"}, PM.Access.Groups.User.Level, function(args, sender, i
 	end
 end, "CM_GETACCESS_HELP")

-CM:Register({"setaccess"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"setaccess"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if #args < 1 then
 		return false, "CM_SETACCESS_USAGE"
 	end
@@ -488,7 +489,7 @@ CM:Register({"setaccess"}, PM.Access.Local, function(args, sender, isChat)
 	end
 end, "CM_SETACCESS_HELP")

-CM:Register({"owner"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"owner"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat then
 		return false, "CM_ERR_NOCHAT"
 	end
@@ -496,7 +497,7 @@ CM:Register({"owner"}, PM.Access.Local, function(args, sender, isChat)
 	return PM:SetOwner(player)
 end, "CM_OWNER_HELP")

-CM:Register({"admin"}, PM.Access.Groups.Owner.Level, function(args, sender, isChat)
+CM:Register({"admin"}, PM.Access.Groups.Owner.Level, function(args, sender, isChat, bnetInfo)
 	if isChat then
 		return false, "CM_ERR_NOCHAT"
 	end
@@ -507,7 +508,7 @@ CM:Register({"admin"}, PM.Access.Groups.Owner.Level, function(args, sender, isCh
 	return PM:SetAdmin(player)
 end, "CM_ADMIN_HELP")

-CM:Register({"op"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"op"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if type(args[1]) == "string" then
 		local player = PM:GetOrCreatePlayer(args[1])
 		return PM:SetOp(player)
@@ -516,7 +517,7 @@ CM:Register({"op"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
 	end
 end, "CM_OP_HELP")

-CM:Register({"user"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"user"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if type(args[1]) == "string" then
 		local player = PM:GetOrCreatePlayer(args[1])
 		return PM:SetUser(player)
@@ -525,7 +526,7 @@ CM:Register({"user"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
 	end
 end, "CM_USER_HELP")

-CM:Register({"ban"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"ban"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_BAN_USAGE"
 	end
@@ -533,7 +534,7 @@ CM:Register({"ban"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat
 	return PM:BanUser(player)
 end, "CM_BAN_HELP")

-CM:Register({"auth", "authenticate", "a"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"auth", "authenticate", "a"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat and isChat ~= "WHISPER" then return false, "CM_ERR_NOCHAT" end
 	if #args < 2 then return false, "CM_AUTH_USAGE" end
 	local arg = tostring(args[1]):lower()
@@ -558,72 +559,76 @@ CM:Register({"auth", "authenticate", "a"}, PM.Access.Local, function(args, sende
 	return false, "CM_AUTH_USAGE"
 end, "CM_AUTH_HELP")

-CM:Register({"authme", "authenticateme", "am"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"authme", "authenticateme", "am"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then return false, "CM_ERR_CHATONLY" end
 	if #args <= 0 then return false, "CM_AUTHME_USAGE" end
 	local pass = tostring(args[1])
 	return AM:Authenticate(sender.Info.Name, pass)
 end, "CM_AUTHME_HELP")

-CM:Register({"accept", "acceptinvite", "acceptinv", "join", "joingroup"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"accept", "acceptinvite", "acceptinv", "join", "joingroup"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not IM:IsEnabled() or not IM:IsGroupEnabled() then
 		return "CM_ERR_DISABLED"
 	end
 	return IM:AcceptGroupInvite()
 end, "CM_ACCEPTINVITE_HELP")

-CM:Register({"decline", "declineinvite", "declineinv", "cancelinvite", "cancelinv"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"decline", "declineinvite", "declineinv", "cancelinvite", "cancelinv"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not IM:IsEnabled() or not IM:IsGroupEnabled() then
 		return "CM_ERR_DISABLED"
 	end
 	return IM:DeclineGroupInvite()
 end, "CM_DECLINEINVITE_HELP")

-CM:Register({"acceptguildinvite", "acceptginvite", "acceptguildinv", "acceptginv"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"acceptguildinvite", "acceptginvite", "acceptguildinv", "acceptginv"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not IM:IsEnabled() or not IM:IsGuildEnabled() then
 		return "CM_ERR_DISABLED"
 	end
 	return IM:AcceptGuildInvite()
 end, "CM_ACCEPTGUILDINVITE_HELP")

-CM:Register({"declineguildinvite", "declineginvite", "declineguildinv", "declineginv"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"declineguildinvite", "declineginvite", "declineguildinv", "declineginv"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not IM:IsEnabled() or not IM:IsGuildEnabled() then
 		return "CM_ERR_DISABLED"
 	end
 	return IM:DeclineGuildInvite()
 end, "CM_DECLINEGUILDINVITE_HELP")

-CM:Register({"invite", "inv"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"invite", "inv"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
+	local pID
+	if bnetInfo then pID = bnetInfo.PresenceID end
 	if type(args[1]) == "string" then
 		local player = PM:GetOrCreatePlayer(args[1])
-		return PM:Invite(player, sender)
+		return PM:Invite(player, sender, pID)
 	else
-		return PM:Invite(sender, sender)
+		return PM:Invite(sender, sender, pID)
 	end
 end, "CM_INVITE_HELP")

-CM:Register({"inviteme", "invme"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"inviteme", "invme"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
-	return PM:Invite(sender, sender)
+	local pID
+	if bnetInfo then pID = bnetInfo.PresenceID end
+	return PM:Invite(sender, sender, pID)
 end, "CM_INVITEME_HELP")

-CM:Register({"blockinvites", "blockinvite", "denyinvites", "denyinvite"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"blockinvites", "blockinvite", "denyinvites", "denyinvite"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
 	return PM:DenyInvites(sender, isChat == "WHISPER" or isChat == "BNET")
 end, "CM_DENYINVITE_HELP")

-CM:Register({"allowinvites", "allowinvite"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"allowinvites", "allowinvite"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
 	return PM:AllowInvites(sender, isChat == "WHISPER" or isChat == "BNET")
 end, "CM_ALLOWINVITE_HELP")

-CM:Register({"kick"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"kick"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_KICK_USAGE"
 	end
@@ -637,28 +642,28 @@ CM:Register({"kick"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
 	return PM:Kick(player, sender, reason, override)
 end, "CM_KICK_HELP")

-CM:Register({"kingme", "givelead"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"kingme", "givelead"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
 	return PM:PromoteToLeader(sender)
 end, "CM_KINGME_HELP")

-CM:Register({"opme", "assistant", "assist"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"opme", "assistant", "assist"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
 	return PM:PromoteToAssistant(sender)
 end, "CM_OPME_HELP")

-CM:Register({"deopme", "deassistant", "deassist"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"deopme", "deassistant", "deassist"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if not isChat then
 		return false, "CM_ERR_CHATONLY"
 	end
 	return PM:DemoteAssistant(sender)
 end, "CM_DEOPME_HELP")

-CM:Register({"leader", "lead"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"leader", "lead"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_LEADER_USAGE"
 	end
@@ -666,7 +671,7 @@ CM:Register({"leader", "lead"}, PM.Access.Groups.Op.Level, function(args, sender
 	return PM:PromoteToLeader(player)
 end, "CM_LEADER_HELP")

-CM:Register({"promote"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"promote"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_PROMOTE_USAGE"
 	end
@@ -674,7 +679,7 @@ CM:Register({"promote"}, PM.Access.Groups.Op.Level, function(args, sender, isCha
 	return PM:PromoteToAssistant(player)
 end, "CM_PROMOTE_HELP")

-CM:Register({"demote"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"demote"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_DEMOTE_USAGE"
 	end
@@ -682,7 +687,7 @@ CM:Register({"demote"}, PM.Access.Groups.Op.Level, function(args, sender, isChat
 	return PM:DemoteAssistant(player)
 end, "CM_DEMOTE_HELP")

-CM:Register({"queue", "q"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"queue", "q"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return false, "CM_QUEUE_USAGE"
 	end
@@ -703,7 +708,7 @@ CM:Register({"queue", "q"}, PM.Access.Groups.User.Level, function(args, sender,
 	return QM:Queue(index)
 end, "CM_QUEUE_HELP")

-CM:Register({"leavelfg", "cancellfg", "cancel", "leavelfd", "cancellfd"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"leavelfg", "cancellfg", "cancel", "leavelfd", "cancellfd"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not QM.QueuedByCommand then
 		return false, "CM_LEAVELFG_FAIL"
 	end
@@ -712,7 +717,7 @@ end, "CM_LEAVELFG_HELP")

 -- So apparently Blizzard does not allow accepting invites without HW event... Making this command useless...
 -- I'm keeping this command here for the future, if there will ever be a way to make this work.
-CM:Register({"acceptlfg", "acceptlfd", "joinlfg", "joinlfd"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"acceptlfg", "acceptlfd", "joinlfg", "joinlfd"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not C.Settings.DEBUG then
 		return false, "CM_ERR_PERMDISABLED"
 	end
@@ -725,7 +730,7 @@ CM:Register({"acceptlfg", "acceptlfd", "joinlfg", "joinlfd"}, PM.Access.Groups.U
 	return QM:Accept()
 end, "CM_ACCEPTLFG_HELP")

-CM:Register({"convert", "conv"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"convert", "conv"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if GT:IsLFGGroup() then
 		return false, "CM_CONVERT_LFG"
 	elseif not GT:IsGroup() then
@@ -754,18 +759,18 @@ CM:Register({"convert", "conv"}, PM.Access.Groups.Op.Level, function(args, sende
 	return false, "CM_CONVERT_INVALID"
 end, "CM_CONVERT_HELP")

-CM:Register({"list"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"list"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if not args[1] then
 		return false, "CM_LIST_USAGE"
 	end
 	return PM:ListToggle(args[1]:lower())
 end, "CM_LIST_HELP")

-CM:Register({"listmode", "lm", "lmode"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"listmode", "lm", "lmode"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	return PM:ToggleListMode()
 end, "CM_LISTMODE_HELP")

-CM:Register({"groupallow", "gallow"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"groupallow", "gallow"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_GROUPALLOW_USAGE"
 	end
@@ -774,7 +779,7 @@ CM:Register({"groupallow", "gallow"}, PM.Access.Groups.Admin.Level, function(arg
 	return PM:GroupAccess(group, cmd, true)
 end, "CM_GROUPALLOW_HELP")

-CM:Register({"groupdeny", "gdeny", "deny"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"groupdeny", "gdeny", "deny"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_GROUPDENY_USAGE"
 	end
@@ -783,7 +788,7 @@ CM:Register({"groupdeny", "gdeny", "deny"}, PM.Access.Groups.Admin.Level, functi
 	return PM:GroupAccess(group, cmd, false)
 end, "CM_GROUPDENY_HELP")

-CM:Register({"resetgroupaccess", "groupaccessreset", "removegroupaccess", "groupaccessremove", "rga", "gar"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"resetgroupaccess", "groupaccessreset", "removegroupaccess", "groupaccessremove", "rga", "gar"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_RESETGROUPACCESS_USAGE"
 	end
@@ -792,7 +797,7 @@ CM:Register({"resetgroupaccess", "groupaccessreset", "removegroupaccess", "group
 	return PM:GroupAccessRemove(group, cmd)
 end, "CM_RESETGROUPACCESS_HELP")

-CM:Register({"userallow", "uallow"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"userallow", "uallow"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_USERALLOW_USAGE"
 	end
@@ -801,7 +806,7 @@ CM:Register({"userallow", "uallow"}, PM.Access.Groups.Admin.Level, function(args
 	return PM:PlayerAccess(player, cmd, true)
 end, "CM_USERALLOW_HELP")

-CM:Register({"userdeny", "udeny"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"userdeny", "udeny"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_USERDENY_USAGE"
 	end
@@ -810,7 +815,7 @@ CM:Register({"userdeny", "udeny"}, PM.Access.Groups.Admin.Level, function(args,
 	return PM:PlayerAccess(player, cmd, false)
 end, "CM_USERDENY_HELP")

-CM:Register({"resetuseraccess", "useraccessreset", "removeuseraccess", "useraccessremove", "rua", "uar"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat)
+CM:Register({"resetuseraccess", "useraccessreset", "removeuseraccess", "useraccessremove", "rua", "uar"}, PM.Access.Groups.Admin.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 1 then
 		return false, "CM_RESETUSERACCESS_USAGE"
 	end
@@ -819,21 +824,21 @@ CM:Register({"resetuseraccess", "useraccessreset", "removeuseraccess", "useracce
 	return PM:PlayerAccessRemove(player, cmd)
 end, "CM_RESETUSERACCESS_HELP")

-CM:Register({"toggle", "t"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"toggle", "t"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat then
 		return false, "CM_ERR_NOCHAT"
 	end
 	return C:Toggle()
 end, "CM_TOGGLE_HELP")

-CM:Register({"toggledebug", "td", "debug", "d"}, PM.Access.Local, function(args, sender, isChat)
+CM:Register({"toggledebug", "td", "debug", "d"}, PM.Access.Local, function(args, sender, isChat, bnetInfo)
 	if isChat then
 		return false, "CM_ERR_NOCHAT"
 	end
 	return C:ToggleDebug()
 end, "CM_TOGGLEDEBUG_HELP")

-CM:Register({"readycheck", "rc"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"readycheck", "rc"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		if PM:GetAccess(sender) > PM.Access.Groups.Op.Level then
 			return "CM_ERR_NOACCESS", {sender.Info.Name, PM.Access.Groups.Op.Level, PM:GetAccess(sender)}
@@ -873,7 +878,7 @@ CM:Register({"readycheck", "rc"}, PM.Access.Groups.User.Level, function(args, se
 	return false, "CM_READYCHECK_FAIL"
 end, "CM_READYCHECK_HELP")

-CM:Register({"loot", "l"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"loot", "l"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if GT:IsLFGGroup() then
 		return false, "CM_LOOT_LFG"
 	end
@@ -916,7 +921,7 @@ CM:Register({"loot", "l"}, PM.Access.Groups.Op.Level, function(args, sender, isC
 	return false, usage
 end, "CM_LOOT_HELP")

-CM:Register({"roll", "r"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"roll", "r"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if #args <= 0 then
 		return RM:StartRoll(sender.Info.Name)
 	end
@@ -978,7 +983,7 @@ CM:Register({"roll", "r"}, PM.Access.Groups.Op.Level, function(args, sender, isC
 	return false, "CM_LOOT_USAGE"
 end, "CM_LOOT_HELP")

-CM:Register({"raidwarning", "rw", "raid_warning"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"raidwarning", "rw", "raid_warning"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not GT:IsRaid() then
 		return false, "CM_RAIDWARNING_NORAID"
 	elseif not GT:IsRaidLeaderOrAssistant() then
@@ -999,7 +1004,7 @@ CM:Register({"raidwarning", "rw", "raid_warning"}, PM.Access.Groups.User.Level,
 	return "CM_RAIDWARNING_SENT"
 end, "CM_RAIDWARNING_HELP")

-CM:Register({"dungeondifficulty", "dungeondiff", "dd", "dungeonmode", "dm"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"dungeondifficulty", "dungeondiff", "dd", "dungeonmode", "dm"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if #args < 1 then
 		return GT:GetDungeonDifficultyString()
 	end
@@ -1016,7 +1021,7 @@ CM:Register({"dungeondifficulty", "dungeondiff", "dd", "dungeonmode", "dm"}, PM.
 	return GT:SetDungeonDifficulty(diff)
 end, "CM_DUNGEONMODE_HELP")

-CM:Register({"raiddifficulty", "raiddiff", "rd", "raidmode", "rm"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"raiddifficulty", "raiddiff", "rd", "raidmode", "rm"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if #args < 1 then
 		return GT:GetRaidDifficultyString()
 	end
@@ -1037,49 +1042,49 @@ CM:Register({"raiddifficulty", "raiddiff", "rd", "raidmode", "rm"}, PM.Access.Gr
 	return GT:SetRaidDifficulty(diff)
 end, "CM_RAIDMODE_HELP")

-CM:Register({"release", "rel"}, PM.Access.Groups.Op.Level, function(args, sender, isChat)
+CM:Register({"release", "rel"}, PM.Access.Groups.Op.Level, function(args, sender, isChat, bnetInfo)
 	if not DM:IsEnabled() or not DM:IsReleaseEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return DM:Release()
 end, "CM_RELEASE_HELP")

-CM:Register({"resurrect", "ressurrect", "ress", "res"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"resurrect", "ressurrect", "ress", "res"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not DM:IsEnabled() or not DM:IsResurrectEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return DM:Resurrect()
 end, "CM_RESURRECT_HELP")

-CM:Register({"acceptsummon", "as", "acceptsumm", "asumm"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"acceptsummon", "as", "acceptsumm", "asumm"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not SM:IsEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return SM:AcceptSummon()
 end, "CM_ACCEPTSUMMON_HELP")

-CM:Register({"declinesummon", "ds", "declinesumm", "dsumm", "cancelsummon", "csumm"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"declinesummon", "ds", "declinesumm", "dsumm", "cancelsummon", "csumm"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not SM:IsEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return SM:DeclineSummon()
 end, "CM_DECLINESUMMON_HELP")

-CM:Register({"acceptduel", "acceptd"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"acceptduel", "acceptd"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not CDM:IsEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return CDM:AcceptDuel()
 end, "CM_ACCEPTDUEL_HELP")

-CM:Register({"declineduel", "declined"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"declineduel", "declined"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not CDM:IsEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
 	return CDM:DeclineDuel()
 end, "CM_DECLINEDUEL_HELP")

-CM:Register({"startduel", "startd", "challenge"}, PM.Access.Groups.User.Level, function(args, sender, isChat)
+CM:Register({"startduel", "startd", "challenge"}, PM.Access.Groups.User.Level, function(args, sender, isChat, bnetInfo)
 	if not CDM:IsEnabled() then
 		return false, "CM_ERR_DISABLED"
 	end
diff --git a/PlayerManager.lua b/PlayerManager.lua
index d80559a..bfcede0 100644
--- a/PlayerManager.lua
+++ b/PlayerManager.lua
@@ -232,6 +232,18 @@ function PM:LoadSavedVars()
 	end
 	Players = self.Data.PLAYERS[GetRealmName()]
 	List = self.Data.LIST
+
+	self:UpdatePlayerData()
+end
+
+function PM:UpdatePlayerData()
+	for realm,players in pairs(self.Data.PLAYERS) do
+		for name,player in pairs(players) do
+			if not player.Info.Realm then
+				player.Info.Realm = realm
+			end
+		end
+	end
 end

 function PM:ParseMessage(message)
@@ -261,20 +273,22 @@ end
 -- @param name Name of player.
 -- @return Player from list of players if exists, otherwise a new player object.
 --
-function PM:GetOrCreatePlayer(name)
+function PM:GetOrCreatePlayer(name, realm)
 	name = (name or UnitName("player")):lower():gsub("^%l", string.upper)
-	if CET:HasKey(Players, name) then
-		return Players[name]
+	realm = realm or GetRealmName()
+	if CET:HasKey(self.Data.PLAYERS[realm], name) then
+		return self.Data.PLAYERS[realm][name]
 	else
 		local player = CET:Copy(Player)
 		player.Info.Name = name
+		player.Info.Realm = realm
 		if player.Info.Name == UnitName("player") then
 			player.Info.Group = self.Access.Groups.Owner.Name
 		else
 			player.Info.Group = self.Access.Groups.User.Name
 		end
-		Players[player.Info.Name] = player
-		log:Normal(L("PM_PLAYER_CREATE"):format(player.Info.Name))
+		self.Data.PLAYERS[realm][player.Info.Name] = player
+		log:Normal(L("PM_PLAYER_CREATE"):format(player.Info.Name, player.Info.Realm))
 		return player
 	end
 end
@@ -283,8 +297,8 @@ end
 -- @param player Player object to update.
 --
 function PM:UpdatePlayer(player)
-	Players[player.Info.Name] = player
-	log:Normal(L("PM_PLAYER_UPDATE"):format(player.Info.Name))
+	self.Data.PLAYERS[player.Info.Realm][player.Info.Name] = player
+	log:Normal(L("PM_PLAYER_UPDATE"):format(player.Info.Name, player.Info.Realm))
 end

 --- Completely remove a command from a group's access list.
@@ -603,10 +617,11 @@ end
 -- Also sends a message to the invited player about the event.
 -- @param player Player object of player to invite.
 -- @param sender Player object of the inviting player.
+-- @param pID Presence ID if this was an Invite(Me) command from B.Net chat
 -- @return String stating the result of the invite, false if error.
 -- @return Error message if unsuccessful, nil otherwise.
 --
-function PM:Invite(player, sender)
+function PM:Invite(player, sender, pID)
 	if not sender then sender = self:GetOrCreatePlayer(UnitName("player")) end
 	if player.Info.Name == UnitName("player") then
 		return false, "PM_INVITE_SELF"
@@ -619,7 +634,11 @@ function PM:Invite(player, sender)
 		if self.Invites[player.Info.Name] then
 			return false, "PM_INVITE_ACTIVE", {player.Info.Name}
 		elseif player.Info.Name == sender.Info.Name then
-			InviteUnit(player.Info.Name)
+			if player.Info.Realm == GetRealmName() or not pID then
+				InviteUnit(player.Info.Name)
+			else -- Invite(Me) command sent from B.Net chat
+				BNInviteFriend(pID)
+			end
 			return "PM_INVITE_NOTIFYTARGET"
 		elseif player.Settings.Invite then
 			InviteUnit(player.Info.Name)
diff --git a/SummonManager.lua b/SummonManager.lua
index 380f825..612e1a2 100644
--- a/SummonManager.lua
+++ b/SummonManager.lua
@@ -35,13 +35,16 @@ local GetSummonConfirmTimeLeft = GetSummonConfirmTimeLeft

 local C = Command

-C.SummonManager = {}
+C.SummonManager = {
+	VarVersion = 1
+}

 local L = C.LocaleManager
 local SM = C.SummonManager
 local CM
 local GT = C.GroupTools

+local DEFAULT_DELAY = 5
 local MAX_DELAY = 110 -- 1 minute 50 seconds, summons expire after 2 minutes (usually)

 local LastSummoner
@@ -70,22 +73,28 @@ function SM:LoadSavedVars()

 	self.Settings = C.Global["SUMMON_MANAGER"]

+	if not self.Settings.VERSION or self.Settings.VERSION < self.VarVersion then
+		wipe(self.Settings)
+	end
+
 	if type(self.Settings.ENABLED) ~= "boolean" then
 		self.Settings.ENABLED = true
 	end

-	if type(self.Settings.TIME) ~= "number" then
-		self.Settings.TIME = 0
+	if type(self.Settings.DELAY) ~= "number" then
+		self.Settings.DELAY = DEFAULT_DELAY
 	end
+
+	self.Settings.VERSION = self.VarVersion
 end

 function SM:OnSummon()
 	if self.DelayActive then return end
-	if self.Settings.TIME > 0 then
+	if self.Settings.DELAY > 0 then
 		self.DelayActive = true
 		local frame = CreateFrame("Frame")
 		frame.Time = 0 -- Current time
-		frame.Delay = self.Settings.TIME -- Delay to wait
+		frame.Delay = self.Settings.DELAY -- Delay to wait
 		frame:SetScript("OnUpdate", function(self, elapsed)
 			self.Time = self.Time + elapsed
 			if self.Time >= self.Delay then
diff --git a/locales/enUS.lua b/locales/enUS.lua
index fbb9852..c07b09c 100644
--- a/locales/enUS.lua
+++ b/locales/enUS.lua
@@ -394,8 +394,8 @@ local L = {
 	PM_KICK_NOPRIV = "Unable to kick %s from group. Not group leader or assistant.",
 	PM_KICK_TARGETASSIST = "Unable to kick %s, assistants cannot kick other assistants from group.",

-	PM_PLAYER_CREATE = "Created player %q with default settings.",
-	PM_PLAYER_UPDATE = "Updated player %q.",
+	PM_PLAYER_CREATE = "Created player %q (%s) with default settings.",
+	PM_PLAYER_UPDATE = "Updated player %q (%s).",

 	PM_GA_REMOVED = "%q removed from group %s.",
 	PM_GA_EXISTSALLOW = "%q already has that command on the allow list.",
diff --git a/locales/svSE.lua b/locales/svSE.lua
index 850648e..2938a48 100644
--- a/locales/svSE.lua
+++ b/locales/svSE.lua
@@ -394,8 +394,8 @@ local L = {
 	PM_KICK_NOPRIV = "Unable to kick %s from group. Not group leader or assistant.",
 	PM_KICK_TARGETASSIST = "Unable to kick %s, assistants cannot kick other assistants from group.",

-	PM_PLAYER_CREATE = "Created player %q with default settings.",
-	PM_PLAYER_UPDATE = "Updated player %q.",
+	PM_PLAYER_CREATE = "Created player %q (%s) with default settings.",
+	PM_PLAYER_UPDATE = "Updated player %q (%s).",

 	PM_GA_REMOVED = "%q removed from group %s.",
 	PM_GA_EXISTSALLOW = "%q already has that command on the allow list.",