Elegant way to determine if an AddOn has been loaded before?

Is there an elegant way to determine if an AddOn is being loaded for the first time, and if so setting defaults into the saved variable, and if it’s not the first time retrieving the stored settings from the variable?

For example I’m currently doing this:

mySavedVariable = mySavedVariable or {}

… which I hope checks to see if the save variable exists as a table, and if it doesn’t already creates it as an empty table (I pulled the code from another Addon).

I then go on to set default table elements (the dimensions and position of a frame) if it’s the first time, or copy that table into a new local variable for use in my AddOn.

Is this even part way correct? I’m getting the following error from the game which I suspect may be related but I’m at a loss:

Usage: <unnamed>:SetHeight(height)
Time: Wed Oct 30 16:57:02 2019
Count: 1
Stack: Interface\AddOns\myAddon\myAddon.lua:41: Usage: <unnamed>:SetHeight(height)
[C]: in function `SetHeight'
Interface\AddOns\myAddon\myAddon.lua:41: in function `myFrame_OnLoad'
[string "*:OnLoad"]:1: in function <[string "*:OnLoad"]:1>

Locals: (*temporary) = <unnamed> {
 0 = <userdata>
}
(*temporary) = nil

saved variables are set in your TOC file, otherwise they dont persist so i presume you already have this in there?

## SavedVariables: mySavedVariable

after which, yes, just doing a mySavedVariable = mySavedVariable or { } would work to initialise it. just make sure its practically the first line in your code.

in regards to the error youd be better off posting the code thats having the issue, ie Interface\AddOns\myAddon\myAddon.lua - line 41 (preferably the whole myFrame_OnLoad function)

The full OnLoad function is here:

