Mercurial > wow > skeletonkey
changeset 74:9824d524a661
- binding slot mixin:
- store key binding definitions under their slot's data table
- apply action button attributes when a slot is assigned
- obtain correct macro body text when a macro is slotted
- fix algorithm for resolving renamed macro indices
- move spell detail lookup code out of mixin script
- event chains:
- initialize addon from PLAYER_LOGIN
- reload keybinds from PLAYER_SPECIALIZATION_CHANGED, after spec profile is resolved
- refresh interface content from SPELLS_CHANGED
- hotkey text:
- restore communication and detection of key binding updates and reflect them accordingly
- properly respond to dynamic bindings that result from talent updates
author | Nenue |
---|---|
date | Sat, 14 Jan 2017 02:29:33 -0500 |
parents | 68365bda5ab5 |
children | e75a2fd448c0 |
files | ActionTemplates.lua BindingsFrame.lua Events.lua KeyButton.lua SkeletonKey.lua SkeletonKey.xml |
diffstat | 6 files changed, 195 insertions(+), 149 deletions(-) [+] |
line wrap: on
line diff
--- a/ActionTemplates.lua Sat Jan 07 12:52:05 2017 -0500 +++ b/ActionTemplates.lua Sat Jan 14 02:29:33 2017 -0500 @@ -106,13 +106,77 @@ --- Resolves the SecureActionButton attribute names used for the given action kb.RegisterAction = function(actionType, id, name) assert(atype[actionType], 'Missing actionType handler for `'..tostring(actionType)..'`') - local target, attributeName, attributeValue, button = atype[actionType](id, name) - local command = target .. attributeName - - return attributeName, attributeValue, command, target, button + local prefix, attributeName, attributeValue, button = atype[actionType](id, name) + local command = prefix .. attributeName + return attributeName, attributeValue, command, prefix, button end +local spells = {} +local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon) + if not spells[spellID] then + spells[spellID] = {} + spells[spellID].actionType = 'spell' + spells[spellID].actionID = spellID + spells[spellID].actionName = spellName + spells[spellID].iconPath = icon + spells[spellID].statusText = '|cFFBBBBBBSpell|r' + spells[spellID].dynamicType = nil + end + return spells[spellID] +end + +-- tries to resolve spells from talent overrides/profession book/etc +local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'} +kb.ResolveSpellSlot = function(self) + local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath + --print(' In:', spellName, spellID, command) + --print(GetSpellInfo(spellName or spellID)) + local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellName or spellID) + local isAvailable = internalName and true + + if internalName and (internalName ~= spellName) then + -- it's a binding for the originating spell, leave it as is + print(' |cFFFF4400spell is an override(', internalName, '~=', spellName,') leave the name info alone') + self.statusText = '|cFFFFFF00Spell|r' + self.isAvailable = true + return + end + + -- let's us match spells replaced by talents + local info = kb.DynamicSpells[internalName or spellName] + if not info then + local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)") + if kb.DynamicSpells[dynamicType] then + print('|cFFFF4400resolving dynamic type index:', internalName, spellName, command) + dynamicIndex = tonumber(dynamicIndex) + dynamicSubIndex = tonumber(dynamicSubIndex) + local cache = kb.DynamicSpells[dynamicType] + print('type:', dynamicType) + if dynamicIndex and cache[dynamicIndex] then + info = kb.DynamicSpells[dynamicType][dynamicIndex] + print('index:', dynamicIndex) + if dynamicSubIndex and info[dynamicSubIndex] then + info = info[dynamicSubIndex] + print('sub-index:', dynamicSubIndex) + end + isAvailable = true + end + end + if not info then + info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon) + end + end + info.isAvailable = isAvailable + + print('|cFF00FF88Slot Details:|r', info.actionName, info.actionID, info.dynamicType, info.isAvailable) + for k,v in pairs(info) do + --cprint(' ',k,v) + self[k] = v + end + + return info +end kb.ApplyTalentBinding = function(talentInfo, cache) @@ -312,15 +376,20 @@ if not configTable.assignedKeys then configTable.assignedKeys = {GetBindingKey(configTable.command) } end - if configTable.dynamicType then - kb:print(table.concat(configTable.assignedKeys, ', ') .. ' bound to '.. configTable.actionName) + if configTable.dynamicType == 'talent' then + --kb:print(table.concat(configTable.assignedKeys, ', ') .. ' bound to '.. configTable.actionName) end + for _, key in pairs(configTable.assignedKeys) do + + SetBinding(key, configTable.command) + end + end end end kb.ApplyAllBindings =function () - cprint('|cFF0088FFApplyAllBindings()') + print('|cFFFFFF00ApplyAllBindings()') wipe(kb.TalentBindings) wipe(kb.bindings) --kb:print('Loading binding profile', kb.profileName) @@ -366,7 +435,6 @@ if kb.talentsPushed then return end - wipe(kb.TalentCache) for row =1, MAX_TALENT_TIERS do for col = 1, NUM_TALENT_COLUMNS do local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) @@ -406,7 +474,6 @@ end kb.talentsPushed = true - kb.UpdateDynamicButtons('talent') end @@ -638,12 +705,9 @@ if #kb.pendingAttributes == 0 then kb:print(kb.L('Key bindings will be applied when you exit combat.')) end - tinsert(kb.pendingAttributes, {target, name, value}) SkeletonKey:RegisterEvent('PLAYER_REGEN_ENABLED') - else - --cprint('|cFFFF4444' .. target:GetName()..'|r.|cFFFFFF00'.. tostring(name)..'|r = "'..tostring(value)..'"') target:SetAttribute(name, value) end
--- a/BindingsFrame.lua Sat Jan 07 12:52:05 2017 -0500 +++ b/BindingsFrame.lua Sat Jan 14 02:29:33 2017 -0500 @@ -17,7 +17,8 @@ SkeletonKeyButtonMixin = {} local _, kb = ... -local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SK', ...) end or nop +local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SKUI', ...) end or nop +local gprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SK', ...) end or nop local L = kb.L local BINDS_PER_ROW = 2 local BINDING_TYPE_SPECIALIZATION = 3 @@ -249,7 +250,7 @@ --- push current information into living UI function SkeletonKeyMixin:Update(force) - print('|cFFFF8800'..self:GetName()..':Update()|r', InCombatLockdown() and 'combat', self:IsShown()) + gprint('|cFFFF8800'..self:GetName()..':Update()|r', InCombatLockdown() and 'combat', self:IsShown()) for index, frame in ipairs(self.Plugins) do if frame.Update then frame:Update(force) @@ -351,6 +352,7 @@ else tabID = BINDING_TYPE_GLOBAL end + print(selectedProfile) scrollOffset = scrollOffset or 0 local leftSlot, upSlot
--- a/Events.lua Sat Jan 07 12:52:05 2017 -0500 +++ b/Events.lua Sat Jan 14 02:29:33 2017 -0500 @@ -21,33 +21,28 @@ end kb.PLAYER_REGEN_ENABLED = function() - SkeletonKey:Update() -end - -kb.PLAYER_SPECIALIZATION_CHANGED = function(...) - - kb.UpdateSpecInfo() - kb.UpdateTalentInfo() - - kb.SelectProfileSet(kb.profileName) - kb.ApplyAllBindings() - SkeletonKey:Update(true) -end -kb.PLAYER_TALENT_UPDATE = function() - --kb.UpdateTalentInfo() - --kb.SelectProfileSet(kb.profileName) - --kb.ApplyAllBindings() - --SkeletonKey:Update() + SkeletonKey:SetShown(kb.db.showUI) end kb.ACTIONBAR_SLOT_CHANGED = function(self, event, slot) --kb.HotKeyText(slot) return true end +kb.PLAYER_TALENT_UPDATE = function() + kb.TalentsChanged = true +end + -- only need to respond to this for pet actions -kb.SPELLS_CHANGED = function(self, event, unit) - print('|cFFFF0088'.. event..'|r', unit) +kb.PLAYER_SPECIALIZATION_CHANGED = function(self, event, unit) + kb.UpdateSpecInfo() + kb.UpdateTalentInfo() kb.UpdatePetInfo() + kb.SelectProfileSet(kb.profileName) + kb.ApplyAllBindings() +end + +kb.SPELLS_CHANGED = function() + SkeletonKey:Update() end kb.UPDATE_MACROS = function()
--- a/KeyButton.lua Sat Jan 07 12:52:05 2017 -0500 +++ b/KeyButton.lua Sat Jan 14 02:29:33 2017 -0500 @@ -5,7 +5,7 @@ -- Deals with display and manipulation of binding slots local _, kb = ... -local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SkeletonKey', ...) end or function() end +local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('KeyButton', ...) end or function() end local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end local L = kb.L local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs @@ -170,7 +170,7 @@ end - local name, icon, _ + local name, icon, _, macroName, macroText local pickupID, pickupBook if actionType == 'spell' then @@ -178,7 +178,8 @@ name, _, icon = GetSpellInfo(actionID) elseif actionType == 'macro' then - name, icon = GetMacroInfo(actionID) + name, icon, macroText = GetMacroInfo(actionID) + macroName = name elseif actionType == 'petaction' then if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then @@ -217,7 +218,7 @@ icon = petIcon end - local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) + local _, macroBody, command = kb.RegisterAction(actionType, actionID, name) local slotInfo = { command = command, actionName = name, @@ -225,7 +226,7 @@ actionType = actionType, actionID = actionID, macroName = macroName, - macroText = macroText, + macroText = macroText or macroBody, spellbookSlot = pickupID, spellbookType = pickupBook, assignedKeys = {GetBindingKey(command)} @@ -242,6 +243,11 @@ StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') else kb.currentProfile.buttons[self:GetID()] = slotInfo + if #slotInfo.assignedKeys >= 1 then + kb:print('Obtained following hotkeys:', table.concat(slotInfo.assignedKeys, ', ')) + + end + kb.LoadBinding(slotInfo) self:SetSlot(slotInfo) self:UpdateSlot() self.active = nil @@ -312,8 +318,8 @@ if self.command then - print('|cFFFF4400', self.actionName, #self.assignedKeys, self.assignedKeys) - print(table.concat(self.assignedKeys, ',')) + print('|cFFFF4400', self.actionName, #self.assignedKeys, table.concat(self.assignedKeys, ',')) + print(self.isAvailable) print(self.actionID) self.bindingText= kb.BindingString(unpack(self.assignedKeys)) if not self.isAvailable then @@ -336,13 +342,7 @@ else self.macro:Hide() if self.actionType == 'spell' then - local dummy = GetSpellInfo(self.actionName) - if not dummy then - self.icon:SetDesaturated(true) - else - self.icon:SetDesaturated(false) - end - + self.isAvailable = GetSpellInfo(self.actionName) and true or false end end @@ -378,12 +378,14 @@ end - self.ignoreTexture:SetShown(self.command and not self.isAvailable) - if not self.isAvailable then - self.bind:SetTextColor(0.7,0.7,0.7,1) + self.bind:SetTextColor(.7,.7,.7,1) + self.ignoreTexture:SetShown(self.command and true) + self.icon:SetVertexColor(.5,.5,.5) else + self.ignoreTexture:SetShown(false) self.bind:SetTextColor(1,1,1,1) + self.icon:SetVertexColor(1,1,1) end @@ -459,76 +461,10 @@ end -local spells = {} -local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon) - if not spells[spellID] then - spells[spellID] = {} - spells[spellID].actionType = 'spell' - spells[spellID].actionID = spellID - spells[spellID].actionName = spellName - spells[spellID].iconPath = icon - spells[spellID].statusText = '|cFFBBBBBBSpell|r' - spells[spellID].dynamicType = nil - end - return spells[spellID] +local DoMacroCheck = function(name, macroText, searchID, roughResult) + + return matchID, matchName, matchBody, endOfSearch end - -local tempInfo = {} --- tries to resolve spells from talent overrides/profession book/etc -local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'} -local SkeletonKey_GetSpellDetails = function(self) - - local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath - - - print(' In:', spellName, spellID, command) - print(GetSpellInfo(spellName or spellID)) - local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellName or spellID) - local isAvailable = internalName and true - - if internalName and (internalName ~= spellName) then - -- it's a binding for the originating spell, leave it as is - print(' |cFFFF4400spell is an override(', internalName, '~=', spellName,') leave the name info alone') - self.statusText = '|cFFFFFF00Spell|r' - self.isAvailable = true - return - end - - -- let's us match spells replaced by talents - local info = kb.DynamicSpells[internalName or spellName] - if not info then - local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)") - if kb.DynamicSpells[dynamicType] then - print('|cFFFF4400resolving dynamic type index:', internalName, spellName, command) - dynamicIndex = tonumber(dynamicIndex) - dynamicSubIndex = tonumber(dynamicSubIndex) - local cache = kb.DynamicSpells[dynamicType] - print('type:', dynamicType) - if dynamicIndex and cache[dynamicIndex] then - info = kb.DynamicSpells[dynamicType][dynamicIndex] - print('index:', dynamicIndex) - if dynamicSubIndex and info[dynamicSubIndex] then - info = info[dynamicSubIndex] - print('sub-index:', dynamicSubIndex) - end - isAvailable = true - end - end - if not info then - info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon) - end - end - info.isAvailable = isAvailable - - print('|cFF00FF88SpellDetails:|r', info.actionName, info.actionID, info.dynamicType, info.isAvailable) - for k,v in pairs(info) do - --cprint(' ',k,v) - self[k] = v - end - - return info -end - --- Assigns the slot via table copy; any manipulations from this point are temporary and function skb:SetSlot(slotInfo) print('slot info', self:GetID()) @@ -549,7 +485,7 @@ isBound = kb.IsCommandBound(self, self.command) if actionType == 'spell' then - local info = SkeletonKey_GetSpellDetails(self) + local info = kb.ResolveSpellSlot(self) name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook = self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType self.isAvailable = info and info.isAvailable elseif actionType == 'petaction' then @@ -573,35 +509,75 @@ self.isAvailable = (kb.PetCache.spellslot[name]) elseif actionType == 'macro' then if actionID then - -- look for corruption + + -- Update stored information if it mis-matches local nameByID, _, bodyByID = GetMacroInfo(actionID) - local nameByName, _, bodyByName = GetMacroInfo(name) + --print(bodyByID, "\n", macroText) if (nameByID ~= name) or (bodyByID ~= macroText) then - local prevIndex = actionID - actionID = GetMacroIndexByName(name) - local firstName, _, firstBody = GetMacroInfo(actionID) + --kb:print('mismatches for slot', self:GetID(), actionID, ((nameByID ~= name) and 'name' or ''), ((bodyByID ~= macroText) and 'body' or '')) + local matchID, matchName, matchBody, hasMultiple + local roughResult = "" + + local newID = GetMacroIndexByName(name) + local firstName, _, firstBody = GetMacroInfo(newID) if (firstName ~= name) or (firstBody ~= macroText) then + + -- go even deeper - for i = 1, GetNumMacros() do - local searchName, _ , searchBody = GetMacroInfo(i) + local numAccount, numCharacter = GetNumMacros() + local searchID = 1 + while searchID <= (120+numCharacter) do + --kb:print(searchID) + + + local searchName, _ , searchBody = GetMacroInfo(searchID) if (searchName == name) and (searchBody == macroText) then + --kb:print('definitely', matchID, searchName, '\n', searchBody) -- complete match - actionID = i - kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')') + matchID = searchID + matchName = searchName + matchBody = searchBody break elseif (searchName == name) or (searchBody == macroText) then -- partial match, continue the search - actionID = i - kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')') + + if matchID then + hasMultiple = true + roughResult = roughResult .. "\n" .. tostring(searchID) .. ':'..tostring(searchName) + end + + matchID = searchID + matchName = searchName + matchBody = searchBody + --kb:print('possibly', matchID, matchName, '\n', matchBody) end + + if searchID == numAccount then + searchID = 120 + end + searchID = searchID + 1 end + else + matchID = newID + matchName = firstName + matchBody = firstBody end + --kb:print(matchID, hasMultiple) + if hasMultiple then + kb:print('Macro assignment in slot #'..tostring(self:GetID())..' has multiple possible indexes:\nSaved Info: '..tostring(actionID)..'/'..tostring(name)..'\n|cFFFFFF00', roughResult) + elseif matchID then + kb:print('Macro for slot #'..tostring(self:GetID())..' ('..tostring(name)..') has probably changed:', ((actionID ~= newID) and (' |cFFFF4400'..tostring(actionID)..'|r to |cFF00FF88' .. newID .. '|r.') or ''), 'We\'re not sure, so you may want to re-do that assignment.') + actionID = matchID + name = matchName + macroName = matchName + macroText = matchBody + end end else actionID = GetMacroIndexByName(name) end - self.statusText = 'Macro' + self.statusText = 'Macro ' .. tostring(actionID) self.isAvailable = true else if not actionID then @@ -692,6 +668,8 @@ self.iconPath = icon self.profile = kb.db.bindMode self:RegisterForDrag('LeftButton') + + return slotInfo end kb.GetCommandAction = function(command)
--- a/SkeletonKey.lua Sat Jan 07 12:52:05 2017 -0500 +++ b/SkeletonKey.lua Sat Jan 14 02:29:33 2017 -0500 @@ -151,8 +151,8 @@ for i = 1, select('#', ...) do local key = select(i, ...) if type(key) == 'string' then - stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') - end + stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') + end end if #stack >= 1 then @@ -243,8 +243,8 @@ local defaultMode --- General info classHeader, className, classID = UnitClass('player') - print('|cFF00FF00profile:|r', name) - print('|cFF00FF00class:|r', UnitClass('player')) + --kb:print('|cFF00FF00profile:|r', name) + --kb:print('|cFF00FF00class:|r', UnitClass('player')) defaultMode = BINDING_TYPE_GLOBAL if db[name] then @@ -287,9 +287,10 @@ setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end}) setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end}) - print('|cFF00FF00bindMode:|r', db.bindMode) kb.currentProfile = kb.loadedProfiles[db.bindMode] kb.currentHeader = kb.configHeaders[db.bindMode] + + print('|cFF88FF00SelectProfile()|r', kb.profileName, classHeader, kb.specInfo.name) end @@ -317,9 +318,10 @@ print('|cFF0088FF'..self:GetName()..':OnLoad()') self.CloseButton:SetScript('OnClick', CloseButton_OnClick) - self:RegisterEvent('PLAYER_LOGIN') self:RegisterEvent('PLAYER_ENTERING_WORLD') self:RegisterEvent('ADDON_LOADED') + self:RegisterEvent('PLAYER_LOGIN') + self:RegisterUnitEvent('PLAYER_SPECIALIZATION_CHANGED', 'player') self:EnableKeyboard(false) self.zoomScale = self:GetScale() @@ -330,13 +332,15 @@ end function SkeletonKeyMixin:OnEvent(event, arg) - if event == 'ADDON_LOADED' then + print('|cFFFF0088'.. event..'|r', unit) + if event == 'PLAYER_LOGIN' then print('|cFF00FFFF'..event ..'|r', arg or '', IsLoggedIn()) - if IsLoggedIn() and not self.initialized then + if not self.initialized then self:Setup() self.initialized = true - self:Update() + kb.ApplyAllBindings() + self:Update(true) end @@ -351,6 +355,11 @@ end end +function SkeletonKeyMixin:RefreshSpells() + + kb.UpdateTalentInfo() + kb.UpdatePetInfo() +end --- post ADDON_LOADED function SkeletonKeyMixin:Setup () @@ -365,10 +374,10 @@ kb.UpdateSpecInfo() kb.UpdateTalentInfo() kb.SelectProfileSet(kb.profileName) + self:SetShown(kb.db.showUI) -- todo: redo import checking kb.UpdateSystemBinds() - kb.ApplyAllBindings() if not InCombatLockdown() then kb.CreateHooks() @@ -380,17 +389,14 @@ SLASH_SKB2 = "/skeletonkey" SlashCmdList.SKB = kb.Command - self:SetShown(kb.db.showUI) - self:Update(true) self:RegisterEvent('UPDATE_MACROS') - self:RegisterEvent('UPDATE_BINDINGS') + --self:RegisterEvent('UPDATE_BINDINGS') self:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player', 'pet') - self:RegisterUnitEvent('PLAYER_SPECIALIZATION_CHANGED', 'player', 'pet') - self:RegisterUnitEvent('SPELLS_CHANGED') - self:RegisterUnitEvent('TALENT_UPDATE', 'player', 'pet') self:RegisterEvent('PLAYER_REGEN_DISABLED') self:RegisterEvent('PLAYER_REGEN_ENABLED') + self:RegisterEvent('SPELLS_CHANGED') + self:RegisterEvent('PLAYER_TALENT_UPDATE') self:RegisterForDrag('LeftButton') self:SetMovable(true)
--- a/SkeletonKey.xml Sat Jan 07 12:52:05 2017 -0500 +++ b/SkeletonKey.xml Sat Jan 14 02:29:33 2017 -0500 @@ -297,9 +297,9 @@ </FontString> <Texture parentKey="ignoreTexture" file="Interface\PaperDollInfoFrame\UI-GearManager-LeaveItem-Transparent" hidden="true"> + <Size x="24" y="24" /> <Anchors> - <Anchor point="TOPLEFT" x="0" y="0" /> - <Anchor point="BOTTOMRIGHT" x="0" y="0" /> + <Anchor point="TOPLEFT" x="2" y="-2" /> </Anchors> </Texture> </Layer>