oUF

97.2k Downloads

ClassIcons: error when starting quest "Huln's War - The Arrival"

Blazeflack opened this issue ยท 18 comments

commented

In the "Huln's War - The Arrival" quest you speak to an NPC which then transfers you to Azshara and force you into a vehicle state.

This causes the following error when playing on a Shadow Priest:

Message: ...e\AddOns\ElvUI\Libraries\oUF\elements\classicons.lua line 109:
   attempt to index field '?' (a nil value)
Debug:
   ...e\AddOns\ElvUI\Libraries\oUF\elements\classicons.lua:109:
      ...e\AddOns\ElvUI\Libraries\oUF\elements\classicons.lua:73
   (tail call): ?
   ...e\AddOns\ElvUI\Libraries\oUF\elements\classicons.lua:170:
      ...e\AddOns\ElvUI\Libraries\oUF\elements\classicons.lua:147
   (tail call): ?
   ElvUI\Libraries\oUF\ouf.lua:174: UpdateAllElements()
   ...ace\AddOns\ElvUI\Modules\unitframes\units\player.lua:193:
      ...ace\AddOns\ElvUI\Modules\unitframes\units\player.lua:80
   [C]: ?()
   ...rface\AddOns\ElvUI\Modules\unitframes\unitframes.lua:905: Update()
   ...rface\AddOns\ElvUI\Modules\unitframes\unitframes.lua:454: Update_AllFrames()
   ...rface\AddOns\ElvUI\Modules\unitframes\unitframes.lua:1125: ?()
   ...ibraries\CallbackHandler-1.0\CallbackHandler-1.0.lua:145:
      ...ibraries\CallbackHandler-1.0\CallbackHandler-1.0.lua:145
   [string "safecall Dispatcher[1]"]:4:
      [string "safecall Dispatcher[1]"]:4
   [C]: ?
   [string "safecall Dispatcher[1]"]:13: ?()
   ...ibraries\CallbackHandler-1.0\CallbackHandler-1.0.lua:90: Fire()
   ...AddOns\ElvUI\Libraries\AceEvent-3.0\AceEvent-3.0.lua:120:
      ...AddOns\ElvUI\Libraries\AceEvent-3.0\AceEvent-3.0.lua:119
Locals:
None

I added some debug prints to try to understand what is happening, and this is the result:

VisibilityPath: PLAYER_ENTERING_WORLD player
Path: ClassPowerEnable vehicle COMBO_POINTS
Update event, unit, powerType: ClassPowerEnable vehicle COMBO_POINTS
Update cur, max: 0 5
VisibilityPath: nil player
Path: nil player nil
Update event, unit, powerType: nil player nil
Update cur, max: 0 100
VisibilityPath: RefreshUnit vehicle
Path: RefreshUnit vehicle COMBO_POINTS
Update event, unit, powerType: RefreshUnit vehicle COMBO_POINTS
Update cur, max: 0 5

The important part is this:

VisibilityPath: nil player
Path: nil player nil
Update event, unit, powerType: nil player nil
Update cur, max: 0 100

For some reason an Update is triggered with nil values for event and powerType while unit is "player".

We may need to check for this scenario at the top of the Update function and prevent it from going further. Another solution could be to simply check if "element[i]" exists before trying to show or hide it in this block of code:

for i = 1, max do
    if(i <= cur) then
        element[i]:Show()
    else
        element[i]:Hide()
    end
end
commented

Would want to find out what triggered the second update, no event (including fake ones) should ever be passed as nil.
I assume you're using the latest version from this repo or from WoWI right?

commented

I copied the ClassIcons file from this repo before starting the test yes.

commented

I fixed this locally with the following code edit.
Before:

    if(not (unit == 'player' and powerType == ClassPowerType)
        and not (unit == 'vehicle' and powerType == 'COMBO_POINTS')) then
        return
    end

After:

    if(not (unit == 'player' and (powerType == ClassPowerType or powerType ~= nil))
        and not (unit == 'vehicle' and powerType == 'COMBO_POINTS')) then
        return
    end
