Compare with Previous | Blame | View Log
-- TODO: Localize this data --[[ Mostly a copy of transcriptor, with changes to the formating. --]] local mod = LibStub("AceAddon-3.0"):NewAddon("RaidWatch2_Logger", "AceEvent-3.0", "AceConsole-3.0") local RW = LibStub("AceAddon-3.0"):GetAddon("Raid Watch") local party = RW.Party local logName = "" local activeLog = {} local insert = table.insert local fmt = string.format local logStartTime = nil local AL = LibStub("AceLocale-3.0") local L = AL:GetLocale("RaidWatch2_Logger") -- Format is : [time] areaid/dungeon@difficulty (rev) local logNameFormat = "[%s] %d/%s@%s-%d (r%d)" local lineFormat = "<%s> %s" local totalFormat = "[%s] %s" local eventsToTrack = { "PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "CHAT_MSG_MONSTER_EMOTE", "CHAT_MSG_MONSTER_SAY", "CHAT_MSG_MONSTER_WHISPER", "CHAT_MSG_MONSTER_YELL", "CHAT_MSG_RAID_WARNING", "CHAT_MSG_RAID_BOSS_EMOTE", "CHAT_MSG_RAID_BOSS_WHISPER", "PLAYER_TARGET_CHANGED", "UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_INTERRUPTED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_STOP", "UPDATE_WORLD_STATES", "WORLD_STATE_UI_TIMER_UPDATE", "COMBAT_LOG_EVENT_UNFILTERED", "INSTANCE_ENCOUNTER_ENGAGE_UNIT", } local aliases = { ["COMBAT_LOG_EVENT_UNFILTERED"] = "CLEU", ["PLAYER_REGEN_DISABLED"] = "REGEN_DISABLED", ["PLAYER_REGEN_ENABLED"] = "REGEN_ENABLED", ["CHAT_MSG_MONSTER_EMOTE"] = "MONSTER_EMOTE", ["CHAT_MSG_MONSTER_SAY"] = "MONSTER_SAY", ["CHAT_MSG_MONSTER_WHISPER"] = "MONSTER_WHISPER", ["CHAT_MSG_MONSTER_YELL"] = "MONSTER_YELL", ["CHAT_MSG_RAID_WARNING"] = "RAID_WARNING", ["CHAT_MSG_RAID_BOSS_EMOTE"] = "RAID_BOSS_EMOTE", ["CHAT_MSG_RAID_BOSS_WHISPER"] = "RAID_BOSS_WHISPER", ["UNIT_SPELLCAST_START"] = "CAST_START", ["UNIT_SPELLCAST_STOP"] = "CAST_STOP", ["UNIT_SPELLCAST_SUCCEEDED"] = "CAST_SUCCEEDED", ["UNIT_SPELLCAST_INTERRUPTED"] = "CAST_INTERRUPTED", ["UNIT_SPELLCAST_CHANNEL_START"] = "CAST_CHANNEL_START", ["UNIT_SPELLCAST_CHANNEL_STOP"] = "CAST_CHANNEL_STOP", ["UNIT_SPELLCAST_INTERRUPTIBLE"] = "CAST_INTERRUPTIBLE", ["UNIT_SPELLCAST_NOT_INTERRUPTIBLE"] = "CAST_NOT_INTERRUPTIBLE", ["INSTANCE_ENCOUNTER_ENGAGE_UNIT"] = "ENGAGE", ["WORLD_STATE_UI_TIMER_UPDATE"] = "WORLD_TIMER", ["UPDATE_WORLD_STATES"] = "WORLD_STATE", } local menu = {} local popupFrame = CreateFrame("Frame", "RaidWatch2LoggerMenu", eventFrame, "UIDropDownMenuTemplate") local function openMenu(frame) EasyMenu(menu, popupFrame, frame, 20, 4, "MENU") end local function strjoin(delimiter, ...) local ret = nil for i = 1, select("#", ...) do ret = (ret or "") .. tostring((select(i, ...))) .. ":" end return ret end local default = { profile = { Minimap = { hide = true, } } } function mod:OnInitialize() local db = LibStub("AceDB-3.0"):New("RaidWatch2LoggerDB", default, "Default") self.db = db.profile self.db.Minimap = self.db.Minimap or {} self.db.Log = self.db.Log or {} self.db.IgnoredEvents = self.db.IgnoredEvents or {} self.db.version = 1 self.logging = false end function mod:OnEnable() self:RegisterChatCommand("rwlog", "SlashHandler") for i, v in next, eventsToTrack do table.insert(menu, { text = v, tooltipTitle = v, tooltipText = L["Disable logging of %s events."]:format(v), func = function() mod.db.IgnoredEvents[v] = not mod.db.IgnoredEvents[v] end, checked = function() return mod.db.IgnoredEvents[v] end, }) end self:SetUpLDB() end function mod:ClearLog() if self.logging then print(L["Stop the log before trying to clear it."]) else print(L["Clearing log."]) self.db.Log = {} self.db.IgnoredEvents = {} end end -- TODO move to thier own functions local sh = {} function mod.UPDATE_WORLD_STATES() local ret = nil for i = 1, GetNumWorldStateUI() do local m = strjoin(":", GetWorldStateUIInfo(i)) if m and m:trim() ~= "0:" then ret = (ret or "") .. "|" .. m end end return ret end mod.WORLD_STATE_UI_TIMER_UPDATE = mod.UPDATE_WORLD_STATES function mod.COMBAT_LOG_EVENT_UNFILTERED(_, ...) return strjoin(":", ...) end function mod.PLAYER_REGEN_DISABLED() return " *START* " end function mod.PLAYER_REGEN_ENABLED() return " *END* " end function mod.UNIT_SPELLCAST_STOP(unit) return UnitName(unit) end mod.UNIT_SPELLCAST_CHANNEL_STOP = mod.UNIT_SPELLCAST_STOP mod.UNIT_SPELLCAST_INTERRUPTED = mod.UNIT_SPELLCAST_STOP function mod.PLAYER_TARGET_CHANGED() if UnitExists("target") and not UnitInRaid("target") then local level = UnitLevel("target") or "nil" local reaction = "Hostile" if UnitIsFriend("target", "player") then reaction = "Friendly" end local classification = UnitClassification("target") or "nil" local creatureType = UnitCreatureType("target") or "nil" local typeclass if classification == "normal" then typeclass = creatureType else typeclass = (classification.." "..creatureType) end local name = UnitName("target") or "nil" local mobid = "nil" local guid = UnitGUID("target") if guid then mobid = tonumber(guid:sub(7, 10), 16) end return (fmt("[%s|%s|%s]:[%s|%s|%s]", tostring(level), tostring(reaction), tostring(typeclass), tostring(name), tostring(guid), tostring(mobid))) end end function mod.UNIT_SPELLCAST_START(unit) local spell, rank, displayName, icon, startTime, endTime = UnitCastingInfo(unit) if not spell then return end local time = ((endTime - startTime) / 1000) return fmt("[%s][%s][%s][%s][%s][%s]", UnitName(unit), tostring(spell), tostring(rank), tostring(displayName), tostring(icon), tostring(time)) end function mod.UNIT_SPELLCAST_CHANNEL_START(unit) local spell, rank, displayName, icon, startTime, endTime = UnitChannelInfo(unit) if not spell then return end local time = ((endTime - startTime) / 1000) return fmt("[%s][%s][%s][%s][%s][%s]", UnitName(unit), tostring(spell), tostring(rank), tostring(displayName), tostring(icon), tostring(time)) end function mod.CHAT_MSG_RAID_BOSS_EMOTE(...) local message, sender, _,_,target,_,_,_,_,_,_ = ... -- scan party to fin the send local bossGUID for _, player in pairs(party.group) do if UnitName(player.id.."target") == sender then bossGUID = UnitGUID(player.id.."target") end end health = -1 if bossGUID then health = UnitHealth(bossGUID) / UnitHealthMax(bossGUID) health = math.floor(100 * health) end -- if we could find the target, record the health at the time of the yell. return fmt("%s:%s:%s:%d",message,sender,target,health) end mod.CHAT_MSG_MONSTER_EMOTE = mod.CHAT_MSG_RAID_BOSS_EMOTE mod.CHAT_MSG_MONSTER_SAY = mod.CHAT_MSG_RAID_BOSS_EMOTE mod.CHAT_MSG_MONSTER_YELL = mod.CHAT_MSG_RAID_BOSS_EMOTE mod.CHAT_MSG_MONSTER_WHISPER = mod.CHAT_MSG_RAID_BOSS_EMOTE mod.CHAT_MSG_RAID_BOSS_WHISPER = mod.CHAT_MSG_RAID_BOSS_EMOTE mod.CHAT_MSG_RAID_WARNING = mod.CHAT_MSG_RAID_BOSS_EMOTE function mod.UNIT_SPELLCAST_SUCCEEDED(unit, ...) return strjoin(":", UnitName(unit), ...) end function mod:EventHandler(event,...) if self.db.IgnoredEvents[event] then return end local line = nil if self[event] and event:find("^UNIT_SPELLCAST") then local unit = ... if not UnitExists(unit) or UnitInRaid(unit) or UnitInParty(unit) or UnitIsFriend("player", unit) then return end line = self[event](...) elseif self[event] then line = self[event](...) else line = strjoin(":", ...) end if type(line) ~= "string" or line:len() < 5 then return end local e = aliases[event] or event local t = GetTime() - logStartTime insert(activeLog.total, lineFormat:format(fmt("%.1f", t), totalFormat:format(e, line))) -- We only have CLEU in the total log, it's way too much information to log twice. if event == "COMBAT_LOG_EVENT_UNFILTERED" then return end if type(activeLog[e]) ~= "table" then activeLog[e] = {} end insert(activeLog[e], lineFormat:format(fmt("%.1f", t), line)) end function mod:StopLog() self.logging = false self.ldbojb.icon = [[Interface\Icons\INV_Misc_Book_14.blp]] self.ldbojb.text = L["Raid Watch2 Loggger |cff696969Idle|r"] self:UnregisterAllEvents() end function mod:StartLog(silent) if self.logging then return nil end self.logging = true self.ldbojb.icon = [[Interface\Icons\INV_Misc_Note_04.blp]] self.ldbojb.text = L["Raid Watch 2 Logger |cffFF0000Recording|r"] logStartTime = GetTime() local name, itype, difficulty, difficultyName, maxPlayers, playerDifficulty, isDynamicInstance = GetInstanceInfo() logName = logNameFormat:format(date("%H:%M:%S"), GetCurrentMapAreaID(), GetRealZoneText(), itype, difficulty, revision or 1) if type(self.db.Log[logName]) ~= "table" then self.db.Log[logName] = {} end if type(self.db.IgnoredEvents) ~= "table" then self.db.IgnoredEvents = {} end activeLog = self.db.Log[logName] if type(activeLog.total) ~= "table" then activeLog.total = {} end for i, event in next, eventsToTrack do self:RegisterEvent(event,"EventHandler") end end function mod:SlashHandler(input, button, ...) local LI = LibStub("LibDBIcon-1.0",true) if input == "" then if self.logging then mod:StopLog() else mod:StartLog() end elseif input == "clear" then mod:ClearLog() elseif input == "show" then mod.db.Minimap.hide = false if LI then LI:Show("RW2Log") end elseif input == "hide" then mod.db.Minimap.hide = true if LI then LI:Hide("RW2Log") end end end function mod:SetUpLDB() local LDB = LibStub("LibDataBroker-1.1") if not LDB then print("NO LDB") end local l = LDB:NewDataObject("RW2Log") l.type = "data source" l.icon = [[Interface\Icons\INV_Misc_Book_14.blp]] l.tocname = "RaidWatch_Logger" l.text = L["Raid Watch2 Loggger |cff696969Idle|r"] l.OnClick = function(self, button) if button == "LeftButton" then if IsAltKeyDown() then mod:ClearLog() else if not mod.logging then mod:StartLog() elseif mod.logging then mod:StopLog() end end elseif button == "RightButton" then openMenu(self) end end l.OnTooltipShow = function(tt) if mod.logging then tt:AddLine(logName, 1, 1, 1, 1) else tt:AddLine(L["|cff696969Idle|r"], 1, 1, 1, 1) end tt:AddLine(" ") tt:AddLine(L["|cffeda55fClick|r to start or stop transcribing. |cffeda55fRight-Click|r to configure events. |cffeda55fAlt-Left Click|r to clear all stored transcripts."], 0.2, 1, 0.2, 1) end local LibDBIcon = LibStub("LibDBIcon-1.0") if not LibDBIcon then return end LibDBIcon:Register("RW2Log", l, mod.db.Minimap) self.ldbojb = l end