function PetExpBar_OnLoad()
	x,y=UnitClass("player") if x=="Hunter" then
	PetBarFrame = CreateFrame("Frame",nil,UIParent)
	
	CBPetBars = CBPetBars or {}
	--if CBPetBars is empty, fill it with default values
	if CBPetBars == nil then CBPetBars = {
								height = 14,
								width = 300,
								xPos = 35,
								yPos = -5,
							}
	end	
	-- Load the new default or previous saved frame variables
	height = CBPetBars.height
	width = CBPetBars.width
	xPos = CBPetBars.xPos
	yPos = CBPetBars.yPos
	
	--PetBarFrame:RegisterEvent("PLAYER_LOGIN")
	PetBarFrame:RegisterEvent("PLAYER_LOGOUT")
	
	PetBarFrame:SetScript("OnEvent", function(self,event,...)
		--elseif event == "PLAYER_LOGOUT" then
			-- Player is logging out, save frame size and position
			point, relativeTo, relativePoint, xOfs, yOfs = PetBarFrame:GetPoint()
			CBPetBars.height = height
			CBPetBars.width = width
			CBPetBars.xPos = PetBarFrame.xOfs
			CBPetBars.yPos = PetBarFrame.yOfs		
		--end
	end)
	
	PetBarFrame:SetPoint("LEFT",PetActionBarFrame,"RIGHT",xPos,yPos)
	PetBarFrame:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 11,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrame:SetBackdropColor(.15,.15,.15,.50)
	PetBarFrame:SetBackdropBorderColor(.75,.75,.75,.5)
	
	PetBarFrame:SetFrameLevel(1)
	PetBarFrame:SetHeight(height)
	PetBarFrame:SetWidth(width)
	PetBarFrame:EnableMouse(true)
	PetBarFrame:SetMovable(true)
	PetBarFrame:SetResizable(true)
	PetBarFrame:SetMinResize(100,12)
	PetBarFrame:SetMaxResize(1000,50)
	PetBarFrame:SetScript("OnMouseDown",function() PetBarTryToMove() PetExpUpdate() end)
	PetBarFrame:SetScript("OnMouseUp",function() PetBarStopMoving() end)


	width = PetBarFrame:GetWidth()
	height = PetBarFrame:GetHeight()

	PetBarFrameSectionOne = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionOne:SetFrameLevel(1)
	PetBarFrameSectionOne:SetHeight(height)
	PetBarFrameSectionOne:SetWidth(width/6+1)
	PetBarFrameSectionOne:SetPoint("LEFT",PetBarFrame,"LEFT",1,0)
	PetBarFrameSectionOne:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionOne:SetBackdropColor(.4,.4,.4,0)
	PetBarFrameSectionOne:SetBackdropBorderColor(.75,.75,.75)

	PetBarFrameSectionTwo = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionTwo:SetFrameLevel(1)
	PetBarFrameSectionTwo:SetHeight(height)
	PetBarFrameSectionTwo:SetWidth(width/6+2)
	PetBarFrameSectionTwo:SetPoint("LEFT",PetBarFrameSectionOne,"RIGHT",-2,0)
	PetBarFrameSectionTwo:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionTwo:SetBackdropColor(.4,.4,.4,0)
	PetBarFrameSectionTwo:SetBackdropBorderColor(.75,.75,.75)

	PetBarFrameSectionThree = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionThree:SetFrameLevel(1)
	PetBarFrameSectionThree:SetHeight(height)
	PetBarFrameSectionThree:SetWidth(width/6+2)
	PetBarFrameSectionThree:SetPoint("LEFT",PetBarFrameSectionTwo,"RIGHT",-2,0)
	PetBarFrameSectionThree:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionThree:SetBackdropColor(.4,.4,.4,0)
	PetBarFrameSectionThree:SetBackdropBorderColor(.75,.75,.75)

	PetBarFrameSectionFour = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionFour:SetFrameLevel(1)
	PetBarFrameSectionFour:SetHeight(height)
	PetBarFrameSectionFour:SetWidth(width/6+2)
	PetBarFrameSectionFour:SetPoint("LEFT",PetBarFrameSectionThree,"RIGHT",-2,0)
	PetBarFrameSectionFour:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionFour:SetBackdropColor(.4,.4,.4,0)
	PetBarFrameSectionFour:SetBackdropBorderColor(.75,.75,.75)

	PetBarFrameSectionFive = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionFive:SetFrameLevel(1)
	PetBarFrameSectionFive:SetHeight(height)
	PetBarFrameSectionFive:SetWidth(width/6+2)
	PetBarFrameSectionFive:SetPoint("LEFT",PetBarFrameSectionFour,"RIGHT",-2,0)
	PetBarFrameSectionFive:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionFive:SetBackdropColor(.4,.4,.4,0)
	PetBarFrameSectionFive:SetBackdropBorderColor(.75,.75,.75)

	PetBarFrameSectionSix = CreateFrame("Frame",nil,PetBarFrame)
	PetBarFrameSectionSix:SetFrameLevel(1)
	PetBarFrameSectionSix:SetHeight(height)
	PetBarFrameSectionSix:SetWidth(width/6+0)
	PetBarFrameSectionSix:SetPoint("LEFT",PetBarFrameSectionFive,"RIGHT",-2,0)
	PetBarFrameSectionSix:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
	tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
	PetBarFrameSectionSix:SetBackdropColor(.9,.9,.9,0)
	PetBarFrameSectionSix:SetBackdropBorderColor(.75,.75,.75)
	
	--SetTextSize()
	PetExpText = PetBarFrame:CreateFontString(nil,"HIGHLIGHT","NumberFont_Outline_Med")
	PetExpText:SetPoint("CENTER",PetBarFrame,"CENTER",-8,2)

	PetExpBar = CreateFrame("Frame",nil,PetBarFrame)
	PetExpBar:SetFrameLevel(1)
	PetExpBar:SetPoint("LEFT",PetBarFrame,"LEFT",3,0)
	PetExpBar:SetHeight(10)
	PetExpBar:RegisterEvent("UNIT_PET_EXPERIENCE")
	PetExpBar:SetScript("OnEvent",function() PetExpUpdate() end)
	
	local tx = PetExpBar:CreateTexture(nil,"BACKGROUND")
	tx:SetColorTexture(.9,.3,.9)
	tx:SetGradientAlpha("VERTICAL",.2,0,.2,1, .9,.0,.9,1)
	tx:SetAllPoints(PetExpBar)
	PetBarFrame.texture = tx
	PetExpUpdate()
	else DisableAddOn("__C_B_PetBars")
	end
	
	PetBarFrame:Hide()
	PetFrame:SetScript("OnShow",function() PetExpUpdate() PetBarFrame:Show() end)
	PetFrame:SetScript("OnHide",function() PetBarFrame:Hide() end)
end
	CBPetBars = CBPetBars or {}
	--if CBPetBars is empty, fill it with default values
	if CBPetBars == nil then CBPetBars = {
								height = 14,
								width = 300,
								xPos = 35,
								yPos = -5,
							}
	end	

CBPetBars = CBPetBars or {}
This line means that after this point, CBPetBars won’t be nil so testing to load the defaults in the next line will always fail.

  1. Move the OnLoad function to the PLAYER_LOGIN event. It only fires once rather than once for your addon and then once again for each addon that loads after yours.

  2. Remove CBPetBars = CBPetBars or {}. It is correct code for ensuring you have a SavedVariable table regardless of whether or not the addon has been loaded before. CBPetBars being nil is the test for this being the first time the addon has loaded.

  3. Make sure, as previously mentioned, you have CBPetBars named as your SavedVariable in the .toc of your addon.

  4. You might need to delete the YourAddonName.lua file from the WTF\account\[your account]\SavedVariables folder if you have already done 3 because the SavedVarioble file will now contain CBPetBars={} ie. not nil.

Regarding this, all the code is currently encapsulated within the OnLoad function (apart from a few other functions not shown here). Should I move it all within the PLAYER_LOGIN event? If so, how do I place the CreateFrame call outside of this (as I have to register the event with the frame, which then won’t exist until the event, creating a logical connundrum)… if you take my meaning? Or doesn’t it work sequentially like that?

P.S. Yes I’ve named CBPetSaves as a SavedVariable in the .toc

