sdm_msgPrefix = "SupDupMac" sdm_msgPrefixLength = string.len(sdm_msgPrefix) sdm_msgCommandLength = 1 sdm_msgLengthLimit = 254 sdm_msgCommands = { SendFirst = "1", -- I'm sending you the first part of a macro SendMore = "2", -- I'm sending you more of the macro SendFailed = "3", -- I failed to send you the macro Receiving = "4", -- I just received the first part of your macro ReceivingDone = "5", -- I just saved the macro that you sent me ReceivingFailed = "6", -- I failed to receive your macro } function sdm_OnUpdate(self, elapsed) --used for sending macros self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed if self.TimeSinceLastUpdate > sdm_updateInterval then if sdm_sending.i == 2 then sdm_sending.command = sdm_msgCommands.SendMore end SendAddonMessage(sdm_msgPrefix, sdm_sending.command..sdm_sending.lines[sdm_sending.i], sdm_sending.channel, sdm_sending.target) sdm_sendStatusBar:SetValue(sdm_sending.i) sdm_sending.i = sdm_sending.i+1 if sdm_sending.i>sdm_sending.numLines then sdm_EndSending("|cff44ff00Sent to "..(sdm_sending.target or sdm_sending.channel).."|r") end self.TimeSinceLastUpdate = 0 end end function sdm_RegisterMessages() sdm_eventFrame:RegisterEvent("CHAT_MSG_ADDON") local success = RegisterAddonMessagePrefix(sdm_msgPrefix) if not success then print(sdm_printPrefix.."You have too many addon prefixes registered. SDM will not be able to send or receive macros.") end end -- create an invisible frame that is used to measure time local f = CreateFrame("Frame", "sdm_updateFrame", UIParent) f:Hide() f:SetScript("OnShow", function(self) self.TimeSinceLastUpdate = 0 end) f:SetScript("OnUpdate", sdm_OnUpdate) function sdm_SendMacro(mTab, chan, tar) if sdm_sending then print(sdm_printPrefix.."You are already sending something.") return end print(sdm_printPrefix.."Sending to the following people (if nobody is listed, then nobody is waiting):") sdm_RegisterMessages() local perCharacter=nil --make the string that will be split up and sent. It consists of a bunch of values separated by commas. They are, in order: the version the sender is running, the minimum version the receiver must have, the type of macro, the index of the icon, the perCharacter status ("" or "nil"), the length of the name, the length of the text, the name, and the text. There is no comma between the name and the text. local textToSend = sdm_version..","..sdm_minVersion..","..mTab.type..","..tostring(mTab.icon)..","..tostring(mTab.characters)..","..mTab.name:len()..","..mTab.text:len()..","..mTab.name..mTab.text local comm = sdm_msgCommands.SendFirst -- if the command is SendFirst, it's the first part. If it's SendMore, it's any part after the first. local lineLen = sdm_msgLengthLimit - sdm_msgPrefixLength - sdm_msgCommandLength local linesToSend={} local pos = 1 while pos <= textToSend:len() do table.insert(linesToSend, textToSend:sub(pos, pos+lineLen-1)) pos = pos+lineLen end sdm_sending={ i=1, lines = linesToSend, numLines = getn(linesToSend), channel = chan, target = tar, command = comm } sdm_sendStatusBar:SetMinMaxValues(0, sdm_sending.numLines) sdm_sendStatusBar:SetValue(0) sdm_sendStatusBar_text:SetText("|cffffccffSending to "..(sdm_sending.target or sdm_sending.channel).."|r") sdm_cancelSendButton:Enable() sdm_sendButton:Disable() sdm_sendPartyRadio:Disable() sdm_sendRaidRadio:Disable() sdm_sendBattlegroundRadio:Disable() sdm_sendGuildRadio:Disable() sdm_sendTargetRadio:Disable() sdm_sendArbitraryRadio:Disable() sdm_sendInput:EnableMouse(nil) sdm_updateFrame:Show() end function sdm_EndSending(text) sdm_updateFrame:Hide() sdm_sendStatusBar_text:SetText(text) sdm_sending=nil sdm_cancelSendButton:Disable() if sdm_currentEdit then sdm_sendButton:Enable() end sdm_sendPartyRadio:Enable() sdm_sendRaidRadio:Enable() sdm_sendBattlegroundRadio:Enable() sdm_sendGuildRadio:Enable() sdm_sendTargetRadio:Enable() sdm_sendArbitraryRadio:Enable() sdm_sendInput:EnableMouse(1) end function sdm_WaitForMacro(name) if sdm_receiving then print(sdm_printPrefix.."You are already receiving or waiting.") return end sdm_RegisterMessages() sdm_receiving = {playerName=name, first=true} sdm_receiveStatusBar:SetValue(0) sdm_receiveStatusBar_text:SetText("|cffffccffWaiting for "..sdm_receiving.playerName.."|r") sdm_cancelReceiveButton:Enable() sdm_receiveButton:Disable() sdm_receiveTargetRadio:Disable() sdm_receiveArbitraryRadio:Disable() sdm_receiveAnyoneRadio:Disable() sdm_receiveInput:EnableMouse(nil) sdm_SelectItem(nil) sdm_newFrame:Show() sdm_newMacroNameInput:ClearFocus() sdm_newMacroNameInput:SetText("Receiving macro...") sdm_newMacroNameInput:EnableMouse(nil) sdm_buttonRadio:Disable() sdm_floatingRadio:Disable() sdm_scriptRadio:Disable() sdm_globalRadio:Disable() sdm_charspecRadio:Disable() sdm_createMacroButton:Disable() sdm_saveAsText = nil sdm_saveAsIcon = nil end function sdm_InterpretAddonMessage(...) --print("debug: interpreting") local prefix, message, _, sender = ... if prefix ~= sdm_msgPrefix or sender==sdm_thisChar.name then return end local command = message:sub(1,1) local txt=message:sub(2) if sdm_receiving and not sdm_receiving.text then if sdm_receiving.playerName == "" and command == sdm_msgCommands.SendFirst then sdm_receiving.playerName = sender end if sender:upper() ~= sdm_receiving.playerName:upper() then return end if command == sdm_msgCommands.SendFirst then -- this is the first part of the macro (also contains data such as name and type) sdm_ReceiveLine(txt, true) elseif command == sdm_msgCommands.SendMore then -- this is some part other than the first sdm_ReceiveLine(txt, false) elseif command == sdm_msgCommands.SendFailed then -- this is a reason why the sender failed to send us the macro print(sdm_printPrefix..sender.." failed to send the macro. Reason: "..txt) sdm_EndReceiving("|cffff0000Failed|r") end elseif command == sdm_msgCommands.Receiving then print(sdm_printPrefix..sender.." has begun to receive your macro...") elseif command == sdm_msgCommands.ReceivingDone then -- the target has finished receiving print(sdm_printPrefix..sender.." has accepted your macro.") elseif command == sdm_msgCommands.ReceivingFailed then -- this is a reason why the recipient failed to receive our macro local version, reason = sdm_SplitString(txt, ",", 1) print(sdm_printPrefix..sender.." did not receive your macro. Reason: "..reason) end end function sdm_ReceiveLine(line, send1) --print("debug: in recline") if sdm_receiving.first and send1 then --this is the first line sdm_receiving.nameAndText, sdm_receiving.textLen, sdm_receiving.playerNameLen, sdm_receiving.perCharacter, sdm_receiving.icon, sdm_receiving.type, sdm_receiving.minVersion, sdm_receiving.sendersVersion = sdm_SplitString(line, ",", 7) sdm_receiving.perCharacter = (sdm_receiving.perCharacter~="nil") if sdm_receiving.icon=="nil" then sdm_receiving.icon = nil else sdm_receiving.icon = sdm_receiving.icon end sdm_receiving.textLen = 0 + sdm_receiving.textLen sdm_receiving.playerNameLen = 0 + sdm_receiving.playerNameLen sdm_receiving.first = false sdm_receiveStatusBar:SetMinMaxValues(0, sdm_receiving.playerNameLen + sdm_receiving.textLen) sdm_receiveStatusBar_text:SetText("|cffffccffReceiving|r") if sdm_CompareVersions(sdm_receiving.sendersVersion, sdm_minVersion)==2 or sdm_CompareVersions(sdm_version, sdm_receiving.minVersion)==2 then print(sdm_printPrefix.."You failed to recieve the macro due to a version incompatibility.") SendAddonMessage(sdm_msgPrefix, sdm_msgCommands.ReceivingFailed.."Incompatible Versions,"..sdm_version, "WHISPER", sdm_receiving.playerName) sdm_EndReceiving("|cffff0000Failed|r") return else SendAddonMessage(sdm_msgPrefix, sdm_msgCommands.Receiving..sdm_version, "WHISPER", sdm_receiving.playerName) end elseif (not sdm_receiving.first) and (not send1) then sdm_receiving.nameAndText = sdm_receiving.nameAndText..line else return end local currLen = sdm_receiving.nameAndText:len() sdm_receiveStatusBar:SetValue(currLen) if currLen == (sdm_receiving.playerNameLen + sdm_receiving.textLen) then sdm_receiveStatusBar_text:SetText("|cffff9900Click \"Create\" to save|r") UIFrameFlash(sdm_createMacroButton_flash, 0.5, 0.5, 1e6, false) sdm_newMacroNameInput:EnableMouse(1) sdm_buttonRadio:Enable() sdm_floatingRadio:Enable() sdm_scriptRadio:Enable() sdm_globalRadio:Enable() sdm_charspecRadio:Enable() sdm_createMacroButton:Enable() if sdm_receiving.type=="b" then sdm_buttonRadio:Click() elseif sdm_receiving.type=="f" then sdm_floatingRadio:Click() elseif sdm_receiving.type=="s" then sdm_scriptRadio:Click() end if sdm_receiving.perCharacter then sdm_charspecRadio:Click() else sdm_globalRadio:Click() end sdm_receiving.name=sdm_receiving.nameAndText:sub(1,sdm_receiving.playerNameLen) sdm_newMacroNameInput:SetText(sdm_receiving.name) sdm_receiving.text=sdm_receiving.nameAndText:sub(sdm_receiving.playerNameLen+1,sdm_receiving.playerNameLen+sdm_receiving.textLen) end end function sdm_EndReceiving(text) sdm_receiveStatusBar_text:SetText(text) sdm_cancelReceiveButton:Disable() sdm_receiveButton:Enable() sdm_newButton:Enable() sdm_receiveTargetRadio:Enable() sdm_receiveArbitraryRadio:Enable() sdm_receiveAnyoneRadio:Enable() sdm_receiveInput:EnableMouse(1) sdm_newMacroNameInput:SetText("") sdm_newMacroNameInput:EnableMouse(1) sdm_buttonRadio:Enable() sdm_floatingRadio:Enable() sdm_scriptRadio:Enable() sdm_globalRadio:Enable() sdm_charspecRadio:Enable() sdm_createMacroButton:Enable() sdm_receiving=nil end function sdm_CancelSend() SendAddonMessage(sdm_msgPrefix, sdm_msgCommands.SendFailed.."Cancelled", sdm_sending.channel, sdm_sending.target) sdm_EndSending("|cffff0000Cancelled|r") end function sdm_CancelReceive() if sdm_receiving.playerName~="" then SendAddonMessage(sdm_msgPrefix, sdm_msgCommands.ReceivingFailed.."Cancelled,"..sdm_version, "WHISPER", sdm_receiving.playerName) end sdm_EndReceiving("|cffff0000Cancelled|r") sdm_newFrame:Hide() end function sdm_SplitString(s, pattern, limit, ...) --iterates through "s", splitting it between occurrences of "pattern", and returning the split portions IN BACKWARDS ORDER. Splits a maximum of times (optional) if limit==0 then return s, ... end local index = s:find(pattern) if (not index) then return s, ... end return sdm_SplitString(s:sub(index+pattern:len()), pattern, limit-1, s:sub(1, index-1), ...) end function sdm_SendButtonClicked() local channel local target if sdm_sendPartyRadio:GetChecked() then channel="PARTY" elseif sdm_sendRaidRadio:GetChecked() then channel="RAID" elseif sdm_sendBattlegroundRadio:GetChecked() then channel="BATTLEGROUND" elseif sdm_sendGuildRadio:GetChecked() then channel="GUILD" elseif sdm_sendTargetRadio:GetChecked() then channel="WHISPER" if UnitIsPlayer("target") then target, realm = UnitName("target") if realm and realm~="" then target = target.."-"..realm end end elseif sdm_sendArbitraryRadio:GetChecked() then channel="WHISPER" target=sdm_sendInput:GetText() end if channel=="WHISPER" and ((not target) or target=="" or target==sdm_thisChar.name) then return end sdm_sendInput:ClearFocus() sdm_SendMacro(sdm_macros[sdm_currentEdit], channel, target) end function sdm_ReceiveButtonClicked() local sender if sdm_receiveTargetRadio:GetChecked() then if UnitIsPlayer("target") then sender, realm = UnitName("target") if realm and realm~="" then sender = sender.."-"..realm end end elseif sdm_receiveArbitraryRadio:GetChecked() then sender=sdm_receiveInput:GetText() elseif sdm_receiveAnyoneRadio:GetChecked() then sender = "" end if ((not sender) or sender=="" or sender==sdm_thisChar.name) then return end sdm_receiveInput:ClearFocus() sdm_SaveConfirmationBox("sdm_WaitForMacro("..sdm_Stringer(sender)..")") end sdm_sending=nil --info about the macro you're trying to send sdm_receiving=nil --info about the macro you're receiving (or waiting to receive) sdm_updateInterval=0.25 --can be as low as 0.01 and still work, but it might disconnect you if there are other addons sending out messages too. 0.25 is slower but safer. sdm_minVersion="2.4" --the oldest version that is compatible with this one for exchanging macros