init
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
if not WeakAuras.IsCorrectVersion() then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, error, coroutine = pairs, error, coroutine
|
||||
|
||||
-- WoW APIs
|
||||
local GetSpellInfo, IsSpellKnown = GetSpellInfo, IsSpellKnown
|
||||
|
||||
local WeakAuras = WeakAuras
|
||||
|
||||
local spellCache = {}
|
||||
WeakAuras.spellCache = spellCache
|
||||
|
||||
local cache
|
||||
local bestIcon = {}
|
||||
local dynFrame = WeakAuras.dynFrame
|
||||
|
||||
-- Builds a cache of name/icon pairs from existing spell data
|
||||
-- This is a rather slow operation, so it's only done once, and the result is subsequently saved
|
||||
function spellCache.Build(callback)
|
||||
if cache then
|
||||
local co = coroutine.create(function()
|
||||
local id = 0
|
||||
local misses = 0
|
||||
|
||||
while misses < 400 do
|
||||
id = id + 1
|
||||
local name, _, icon = GetSpellInfo(id)
|
||||
|
||||
if(icon == 136243) then -- 136243 is the a gear icon, we can ignore those spells
|
||||
misses = 0;
|
||||
elseif name and name ~= "" then
|
||||
cache[name] = cache[name] or {}
|
||||
cache[name][id] = icon
|
||||
misses = 0
|
||||
else
|
||||
misses = misses + 1
|
||||
end
|
||||
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
end)
|
||||
dynFrame:AddAction(callback, co)
|
||||
else
|
||||
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
||||
end
|
||||
end
|
||||
|
||||
function spellCache.GetIcon(name)
|
||||
if (name == nil) then
|
||||
return nil;
|
||||
end
|
||||
if cache then
|
||||
if (bestIcon[name]) then
|
||||
return bestIcon[name]
|
||||
end
|
||||
|
||||
local icons = cache[name]
|
||||
local bestMatch = nil
|
||||
if (icons) then
|
||||
for spellId, icon in pairs(icons) do
|
||||
if (not bestMatch) then
|
||||
bestMatch = spellId
|
||||
elseif(type(spellId) == "number" and IsSpellKnown(spellId)) then
|
||||
bestMatch = spellId
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
bestIcon[name] = bestMatch and icons[bestMatch];
|
||||
return bestIcon[name];
|
||||
else
|
||||
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
||||
end
|
||||
end
|
||||
|
||||
function spellCache.AddIcon(name, id, icon)
|
||||
if cache then
|
||||
if name then
|
||||
cache[name] = cache[name] or {}
|
||||
if id and icon then
|
||||
cache[name][id] = icon
|
||||
end
|
||||
end
|
||||
else
|
||||
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
||||
end
|
||||
end
|
||||
|
||||
function spellCache.Get()
|
||||
if cache then
|
||||
return cache
|
||||
else
|
||||
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
||||
end
|
||||
end
|
||||
|
||||
function spellCache.Load(data)
|
||||
cache = cache or data
|
||||
end
|
||||
|
||||
-- This function computes the Levenshtein distance between two strings
|
||||
-- It is used in this program to match spell icon textures with "good" spell names; i.e.,
|
||||
-- spell names that are very similar to the name of the texture
|
||||
local function Lev(str1, str2)
|
||||
local matrix = {};
|
||||
for i=0, str1:len() do
|
||||
matrix[i] = {[0] = i};
|
||||
end
|
||||
for j=0, str2:len() do
|
||||
matrix[0][j] = j;
|
||||
end
|
||||
for j=1, str2:len() do
|
||||
for i =1, str1:len() do
|
||||
if(str1:sub(i, i) == str2:sub(j, j)) then
|
||||
matrix[i][j] = matrix[i-1][j-1];
|
||||
else
|
||||
matrix[i][j] = math.min(matrix[i-1][j], matrix[i][j-1], matrix[i-1][j-1]) + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return matrix[str1:len()][str2:len()];
|
||||
end
|
||||
|
||||
function spellCache.BestKeyMatch(nearkey)
|
||||
local bestKey = "";
|
||||
local bestDistance = math.huge;
|
||||
local partialMatches = {};
|
||||
if cache[nearkey] then
|
||||
return nearkey
|
||||
end
|
||||
for key, value in pairs(cache) do
|
||||
if key:lower() == nearkey:lower() then
|
||||
return key
|
||||
end
|
||||
if(key:lower():find(nearkey:lower(), 1, true)) then
|
||||
partialMatches[key] = value;
|
||||
end
|
||||
end
|
||||
for key, value in pairs(partialMatches) do
|
||||
local distance = Lev(nearkey, key);
|
||||
if(distance < bestDistance) then
|
||||
bestKey = key;
|
||||
bestDistance = distance;
|
||||
end
|
||||
end
|
||||
|
||||
return bestKey;
|
||||
end
|
||||
|
||||
function spellCache.CorrectAuraName(input)
|
||||
if (not cache) then
|
||||
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
||||
end
|
||||
|
||||
local spellId = WeakAuras.SafeToNumber(input);
|
||||
if(spellId) then
|
||||
local name, _, icon = GetSpellInfo(spellId);
|
||||
if(name) then
|
||||
spellCache.AddIcon(name, spellId, icon)
|
||||
return name, spellId;
|
||||
else
|
||||
return "Invalid Spell ID";
|
||||
end
|
||||
else
|
||||
local ret = spellCache.BestKeyMatch(input);
|
||||
if(ret == "") then
|
||||
return "No Match Found", nil;
|
||||
else
|
||||
return ret, nil;
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user