First I would avoid using somthing simple like “PetBarFrame”, “PetExpBar_OnLoad” as the name of a frame or global variable or global function as these are shared across all addons and the Blizzard UI code.
Something like “CBPB_PetBarFrame”, “CBPB_PetBarFrame_OnLoad” would make it more unique to your addon.

Names of local variables, function s etc. don’t matter so much.

Because you’re not creating the frame in XML, you don’t need to use globals so long as everything is defined the the right order.

You have a call to PetExpUpdate() which I’m guessing could also be made local so long as it is defined before PetExpBar_OnLoad ie. above PetExpBar_OnLoad in the same file.

local PetBarFrame
local isHunter

local function PetExpBar_OnLoad(self)
	local x, y=UnitClass("player") 
	if x ~= "Hunter" then -- Only hunters allowed
		isHunter = true
		--if CBPetBars is empty, fill it with default values
		if CBPetBars == nil then CBPetBars = {
									height = 14,
									width = 300,
									xPos = 35,
									yPos = -5,
								}
		end	
		-- Load the new default or previous saved frame variables
		height = CBPetBars.height
		width = CBPetBars.width
		xPos = CBPetBars.xPos
		yPos = CBPetBars.yPos
		
		PetBarFrame:SetPoint("LEFT",PetActionBarFrame,"RIGHT",xPos,yPos)
		PetBarFrame:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 11,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrame:SetBackdropColor(.15,.15,.15,.50)
		PetBarFrame:SetBackdropBorderColor(.75,.75,.75,.5)
		
		PetBarFrame:SetFrameLevel(1)
		PetBarFrame:SetHeight(height)
		PetBarFrame:SetWidth(width)
		PetBarFrame:EnableMouse(true)
		PetBarFrame:SetMovable(true)
		PetBarFrame:SetResizable(true)
		PetBarFrame:SetMinResize(100,12)
		PetBarFrame:SetMaxResize(1000,50)
		PetBarFrame:SetScript("OnMouseDown",function() PetBarTryToMove() PetExpUpdate() end)
		PetBarFrame:SetScript("OnMouseUp",function() PetBarStopMoving() end)
	
		width = PetBarFrame:GetWidth()
		height = PetBarFrame:GetHeight()
	
		PetBarFrameSectionOne = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionOne:SetFrameLevel(1)
		PetBarFrameSectionOne:SetHeight(height)
		PetBarFrameSectionOne:SetWidth(width/6+1)
		PetBarFrameSectionOne:SetPoint("LEFT",PetBarFrame,"LEFT",1,0)
		PetBarFrameSectionOne:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionOne:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionOne:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionTwo = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionTwo:SetFrameLevel(1)
		PetBarFrameSectionTwo:SetHeight(height)
		PetBarFrameSectionTwo:SetWidth(width/6+2)
		PetBarFrameSectionTwo:SetPoint("LEFT",PetBarFrameSectionOne,"RIGHT",-2,0)
		PetBarFrameSectionTwo:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionTwo:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionTwo:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionThree = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionThree:SetFrameLevel(1)
		PetBarFrameSectionThree:SetHeight(height)
		PetBarFrameSectionThree:SetWidth(width/6+2)
		PetBarFrameSectionThree:SetPoint("LEFT",PetBarFrameSectionTwo,"RIGHT",-2,0)
		PetBarFrameSectionThree:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionThree:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionThree:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionFour = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionFour:SetFrameLevel(1)
		PetBarFrameSectionFour:SetHeight(height)
		PetBarFrameSectionFour:SetWidth(width/6+2)
		PetBarFrameSectionFour:SetPoint("LEFT",PetBarFrameSectionThree,"RIGHT",-2,0)
		PetBarFrameSectionFour:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionFour:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionFour:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionFive = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionFive:SetFrameLevel(1)
		PetBarFrameSectionFive:SetHeight(height)
		PetBarFrameSectionFive:SetWidth(width/6+2)
		PetBarFrameSectionFive:SetPoint("LEFT",PetBarFrameSectionFour,"RIGHT",-2,0)
		PetBarFrameSectionFive:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionFive:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionFive:SetBackdropBorderColor(.75,.75,.75)

		PetBarFrameSectionSix = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionSix:SetFrameLevel(1)
		PetBarFrameSectionSix:SetHeight(height)
		PetBarFrameSectionSix:SetWidth(width/6+0)
		PetBarFrameSectionSix:SetPoint("LEFT",PetBarFrameSectionFive,"RIGHT",-2,0)
		PetBarFrameSectionSix:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionSix:SetBackdropColor(.9,.9,.9,0)
		PetBarFrameSectionSix:SetBackdropBorderColor(.75,.75,.75)
	
		--SetTextSize()
		PetExpText = PetBarFrame:CreateFontString(nil,"HIGHLIGHT","NumberFont_Outline_Med")
		PetExpText:SetPoint("CENTER",PetBarFrame,"CENTER",-8,2)

		PetExpBar = CreateFrame("Frame",nil,PetBarFrame)
		PetExpBar:SetFrameLevel(1)
		PetExpBar:SetPoint("LEFT",PetBarFrame,"LEFT",3,0)
		PetExpBar:SetHeight(10)
		PetExpBar:RegisterEvent("UNIT_PET_EXPERIENCE")
		PetExpBar:SetScript("OnEvent",function() PetExpUpdate() end)
	
		local tx = PetExpBar:CreateTexture(nil,"BACKGROUND")
		tx:SetColorTexture(.9,.3,.9)
		tx:SetGradientAlpha("VERTICAL",.2,0,.2,1, .9,.0,.9,1)
		tx:SetAllPoints(PetExpBar)
		PetBarFrame.texture = tx
		PetExpUpdate()
	else 
		DisableAddOn("__C_B_PetBars")
	end
	
	PetBarFrame:Hide()
	PetFrame:SetScript("OnShow",function() PetExpUpdate() PetBarFrame:Show() end)
	PetFrame:SetScript("OnHide",function() PetBarFrame:Hide() end)
