--[[ ############################################################################## _____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_ # ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__ # __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____ # ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____ # ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____ # _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____ # __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ # _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_# ___\///////////___________\///___________\/////////_____\///////////_# ############################################################################## S U P E R - V I L L A I N - U I By: Munglunch # ############################################################################## ]]-- --[[ GLOBALS ]]-- local _G = _G; local unpack = _G.unpack; local select = _G.select; local pairs = _G.pairs; local type = _G.type; local rawset = _G.rawset; local rawget = _G.rawget; local tinsert = _G.tinsert; local tremove = _G.tremove; local tostring = _G.tostring; local error = _G.error; local getmetatable = _G.getmetatable; local setmetatable = _G.setmetatable; local string = _G.string; local math = _G.math; local table = _G.table; --[[ STRING METHODS ]]-- local upper = string.upper; local format, find, match, gsub = string.format, string.find, string.match, string.gsub; --[[ MATH METHODS ]]-- local floor = math.floor --[[ TABLE METHODS ]]-- local twipe, tsort, tconcat = table.wipe, table.sort, table.concat; --[[ ############################################################ /$$ /$$$$$$ /$$$$$$ /$$$$$$ /$$ /$$$$$$ | $$ /$$__ $$ /$$__ $$ /$$__ $$| $$ /$$__ $$ | $$ | $$ \ $$| $$ \__/| $$ \ $$| $$ | $$ \__/ | $$ | $$ | $$| $$ | $$$$$$$$| $$ | $$$$$$ | $$ | $$ | $$| $$ | $$__ $$| $$ \____ $$ | $$ | $$ | $$| $$ $$| $$ | $$| $$ /$$ \ $$ | $$$$$$$$| $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$$| $$$$$$/ |________/ \______/ \______/ |__/ |__/|________/ \______/ ############################################################ ]]-- local PLUGIN_LISTING = ""; local ModuleQueue, ScriptQueue = {},{}; local INFO_BY = "%s |cff0099FFby %s|r"; local INFO_VERSION = "%s%s |cff33FF00Version: %s|r"; local INFO_NAME = "Plugins"; local INFO_HEADER = "Supervillain UI (version %.3f): Plugins"; if GetLocale() == "ruRU" then INFO_BY = "%s |cff0099FFот %s|r"; INFO_VERSION = "%s%s |cff33FF00Версия: %s|r"; INFO_NAME = "Плагины"; INFO_HEADER = "Supervillain UI (устарела %.3f): Плагины"; end --[[ APPENDED OPTIONS TABLE ]]-- SVUI[1].Options.args.plugins = { order = -2, type = "group", name = "Plugins", childGroups = "tab", args = { pluginheader = { order = 1, type = "header", name = "Supervillain Plugins", }, pluginOptions = { order = 2, type = "group", name = "", args = { pluginlist = { order = 1, type = "group", name = "Summary", args = { active = { order = 1, type = "description", name = function() return PLUGIN_LISTING end } } }, } } } } --[[ ############################################################################### /$$$$$$$ /$$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$$/$$$$$$$ /$$ /$$ | $$__ $$| $$_____/ /$$__ $$|_ $$_/ /$$__ $$|__ $$__/ $$__ $$| $$ /$$/ | $$ \ $$| $$ | $$ \__/ | $$ | $$ \__/ | $$ | $$ \ $$ \ $$ /$$/ | $$$$$$$/| $$$$$ | $$ /$$$$ | $$ | $$$$$$ | $$ | $$$$$$$/ \ $$$$/ | $$__ $$| $$__/ | $$|_ $$ | $$ \____ $$ | $$ | $$__ $$ \ $$/ | $$ \ $$| $$ | $$ \ $$ | $$ /$$ \ $$ | $$ | $$ \ $$ | $$ | $$ | $$| $$$$$$$$| $$$$$$/ /$$$$$$| $$$$$$/ | $$ | $$ | $$ | $$ |__/ |__/|________/ \______/ |______/ \______/ |__/ |__/ |__/ |__/ ############################################################################### ]]-- local rootstring = function(self) return self.___addonName end local changeDBVar = function(self, value, key, sub1, sub2, sub3) local core = self.___core local schema = self.___schema local config = core.db[schema] if((sub1 and sub2 and sub3) and (config[sub1] and config[sub1][sub2] and config[sub1][sub2][sub3])) then core.db[schema][sub1][sub2][sub3][key] = value elseif((sub1 and sub2) and (config[sub1] and config[sub1][sub2])) then core.db[schema][sub1][sub2][key] = value elseif(sub1 and config[sub1]) then core.db[schema][sub1][key] = value else core.db[schema][key] = value end self.db = core.db[schema] if(self.UpdateLocals) then self:UpdateLocals() end end local innerOnEvent = function(self, event, ...) local obj = self.module if self[event] and type(self[event]) == "function" then self[event](obj, event, ...) end end local registerEvent = function(self, eventname, eventfunc) if not self.___eventframe then self.___eventframe = CreateFrame("Frame", nil) self.___eventframe.module = self self.___eventframe:SetScript("OnEvent", innerOnEvent) end if(not self.___eventframe[eventname]) then local fn = eventfunc if type(eventfunc) == "string" then fn = self[eventfunc] elseif(not fn and self[eventname]) then fn = self[eventname] end self.___eventframe[eventname] = fn end self.___eventframe:RegisterEvent(eventname) end local unregisterEvent = function(self, event, ...) if(self.___eventframe) then self.___eventframe:UnregisterEvent(event) end end local innerOnUpdate = function(self, elapsed) if self.elapsed and self.elapsed > (self.throttle) then local obj = self.module local core = obj.___core local callbacks = self.callbacks for name, fn in pairs(callbacks) do local _, error = pcall(fn, obj) if(error and core.Debugging) then print(error) end end self.elapsed = 0 else self.elapsed = (self.elapsed or 0) + elapsed end end local registerUpdate = function(self, updatefunc, throttle) if not self.___updateframe then self.___updateframe = CreateFrame("Frame", nil); self.___updateframe.module = self; self.___updateframe.callbacks = {}; self.___updateframe.elapsed = 0; self.___updateframe.throttle = throttle or 0.2; end if(updatefunc and type(updatefunc) == "string" and self[updatefunc]) then self.___updateframe.callbacks[updatefunc] = self[updatefunc] end self.___updateframe:SetScript("OnUpdate", innerOnUpdate) end local unregisterUpdate = function(self, updatefunc) if(updatefunc and type(updatefunc) == "string" and self.___updateframe.callbacks[updatefunc]) then self.___updateframe.callbacks[updatefunc] = nil if(#self.___updateframe.callbacks == 0) then self.___updateframe:SetScript("OnUpdate", nil) end else self.___updateframe:SetScript("OnUpdate", nil) end end local add_OptionsIndex = function(self, index, data) local addonName = self.___addonName local schema = self.___schema local core = self.___core local header = GetAddOnMetadata(addonName, "X-SVUI-Header") core.Options.args.plugins.args.pluginOptions.args[schema].args[index] = data end local function SetPluginString(addonName) local pluginString = PLUGIN_LISTING or "" local author = GetAddOnMetadata(addonName, "Author") or "Unknown" local Pname = GetAddOnMetadata(addonName, "Title") or addonName local version = GetAddOnMetadata(addonName, "Version") or "???" pluginString = INFO_BY:format(pluginString, author) pluginString = ("%s%s"):format(pluginString, Pname) pluginString = INFO_VERSION:format(pluginString, "|cff00FF00", version) pluginString = ("%s|r\n"):format(pluginString) PLUGIN_LISTING = pluginString end local function SetInternalModule(obj, core, schema) local addonmeta = {} local oldmeta = getmetatable(obj) if oldmeta then for k, v in pairs(oldmeta) do addonmeta[k] = v end end addonmeta.__tostring = rootstring setmetatable( obj, addonmeta ) local addonName = ("SVUI [%s]"):format(schema) obj.___addonName = addonName obj.___schema = schema obj.___core = core obj.initialized = false obj.CombatLocked = false obj.ChangeDBVar = changeDBVar obj.RegisterEvent = registerEvent obj.UnregisterEvent = unregisterEvent obj.RegisterUpdate = registerUpdate obj.UnregisterUpdate = unregisterUpdate return obj end local function SetExternalModule(obj, core, schema, addonName, header, lod) local addonmeta = {} local oldmeta = getmetatable(obj) if oldmeta then for k, v in pairs(oldmeta) do addonmeta[k] = v end end addonmeta.__tostring = rootstring setmetatable( obj, addonmeta ) obj.___addonName = addonName obj.___schema = schema obj.___header = header obj.___core = core obj.___lod = lod obj.initialized = false obj.CombatLocked = false obj.ChangeDBVar = changeDBVar obj.RegisterEvent = registerEvent obj.UnregisterEvent = unregisterEvent obj.RegisterUpdate = registerUpdate obj.UnregisterUpdate = unregisterUpdate obj.AddOption = add_OptionsIndex if(lod) then -- print("PLUGIN: " .. addonName) core.Options.args.plugins.args.pluginOptions.args[schema] = { type = "group", name = header, childGroups = "tree", args = { enable = { order = 1, type = "execute", width = "full", name = function() local nameString = "Disable" if(not IsAddOnLoaded(addonName)) then nameString = "Enable" end return nameString end, func = function() if(not IsAddOnLoaded(addonName)) then local loaded, reason = LoadAddOn(addonName) core:UpdateDatabase() obj:ChangeDBVar(true, "enable") else obj:ChangeDBVar(false, "enable") core:StaticPopup_Show("RL_CLIENT") end end, } } } else core.Options.args.plugins.args.pluginOptions.args[schema] = { type = "group", name = header, childGroups = "tree", args = { enable = { order = 1, type = "toggle", name = "Enable", get = function() return obj.db.enable end, set = function(key, value) obj:ChangeDBVar(value, "enable") end, } } } end return obj end local Registry_NewCallback = function(self, fn) if(fn and type(fn) == "function") then self.Callbacks[#self.Callbacks+1] = fn end end local Registry_NewScript = function(self, fn) if(fn and type(fn) == "function") then ScriptQueue[#ScriptQueue+1] = fn end end local Registry_NewPackage = function(self, obj, schema) local core = self.___core if(core[schema]) then return end ModuleQueue[#ModuleQueue+1] = schema self.Modules[#self.Modules+1] = schema core[schema] = SetInternalModule(obj, core, schema) if(core.AddonLaunched) then if(core[schema].Load) then core[schema]:Load() end end end local Registry_NewPlugin = function(self, obj) local core = self.___core local coreName = core.___addonName local addonName = obj.___addonName if(addonName and addonName ~= coreName) then local schema = GetAddOnMetadata(addonName, "X-SVUI-Schema"); local header = GetAddOnMetadata(addonName, "X-SVUI-Header"); local lod = IsAddOnLoadOnDemand(addonName) if(not schema) then return end ModuleQueue[#ModuleQueue+1] = schema self.Modules[#self.Modules+1] = schema SetPluginString(addonName) core[schema] = SetExternalModule(obj, core, schema, addonName, header, lod) if(core.AddonLaunched and core[schema].Load) then core[schema]:Load() --print(schema) end end end local Registry_NewAddon = function(self, addonName, schema, header) local core = self.___core self.Addons[addonName] = schema; core.Options.args.plugins.args.pluginOptions.args[schema] = { type = "group", name = header, childGroups = "tree", args = { enable = { order = 1, type = "execute", width = "full", name = function() local nameString = "Disable" if(not IsAddOnLoaded(addonName)) then nameString = "Enable" end return nameString end, func = function() if(not IsAddOnLoaded(addonName)) then local loaded, reason = LoadAddOn(addonName) core:UpdateDatabase() core.db[schema].enable = true self:LoadPackages() else core.db[schema].enable = false core:StaticPopup_Show("RL_CLIENT") end end, } } } end local Registry_FetchAddons = function(self) local addonCount = GetNumAddOns() local core = self.___core for i = 1, addonCount do local addonName, _, _, _, _, reason = GetAddOnInfo(i) local lod = IsAddOnLoadOnDemand(i) local header = GetAddOnMetadata(i, "X-SVUI-Header") local schema = GetAddOnMetadata(i, "X-SVUI-Schema") if(lod and schema) then self:NewAddon(addonName, schema, header) end end end local Registry_RunCallbacks = function(self) local callbacks = self.Callbacks for i=1, #callbacks do local fn = callbacks[i] if(fn and type(fn) == "function") then fn() end end end local Registry_Update = function(self, name, dataOnly) local core = self.___core local obj = core[name] if obj then if core.db[name] then obj.db = core.db[name] end if obj.ReLoad and not dataOnly then obj:ReLoad() end end end local Registry_UpdateAll = function(self) local modules = self.Modules local core = self.___core for _,name in pairs(modules) do local obj = core[name] if core.db[name] then obj.db = core.db[name] end if obj and obj.ReLoad then obj:ReLoad() end end end local Registry_LoadOnDemand = function(self) local core = self.___core local addons = self.Addons for name,schema in pairs(addons) do local config = core.db[schema] if(config and (config.enable or config.enable ~= false)) then if(not IsAddOnLoaded(name)) then local loaded, reason = LoadAddOn(name) end EnableAddOn(name) end end end local Registry_Load = function(self) if not ModuleQueue then return end local core = self.___core for i=1,#ModuleQueue do local name = ModuleQueue[i] local obj = core[name] if obj and not obj.initialized then if core.db[name] then obj.db = core.db[name] end if obj.Load then local halt = false if(obj.db.incompatible) then for addon,_ in pairs(obj.db.incompatible) do if IsAddOnLoaded(addon) then halt = true end end end if(not halt) then obj:Load() obj.Load = nil --print(name) end end obj.initialized = true; end end twipe(ModuleQueue) if not ScriptQueue then return end for i=1, #ScriptQueue do local fn = ScriptQueue[i] if(fn and type(fn) == "function") then fn() end end ScriptQueue = nil end local Registry = { ___core = SVUI[1], Modules = {}, Addons = {}, Callbacks = {}, INFO_VERSION = INFO_VERSION, INFO_NEW = INFO_NEW, INFO_NAME = INFO_NAME, INFO_HEADER = INFO_HEADER, NewCallback = Registry_NewCallback, NewScript = Registry_NewScript, NewPackage = Registry_NewPackage, NewPlugin = Registry_NewPlugin, NewAddon = Registry_NewAddon, FindAddons = Registry_FetchAddons, LoadRegisteredAddons = Registry_LoadOnDemand, RunCallbacks = Registry_RunCallbacks, Update = Registry_Update, UpdateAll = Registry_UpdateAll, LoadPackages = Registry_Load, } --[[ ENSURE META METHODS ]]-- local mt = {} local old = getmetatable(Registry) if old then for k, v in pairs(old) do mt[k] = v end end mt.__tostring = rootstring setmetatable(Registry, mt) SVUI[3] = Registry