adam@0: local _, AskMrRobot = ... adam@0: adam@0: -- initialize the ExportTab class adam@0: AskMrRobot.CombatLogTab = AskMrRobot.inheritsFrom(AskMrRobot.Frame) adam@0: adam@0: -- helper to create text for this tab adam@0: local function CreateText(tab, font, relativeTo, xOffset, yOffset, text) adam@0: local t = tab:CreateFontString(nil, "ARTWORK", font) adam@0: t:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", xOffset, yOffset) adam@0: t:SetPoint("RIGHT", tab, "RIGHT", -25, 0) adam@0: t:SetWidth(t:GetWidth()) adam@0: t:SetJustifyH("LEFT") adam@0: t:SetText(text) adam@0: adam@0: return t adam@0: end adam@0: adam@0: local function newCheckbox(tab, label, tooltipTitle, description, onClick) adam@0: local check = CreateFrame("CheckButton", "AmrCheck" .. label, tab, "InterfaceOptionsCheckButtonTemplate") adam@0: check:SetScript("OnClick", function(self) adam@0: PlaySound(self:GetChecked() and "igMainMenuOptionCheckBoxOn" or "igMainMenuOptionCheckBoxOff") adam@0: onClick(self, self:GetChecked() and true or false) adam@0: end) adam@0: check.label = _G[check:GetName() .. "Text"] adam@0: check.label:SetText(label) adam@0: check.tooltipText = tooltipTitle adam@0: check.tooltipRequirement = description adam@0: return check adam@0: end adam@0: adam@0: function AskMrRobot.CombatLogTab:new(parent) adam@0: adam@0: local tab = AskMrRobot.Frame:new(nil, parent) adam@0: setmetatable(tab, { __index = AskMrRobot.CombatLogTab }) adam@0: tab:SetPoint("TOPLEFT") adam@0: tab:SetPoint("BOTTOMRIGHT") adam@0: tab:Hide() adam@0: adam@0: local text = tab:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") adam@0: text:SetPoint("TOPLEFT", 0, -5) adam@0: text:SetText("Combat Logging") adam@0: adam@0: local manulText = CreateText(tab, "GameFontWhite", text, 0, -15, "Manual:") adam@0: manulText:SetJustifyV("MIDDLE") adam@0: manulText:SetHeight(30) adam@0: adam@0: local btn = CreateFrame("Button", "AmrCombatLogStart", tab, "UIPanelButtonTemplate") adam@0: btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 75, -15) adam@0: btn:SetText("Start Logging") adam@0: btn:SetWidth(120) adam@0: btn:SetHeight(30) adam@0: tab.btnStart = btn adam@0: adam@0: btn:SetScript("OnClick", function() adam@0: tab:StartLogging() adam@0: end) adam@0: adam@0: btn = CreateFrame("Button", "AmrCombatLogEnd", tab, "UIPanelButtonTemplate") adam@0: btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 225, -15) adam@0: btn:SetText("Stop Logging") adam@0: btn:SetWidth(120) adam@0: btn:SetHeight(30) adam@0: tab.btnEnd = btn adam@0: adam@0: btn:SetScript("OnClick", function() adam@0: tab:StopLogging() adam@0: end) adam@0: adam@0: local autoText = CreateText(tab, "GameFontWhite", text, 0, -50, "Automatic:") adam@0: autoText:SetJustifyV("MIDDLE") adam@0: autoText:SetHeight(28) adam@0: adam@0: local autoChk = newCheckbox(tab, adam@0: "Always log Siege of Orgrimmar", adam@0: "Auto-Log Siege of Orgrimmar", adam@0: "Automatically start logging when you enter SoO and stop when you leave SoO.\n\nNote that you should disable similar features in other addons to avoid conflicts.", adam@0: function(self, value) adam@0: if value then adam@0: AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] = "enabled" adam@0: else adam@0: AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] = "disabled" adam@0: end adam@0: adam@0: AmrLogData._lastZone = nil adam@0: AmrLogData._lastDiff = nil adam@0: tab:UpdateAutoLogging() adam@0: end adam@0: ) adam@0: autoChk:SetChecked(AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled") adam@0: autoChk:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 75, -50) adam@0: autoChk:SetHeight(30) adam@0: adam@0: text = CreateText(tab, "GameFontNormalLarge", text, 0, -100, "Character Data") adam@0: adam@0: btn = CreateFrame("Button", "AmrCombatLogSaveCharData", tab, "UIPanelButtonTemplate") adam@0: btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -5) adam@0: btn:SetText("Save Character Data") adam@0: btn:SetWidth(150) adam@0: btn:SetHeight(30) adam@0: adam@0: btn:SetScript("OnClick", function() adam@0: -- reload the UI will save character data to disk adam@0: ReloadUI() adam@0: end) adam@0: adam@0: text = CreateText(tab, "GameFontNormalLarge", btn, 0, -30, "INSTRUCTIONS") adam@0: text = CreateText(tab, "GameFontWhite", text, 0, -10, "1. Use the Start/Stop buttons or check 'Always log Siege of Orgrimmar'.") adam@0: text = CreateText(tab, "GameFontWhite", text, 0, -10, "2. When you are ready to upload, press 'Save Character Data'. *") adam@0: text = CreateText(tab, "GameFontWhite", text, 0, -10, "3. Exit World of Warcraft. **") adam@0: text = CreateText(tab, "GameFontWhite", text, 0, -10, "4. Launch the Ask Mr. Robot client and follow the instructions. ***") adam@0: adam@0: text = CreateText(tab, "GameFontNormalSmall", text, 0, -30, "|c00999999* This will reload your UI to ensure that all collected data is saved to disk. This step is not necessary if you log out of the game before uploading.|r") adam@0: text = CreateText(tab, "GameFontNormalSmall", text, 0, -10, "|c00999999** Exiting WoW before uploading your combat log is optional, but highly recommended. This prevents your log file from getting ridiculously large and slowing down your uploads.|r") adam@0: text = CreateText(tab, "GameFontNormalSmall", text, 0, -10, "|c00999999*** You can download the client program at|r |c003333ffhttp://www.askmrrobot.com/wow/combatlog/upload|r|c00999999.|r") adam@0: adam@0: --[[ adam@0: btn = CreateFrame("Button", "AmrCombatLogTest", tab, "UIPanelButtonTemplate") adam@0: btn:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -15) adam@0: btn:SetText("Test") adam@0: btn:SetWidth(120) adam@0: btn:SetHeight(30) adam@0: adam@0: btn:SetScript("OnClick", function() adam@0: AskMrRobot.ExportToAddonChat(time()) adam@0: end) adam@0: ]] adam@0: adam@0: -- when we start up, ensure that logging is still enabled if it was enabled when they last used the addon adam@0: if (tab:IsLogging()) then adam@0: SetCVar("advancedCombatLogging", 1) adam@0: LoggingCombat(true) adam@0: end adam@0: adam@0: -- if auto-logging is enabled, do a check when the addon is loaded to make sure that state is set correctly adam@0: if AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled" then adam@0: tab:UpdateAutoLogging() adam@0: end adam@0: adam@0: tab:SetScript("OnShow", function() adam@0: tab:Update() adam@0: end) adam@0: adam@0: return tab adam@0: end adam@0: adam@0: function AskMrRobot.CombatLogTab:IsLogging() adam@0: return AmrLogData._logging == true adam@0: end adam@0: adam@0: function AskMrRobot.CombatLogTab:StartLogging() adam@0: adam@0: -- archive the current logging session so that users don't accidentally blow away data before uploading it adam@0: if AmrLogData._current2 ~= nil then adam@0: if not AmrLogData._history2 then AmrLogData._history2 = {} end adam@0: adam@0: -- add new entries adam@0: for name, timeList in AskMrRobot.spairs(AmrLogData._current2) do adam@0: if not AmrLogData._history2[name] then AmrLogData._history2[name] = {} end adam@0: for timestamp, dataString in AskMrRobot.spairs(timeList) do adam@0: AmrLogData._history2[name][timestamp] = dataString adam@0: end adam@0: end adam@0: adam@0: -- delete entries that are more than 10 days old adam@0: local now = time() adam@0: local interval = 60 * 60 * 24 * 10 adam@0: for name, timeList in AskMrRobot.spairs(AmrLogData._history2) do adam@0: for timestamp, dataString in AskMrRobot.spairs(timeList) do adam@0: if difftime(now, tonumber(timestamp)) > interval then adam@0: timeList[timestamp] = nil adam@0: end adam@0: end adam@0: adam@0: local count = 0 adam@0: for timestamp, dataString in pairs(timeList) do adam@0: count = count + 1 adam@0: end adam@0: if count == 0 then adam@0: AmrLogData._history2[name] = nil adam@0: end adam@0: end adam@0: end adam@0: adam@0: -- clean up old-style logging data from previous versions of the addon adam@0: for k, v in AskMrRobot.spairs(AmrLogData) do adam@0: if k ~= "_logging" and k ~= "_autoLog" and k ~= "_lastZone" and k ~= "_lastDiff" and k ~= "_current2" and k ~= "_history2" then adam@0: AmrLogData[k] = nil adam@0: end adam@0: end adam@0: adam@0: -- start a new logging session adam@0: AmrLogData._current2 = {} adam@0: AmrLogData._logging = true adam@0: adam@0: -- always enable advanced combat logging via our addon, gathers more detailed data for better analysis adam@0: SetCVar("advancedCombatLogging", 1) adam@0: adam@0: LoggingCombat(true) adam@0: self:Update() adam@0: adam@0: print("You are now logging combat, and Mr. Robot is logging character data for your raid.") adam@0: end adam@0: adam@0: function AskMrRobot.CombatLogTab:StopLogging() adam@0: LoggingCombat(false) adam@0: AmrLogData._logging = false adam@0: self:Update() adam@0: adam@0: print("Combat logging has been stopped.") adam@0: end adam@0: adam@0: -- update the panel and state adam@0: function AskMrRobot.CombatLogTab:Update() adam@0: local isLogging = self:IsLogging() adam@0: adam@0: if isLogging then adam@0: self.btnStart:Disable() adam@0: self.btnEnd:Enable() adam@0: else adam@0: self.btnStart:Enable() adam@0: self.btnEnd:Disable() adam@0: end adam@0: end adam@0: adam@0: -- called to update logging state when auto-logging is enabled adam@0: function AskMrRobot.CombatLogTab:UpdateAutoLogging() adam@0: adam@0: -- get the info about the instance adam@0: --local zone, zonetype, difficultyIndex, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID = GetInstanceInfo() adam@0: local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() adam@0: --local difficulty = difficultyIndex adam@0: -- Unless Blizzard fixes scenarios to not return nil, let's hardcode this into returning "scenario" -Znuff adam@0: --if zonetype == nil and difficultyIndex == 1 then adam@0: --zonetype = "scenario" adam@0: --end adam@0: adam@0: if zone == AmrLogData._lastZone and difficultyIndex == AmrLogData._lastDiff then adam@0: -- do nothing if the zone hasn't actually changed, otherwise we may override the user's manual enable/disable adam@0: return adam@0: end adam@0: adam@0: AmrLogData._lastZone = zone adam@0: AmrLogData._lastDiff = difficultyIndex adam@0: adam@0: if AmrLogData._autoLog[AskMrRobot.instanceIds.SiegeOfOrgrimmar] == "enabled" then adam@0: if tonumber(instanceMapID) == AskMrRobot.instanceIds.SiegeOfOrgrimmar then adam@0: -- if in SoO, make sure logging is on adam@0: if not self:IsLogging() then adam@0: self:StartLogging() adam@0: end adam@0: else adam@0: -- not in SoO, turn logging off adam@0: if self:IsLogging() then adam@0: self:StopLogging() adam@0: end adam@0: end adam@0: end adam@0: adam@0: end adam@0: adam@0: -- read a message sent to the addon channel with a player's info at the time an encounter started adam@0: function AskMrRobot.CombatLogTab:ReadAddonMessage(message) adam@0: adam@0: -- message will be of format: timestamp\nrealm\nname\n[stuff] adam@0: local parts = {} adam@0: for part in string.gmatch(message, "([^\n]+)") do adam@0: tinsert(parts, part) adam@0: end adam@0: adam@0: local timestamp = parts[1] adam@0: local name = parts[2] .. ":" .. parts[3] adam@0: local data = parts[4] adam@0: adam@0: if (data == "done") then adam@0: -- we have finished receiving this message; now process it to reduce the amount of duplicate data adam@0: local setup = AmrLogData._current2[name][timestamp] adam@0: adam@0: if (AmrLogData._previousSetup == nil) then adam@0: AmrLogData._previousSetup = {} adam@0: end adam@0: adam@0: local previousSetup = AmrLogData._previousSetup[name] adam@0: adam@0: if (previousSetup == setup) then adam@0: -- if the last-seen setup for this player is the same as the current one, we don't need this entry adam@0: AmrLogData._current2[name][timestamp] = nil adam@0: else adam@0: -- record the last-seen setup adam@0: AmrLogData._previousSetup[name] = setup adam@0: end adam@0: else adam@0: -- concatenate messages with the same timestamp+name adam@0: if (AmrLogData._current2[name] == nil) then adam@0: AmrLogData._current2[name] = {} adam@0: end adam@0: adam@0: if (AmrLogData._current2[name][timestamp] == nil) then adam@0: AmrLogData._current2[name][timestamp] = data adam@0: else adam@0: AmrLogData._current2[name][timestamp] = AmrLogData._current2[name][timestamp] .. data adam@0: end adam@0: end adam@0: end