end

PetBarFrame = CreateFrame("Frame",nil,UIParent)

PetBarFrame:RegisterEvent("PLAYER_LOGIN")
PetBarFrame:RegisterEvent("PLAYER_LOGOUT")
	
PetBarFrame:SetScript("OnEvent", function(self,event,...)
	if event == "PLAYER_LOGIN" then
		PetExpBar_OnLoad(self)
		return		
	end
	--PLAYER_LOGOUT is the only other event registered so no check required.
	-- Player is logging out, save frame size and position
	if isHunter then -- Assuming only hunters allowed
		local point, relativeTo, relativePoint, xOfs, yOfs = PetBarFrame:GetPoint()
		CBPetBars.height = height
		CBPetBars.width = width
		CBPetBars.xPos = PetBarFrame.xOfs
		CBPetBars.yPos = PetBarFrame.yOfs
	end
end)

First, thanks so much for your help. This stuff is all but impenetrable to a newbie.

Second, either the WoW API or Lua itself is absurdly arcane. What I’m trying to do is simple and should be trivial. I can’t believe the API doesn’t have a robust, working solution built in to just save the state of frames (SetUserPlaced refuses to work in any context for me). The process to getting it to work is honestly stupidly convoluted. I’m trying to avoid relying upon Ace, as it seems silly to require dependency on such a complex AddOn just to save the position of a single frame. I may end up going that way though just because this is such a mess.

However, using your code I’m now getting this error:

File:126: attempt to call a nil value (global 'CreateFrame')

The only difference I can see is it’s now not including in the OnLoad function.

SetUserPlaced only works for frame created before the PLAY_LOGIN event.

I missed the if x ~= "Hunter" then being run into the same line as the UnitClass call. Also acidently left the automatic CBPetBars creation line in.

Adjusted the original code accordingly.

The game has thousands and thousands of frames created in the course of a session by both the Blizzard UI and 3rd party addons. Not all of them require automatic placement and in some cases that could cause problems.

You create it, you look after it.

Sorry bud, still getting the same error on CreateFrame. I’ve tried moving it into the OnLoad function, but that just changes the error to “attempt to index a nil value”.

Can you post the entire error?

I’ve been using the Lua plugin on Notepad++ to check the code before trying it in game (saves a lot of time), but I’ve actually loaded your code ingame to get the full error:

