Nenue@0: -- User: Krakyn Nenue@0: -- Created: 11/30/2015 7:46 AM Nenue@0: if not LibStub then Nenue@0: print('Something has happened...') Nenue@0: end Nenue@0: Devian = LibStub("AceAddon-3.0"):NewAddon("Devian", "AceConsole-3.0", "AceEvent-3.0") Nenue@13: local MAJOR, MINOR = 'Devian-1.3', 'r@project-revision@' Nenue@0: local D = _G.Devian Nenue@0: local STATE_LOW, STATE_HIGH = 1, 2 Nenue@0: local PLAYER_REALM = UnitName("player") .. '-' .. GetRealmName() Nenue@13: local DEVIAN_FRAME = 'DevianConsole' Nenue@18: local print = _G.print Nenue@9: local db Nenue@13: local defaults = { Nenue@13: ['global'] = {[STATE_LOW] = {}, [STATE_HIGH] = {}}, Nenue@13: ['tags'] = {}, Nenue@13: ['channels'] = {[1] = {signature = 'Dvn', name = 'Main', header = "%n [%t]", x = 100, y = 800, height = 500, width = 600, enabled = true}}, Nenue@14: primary_channel = 1, Nenue@13: current_channel = 1, Nenue@14: toggle = true, Nenue@13: dnd_status = true, Nenue@13: dnd_message = "Debugging. Your messages may get eaten.", Nenue@13: font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]], Nenue@13: fontsize = 13, Nenue@13: fontoutline = 'NONE', Nenue@14: backdrop = {1,1,1,0.2}, Nenue@14: backgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.3, 0, 0, 0, 0.5}, Nenue@14: backblend = 'BLEND', Nenue@14: frontdrop = {1,1,1,1}, Nenue@14: frontgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.9, 0, 0, 0, 0.9}, Nenue@22: frontblend = 'BLEND', Nenue@22: frontborder = {1,0,0,1}, Nenue@22: backborder = {0,0,1,0.75}, Nenue@13: } Nenue@9: Nenue@4: Nenue@13: local function ScanAddOnList(cmd, ...) Nenue@0: local list_state Nenue@0: Nenue@14: local args = {} Nenue@14: local arg, n = D:GetArgs(cmd, 1) Nenue@14: while arg do Nenue@14: table.insert(args, arg) Nenue@14: arg, n = D:GetArgs(cmd,1,n) Nenue@14: end Nenue@14: local mode, tag, dest = unpack(args) Nenue@0: Nenue@13: Nenue@14: -- no args, toggle ui Nenue@0: if mode == nil then Nenue@0: list_state = db.enabled and STATE_LOW or STATE_HIGH Nenue@0: db.enabled = (db.enabled == false) and true or false Nenue@17: --print(list_state, db.enabled) Nenue@0: Nenue@0: if list_state == STATE_LOW then Nenue@0: end Nenue@14: elseif mode == 'stack' then Nenue@14: return D:StackFrames() Nenue@14: elseif mode == 'grid' then Nenue@14: return D:DistributeFrames() Nenue@14: elseif mode == 'tag' then -- tagging Nenue@14: if tag ~= nil and dest ~= nil then Nenue@18: local channel = D:SetChannel(dest:match('%a'), dest:match('%d')) Nenue@18: if not D.tags[tag] then Nenue@18: D.tags[tag] = {} Nenue@14: end Nenue@18: if D.tags[tag][channel.index] then Nenue@18: D.tags[tag][channel.index] = nil Nenue@18: D:Print('Removed |cFFFFFF00'..tag..'|r from |cFF00FFFF'.. dest .. '|r') Nenue@18: else Nenue@18: D.tags[tag][channel.index] = channel.index Nenue@18: D:Print('Assigning |cFFFFFF00'..tag..'|r to |cFF00FFFF'.. dest .. '|r') Nenue@18: end Nenue@18: Nenue@14: else Nenue@14: D:Print('Usage: /dvn tag ') Nenue@14: end Nenue@14: return Nenue@14: elseif mode ~= nil then Nenue@14: mode = tonumber(mode) Nenue@0: if mode > 2 then Nenue@17: --print('Something has happened.') Nenue@0: return Nenue@0: end Nenue@0: list_state = mode == STATE_LOW and STATE_LOW or STATE_HIGH Nenue@0: end Nenue@0: local char_list, global_list = db[PLAYER_REALM][list_state], db.global[list_state] Nenue@0: Nenue@0: local playername = UnitName("player") Nenue@0: Nenue@0: for i = 1, GetNumAddOns() do Nenue@0: local name = GetAddOnInfo(i) Nenue@0: local enableState, globalState = GetAddOnEnableState(playername, i), GetAddOnEnableState(nil, i) Nenue@0: Nenue@0: if mode == STATE_LOW or mode == STATE_HIGH then Nenue@0: char_list[name] = enableState Nenue@0: global_list[name] = globalState Nenue@0: else Nenue@13: if char_list[name] or global_list[name] then Nenue@0: Nenue@0: if char_list[name] ~= 0 and global_list[name] ~= 0 then Nenue@0: local value = false Nenue@0: if char_list[name] == 2 and global_list[name] == 1 then Nenue@0: value = UnitName("player") Nenue@0: elseif global_list[name] == 2 then Nenue@0: value = true Nenue@0: end Nenue@17: --print('EnableAddOn(', i, ',', value,')') Nenue@0: EnableAddOn(i, value) Nenue@0: else Nenue@0: local value = true Nenue@0: if char_list[name] == 2 and global_list[name] == 1 then Nenue@0: value = UnitName("player") Nenue@0: end Nenue@17: --print('DisableAddOn(', i, ',', value,')') Nenue@0: DisableAddOn(i,value) Nenue@0: end Nenue@13: end Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: if mode == nil then Nenue@0: ReloadUI() Nenue@0: end Nenue@0: if mode == STATE_LOW then Nenue@0: D:Print('Developement AddOn list saved.') Nenue@0: else Nenue@0: D:Print('Standard AddOn list saved.') Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: Nenue@13: local function Console_MinMax(self) Nenue@13: if self.minimized then Nenue@7: self:Maximize() Nenue@7: else Nenue@7: self:Minimize() Nenue@7: end Nenue@7: end Nenue@13: Nenue@13: local function Console_Minimize(self) Nenue@13: self:SetHeight(20) Nenue@13: self:SetMaxResize(GetScreenWidth(),20) Nenue@13: self.minimized = true Nenue@14: self.out:Hide() Nenue@14: self:Save() Nenue@7: end Nenue@0: Nenue@13: local function Console_Maximize(self) Nenue@13: local db = db.channels[self.index] Nenue@13: self:SetHeight(db.height) Nenue@13: self:SetMaxResize(GetScreenWidth(),GetScreenHeight()) Nenue@13: self.minimized = nil Nenue@14: self.out:Show() Nenue@14: self:Save() Nenue@13: end Nenue@13: Nenue@13: Nenue@13: local function Console_Save(self) Nenue@13: local db = db.channels[self.index] Nenue@14: if self.x then Nenue@14: db.x = self.x Nenue@14: else Nenue@14: db.x = self:GetLeft() Nenue@14: end Nenue@14: Nenue@14: if self.y then Nenue@14: db.y = self.y Nenue@14: else Nenue@14: db.y = (self:GetTop() - GetScreenHeight()) Nenue@14: end Nenue@14: Nenue@14: if self.width then Nenue@14: db.width = self.width Nenue@14: else Nenue@14: db.width = self:GetWidth() Nenue@14: end Nenue@14: Nenue@13: if not self.minimized then Nenue@14: if self.height then Nenue@14: db.height = self.height Nenue@14: else Nenue@14: db.height = self:GetHeight() Nenue@14: end Nenue@14: self:SetHeight(db.height) Nenue@13: end Nenue@14: Nenue@14: db.minimized = self.minimized and true or nil Nenue@14: db.enabled = self:IsVisible() and true or nil Nenue@14: db.active = self.active and true or nil Nenue@17: --print('save:', db.signature, 'min=', db.minimized, ' enabled=', db.enabled, ' active = ', db.active, 'x=', db.x, 'y=', db.y, 'h=', db.height, 'w=', db.width) Nenue@13: self:SetPoint('TOPLEFT', UIParent, 'TOPLEFT', db.x, db.y) Nenue@14: self:SetWidth(db.width) Nenue@13: end Nenue@13: Nenue@14: -- Console frame toggler Nenue@14: -- @paramsig [...] Nenue@14: -- @param ... one or more space-seperated channel keys Nenue@13: local function Console_Toggle(input) Nenue@14: local search = {} Nenue@14: local key, n = D:GetArgs(input, 1) Nenue@14: if key then Nenue@14: repeat Nenue@14: if D.sig[key] then Nenue@14: table.insert(search, D.sig[key]) Nenue@14: elseif D.console[key] then Nenue@14: table.insert(search, D.console[key]) Nenue@14: end Nenue@14: key, n = D:GetArgs(input,1,n) Nenue@14: until n == 1e9 Nenue@13: else Nenue@13: search = D.console Nenue@13: end Nenue@13: Nenue@14: db.toggle = not db.toggle and true or nil Nenue@13: for _, c in ipairs(search) do Nenue@14: if db.toggle then Nenue@14: c:Show() Nenue@26: if db.current_channel == c.index then Nenue@26: c:ToFront() Nenue@26: end Nenue@14: else Nenue@14: c.enabled = nil Nenue@14: c.minimized = nil Nenue@14: c:Maximize() Nenue@13: c:Hide() Nenue@13: end Nenue@13: end Nenue@14: Nenue@14: if db.toggle then Nenue@14: D:Print('toggled on?') Nenue@14: else Nenue@14: D:Print('toggled off?') Nenue@14: end Nenue@13: end Nenue@13: Nenue@18: --- Brings the console to the front. Nenue@18: -- Frame method used to bring a console frame to the front of the display stack. Nenue@14: local function Console_ToFront(c) Nenue@14: --print(D.raise_ct, 'Raising', c.signature) Nenue@14: --print(unpack(db.frontdrop)) Nenue@14: --print(unpack(db.frontgrad)) Nenue@14: --print(db.frontblend) Nenue@22: -- D.raise_ct = D.raise_ct + 1 Nenue@14: c:Raise() Nenue@14: c.out.backdrop:SetTexture(unpack(db.frontdrop)) Nenue@14: c.out.backdrop:SetGradientAlpha(unpack(db.frontgrad)) Nenue@14: c.out.backdrop:SetBlendMode(db.frontblend) Nenue@20: db.current_channel = c.index Nenue@18: Nenue@18: for _, part in pairs(c.border) do Nenue@24: part:SetTexture(unpack(db.frontborder)) Nenue@18: end Nenue@14: Nenue@14: for id, bc in pairs(D.console) do Nenue@14: if id ~= c.index then Nenue@14: --print(D.raise_ct, 'Lowering', bc.signature) Nenue@14: --print(unpack(db.backdrop)) Nenue@14: --print(unpack(db.backgrad)) Nenue@14: --print(db.backblend) Nenue@14: bc.out.backdrop:SetTexture(unpack(db.backdrop)) Nenue@14: bc.out.backdrop:SetGradientAlpha(unpack(db.backgrad)) Nenue@14: bc.out.backdrop:SetBlendMode(db.backblend) Nenue@18: Nenue@18: for _, part in pairs(bc.border) do Nenue@24: part:SetTexture(unpack(db.backborder)) Nenue@14: end Nenue@18: end Nenue@18: Nenue@14: end Nenue@14: Nenue@14: end Nenue@14: Nenue@18: --- Constructs the frame object for a console channel Nenue@18: -- Initializes the console channel at a specified index. Nenue@18: -- Configuration data can be overridden by passing a desired settings table. Nenue@18: -- @param i Numeric index of the channel as it manifests in db.channels Nenue@18: -- @param vars Optional settings table to be used. Nenue@13: local function CreateConsole(i, vars) Nenue@14: Nenue@14: if not vars then Nenue@14: vars = db.channels[i] Nenue@14: end Nenue@14: Nenue@17: --print('make:', vars.signature, '(', vars.x, vars.y, ')', vars.width, 'x', vars.height) Nenue@13: local f = CreateFrame('Frame', 'DevianChannelFrame' .. tostring(i), UIParent, DEVIAN_FRAME) Nenue@14: f:SetPoint('TOPLEFT', UIParent, 'TOPLEFT', vars.x, vars.y) Nenue@13: f:SetSize(vars.width, vars.height) Nenue@13: f:Lower() Nenue@13: f.out:SetFont(db.font, db.fontsize, db.fontoutline) Nenue@22: if (db.current_channel == i) then Nenue@24: f.out.backdrop:SetTexture(unpack(db.frontdrop)) Nenue@22: else Nenue@24: f.out.backdrop:SetTexture(unpack(db.backdrop)) Nenue@22: end Nenue@22: Nenue@13: f.Save = Console_Save Nenue@13: f.Minimize = Console_Minimize Nenue@13: f.Maximize = Console_Maximize Nenue@13: f.MinMax = Console_MinMax Nenue@14: f.ToFront = Console_ToFront Nenue@13: f.Toggle = D.Console_Toggle Nenue@13: f.name = vars.name Nenue@13: f.index = i Nenue@14: f.signature = vars.signature Nenue@14: f.format = vars.header Nenue@14: f.x = vars.x Nenue@14: f.y = vars.y Nenue@14: f.width = vars.width Nenue@14: f.height = vars.height Nenue@13: Nenue@14: if vars.enabled then Nenue@14: f.enabled = true Nenue@14: if db.toggle then Nenue@14: f:Show() Nenue@14: end Nenue@13: end Nenue@14: if vars.minimized then Nenue@13: f:Minimize() Nenue@22: else Nenue@22: f:Maximize() Nenue@13: end Nenue@13: Nenue@13: return f Nenue@13: end Nenue@13: Nenue@18: --- Creates a Devian-style output. Nenue@18: -- The first argument describes the channel to output on, and the remaining arguments are concatenated in a manner similar to default print() Nenue@18: -- This becomes the print handler when development mode is active. The original print() function is assigned to oldprint(). Nenue@18: -- @param Tag, signature, or numeric index of the channel to output on. Defaults to primary channel. Nenue@18: -- @param ... Output contents. Nenue@0: local function Message(prefix, ...) Nenue@24: if db.enabled == true then Nenue@23: return D.oldprint(prefix, ...) Nenue@23: end Nenue@23: Nenue@1: if prefix == nil then Nenue@13: prefix = 1 Nenue@1: end Nenue@9: Nenue@18: local sendq = {} Nenue@18: local tag, id Nenue@13: local byName = true Nenue@18: if D.tags[prefix] then Nenue@18: for _, id in pairs(D.tags[prefix]) do Nenue@18: if D.console[id] then Nenue@18: sendq[id] = D.console[id] Nenue@18: end Nenue@18: end Nenue@18: end Nenue@18: Nenue@13: if D.sig[prefix] then Nenue@18: sendq[D.sig[prefix].index] = D.sig[prefix] Nenue@13: elseif D.console[prefix] then Nenue@18: sendq[D.console[prefix]] = D.console[prefix] Nenue@13: else Nenue@18: sendq[D.primary_channel] = D.console[D.primary_channel] Nenue@13: end Nenue@18: Nenue@9: -- color me timbers Nenue@9: local pcolor Nenue@18: if (not db.tagcolor[prefix]) and byName then Nenue@0: local c = {0, 0, 0 } Nenue@0: local max = string.len(prefix) Nenue@0: for i = 1, max, 3 do Nenue@0: for k, v in ipairs(c) do Nenue@0: local j = i + (k - 1) Nenue@0: c[k] = c[k] + (j <= max and string.byte(prefix,j) or 0) Nenue@0: end Nenue@0: end Nenue@0: for k,v in ipairs(c) do Nenue@0: c[k] = c[k] % 255 Nenue@0: if c[k] < 64 then Nenue@0: c[k] = 0 Nenue@0: elseif c[k] > 127 then Nenue@0: c[k] = 255 Nenue@0: end Nenue@0: end Nenue@18: db.tagcolor[prefix] = string.format('%02X%02X%02X', unpack(c)) Nenue@0: end Nenue@18: pcolor = db.tagcolor[prefix] Nenue@0: Nenue@18: local buffer = {'|cFF'.. pcolor..prefix ..'|r'} Nenue@0: for i = 1, select('#',...) do Nenue@0: local var = select(i, ...) Nenue@0: Nenue@0: if type(var) == 'table' then Nenue@20: if type(var.GetName) == 'function' then Nenue@20: var = '' Nenue@20: else Nenue@20: var = '' Nenue@20: end Nenue@20: Nenue@0: elseif type(var) == 'boolean' then Nenue@0: var = var and 'true' or 'false' Nenue@0: elseif type(var) == 'function' then Nenue@0: var = '' Nenue@0: elseif type(var) == 'nil' then Nenue@0: var = 'nil' Nenue@0: end Nenue@0: Nenue@0: table.insert(buffer, var) Nenue@0: end Nenue@18: local message = table.concat(buffer, ' ') Nenue@18: for id, channel in pairs(sendq) do Nenue@18: channel.out:AddMessage(message) Nenue@18: end Nenue@0: table.wipe(buffer) Nenue@0: end Nenue@0: Nenue@18: --- Spaces each frame evenly across the screen. Nenue@14: function D:DistributeFrames() -- Nenue@17: --print('frame grid:', max, num_side) Nenue@14: local max = self.num_channels Nenue@14: local num_side = math.ceil(math.sqrt(max)) Nenue@14: local w = GetScreenWidth() / num_side Nenue@14: local h = GetScreenHeight() / num_side Nenue@14: for i, frame in pairs(D.console) do Nenue@14: local dx = (i-1) % num_side Nenue@14: local dy = math.floor((i-1) / num_side) Nenue@14: Nenue@17: --print('move:', frame.signature, 'dx=', dx, 'dy=', dy) Nenue@17: --print('move:', frame.signature, ' x=', dx * w, 'y=', -(dy * h), 'h=', h, 'w=', w) Nenue@14: frame.width = w Nenue@14: frame.height = h Nenue@14: frame.x = dx * w Nenue@14: frame.y = -(dy * h) Nenue@14: frame:Save() Nenue@14: end Nenue@14: Nenue@14: end Nenue@14: Nenue@18: --- Place all frames stacked beneath the primary frame. Nenue@14: function D:StackFrames() Nenue@14: local last Nenue@14: for i, frame in pairs(self.console) do Nenue@14: if last then Nenue@14: frame.x = last.x Nenue@14: frame.y = last.y - 20 Nenue@14: else Nenue@14: frame.x = (GetScreenWidth()-frame:GetWidth())/2 Nenue@14: frame.y = 0 Nenue@14: end Nenue@14: frame:Save() Nenue@14: last = frame Nenue@14: end Nenue@14: end Nenue@14: Nenue@18: --- Updates a console "channel" entry, generating a new one if necessary. Nenue@18: -- Config data will be take from cinfo. If cinfo is a string, then only channel signature is set. The remaining variables are filled in from the primary channel. Nenue@18: -- i can be given to select a specific channel table entry to work on. Otherwise, it will just create a new channel and the frame associated with it. Nenue@18: -- @usage cinfo [, i] Nenue@18: -- @param cinfo Config variables table, or a string to be used as channel signature Nenue@18: -- @param i Console index. If valid, settings will be inherited from that channel. Nenue@14: function D:SetChannel(cinfo, i) Nenue@17: --print('join:', i , cinfo) Nenue@14: local t_info = {} Nenue@18: local dbvars = db.channels[self.primary_channel] Nenue@18: if type(cinfo) == 'string' then Nenue@18: local signame = tostring(cinfo) Nenue@18: t_info.signature = signame Nenue@18: end Nenue@18: Nenue@14: if type(cinfo) ~= 'table' then Nenue@14: cinfo = {} Nenue@14: end Nenue@18: Nenue@18: if i then Nenue@14: i = tonumber(i) Nenue@14: if db.channels[i] then Nenue@18: dbvars = db.channels[i] Nenue@18: else Nenue@18: -- if there is no channels[i], then we need to check for sig collision Nenue@18: local sigvar = signame Nenue@18: local j = 2 Nenue@18: while D.sig[sigvar] do Nenue@18: sigvar = signame .. j Nenue@18: j = j + 1 Nenue@18: end Nenue@18: t_info.signature = sigvar Nenue@14: end Nenue@14: end Nenue@14: Nenue@18: if not (cinfo.signature or t_info.signature) then Nenue@18: t_info.signature = 'Console'..i Nenue@18: end Nenue@18: Nenue@18: for k,v in pairs(dbvars) do Nenue@14: if not t_info[k] then Nenue@14: if cinfo[k] then Nenue@14: t_info[k] = cinfo[k] Nenue@18: elseif db.channels[self.primary_channel][k] then Nenue@18: t_info[k] = db.channels[self.primary_channel][k] Nenue@14: end Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: if not db.channels[i] then Nenue@14: t_info.x = t_info.x + 20 Nenue@14: t_info.y = t_info.y - 20 Nenue@14: db.channels[i] = t_info Nenue@14: end Nenue@18: Nenue@14: if not self.console[i] then Nenue@14: self.console[i] = CreateConsole(i, t_info) Nenue@14: end Nenue@18: local channel = self.console[i] Nenue@18: self.sig[t_info.signature] = channel Nenue@18: self.sigID[t_info.signature] = i Nenue@18: self.IDsig[i] = t_info.signature Nenue@20: if i == db.current_channel then Nenue@20: channel:ToFront() Nenue@26: end Nenue@20: Nenue@18: return channel Nenue@14: end Nenue@14: Nenue@0: function D:OnEnable() Nenue@13: -- commands Nenue@13: local cmdlist = { Nenue@13: ['dvn'] = ScanAddOnList, Nenue@13: ['devian'] = ScanAddOnList, Nenue@13: ['dvc'] = Console_Toggle, Nenue@13: } Nenue@13: for cmd, func in pairs(cmdlist) do Nenue@13: self:RegisterChatCommand(cmd, func, true) Nenue@13: end Nenue@13: Nenue@11: if db.enabled == true then Nenue@0: D:Print('Standard AddOn list active. Type /dvn to switch to development mode.') Nenue@0: else Nenue@0: D:Print('Development AddOn list active. Type /dvn to revert to regular operation.') Nenue@0: end Nenue@13: Nenue@0: end Nenue@0: Nenue@0: function D:OnInitialize() Nenue@13: -- emergency button Nenue@13: self:RegisterChatCommand("cleandvn", function(args) Nenue@13: DevianDB = nil Nenue@13: ReloadUI() Nenue@13: end) Nenue@13: Nenue@13: -- savedvars Nenue@13: local cherry = false Nenue@9: if not _G.DevianDB then Nenue@13: _G.DevianDB = defaults Nenue@13: cherry = "Type /dvnsave to snapshot your current UI" Nenue@9: end Nenue@9: db = _G.DevianDB Nenue@0: Nenue@0: if not db[PLAYER_REALM] then Nenue@9: db[PLAYER_REALM] = {[STATE_LOW] = {}, [STATE_HIGH] = {}} Nenue@0: if not cherry then Nenue@0: cherry = "This character didn't have an AddOn table." Nenue@0: end Nenue@0: end Nenue@0: Nenue@18: Nenue@18: if not db.tags then Nenue@18: db.tags = {} Nenue@13: end Nenue@18: self.tags = db.tags Nenue@0: if cherry then Nenue@0: D:Print(cherry) Nenue@0: end Nenue@0: D.oldprint = getprinthandler() Nenue@0: if not _G.oldprint then Nenue@0: _G.oldprint = D.oldprint Nenue@0: end Nenue@13: Nenue@22: --self.raise_ct = 0 Nenue@14: self.last_channel = 0 Nenue@14: self.num_channels = 0 Nenue@13: self.console = {} Nenue@13: self.sig = {} Nenue@14: self.sigID = {} Nenue@14: self.IDsig = {} Nenue@14: for i, cinfo in pairs(db.channels) do Nenue@14: i = tonumber(i) Nenue@14: if not self.primary_channel then Nenue@14: self.primary_channel = i Nenue@14: end Nenue@14: self:SetChannel(cinfo, i) Nenue@14: if i > self.last_channel then Nenue@14: self.last_channel = i Nenue@14: end Nenue@14: self.num_channels = self.num_channels + 1 Nenue@13: end Nenue@18: Nenue@18: if self.console[db.current_channel] then Nenue@18: self.console[db.current_channel]:ToFront() Nenue@18: end Nenue@18: Nenue@23: if db.enabled then Nenue@24: for i, c in pairs(self.console) do Nenue@23: self.console[i]:Hide() Nenue@23: end Nenue@23: end Nenue@23: Nenue@23: Nenue@18: -- only do this in dev mode Nenue@18: if db.enabled == false then Nenue@18: setprinthandler(Message) Nenue@18: print = function(...) Nenue@18: _G.print('Dvn', ...) Nenue@18: end Nenue@18: end Nenue@13: print(MAJOR, MINOR) Nenue@0: end