CurseForge and Overwolf are joining forces!
Awesome More Information
  • 0

    posted a message on AceAddon:Disable() issue
    Ok, now I understand. I thought GJB: Disable() would put the addon in a "non functioning" state; no event triggers whatsoever except OnEnable

    So I'm better off managing an enabled state of GJB myself. Only thing is, it seems redundant to check all the time for every action such as a button click or event trigger.

    something like this:
    if GJB.enabled then
        -- Do what was called for

    Are there facilities in place to deal with this or is this example the way to go other than managing all events in every callback?

    Thank you very much for helping me understand this.
    Posted in: AddOn HELP!
  • 0

    posted a message on AceAddon:Disable() issue
    Thank you myrroddin for your review.

    1. This will be added considering my project is split in several different files.
    local GJB = LibStub("AceAddon-3.0"):GetAddon("GarrisonJukeBox")

    2. I'm used to initializing variables.

    3. 4. I omitted the default table but this was already in my code.
    GJB.defaults = { 
        profile =  {
    	AddonEnabled = true,
            ... other saved variables here

    5. 6. Will modifying self.db.profile.AddonEnabled further on in the code automatically set the AceAddon's internal enabled variable or do I still need to call GJB : Disable()?

    7. Got it.

    Posted in: AddOn HELP!
  • 0

    posted a message on AceAddon:Disable() issue
    In the OnInitialize, I check if the saved variables for the profile are from an old version and if so, will offer a choice to the user. No matter what choice is given to the user, The addon must cease loading and unregister any events previously registered.

    Maybe I misunderstand the use of the AceAddon:Disable() function. I presumed that this function disabled the addon entirely like when you select what addon you want enabled in the addon options on the game login screen.

    After loading the profile, I check if it's from a version prior to x.x.x.x. If it is, I must inform the user and stop the addon from loading any further.

    As for myrroddin's suggestion on using tokens, I guess it would make sense in the long run considering I already have over 500 strings. The only problem I find with using this method is if I decide to change the way the message is presented to the user, the token might not express the correct message. I'm used to C++ #define in caps, figured I'd use the same here. Thank you.

    GJB = LibStub("AceAddon-3.0"):NewAddon("GarrisonJukeBox", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceSerializer-3.0")
    local L = LibStub("AceLocale-3.0"):GetLocale("GarrisonJukeBox")
    _G["GJB"] = GJB -- Isn't GJB already in the global scope?
    function GJB:OnInitialize()
    	self.db = {}
    	self.db = LibStub("AceDB-3.0"):New("GarrisonJukeBoxDB", self.defaults, true)
    	if self:VersionCheckResetData() then 
    	        self.OnInitialize = nil -- ewww, twice
    		return -- sloppy maybe but it works !!! 
    	self.db.RegisterCallback(self, "OnProfileChanged", "OnProfileChanged")
    	self.db.RegisterCallback(self, "OnProfileCopied", "OnProfileChanged")
    	self.db.RegisterCallback(self, "OnProfileReset", "OnProfileChanged")
    	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("GarrisonJukeBoxDB", self.GenerateOptions)
    	LibStub("AceConfig-3.0"):RegisterOptionsTable("GarrisonJukeBox", self.slashcmd, "gjb")
    	local ACD3 = LibStub("AceConfigDialog-3.0")
    	self.optionsFrames = {}
    	self.optionsFrames.JukeBox = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["ADDON_NAME"], nil, "JukeBox")
    	self.optionsFrames.Zones = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_ZONES"], L["ADDON_NAME"], "Zones")
    	self.optionsFrames.Advanced = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_ADVANCED"], L["ADDON_NAME"], "Advanced")
    	self.optionsFrames.STMode = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_STMODE"], L["ADDON_NAME"], "STMode")
    	self.optionsFrames.Settings = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_SETTINGS"], L["ADDON_NAME"], "Settings")
    	self.optionsFrames.Audio = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_AUDIO"], L["ADDON_NAME"], "Audio")
    	self:RegisterModuleOptions("GJBSlashCmd", self.slashcmd, L["ADDON_SLASHCMD"])
    	self:RegisterModuleOptions("Profiles", function() return LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) end, L["Profiles"])
    	self.optionsFrames.About = ACD3:AddToBlizOptions("GarrisonJukeBoxDB", L["OPT_ABOUT"], L["ADDON_NAME"], "About")
    	self.OnInitialize = nil
    function GJB:OnEnable()
    	self:RegisterEvent("PLAYER_ENTERING_WORLD", "OnPEWEvent")
    	self:RegisterEvent("PET_BATTLE_OPENING_START", "OnPetBattleStart")
    	self:RegisterEvent("PET_BATTLE_OVER", "OnPetBattleEnd")
    	self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "OnZoneChangedNewArea")
    	self:RegisterEvent("ZONE_CHANGED_INDOORS", "OnZoneChangedIndoors")
    	self:RegisterEvent("ZONE_CHANGED", "OnZoneChanged")
    	self:RegisterEvent("GROUP_ROSTER_UPDATE", "OnJoinParty")
    	-- Register callbacks for inter-addon comms
    	self:RegisterComm(COMM_PREFIX .. "ReqVersion", "OnBuddyReqVersion") 	-- Sends requesters version and name-realm to all party members
    	self:RegisterComm(COMM_PREFIX .. "SentVersion", "OnBuddySentVersion") 	-- Sends version back to requester
    	self:RegisterComm(COMM_PREFIX .. "GetMusic", "OnBuddyListenMusic")		-- Get music sent by leader
    -- -------------------------------------------
    -- OnDisable
    -- -------------------------------------------
    function GJB:OnDisable()
    -- add comm events unregisters
    Posted in: AddOn HELP!
  • 0

    posted a message on AceAddon:Disable() issue

    only hides the AceGUI frame 'f'. What I want to achieve is to disable the whole addon 'MyAddon' previously created with
    MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyNewAddon", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceSerializer-3.0")

    The return value I obtain is true, saying the disable method worked, but the addon is still usable. Any clues?
    Posted in: AddOn HELP!
  • 0

    posted a message on AceAddon:Disable() issue

    I'm trying to disable my addon without success. Am I missing something?

    MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceSerializer-3.0")
    local f = AceGUI:Create("Frame")
    f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
    -- Create a button
    local btn = AceGUI:Create("Button")
    		if MyAddon:Disable() then
    -- Add the button to the container
    Posted in: AddOn HELP!
  • 0

    posted a message on PlaySoundKitID vs PlayMusic
    Thanks for your reply Phanx.

    I already have the most up-to-date version of the listfile but it does not contain 6.2 Tanaan Jungle music entries. I actually went through every DBC/DB2 file that seemed pertinent to music with DBC Viewer, but could only find ID references and descriptive names (not actual filenames). I even wrote a parser for the unclassified DB2 files not in the filelist; there were 9 of them if memory serves.

    Then I had an idea. I went on WoWHead and took a look at the stored mp3 files located on ZAM and voila! The actual mp3s (numerically named) contained enough information for me to guess the missing ones.

    Here is a list of the ones I found so far:
    Posted in: AddOn HELP!
  • 0

    posted a message on PlaySoundKitID vs PlayMusic
    Hello everyone!

    I would like to add more ingame music to my addon Garrison Jukebox, like Tanaan Jungle and Timeless Isle. However, I've hit a snag. My current way of playing WoW music is by using the PlayMusic function. I'm having a hard time finding the paths and filenames of some of the missing tunes, thus, unable to add them.

    There is a way of playing music with PlaySoundKitID but there's a catch. If there are multiple songs that can be played within a kit, I cannot track when to trigger my next timer. Consider the following:
    • Path + Filenames within the kit are unknown.
    • The currently playing file within the kit is unknown; thus the length (in seconds) of the file is also unknown.
    • GJB works with a timer (length of the music file in seconds) to trigger the next lookup.

    I'm left with one obvious choice. Take the biggest length file within the kit as a reference and apply it to all elements within the said kit.

    The drawback of this design is that a lot of music will play more than once and cut off in the middle of play.

    If someone knows some other way to do this or can direct me to an updated music filelist, I would greatly appreciate it.

    Thanks ~Az
    Posted in: AddOn HELP!
  • 0

    posted a message on Disable character spell animation
    I tried to mess around with graphical options (game/driver) and it barely changed a thing for the Shaman's Lightning/Water Shields. Like you said, there are no "legal" in terms of respecting the ToU, to accomplish this as of this moment.

    I hope the developers over at Blizzard find a viable solution to this issue by means of an option or Character API for addons.
    Posted in: General Chat
  • 0

    posted a message on Disable character spell animation

    I have a friend that has trouble (illness related) with specific character animations such as the shaman's rotating Lightning Shield and I was wondering if I could help my friend either by changing a setting in the client or using the wow api (addon) to disable such animations from occurring without disabling it's in-game functionality.

    I am aware that the Lightning Shield can be omitted but at the cost of some damage output. Is there another way of accomplishing this?

    Posted in: General Chat
  • 0

    posted a message on PlaySoundKitID
    Thank you, I didn't realize that sounds could be stopped. I thought it was an "in queue" list number; I guess I could have realized it was a handle given the name :P DOH!

    But doesn't that still require me to toggle the Music CVar to play music without the currently playing zone music?

    I currently use PlayMusic / StopMusic in my addon and that takes care of stopping in-game zone music. Adding support for PlaySoundKitID is doable but adds some complexity that I didn't plan for. What sound channel do you suggest I use to replace zone music? I would think "Music" but it doesn't stop the original zone music currently playing before the call.

    Note: I was able to find an ogg or mp3 file (CASC hashed of course) so I'm pretty sure that its callable via path+filename.
    Posted in: AddOn HELP!
  • 0

    posted a message on PlaySoundKitID
    I'm used to the PlayMusic function and was wondering if anyone knows of a website or resource (I've check for some time now without results) that would list the paths and filenames of 6.1 music, including the new Garrison Jukebox rolls?

    I know that PlaySoundKitID plays sound files by passing the ID but there is no way to stop the sound on demand except by messing with CVars; I don't like that.

    Posted in: AddOn HELP!
  • 0

    posted a message on Question about libraries in wow
    The location of the declaration "local fx = {}" was far from practical as the function always returned nil. Thank you for pointing out the obvious. :shock:
    Posted in: Libraries
  • 0

    posted a message on Question about libraries in wow
    I was referring to the get/set functions inside the lib, not the ones called in the addon. My bad; didn't word it correctly.

    Here's my code.
    local LIBFRAMEX = "LibFrameX-1.0"
    local LIBFRAMEX_MINOR = tonumber(("$Revision: 7 $"):match("(%d+)"))
    assert(LibStub, LIBFRAMEX .. " requires LibStub.")
    local lfx = LibStub:NewLibrary(LIBFRAMEX, LIBFRAMEX_MINOR)
    if not lfx then return end = or {}
    -- Function to create a frame with values passed from FrameX:makeFrames
    -- Arguments:
    --		- v:  type tframe table/child table |table|
    -- 	- p: Parent frame |Frame|
    -- Return: 	- the configured frame |Frame|
    -- 				- nil on error
    local function genFrame(v, p)
    	assert( and ~= "", "Can't process a node without a name.") -- error, unnamed node
    	-- create frame
    	local fo = CreateFrame(v.ftype,, p, v.template) -- type, name, parent, template
    	assert(fo, "Failed to create frame " .. -- failed to create the frame
    	-- set parameters
    	fo.root = v.root or false -- make sure we set root to false if not supplied =
    	fo.rgba = v.rgba
    	fo.brgba = v.brgba =
    	fo.dim = v.dim
    	fo.text = v.text = or true -- make sure we set show to true if not supplied
    	-- draw background if any
    	if not fo.root and ( or fo.rgba or fo.brgba) then
    		fo:SetBackdropColor(v.rgba.r/256, v.rgba.g/256, v.rgba.b/256, v.rgba.a)
    		fo:SetBackdropBorderColor(v.brgba.r/256, v.brgba.g/256, v.brgba.b/256, v.brgba.a)
    	-- prepare to set dimensions
    	if v.dim then
    	-- show the frame
    	if == true then
    	return fo
    -- function to load frame data
    -- Recursive function
    -- Arguments:
    --		- t:  type tframe table/child table |table|
    -- 	- p: Parent frame |Frame|
    -- Return: 	- the frame processed |Frame|
    -- 				- nil on error
    local function ProcessConfigData(cfg, p)
    	-- loop through all elements and recursively create all frames
    	local fx = {} -- table to return (represents a node with or without children)
    	for i = 1, #cfg do
    		assert(cfg[i], "Invalid config item.")
    		-- start filling up data structure for this frame
    		local v = cfg[i]
    		local fx = {}
    		fx[i] = genFrame(v, p) -- create the frame
    		assert(fx[i], "Error generating frame.")
    		local fxi = fx[i]
    		fxi:SetPoint(v.pos.a, v.pos.r, v.pos.rp, v.pos.x, v.pos.y) -- align, relative, rel parent, x, y
    		-- check if the frame has a text component
    		if v.text and then
    			local text = fxi.text
    			text = fxi:CreateFontString(nil, "ARTWORK", v.fs or "NumberFont_Shadow_Small")
    			text:SetJustifyH(v.halign or "CENTER")
    			text:SetJustifyV(v.valign or "CENTER")
    			text:SetTextColor(v.text.color.r/256 or 1, v.text.color.g/256 or 1, v.text.color.b/256 or 1, v.text.color.a or 1)
    			text:SetText(v.text.caption or "")
    		--TODO: set texture
    		-- if frame is movable
    		if v.movable and v.movable.enabled then
    		-- register click events
    		if v.clicks then
    		-- create scripts
    		if v.scripts then -- be careful, if you have scripts, you should have a register clicks
    			for y = 1, #v.scripts do
    				s = v.scripts[y]
    				fxi:SetScript(s.event, s.func)
    		-- check if this element has children (recursive call)
    		if v.children then
    			p = fxi -- set parent for next createframe
    			fxi.children = ProcessConfigData(v.children, p)
    	return fx
    -- entry point function to create the frames
    -- Arguments:
    -- 	- addon: Addon table |table|
    --		- config:  main tframe table |table|
    function lfx.makeFrames(addon, cfg)
    	assert(type(addon) == "table", "Invalid argument #1, must be addon table.")
    	assert(type(cfg) == "table", "Invalid argument #2, must be LibFrameX config table.")
 [addon] = {} -- initialize calling addon's store for tframe table[addon].tframes = ProcessConfigData(cfg, UIParent) -- create the frame structure (recursive)
    -- Returns a frame by providing the frame's name
    -- Arguments:
    --		- t: table of tframes |table|
    -- 	- name: string (name of element to be found) |string|
    -- Return: 	- the frame if found |Frame|
    -- 				- false if frame not found or because invalid arguments were passed
    function lfx.searchFrame(t, name)
    	local v = {}
    	for i = 1, #t do -- LINE 271
    		if t[i] then
    			v = t[i]
    			if == name then
    				return v
    			if v.children then
    				return lfx.searchFrame(v.children, name)
    	return v
    function lfx.findFrame(addon, name)
    	local data =[addon].tframes
    	return lfx.searchFrame(data, name)
    -- Sets the position of a specific frame by name
    -- Arguments:
    -- 	- name: string (name of element to be found) |string|
    -- 	- a: anchor point of element |string| (eg: "TOPLEFT")
    -- 	- r: relative to element |Frame|
    -- 	- rp: relative parent anchor point |string| (eg: "TOPLEFT")
    -- 	- x: x Cartesian value
    -- 	- y: y Cartesian value
    -- Return: 	- true if successful
    -- 				- false if name not found or because invalid arguments were passed
    function lfx.setPosition(addon, name, pos) -- a, r, rp, x, y
    	if name and name ~= "" then
    	assert(pos, "Must provide a valid position point table")
    		local f = lfx.findFrame(addon, name)
    		if f then
    			f:SetPoint(pos.a, pos.r, pos.rp, pos.x, pos.y) -- LINE 537
    			return true
    	return false

    The call from the addon
    GJB = LibStub("AceAddon-3.0"):NewAddon("GarrisonJukeBox", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0", "AceSerializer-3.0")
    local L = LibStub("AceLocale-3.0"):GetLocale("GarrisonJukeBox")
    local LFX = LibStub("LibFrameX-1.0")
    assert(LFX, "LibFrameX-1.0 not loaded!")
    GJB.makeFrames = LFX.makeFrames
    GJB.setPosition = LFX.setPosition
    Example pos = {x = 5, y = -1, a = "TOPLEFT", r = "NAME_OF_FRAME", rp = "TOPLEFT"},
    	local pos = self.db.profile.musicplayer.pos
    	self:setPosition("GJBP_BG", pos)  -- THIS IS LINE 1119

    1x ...GarrisonJukeBox\Libs\LibFramex-1.0\LibFrameX-1.0-7.lua:537: attempt to call method 'SetPoint' (a nil value)
    ...GarrisonJukeBox\Libs\LibFramex-1.0\LibFrameX-1.0-7.lua:537: in function `setPosition'
    GarrisonJukeBox\GarrisonJukeBox-v1.0.9.0 release.lua:1119: in function <GarrisonJukeBox\GarrisonJukeBox.lua:1103>
    (tail call): ?

    If I read right, recursive functions are ok to use in LUA. I tried a test with SciTE (LUA interpreter) and it worked fine.
    Posted in: Libraries
  • 0

    posted a message on Question about libraries in wow
    Thank you for your reply Adirelle.

    Wouldn't you need to provide the addon index (self) to every function being called in order to access the right node in the lib data table; like all getter/setter functions?
    Posted in: Libraries
  • 0

    posted a message on Question about libraries in wow
    I've been trying to design a library to dynamically create UIs (frames) based on a configuration table. LibFrameX-1.0

    My first expectation upon seeing the word library meant a reusable "instance" that held properties of its own. However, after having read more and more into it, it seems that libraries share their properties with all other addons using it; like static members of a class.

    - MyAddon1 and MyAddon2 both use MyLib1
    - MyLib1 has a local table called tf and a function MyLib1:FillTable(t)
    - MyAddon1 instantiates ml1 = LibStub:NewLibrary("MyLib1") and calls ml1:FillTable passing a table that looks like this t = {1,2,3}

    Here's where it gets interesting...
    - MyAddon2 also tries to instantiate MyLib1, however, MyLib1 already exists and its major and minor are valid so no need to upgrade. This I understand and this, I think, has answered my question.
    - When MyAddon2 calls ml2:FillTable, with t = {4,5,6}, it overwrites the contents of tf (originally 1,2,3) with 4,5,6.

    My question is this.
    I can segregate each passed tf from the calling addons into its own index using the addon's name or whatever string the user decides... But won't this be a size issue? (15-20 addons all having their config in LibFrameX???)

    fx = LibStub:NewLibrary("LibFrameX-1.0")
    local = or {}
    fx:FillTable(addon, t)[addon].tf = t

    Or is there a better solution to this... Maybe the whole idea is evil...
    Any thoughts?

    Edit: One thought I have is to create a table in the addon, pass it to LibFrameX, have the lib return a fully created frame structure to the addon.
    fx:FillTable(t, tf)
      for i = 1, #t do
        ... processing done here
      return tf

    Then it would be the addon responsible to manage it's frames using functionality of the lib. The only downfall to this approach is that I would need to pass tf to every lib function call. >:(
    Posted in: Libraries
  • To post a comment, please or register a new account.