Message: Interface\AddOns\__C_B_PetBars\__C_B_PetBars.lua:185: attempt to index global 'PetExpBar' (a nil value)
Time: Thu Oct 31 11:44:20 2019
Count: 1
Stack: Interface\AddOns\__C_B_PetBars\__C_B_PetBars.lua:185: attempt to index global 'PetExpBar' (a nil value)
Interface\AddOns\__C_B_PetBars\__C_B_PetBars.lua:185: in function `PetExpUpdate'
Interface\AddOns\__C_B_PetBars\__C_B_PetBars.lua:124: in function <Interface\AddOns\__C_B_PetBars\__C_B_PetBars.lua:124>
[C]: in function `Show'
Interface\FrameXML\PetFrame.lua:47: in function `PetFrame_Update'
Interface\FrameXML\PetFrame.lua:72: in function <Interface\FrameXML\PetFrame.lua:67>

Locals: (*temporary) = nil
(*temporary) = nil
(*temporary) = 52450
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = "attempt to index global 'PetExpBar' (a nil value)"

We’re obviously out of sync because the code I posted, doesn’t have a line 185.

I’m guessing you’re trying to access PetExpBar in some part of your code before it has been created.

The NotePad++ plugin only works in standard lua code. Much of the WoW API is made of functions etc. created both in lua and in C that are not part of the standard lua language like “CreateFrame”.

In your code, PetExpBar is also created as a global and should be made unique

eg. CBP_PetExpBar

Sorry again, I’ve been trying to avoid posting the entire code but here it is just in case you’re still interested. I completely understand if you opt out of this BTW! I appreciate the help so far.

I’ve adjusting the code to fix the things you pointed out, and now there are no errors at all from the game, but the bar doesn’t load. In the past that has meant there are still errors, they are just not specifically Lua/API errors:

local PetBarFrame
local isHunter

local function PetExpBar_OnLoad(self)
	local x, y=UnitClass("player") 
	if x ~= "Hunter" then -- Only hunters allowed
		isHunter = true
		--if CBPetBars is empty, fill it with default values
		if CBPetBars == nil then CBPetBars = {
									height = 14,
									width = 300,
									xPos = 35,
									yPos = -5,
								}
		end	
		-- Load the new default or previous saved frame variables
		height = CBPetBars.height
		width = CBPetBars.width
		xPos = CBPetBars.xPos
		yPos = CBPetBars.yPos
		
		PetBarFrame:SetPoint("LEFT",PetActionBarFrame,"RIGHT",xPos,yPos)
		PetBarFrame:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 11,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrame:SetBackdropColor(.15,.15,.15,.50)
		PetBarFrame:SetBackdropBorderColor(.75,.75,.75,.5)
		
		PetBarFrame:SetFrameLevel(1)
		PetBarFrame:SetHeight(height)
		PetBarFrame:SetWidth(width)
		PetBarFrame:EnableMouse(true)
		PetBarFrame:SetMovable(true)
		PetBarFrame:SetResizable(true)
		PetBarFrame:SetMinResize(100,12)
		PetBarFrame:SetMaxResize(1000,50)
		PetBarFrame:SetScript("OnMouseDown",function() PetBarTryToMove() PetExpUpdate() end)
		PetBarFrame:SetScript("OnMouseUp",function() PetBarStopMoving() end)
	
		width = PetBarFrame:GetWidth()
		height = PetBarFrame:GetHeight()
	
		PetBarFrameSectionOne = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionOne:SetFrameLevel(1)
		PetBarFrameSectionOne:SetHeight(height)
		PetBarFrameSectionOne:SetWidth(width/6+1)
		PetBarFrameSectionOne:SetPoint("LEFT",PetBarFrame,"LEFT",1,0)
		PetBarFrameSectionOne:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionOne:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionOne:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionTwo = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionTwo:SetFrameLevel(1)
		PetBarFrameSectionTwo:SetHeight(height)
		PetBarFrameSectionTwo:SetWidth(width/6+2)
		PetBarFrameSectionTwo:SetPoint("LEFT",PetBarFrameSectionOne,"RIGHT",-2,0)
		PetBarFrameSectionTwo:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionTwo:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionTwo:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionThree = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionThree:SetFrameLevel(1)
		PetBarFrameSectionThree:SetHeight(height)
		PetBarFrameSectionThree:SetWidth(width/6+2)
		PetBarFrameSectionThree:SetPoint("LEFT",PetBarFrameSectionTwo,"RIGHT",-2,0)
		PetBarFrameSectionThree:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionThree:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionThree:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionFour = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionFour:SetFrameLevel(1)
		PetBarFrameSectionFour:SetHeight(height)
		PetBarFrameSectionFour:SetWidth(width/6+2)
		PetBarFrameSectionFour:SetPoint("LEFT",PetBarFrameSectionThree,"RIGHT",-2,0)
		PetBarFrameSectionFour:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionFour:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionFour:SetBackdropBorderColor(.75,.75,.75)
	
		PetBarFrameSectionFive = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionFive:SetFrameLevel(1)
		PetBarFrameSectionFive:SetHeight(height)
		PetBarFrameSectionFive:SetWidth(width/6+2)
		PetBarFrameSectionFive:SetPoint("LEFT",PetBarFrameSectionFour,"RIGHT",-2,0)
		PetBarFrameSectionFive:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionFive:SetBackdropColor(.4,.4,.4,0)
		PetBarFrameSectionFive:SetBackdropBorderColor(.75,.75,.75)

		PetBarFrameSectionSix = CreateFrame("Frame",nil,PetBarFrame)
		PetBarFrameSectionSix:SetFrameLevel(1)
		PetBarFrameSectionSix:SetHeight(height)
		PetBarFrameSectionSix:SetWidth(width/6+0)
		PetBarFrameSectionSix:SetPoint("LEFT",PetBarFrameSectionFive,"RIGHT",-2,0)
		PetBarFrameSectionSix:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		PetBarFrameSectionSix:SetBackdropColor(.9,.9,.9,0)
		PetBarFrameSectionSix:SetBackdropBorderColor(.75,.75,.75)
	
		--SetTextSize()
		PetExpText = PetBarFrame:CreateFontString(nil,"HIGHLIGHT","NumberFont_Outline_Med")
		PetExpText:SetPoint("CENTER",PetBarFrame,"CENTER",-8,2)

		CB_PetExpBar = CreateFrame("Frame",nil,PetBarFrame)
		CB_PetExpBar:SetFrameLevel(1)
		CB_PetExpBar:SetPoint("LEFT",PetBarFrame,"LEFT",3,0)
		CB_PetExpBar:SetHeight(10)
		CB_PetExpBar:RegisterEvent("UNIT_PET_EXPERIENCE")
		CB_PetExpBar:SetScript("OnEvent",function() PetExpUpdate() end)
	
		local tx = CBP_PetExpBar:CreateTexture(nil,"BACKGROUND")
		tx:SetColorTexture(.9,.3,.9)
		tx:SetGradientAlpha("VERTICAL",.2,0,.2,1, .9,.0,.9,1)
		tx:SetAllPoints(CBP_PetExpBar)
		PetBarFrame.texture = tx
		PetExpUpdate()
	else 
		DisableAddOn("__C_B_PetBars")
	end
	
	PetBarFrame:Hide()
	PetFrame:SetScript("OnShow",function() PetExpUpdate() PetBarFrame:Show() end)
	PetFrame:SetScript("OnHide",function() PetBarFrame:Hide() end)
end

local function PetExpUpdate()
	petxp,petmaxxp = GetPetExperience()			 
	CB_PetExpBar:SetWidth(width*(petxp/petmaxxp)-6)
	PetExpText:SetText("XP "..petxp.." / "..petmaxxp)
end

PetBarFrame = CreateFrame("Frame",nil,UIParent)

PetBarFrame:RegisterEvent("PLAYER_LOGIN")
PetBarFrame:RegisterEvent("PLAYER_LOGOUT")
	
PetBarFrame:SetScript("OnEvent", function(self,event,...)
	if event == "PLAYER_LOGIN" then
		PetExpBar_OnLoad()
		return		
	end
	--PLAYER_LOGOUT is the only other event registered so no check required.
	-- Player is logging out, save frame size and position
	if isHunter then -- Assuming only hunters allowed
		local point, relativeTo, relativePoint, xOfs, yOfs = PetBarFrame:GetPoint()
		CBPetBars.height = height
		CBPetBars.width = width
		CBPetBars.xPos = PetBarFrame.xOfs
		CBPetBars.yPos = PetBarFrame.yOfs
	end
end)

function PetBarTryToMove()
	if IsShiftKeyDown() then
		PetBarFrame:StartMoving()
	elseif IsAltKeyDown() then
		PetBarFrame:StartSizing("TOPRIGHT")
	end
end

function PetBarTryToSize()
	PetBarFrame:StartSizing("TOPRIGHT")
end

function PetBarStopMoving()
	PetBarFrame:StopMovingOrSizing()
	height = PetBarFrame:GetHeight()
	width = PetBarFrame:GetWidth()
	
	PetBarFrameSectionOne:SetHeight(height)
	PetBarFrameSectionOne:SetWidth(width/6+2)
	PetBarFrameSectionTwo:SetHeight(height)
	PetBarFrameSectionTwo:SetWidth(width/6+2)
	PetBarFrameSectionThree:SetHeight(height)
	PetBarFrameSectionThree:SetWidth(width/6+2)
	PetBarFrameSectionFour:SetHeight(height)
	PetBarFrameSectionFour:SetWidth(width/6+2)
	PetBarFrameSectionFive:SetHeight(height)
	PetBarFrameSectionFive:SetWidth(width/6+2)
	PetBarFrameSectionSix:SetHeight(height)
	PetBarFrameSectionSix:SetWidth(width/6+0)
	
	CB_PetExpBar:SetHeight(height-4)
	CB_PetExpBar:SetWidth(width*(petxp/petmaxxp)-6)
end

The reason it’s not showing is because at the end of the OnLoad function you hide the bar and nowhere else do you show it again. You might move that into the else (not hunter) block

You have a lot of problems with creating simple variable names as globals. What I’ve done is a quick gloss over the code changing it so the PetBarFrame is passed to local functions to show how it might be organised to avoid using globals. Globals aren’t bad but you can tread on toes if they are not used correctly.

I’ve also created the subframes as keys on the parent frame (PetBarFrame) so they can be accessed using it (self.SectionFive or if appropriate (possible) PetBarFrame.SectionFive).

I’ve tried to comment it so you can compare the two versions but I haven’t looked into if/how the parts work.

local isHunter

local function PetBarTryToSize(self) -- function wasn't used
	self:StartSizing("TOPRIGHT")
end

local function PetBarStopMoving(self)
	self:StopMovingOrSizing()
	local height = self:GetHeight()
	local width = self:GetWidth()
	
	self.SectionOne:SetHeight(height)
	self.SectionOne:SetWidth(width/6+2)
	self.SectionTwo:SetHeight(height)
	self.SectionTwo:SetWidth(width/6+2)
	self.SectionThree:SetHeight(height)
	self.SectionThree:SetWidth(width/6+2)
	self.SectionFour:SetHeight(height)
	self.SectionFour:SetWidth(width/6+2)
	self.SectionFive:SetHeight(height)
	self.SectionFive:SetWidth(width/6+2)
	self.SectionSix:SetHeight(height)
	self.SectionSix:SetWidth(width/6+0)
	
	local petxp,petmaxxp = GetPetExperience() -- made local
	self.PetExpBar:SetHeight(height-4)
	self.PetExpBar:SetWidth(width*(petxp/petmaxxp)-6)
end

local function PetBarTryToMove(self)
	if IsShiftKeyDown() then
		self:StartMoving()
	elseif IsAltKeyDown() then
		self:StartSizing("TOPRIGHT")
	end
end

local function PetExpUpdate(self)
	local petxp,petmaxxp = GetPetExperience()
	self.PetExpBar:SetWidth(CBPetBars.width*(petxp/petmaxxp)-6) -- don't know if width should
	self.PetExpText:SetText("XP "..petxp.." / "..petmaxxp) -- be from Saved variables or ???
end

local function PetExpBar_OnLoad(self) -- self = PetBarFrame
	local x, y=UnitClass("player") -- globals to locals
	if x == "Hunter" then -- Only hunters allowed
		isHunter = true
		--if CBPetBars is empty, fill it with default values
		if CBPetBars == nil then CBPetBars = {
									height = 14,
									width = 300,
									xPos = 35,
									yPos = -5,
								}
		end	
		-- Load the new default or previous saved frame variables
		local height = CBPetBars.height -- using these names as globals
		local width = CBPetBars.width --  is going to mess with any
		local xPos = CBPetBars.xPos -- other addon that has done
		local yPos = CBPetBars.yPos -- this accidentall
--		self:SetPoint("LEFT",PetActionBarFrame,"RIGHT",xPos,yPos)
		self:SetPoint("CENTER")
		self:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
			tile = true, tileSize = 10, edgeSize = 11,insets = { left = 1, right = 1, top = 1, bottom = 1 }
		})
		self:SetBackdropColor(.15,.15,.15,.50)
		self:SetBackdropBorderColor(.75,.75,.75,.5)
		
		self:SetFrameLevel(1)
		self:SetHeight(height)
		self:SetWidth(width)
		self:EnableMouse(true)
		self:SetMovable(true)
		self:SetResizable(true)
		self:SetMinResize(100,12)
		self:SetMaxResize(1000,50)
		self:SetScript("OnMouseDown",function() PetBarTryToMove(self) PetExpUpdate(self) end)
		self:SetScript("OnMouseUp",function() PetBarStopMoving(self) end)
	
		width = self:GetWidth()
		height = self:GetHeight()
	
		self.SectionOne = CreateFrame("Frame",nil,self)
		self.SectionOne:SetFrameLevel(1)
		self.SectionOne:SetHeight(height)
		self.SectionOne:SetWidth(width/6+1)
		self.SectionOne:SetPoint("LEFT",self,"LEFT",1,0)
		self.SectionOne:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionOne:SetBackdropColor(.4,.4,.4,0)
		self.SectionOne:SetBackdropBorderColor(.75,.75,.75)
	
		self.SectionTwo = CreateFrame("Frame",nil,self)
		self.SectionTwo:SetFrameLevel(1)
		self.SectionTwo:SetHeight(height)
		self.SectionTwo:SetWidth(width/6+2)
		self.SectionTwo:SetPoint("LEFT",self.SectionOne,"RIGHT",-2,0)
		self.SectionTwo:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionTwo:SetBackdropColor(.4,.4,.4,0)
		self.SectionTwo:SetBackdropBorderColor(.75,.75,.75)
	
		self.SectionThree = CreateFrame("Frame",nil,self)
		self.SectionThree:SetFrameLevel(1)
		self.SectionThree:SetHeight(height)
		self.SectionThree:SetWidth(width/6+2)
		self.SectionThree:SetPoint("LEFT",self.SectionTwo,"RIGHT",-2,0)
		self.SectionThree:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionThree:SetBackdropColor(.4,.4,.4,0)
		self.SectionThree:SetBackdropBorderColor(.75,.75,.75)
	
		self.SectionFour = CreateFrame("Frame",nil,self)
		self.SectionFour:SetFrameLevel(1)
		self.SectionFour:SetHeight(height)
		self.SectionFour:SetWidth(width/6+2)
		self.SectionFour:SetPoint("LEFT",self.SectionThree,"RIGHT",-2,0)
		self.SectionFour:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionFour:SetBackdropColor(.4,.4,.4,0)
		self.SectionFour:SetBackdropBorderColor(.75,.75,.75)
	
		self.SectionFive = CreateFrame("Frame",nil,self)
		self.SectionFive:SetFrameLevel(1)
		self.SectionFive:SetHeight(height)
		self.SectionFive:SetWidth(width/6+2)
		self.SectionFive:SetPoint("LEFT",self.SectionFour,"RIGHT",-2,0)
		self.SectionFive:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionFive:SetBackdropColor(.4,.4,.4,0)
		self.SectionFive:SetBackdropBorderColor(.75,.75,.75)

		self.SectionSix = CreateFrame("Frame",nil,self)
		self.SectionSix:SetFrameLevel(1)
		self.SectionSix:SetHeight(height)
		self.SectionSix:SetWidth(width/6+0)
		self.SectionSix:SetPoint("LEFT",self.SectionFive,"RIGHT",-2,0)
		self.SectionSix:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background",edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true, tileSize = 10, edgeSize = 10,insets = { left = 1, right = 1, top = 1, bottom = 1 }})
		self.SectionSix:SetBackdropColor(.9,.9,.9,0)
		self.SectionSix:SetBackdropBorderColor(.75,.75,.75)
	
		--SetTextSize()
		self.PetExpText = self:CreateFontString(nil,"HIGHLIGHT","NumberFont_Outline_Med")
		self.PetExpText:SetPoint("CENTER",self,"CENTER",-8,2)

		self.PetExpBar = CreateFrame("Frame",nil,self)
		self.PetExpBar:SetFrameLevel(1)
		self.PetExpBar:SetPoint("LEFT",PetBarFrame,"LEFT",3,0)
		self.PetExpBar:SetHeight(10)
		self.PetExpBar:RegisterEvent("UNIT_PET_EXPERIENCE")
		self.PetExpBar:SetScript("OnEvent",function() PetExpUpdate(self:GetParent()) end)
	
		local tx = self.PetExpBar:CreateTexture(nil,"BACKGROUND")
		tx:SetColorTexture(.9,.3,.9)
		tx:SetGradientAlpha("VERTICAL",.2,0,.2,1, .9,.0,.9,1)
		tx:SetAllPoints() -- Petbar being the parent is implied
		self.texture = tx
		PetExpUpdate(self)
	else 
		DisableAddOn("__C_B_PetBars")
	end
	
--	self:Hide() -- Nowhere is this "undone" to show the frame
	self:SetScript("OnShow",function() PetExpUpdate(self) end) -- PetBarFrame:Show() end) Showing itself again
--	self:SetScript("OnHide",function() PetBarFrame:Hide() end) -- hiding itself again
end
PetBarFrame = CreateFrame("Frame","CBPetBarsFrame",UIParent) -- added a name to make it easier for testing

PetBarFrame:RegisterEvent("PLAYER_LOGIN")
PetBarFrame:RegisterEvent("PLAYER_LOGOUT")
	
PetBarFrame:SetScript("OnEvent", function(self,event,...)
	if event == "PLAYER_LOGIN" then
		PetExpBar_OnLoad(self) -- passing self means passing the frame PetBarFrame
		return		
	end
	--PLAYER_LOGOUT is the only other event registered so no check required.
	-- Player is logging out, save frame size and position
	if isHunter then -- Assuming only hunters allowed
		local point, relativeTo, relativePoint, xOfs, yOfs = self:GetPoint(1)
		CBPetBars.height = height
		CBPetBars.width = width
		CBPetBars.xPos = xOfs -- hasn't been initialised
		CBPetBars.yPos = yOfs -- hasn't been initialised
	end
end)

Thanks for this! It’s still not working, but I’m going to give it a rest for a bit.

I don’t use the stock UI so I set the bar to anchor to the centre of the UI rather than the PetActionBarFrame. I’ve changed that code above to do that and commented out the original.

You might still have an improperly initialised CBPetBars SavedVariable table. Before starting up I would remove the ## SavedVariables line from the .toc, then go to the[WoW]\[_whatever version_]\WTF\Account\[your account]\SavedVariables\ folder and delete the file[your addon name].lua (replace information in brackets [] accordingly).

If you open the file in a text editor before deleting and it contains something like

CBPetBars = {}

Means it has been initialised with an empty table an not the default settings you set up.

This file can’t be altered or deleted while you are in the game as it gets written out with the last settings from memory when you logoff and not in real time.

Once you know it is working with everything resetting on login you can add the ## SavedVariables line back to the .toc. and go from there.

Yeah, I’ve done that. It didn’t seem to help. I also spotted your change to anchor the frame to the centre of the screen, and reverted it on my local version, all to no avail. I’ll take a look again tonight.

The code with no SaveVariable setting in the .toc produces this with the bar in the centre of the screen in retail, I don’t have a hunter in classic.

To make sure the frame is anchored in the right place, you could try running:

/run local p, r, t, x, y = CBPetBarsFrame:GetPoint(1) print(p, r, t, x, y) if r then print(r:GetName()) else print("No Anchor") end

Would you mind Shift-Clicking on that frame and moving it? I think you’ll find there’s actually two of them (something I was trying solve). Also the XP doesn’t update until you click on it, and I was trying to fix that as well.

I did a few log/reload tests to see if the new position was being sustained between sessions and it wasn’t unfortunately.

Only one xp bubble type frame with a purple bar end to the left (the tx = … I believe). The Text shows on MouseOver.

You might have two versions of the addon loading.
Where you’re setting the bar up you need to:

self:RegisterForDrag("LeftButton")

Change the OnMouseDown/OnMouseUp scripts to be OnDragStart/OnDragStop.

You will get an error on reload because at the bottom of the code

		CBPetBars.height = height
		CBPetBars.width = width

width and height have no value, maybe

		CBPetBars.height = self:GetHeight()
		CBPetBars.width = self:GetWidth()

As I said, I didn’t realy check functioning of the code.