FontString not appearing

I’ve got the base functionality of the BattleGroundEnemies companion addon I am working on up and running - I get a correct, two-line Specialization/Class string to the right of the BGE Enemy Player frame to which it applies.

I’m trying to mirror that on the enemy nameplates.

The logic is complex, but I’ve got enough temporary diagnostic displays in place to have isolated at least WHERE the code is failing.

function f.UpdateNameplateOverlay(frame, unitName)

	print('UpdateNameplateOverlay(<input frame>, '..unitName..')')

	if not frame.NPOverlay then
		frame.NPOverlay	= frame:CreateFontString(nil, "HIGH", 5)
		frame.NPOverlay:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
		frame.NPOverlay:SetJustifyH("CENTER")
		frame.NPOverlay:SetJustifyV("CENTER")
		frame.NPOverlay:SetTextColor(1, 1, 1, 1)
		frame.NPOverlay:SetPoint("CENTER")
	end

	frame.NPOverlay:SetText(f.SpecClassByPlayerName(unitName))
	npFrames[unitName]	= frame

end
function f.SpecClassByPlayerName(playerName)
--	return the spec/class string (without mid-newline) from the fixed table
--	based on specID input
--	temporarily returns "Unknown Enemy" when a specID is not found

	print('SpecClassByPlayerName('..playerName..')')

	return (gsub((specClassByName[unitName] or ''), '\n   ', ''))
end

f.UpdateNameplateOverlay(frame,unitName) is correctly receiving a frame and a properly formed unitName (playerName or playerName-realm depending on whether playerName is on my realm or not).

I have a data capture built into a slash command that copies out the specClassByName table into my saved data file. I don’t want to expose that here because it has actual player data in it, but looking at it, it has names that match my diagnostic output with the proper strings in it.

But I am not getting the display I would expect to see overlayed the enemy nameplates.

I’m about convinced I’ve got some trivial error that I’m just not seeing.

Any help would be appreciated.

Most obvious, "HIGH" is a frame strata not a draw layer:

Ooops. Okay. I’ll try something else there. “OVERLAY” looks about right given what I’m doing there.

function f.UpdateNameplateOverlays()
--	spin the nameplate overlays and update (if there is a match to BGE)
--	or hide the text (if there is a frame but no match to BGE)
--	no action needed if there is no frame

	print('UpdateNameplateOverlays()')
	for i = 1, 40 do
		local unitID			= 'nameplate'..i
		if UnitExists(unitID) then
			local unitName	= f.GetFunctionalUnitName(unitID)
			local npFrame	= ((elvUI and f.GetElvNP_NamePlate(unitID)) or _G['NamePlate'..i])
			if npFrame and bgeFrames[unitName] then
				f.UpdateNameplateOverlay(npFrame, unitName)
			elseif npFrame and npFrameOverlay then
				npFrame.NPOverlay:SetText('')
			end
		end
	end
end

Still not getting anything at all.

I went to the Wiki and looked up the proper parameter list for CreateFontString - added the parent frame (just called “frame” here).

Nothing

Odd thing is this works:

function f.UpdateBGESpecClassFrame(inFrame)
--	create or update the FontString object that contains the spec/class string
--	  adjacent to the individual BGE player frames
--	return the frame for storage by playerName or playerName-realm

	print('UpdateBGESpecClassFrame(<inFrame>)')
	local frame				= inFrame
	if not frame.BGEOverlay then
		frame.BGEOverlay	= frame.healthBar:CreateFontString(nil, "OVERLAY", frame, 5)
		frame.BGEOverlay:SetFont("Fonts\\FRIZQT__.TTF", 15, "OUTLINE")
		frame.BGEOverlay:SetJustifyH("LEFT")
		frame.BGEOverlay:SetJustifyV("CENTER")
		frame.BGEOverlay:SetTextColor(1, 1, 1, 1)
		frame.BGEOverlay:SetPoint("LEFT", frame.healthBar, "RIGHT", 60, -3)
	end
	frame.BGEOverlay:SetText(f.SpecClassBySpecID(frame.PlayerSpecID))
	return frame

