Mercurial > wow > turok
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