diff Turok/Turok.lua @ 6:a9b8b0866ece

clear out log jam
author Nenue
date Sun, 21 Feb 2016 08:32:53 -0500
parents
children 9400a0ff8540
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Turok/Turok.lua	Sun Feb 21 08:32:53 2016 -0500
@@ -0,0 +1,554 @@
+--- Turok
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+--- Defines the mechanisms for the storage and dispatch of events data.
+--@debug@
+--@end-debug@
+-- GLOBALS: LibStub, Turok, TurokData, ReloadUI
+local ADDON, Tk = ...
+local db, L
+local MAJOR, MINOR = "Turok", "@project-revision@"
+local T, LGIST, _G = Tk.Addon, Tk.LGIST, _G
+
+
+local pcall, type, ipairs, pairs, format, tinsert, match, strpad, error = pcall, type, ipairs, pairs, string.format, table.insert, string.match, string.rep, error
+local PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax = PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax
+local GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup = GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup
+local UnitInfo, UnitCastingInfo, UnitChannelInfo = UnitInfo, UnitCastingInfo, UnitChannelInfo
+local rawset, unpack, tostring, setmetatable, xpcall, unpack = rawset, unpack, tostring, setmetatable, xpcall, unpack
+
+--@debug@
+local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool
+local print = function(...)
+  if _G.Devian and _G.DevianDB.workspace ~= 1 then
+    _G.print('Turok', ...)
+  end
+end
+local GetPrint = function(trace)
+  return trace and print or function() end
+end
+--@end-debug@
+
+
+
+--- Pull saved variables and make them sane
+function T.OnInitialize(T)
+
+  --@debug@
+  local tmpidx
+  if TurokData and TurokData.spirit and TurokData.spirit.timerindex then
+    tmpidx = TurokData.spirit.timerindex
+  end
+  TurokData = Turok.defaults
+  if tmpidx then
+    TurokData.spirit.timerindex = tmpidx
+  end
+  --@end-debug@
+  T.db = _G.TurokData
+  LibStub("LibFog-1.0"):Embed(T)
+  if T.db.queue_for_wipe then
+    T:Print("db reset flag received")
+    local index = _G.TurokData.spirit.timerindex
+    _G.TurokData = T.defaults
+    T.db = _G.TurokData
+    T.db.spirit.timerindex = index
+  end
+
+  T:RegisterChatCommand("tkr", function()
+    T.db.queue_for_wipe = true
+    ReloadUI()
+  end)
+
+  -- db hierarchy
+  for k, v in pairs(T.db) do
+    if type(v) == 'table' then
+      --@debug@
+      --print('|cFF44FF88loading stored db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@
+      T.LinkTable(T.db, v, 'db', k)
+    end
+  end
+  setmetatable(T.db,
+    {__newindex = function (t, k, v)
+      rawset(t,k,v)
+      if type(v) == 'table' then
+        --@debug@
+        --print('|cFF44FF88creating new db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@
+        T.LinkTable(T.db, v, 'db', k)
+      end
+    end})
+  T.L = setmetatable({}, {__call = function(t, s) return t[s] or s end})
+end
+
+--- Get everything rolling
+function T:OnEnable()
+  db = TurokData
+  L = T.L
+
+  self.dispatchQueue = {}
+  self.sharedTables = {}
+  local skip = {modules = true, db = true, defaultModuleLibraries = true, orderedModules = true, prototype = true, events = true} -- local data that exists before init
+  for id, mod in pairs(self.orderedModules) do
+    mod.ID = id
+    mod.RegisterCallback = self.RegisterCallback
+    print('load', mod:GetName())
+    for k, v in pairs(mod) do
+      if not skip[k] then
+        if match(k, '^[%u_]+$') then
+          if not self.dispatchQueue[k] then
+            self.dispatchQueue[k] = {}
+          end
+          self:RegisterEvent(k, 'Dispatch')
+          self.dispatchQueue[k][id] = mod:GetName()
+        end
+      end
+    end
+  end
+
+  print('events')
+  for k, v in pairs(self.dispatchQueue) do
+    print('  ',k,'->', unpack(v))
+  end
+
+  print('shared')
+  for k, v in pairs(self.sharedTables) do
+    print('  ',k)
+  end
+  --@debug@
+  self:Print(MAJOR, MINOR, 'enabled.')--@end-debug@
+  self:RegisterChatCommand("tkl", function()
+    PlaySoundFile([[Interface\Addons\Turok\Media\sound\wilhelm.ogg]])
+    if not IsAddOnLoaded("Turok_Config") then
+      local loaded, message = LoadAddOn("Turok_Config")
+      if not loaded then
+        return T:Print("|cFFFF0000Load-on-Demand failed!|r Reason: " .. message)
+      end
+      --self.config = LibStub('AceConfigDialog-3.0'):AddToBlizOptions(MAJOR)
+    end
+    InterfaceOptionsFrame_OpenToCategory(MAJOR)
+    InterfaceOptionsFrame_OpenToCategory(MAJOR)
+  end)
+
+  self:RegisterChatCommand("unlock", function()
+    T.unlocked = (not T.unlocked) and true or nil
+    if T.unlocked then
+      self:Print('frames unlocked')
+    else
+      self:Print('frames locked')
+    end
+    for k, v in pairs(self.orderedModules) do
+      if v.UpdateLocked then
+      v:UpdateLocked()
+        end
+    end
+  end)
+
+  self:RegisterChatCommand("lsm", function(input)
+    local a1, n = self:GetArgs(input, 1,0)
+    local a2 = self:GetArgs(input, 1, n)
+    self:Print(self.LSM:Fetch(a1, a2))
+  end)
+
+  local name, realm = UnitFullName('player')
+  LGIST.RegisterCallback(self, "GroupInSpecT_InspectReady", 'GIST_InspectReady')
+  LGIST.RegisterCallback(self, "GroupInSpecT_Update", 'GIST_Update')
+  self:RegisterCharacterInfo(name, realm)
+
+  if InCombatLockdown() then
+    T.inCombat = true
+  end
+
+  T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player')
+  for order, event in ipairs(self.events) do
+    self:RegisterEvent(event, 'Dispatch')
+  end
+end
+
+do
+  local bucket_events = {['PLAYER_SPECIALIZATION_CHANGED'] = {}, ['PLAYER_TALENT_UPDATE'] = {}}
+  local bucket_start = {}
+  local event_queue = {}
+  local wipe, debugstack = table.wipe, debugstack
+
+  --- Passes event data to the appropriate handlers, and runs any callback returned
+  -- @param e event name
+  -- @param ... event arguments as given by WoW Lua
+  -- @return callback1 runs after its corresponding method has been dispatched to
+  -- @return callback2 runs after all dispatching has completed, in the order that dispatches occurred
+  function T:Dispatch(event, ...)
+    if not (self[event] or self.dispatchQueue[event]) then
+      return
+    end
+
+
+    if bucket_events[event] then
+      local unit = ...
+      if unit and unit ~= 'player' then
+        return
+      end
+
+      print(cText('*** Bucket Event:'), cWord(event))
+      if not bucket_start[event] then
+        self['TKBATCH_'..event] = {}
+        bucket_start[event] = GetTime()
+        T:ScheduleTimer( function()
+          print('*** Firing bucketed event ('..#bucket_events[event]..'):', event, unpack(bucket_events[event][#bucket_events[event]]))
+          T:Dispatch('TKBATCH_'..event, unpack(bucket_events[event][#bucket_events[event]]))
+          bucket_start[event] = nil
+
+          self['TKBATCH_'..event] = nil
+        end,0.1)
+      end
+      tinsert(bucket_events[event], {...})
+      return
+    else
+      event = event:gsub('^TKBATCH_', '')
+    end
+
+
+    if event ~= 'COMBAT_LOG_EVENT_UNFILTERED' then print('|cFFFF0088received|r', event, ...) end
+    local args = {event, ...}
+
+    -- if addon is listening directly
+    if self[event] then
+      print(cWord(event))
+      local reg = function() print(unpack(args)) self[event](self, unpack(args)) end
+      tinsert(event_queue, {self, event, reg})
+
+
+    -- if modules want this event directly
+    end
+    if self.dispatchQueue[event] then
+      for id, name in pairs(self.dispatchQueue[event]) do
+        local mod = self.orderedModules[id]
+        local reg = function() print(unpack(args)) mod[event](mod, unpack(args)) end
+        tinsert(event_queue, {mod, event, reg})
+      end
+    else
+      print("Received", event, "but nothing is listening to it.")
+    end
+
+    for i, entry in ipairs(event_queue) do
+      local handler, event, func = unpack(entry)
+      print('->', cWord(handler:GetName()), cBool(result), cText(message))
+      local result, message = xpcall(func, function(m) print(m, debugstack()) return debugstack() end)
+
+      if bucket_events[event] then
+        wipe(bucket_events[event])
+        bucket_events[event].history = {}
+      end
+    end
+    wipe(event_queue)
+  end
+end
+--- Store character data to speed up spec-specific load time
+function T:RegisterCharacterInfo(name,realm)
+  local classLocalized, classEnglish, classID = UnitClass('player')
+
+  -- set savedvars
+  self.playerName = name
+  self.playerRealm = realm
+  self.playerClass = classEnglish
+  self.playerClassLocalized = classLocalized
+  self.playerClassID = classID
+  self.GUID = UnitGUID('player')
+  local namerealm = name..'-'..realm
+  if not db.char[namerealm] then
+    db.char[namerealm]  = {
+      spellBook = {}
+    }
+  end
+  T.spellBook = db.char[namerealm].spellBook
+
+  -- push combat ratings calc
+  self:COMBAT_RATING_UPDATE()
+end
+
+--- Polls for specialization info until it's available
+function T:RegisterSpecEvents()
+  local specPage = GetSpecialization()
+  if specPage then
+
+    local specID, specName, specDesc, specTexture = GetSpecializationInfo(specPage)
+    local specGroup = GetActiveSpecGroup()
+    print('Turok', cText('* Spec Info:'), GetSpecializationInfo(GetSpecialization()))
+    if T.specID and specID ~= T.specID then
+      print('pushing out old spec data')
+      T.previousSpec = {
+        specPage = T.specPage,
+        specGroup = T.specGroup,
+        specID = T.specID,
+        specName = T.specName,
+        specTexture = T.specTexture
+      }
+    elseif not T.previousSpec then
+      print('first run probably')
+      T.previousSpec = {}
+    end
+
+
+    T.specUpdate = (specID ~= T.specID)
+    T.talentsChanged = (T.specGroup ~= specGroup)
+    T.specPage = specPage
+    T.specGroup = specGroup
+    T.specID = specID
+    T.specName = specName
+    T.specTexture = specTexture
+  else
+    print('Turok', cText('* No Spec Info yet, start polling'))
+    -- repeat until we get something to update with
+    T:ScheduleTimer('RegisterSpecEvents', 1)
+  end
+
+  if T.specID and not T.__specevents then
+    T.__specevents = true
+    T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player')
+    T:RegisterEvent('PLAYER_TALENT_UPDATE', 'Dispatch')
+    T:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', 'Dispatch')
+    T:RegisterEvent('ACTIVE_TALENT_GROUP_CHANGED', 'Dispatch')
+    T:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', 'Dispatch')
+  end
+end
+
+--- Event handler wrapper for the Specialization getter used at load time
+  local GetSpecializationSpells, GetSpellInfo = GetSpecializationSpells, GetSpellInfo
+  function T:PLAYER_SPECIALIZATION_CHANGED(event, unit)
+    -- make sure this was fired for player
+    if (unit ~= 'player') then
+      return
+    end
+
+
+    print('Turok', '|cFF00FF00'.. event)
+    -- Set current spec values and fill out previousSpec table
+    T:RegisterSpecEvents()
+    local ot = T.previousSpec
+
+    -- Is the new spec different?
+    if T.specUpdate then
+      print(cText('Spec changed from'), cWord(ot.specName), cText('to'), cKey(T.specName))
+
+      if ot.specPage and not T.spellBook[ot.specPage] then
+        T.spellBook[ot.specPage] = {}
+      end
+
+      local spellBook = {GetSpecializationSpells(T.specPage)}
+      if not T.spellBook[T.specPage] then
+        T.spellBook[T.specPage] = {}
+        for i = 1, #spellBook, 2 do
+          T.spellBook[T.specPage][spellBook[i]] = GetSpellInfo(spellBook[i])
+          if (not ot.specPage) or (T.spellBook[ot.specPage] and not T.spellBook[ot.specPage][spellBook[i]]) then
+            print(cText('activating for spell'), T.spellBook[T.specPage][spellBook[i]])
+          end
+        end
+      end
+
+
+
+      -- list changed spells for use by spell posession checks
+      local diff = {
+        gained = {},
+        lost = {}
+      }
+
+      --- Check against current for removed spells
+      if T.spellBook[ot.specPage] then
+        for id, spellInfo in pairs(T.spellBook[ot.specPage]) do
+          if not T.spellBook[ot.specPage] then
+            tinsert(diff.lost, spellInfo)
+            print('lost', spellInfo.spellName)
+          else
+            print('keep', spellInfo.spellName)
+          end
+        end
+      end
+
+      T.spellBook.change = diff
+    end
+  end
+
+  local GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo = GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo
+  function T:PLAYER_EQUIPMENT_CHANGED(event, slot, hasItem)
+    print('Equip slot #', slot, ' has?', hasItem)
+    if hasItem then
+      local itemID = GetInventoryItemID('player', slot)
+      print('itemID?', itemID)
+      local spellName = GetItemSpell(itemID)
+      print('spell?', spellName)
+      local _, spellID
+      if spellName then
+        _, _, _, _, _, _, spellID = GetSpellInfo(spellName)
+      end
+
+      local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemID)
+      T.equipped[slot] = {
+        itemID = itemID,
+        spellName = spellName,
+        spellID = spellID,
+        name = name,
+        link = link,
+        equipSlot = equipSlot,
+        texture = texture,
+      }
+      print('equipped', name)
+
+    else
+      self.equipped[slot] = nil
+    end
+  end
+
+  local GetPowerRegen, UnitPowerType = GetPowerRegen, UnitPowerType
+  function T:COMBAT_RATING_UPDATE(t,e)
+    --@debug@
+    print('|cFF00FFFFCOMBAT_RATING_UPDATE')--@end-debug@
+    self.haste = UnitSpellHaste('player')
+    self.powerRegen = GetPowerRegen()
+    self.powerType = UnitPowerType('player')
+    self.castTimeMod = 1+ self.haste/100
+    self.GCD = 1.5 * self.castTimeMod
+
+    L.haste = format('%.2f', self.haste)
+    L.focusregen = format('%.2f', self.powerRegen)
+    L.castingmod = format('%.2f', self.castTimeMod)
+  end
+
+function T:UNIT_SPELLCAST_INTERRUPTED(e, unit, spellName, rank, target, castID)
+  if not T.isEventUnit[unit] then
+    return
+  end
+  T.spellevent[unit] = {unit, spellName, rank, target, castID, nil }
+end
+
+function T:UNIT_SPELLCAST_SENT(e,unit, spellName, rank, target, castID)
+  if not T.isEventUnit[unit] then
+    return
+  end
+  T.unit[unit].spellEventString = e
+  T.unit[unit].spellevent = {unit, spellName, rank, target, castID}
+end
+
+function T:UNIT_SPELLCAST (e, unit, spellName, rank, castID, spellID)
+  if not T.isEventUnit[unit] then
+    return
+  end
+  --name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible
+  local q = {UnitCastingInfo(unit)}
+  T.unit[unit].casting = q[1] and q or false
+  T.unit[unit].spellEventString = e
+  T.unit[unit].spellevent = {unit, spellName, rank, nil,castID, spellID }
+  print(e, unit)
+end
+
+function T:UNIT_CHANNEL(e, unit, spellName, rank, castID, spellID)
+  if not T.isEventUnit[unit] then
+    return
+  end
+  --name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible
+  local q = {UnitChannelInfo(unit) }
+  T.unit[unit].channeling = q[1] and q or false
+  T.unit[unit].spellEventString = e
+  T.unit[unit].spellevent = {unit, spellName, rank, nil, castID, spellID }
+  print(e, unit)
+end
+
+T.UNIT_SPELLCAST_START = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_STOP = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_DELAYED = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_INTERRUPTED = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_FAILED = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_SUCCEEDED = T.UNIT_SPELLCAST
+T.UNIT_SPELLCAST_CHANNEL_START = T.UNIT_CHANNEL
+T.UNIT_SPELLCAST_CHANNEL_UPDATE= T.UNIT_CHANNEL
+T.UNIT_SPELLCAST_CHANNEL_STOP= T.UNIT_CHANNEL
+
+local UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath
+    = UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath
+function T:UnitChanged(e, unit)
+  local u = T.unit[unit]
+  local exists = UnitExists(unit)
+  local realm
+  _G.print('Update', cText('  '..unit..' change:'), cText(unit), cText(exists and UnitName(unit)))
+
+  u.exists = exists
+  u.name, realm = UnitName(unit)
+  u.realm = realm or GetRealmName()
+  u.classification = UnitClassification(unit)
+  u.class = UnitClass(unit)
+  u.isFriendly = UnitIsFriend('player', unit)
+  u.isEnemy = UnitIsEnemy('player', unit)
+  u.isFeign = UnitIsFeignDeath(unit)
+  u.isNeutral = not(u.isHostile or u.isFriendly)
+
+  local castinfo, channelinfo = {UnitCastingInfo(unit)}, {UnitChannelInfo(unit)}
+  u.casting = (u.exists and castinfo[1]) and castinfo or false
+  u.channeling = (u.exists and channelinfo[1]) and channelinfo or false
+  u.isCasting = (u.casting or u.channeling) and true or false
+
+
+  for k,v in pairs(T.unit[unit]) do
+    _G.print('Update', cText('  -'), cText(k),'->', cText(v))
+  end
+end
+function T:PLAYER_TARGET_CHANGED(e)
+  T:UnitChanged(e, 'target')
+end
+function T:PLAYER_FOCUS_CHANGED(e)
+  T:UnitChanged(e, 'focus')
+end
+function T:UNIT_PET(e, unit,...)
+  if unit == 'player' then
+    print(e, unit, ...)
+    T:UnitChanged(e, 'pet')
+  end
+end
+
+local Turok_OnCombat = function(inCombat)
+  print(cText('* CombatToggle:'), cBool(inCombat))
+  PlaySoundFile(db['battle_noise'.. (inCombat and '_start' or '_end')])
+
+  for _, region in pairs(Tk.LibFog.animate_regions) do
+    if region.combatFade then
+      print(' |cFFFFFF00+|r', region:GetName())
+      region:UpdateAlpha(inCombat)
+    else
+      print(' |cFFFF4400-|r', region:GetName())
+    end
+  end
+end
+
+--- InCombatLockdown() isn't updated immediately, so we have to assume
+function T:PLAYER_REGEN_DISABLED(e,...)
+  T.inCombat = true
+  Turok_OnCombat(true)
+end
+function T:PLAYER_REGEN_ENABLED(e,...)
+  T.inCombat = nil
+  Turok_OnCombat(false)
+end
+
+-- GIST datas
+function T:GIST_InspectReady (event, guid, unit)
+  print('GIST barf', guid, unit)
+end
+
+function T:GIST_Update(event, guid, unit, info)
+
+  if info.class_id and info.global_spec_id and info.guid and info.lku then
+    --_G.print('GIST', 'Update', unit)
+    --_G.print('GIST','  class:', info.class_id, 'specid:', info.global_spec_id, 'guid:', info.guid)
+
+    self.units[info.guid] = info
+    self.unitsBySlot[info.lku] = info
+  end
+end
+
+-- todo: re-locate these
+
+T.PLAY_MOVIE = function (e, id)
+  MovieFrame:Hide()
+  T:Print('skipped a shitty movie', e, id)
+end
+T.CINEMATIC_START = function(...)
+  CinematicFrame_CancelCinematic()
+  T:Print('skipped a shitty cinematic', ...)
+end
\ No newline at end of file