end

With ElvUI active the frame passed in to f.UpdateNameplateOverlay(frame, unitName) is ElvNP_NamePlate.

Without ElvUI active, the frame passed in is NamePlate.

I’ve got copies of the nameplate frame data also stored in my diagnostic data and it all looks correct to me (lots of things in the ElvUI one I don’t understand, but it’s not like it’s pointing to the wrong type of data or something. It’s processing AS a frame in there.

Simpy from TukUI confirmed that I had the right frame.

Just for fun, I turned off ElvUI and tried this without and got the same result. Not throwing errors, just not displaying the overlay text. Nothing, nada, zip.

function f.UpdateNameplateOverlay(frame, unitName)

You’ve given us no indication if where/how this function is being called so we have no idea what “frame” actually relates to. “ElvNP_NamePlate” and “NamePlate” are ambiguouse enough to be confusing.

If like the BGE frame previously, the frame being passed in here has overlaying frames, your fontstring might be hidden behind those. Maybe make the text larger and anchor it outside the bounds of “frame” to see if it dislpays when not in the CENTER.

As an aside, frame:CreateFontString(…) automatically sets frame as the parent of the fontstring. The inheritance refered to in the third parameter is if you are inhereting from a predefined virtual fontstring template which in this case, you aren’t.

I’ll be more than happy to post the entire code if you want, but it seemed excessive to do so.

The frame being sent in is either the _G[“NamePlateX”] frame (if ElvUI is not loaded) or the _G[“ElvNP_NamePlateX”] frame (if it is).

function f.UpdateNameplateOverlays()
--	spin the nameplate overlays and update (if there is a match to BGE)
--	or hide the text (if there is a frame but no match to BGE)
--	no action needed if there is no frame

	print('UpdateNameplateOverlays()')
	for i = 1, 40 do
		local unitID	= 'nameplate'..i
		if UnitExists(unitID) then
			local unitName	= f.GetFunctionalUnitName(unitID)
			local npFrame	= ((elvUI and f.GetElvNP_NamePlate(unitID)) or _G['NamePlate'..i])
			if npFrame and bgeFrames[unitName] then
				f.UpdateNameplateOverlay(npFrame, unitName)
			elseif npFrame and npFrameOverlay then
				npFrame.NPOverlay:SetText('')
			end
		end
	end
end
function f.GetElvNP_NamePlate(unitID)

	for i = 1, 40 do
		if _G['ElvNP_NamePlate'..i].unit == unitID then
			return _G['ElvNP_NamePlate'..i]
		end
	end
end

Did have to make one change because there is no guarantee that nameplateX will line up with ElvNP_NamePlateX. BUT, inside each ElvNP_NamePlateY is a field called “unit” which has the blizzard nameplateX value in it, so I just spin looking for it.

As soon as I get out of this next BG test, I’ll cut one of the NP frame data portions and paste it in so you can see it.

Is there any reason you’re creating the fontstring as a child of frame rather than frame.healthBar?

Yes.

For one thing, healthBar is capable of being hidden.

As is Name.

Even the nameplate itself is capable of being hidden (in which case none of this will show up) but if the nameplate itself is visible this should be showing up.

In any case, an earlier iteration of this used ElvNP_NamePlateXHealth and I got no joy there either.

As was the case with NamePlateX.healthBar.

Nothing seems to work here and I KNOW it’s possible, but the only addon I see that directly does this is Plater and G-d I don’t feel like snaking my way through that ACE garbage to understand it.

This shouldn’t be that hard and at one point I had SOMETHING showing up (wrong data, but data). I just can’t recreate that now.

I’d be happy if I could just put an arbitrary static FontString on an arbitrary nameplate at this point. Once I have that I can work out the rest.

Also Simpy from the TukUI Discord assured me that ElvNP_NamePlateX would work. He’s the one who clued me in on the fact that the health and name portions of that could be hidden.

Try setting the font size to 30.

You test for

if npFrame and bgeFrames[unitName] then

does bgeFrames[unitName] exist?

I did this just to test the f.UpdateNameplateOverlay function and it seems to work. Get some nameplates up and /run FizzUpdateNameplateOverlays()

local bgeFrames = {}
local npFrames = {}
local f = {}
function f.UpdateNameplateOverlay(frame, unitName)

	print('UpdateNameplateOverlay(<input frame>, '..unitName..')')

	if not frame.NPOverlay then
		frame.NPOverlay	= frame:CreateFontString(nil, "OVERLAY", 5)
		frame.NPOverlay:SetFont("Fonts\\FRIZQT__.TTF", 30, "OUTLINE")
		frame.NPOverlay:SetJustifyH("CENTER")
		frame.NPOverlay:SetJustifyV("CENTER")
		frame.NPOverlay:SetTextColor(1, 1, 1, 1)
		frame.NPOverlay:SetPoint("CENTER")
	end

--	frame.NPOverlay:SetText(f.SpecClassByPlayerName(unitName))
	frame.NPOverlay:SetText("HELLOO!")
	npFrames[unitName]	= frame

end

function FizzUpdateNameplateOverlays()
--	spin the nameplate overlays and update (if there is a match to BGE)
--	or hide the text (if there is a frame but no match to BGE)
--	no action needed if there is no frame

	print('UpdateNameplateOverlays()')
	for i = 1, 5 do
		local unitID	= 'nameplate'..i
		if UnitExists(unitID) then
			local unitName	= UnitName(unitID)-- (f.GetFunctionalUnitName(unitID)
			local npFrame	= ((elvUI and f.GetElvNP_NamePlate(unitID)) or _G['NamePlate'..i])
			if npFrame then --and bgeFrames[unitName] then
				f.UpdateNameplateOverlay(npFrame, unitName)
			elseif npFrame and npFrameOverlay then
				npFrame.NPOverlay:SetText('')
			end
		end
	end
end

I don’t use BGE or ElvUI so…

Thanks. I’m seeing a difference between the Wiki on CreateFontString and what you’re doing there.

I’ve yet to reconcile it, but I’ll use yours.

You test for

if npFrame and bgeFrames[unitName] then

does bgeFrames[unitName] exist?

If it doesn’t, I don’t want to see it. That’s how I filter out friendlies and non-player characters. Only enemies players are in the BGE list.

ElvUI uses unitGUID to tie their nameplates to Blizzard’s so I have to rewrite a big chunk of this. I’ll take the opportunity to use your code there as a test. Thanks.

Apart from the font size and fixed text for testing, my function should be pretty much produce the same as yours. It should also show if the fontstring is behind something else.

fontString = Frame:CreateFontString([name, layer, inheritsFrom, subLayer])

That’s what’s in the wiki.

According to that (and I don’t necessarily believe it), you’re missing a parameter that’s not listed as optional.

They’re all optional [...]

The InheritsFrom is for a font template, not a frame.

So if you put a number in that positional parameter it knows that you’re referring to a sublayer, not a template?

It’s just that normally you can’t just skip a parameter. You have to “nil” it and you do that with tthe name.

I haven’t tested it but I would presume so but you more likely to group that with a drawlayer.

Yeah. It’s working outside of BGE. I’m queue’d for a battleground now to see if it works there.

A combination of things.

  1. The ElvNP frames are OVERLAY sublayer 7.
  2. I can’t get the “HIGHLIGHT” layer to work. It might be reserved, so I had to move them.
  3. I dropped them just below the nameplate, so it’s still pretty close to what I wanted.
  4. I had a default of “” as a spec/class string. I changed that to UnitClass() so at least I get SOMETHING if BGE hasn’t updated.

Thanks, Fizzy. I’m much closer now.

You can create your own child frame and set it’s strata within the structure of the frame passed to f.UpdateNameplateOverlays() then use that as the parent of your fontstring.

It appears I previously made an edit to the wiki that was incorrect. I’ve updated the wiki as follows:

  • CreateFontString() doesn’t have a fourth argument
  • When a FontString is in the same layer as a Texture, it is always in front of it

Meanwhile, “HIGHLIGHT” has special behaviour when used on a frame with mouse input enabled. It appears during mouseover only.

1 Like