commented

I haven't completed the quest yet, so do you guys know if there are any basic layouts that are done "correctly" which I could test it with?

commented

If you are indeed using ElvUI, pass arbitrary events through its call of oUF:UpdateAllElements() and try again.

commented

Whenever Beta/PTR realms are up or become available to me, cuz I can't log in rn, I'll investigate this issue too.

commented

@Blazeflack, I think it might be ElvUI issue, but for some reason it's discovered just now.

You call unit frame's UpdateAllElements method here, but you pass no arguments, that's why event is nil in debug prints.

Everything else might be bad timing, have no time to dig deep rn ๐Ÿ˜ž

Possible workarounds for this situation are to either run powerType ~= nil check, as you did, or override unit in VisibilityPath, if UnitHasVehicleUI('player') returns true, but that will prematurely enable vehicle combo points.

commented

You call UpdateAllElements method, when PLAYER_ENTERING_WORLD fires, and that's fine.

This made me take a look at the reason why the code was there in the first place. It turns out the code should probably never have been called on every PLAYER_ENTERING_WORLD event, just on the initial one when logging in or reloading.

I made a change so this is no longer the case and I expect that will fix the issue for me. It may still be a good idea to guard against this specific issue in oUF like you mentioned.

commented

I made a change so this is no longer the case and I expect that will fix the issue for me. It may still be a good idea to guard against this specific issue in oUF like you mentioned.

@Blazeflack What change? In ElvUI?

commented

@p3lim, yeah.

What about my suggestion?

@p3lim, we may need to set unit to 'vehicle' in VisibilityPath, if UnitHasVehicleUI('player') returns true, to avoid this kind of situations, cuz when we enable ClassIcons, we don't use real data.

commented

@p3lim Yes, the change I made was in ElvUI. UpdateAllElements is no longer called after a loading screen (except the very first one when logging in or reloading), which is what caused the error in my case.

commented

Alright, I'll add a preventative measure for the element to update without values.

Maybe also add an argcheck to UpdateAllElements to make sure it's not being fired without an event (for debugging scenarios like this one). It should be considered good measure anyways.
Want comments on this part tho'.

commented

Might be a good idea, IMHO, better safe than sorry.

commented

Just pass a string as an argument, e.g. frame:UpdateAllElements("ElvUI_UpdateAllElements"), then you'll get "ElvUI_UpdateAllElements" as an event in VisibilityPath.

commented

While it's true that the event will no longer be nil, I don't think it will fix the error, as the update will still go through because you are in a vehicle.

commented

Well, here's how you get this error.

ClassIcons are disabled for shadow priests. You call UpdateAllElements method, when PLAYER_ENTERING_WORLD fires, and that's fine. However, by the time you call it, the widget is enabled for vehicle and not for player, but you pass player data, cuz UNIT_ENTERED_VEHICLE event (that's RefreshUnit event in oUF) hasn't fired yet, thus frame's unit isn't set to 'vehicle'.

That's how you get into Update function with unit = 'player' and powerType = nil, moreover it passes all the checks, lol.

Ugh, my explanation is a bit confusing, here's simplified version

  • Event: PLAYER_ENTERING_WORLD
  • oUF updates widgets
  • ClassIcons widget is enabled for 'vehicle', however self.unit is 'player'
  • ElvUI updates widgets, self.unit is still 'player'
  • Error in ClassIcons, cuz unit is 'player' and not 'vehicle'
  • Event: UNIT_ENTERED_VEHICLE
  • oUF updates self.unit and sets it to 'vehicle'
  • oUF updates widgets
  • Everything works fine

@p3lim, we may need to set unit to 'vehicle' in VisibilityPath, if UnitHasVehicleUI('player') returns true, to avoid this kind of situations, cuz when we enable ClassIcons, we don't use real data.

commented

Thanks for the thorough explanation. I'm not near my computer so I couldn't look into this myself just yet.

commented

Sounds good to me.