Stanzilla / WoWUIBugs

World of Warcraft UI Bug Tracker
153 stars 7 forks source link

`PlayerModel:SetCreature()` must be called twice to properly load models for uncached creatures #564

Open Ghostopheles opened 1 month ago

Ghostopheles commented 1 month ago

If the creature specified in the PlayerModel:SetCreature() function call hasn't been previously loaded and cached, the first call to :SetCreature() will do nothing.

This issue does not occur if you directly use :SetModel() or :SetDisplayInfo(), indicating that the request for the uncached creature info using it's ID is the cause of the issue, not the cache state of the model itself.

My assumption is that the initial call receives no return from the internal function used to look up the model by creature ID. It then requests for that data to be loaded, but doesn't properly notify the PlayerModel frame when it's ready, resulting in the need to call :SetCreature() a second time for it to load the model correctly.

Last tested on 10.2.7.54601

Repro

  1. Create a PlayerModel frame
  2. Call PlayerModel:SetCreature with the CreatureID of a creature you haven't seen in a while
  3. Observe lack of model
  4. Repeat step 2

Example

local creatureID = 203602;

local model = CreateFrame("PlayerModel", nil, UIParent, "ModelWithControlsTemplate");
model:SetPoint("CENTER");
model:SetSize(500, 500);
model:SetScript("OnModelLoaded", function() print("OnModelLoaded") end);

local b = CreateFrame("Button", nil, model, "UIPanelButtonTemplate");
b:SetSize(125, 30);
b:SetPoint("LEFT", model, "RIGHT");
b:SetText("Set Creature");
b:SetScript("OnClick", function() model:SetCreature(creatureID); end);

Expected Behavior of Example Code

  1. First click of the "Set Creature" button does nothing
  2. Second click makes the model appear and prints "OnModelLoaded" to the chat box

[!NOTE] If you aren't able to reproduce the issue with the above code, it's possible the creature chosen has already been cached. In that case, pick an NPC from Wowhead that you haven't seen in a while and replace the creatureID local variable with it's NPC ID.

Ghostopheles commented 1 month ago

Through the use of C_TooltipInfo.GetHyperlink, I can confirm that the issue is indeed tied to the cache state of the specified creature. Using the below example code will handle uncached creatures and only call PlayerModel:SetCreature() when the creature is fully loaded.

Due to the lack of a return from C_TooltipInfo.GetHyperlink, I just assume the next TOOLTIP_DATA_UPDATE event is related to our info call, which could cause some issues in an active environment. Also made CREATURE_ID a global variable so it's easier to play around with.

CREATURE_ID = 186739;

local model = CreateFrame("PlayerModel", nil, UIParent, "ModelWithControlsTemplate");
model:SetPoint("CENTER");
model:SetSize(500, 500);
model:SetScript("OnModelLoaded", function() print("OnModelLoaded") end);

local function SetCreature(id)
    print("Setting creature");
    model:SetCreature(id);
end

local function LoadAndSetCreature(id)
    local guid = format("unit:Creature-0-0-0-0-%s-0", id);
    local data = C_TooltipInfo.GetHyperlink(guid);
    if not data then
        print("Requesting creature load");
        EventUtil.RegisterOnceFrameEventAndCallback("TOOLTIP_DATA_UPDATE", function() SetCreature(id) end);
    else
        print("Creature already cached");
        SetCreature(id);
    end
end

local b = CreateFrame("Button", nil, model, "UIPanelButtonTemplate");
b:SetSize(125, 30);
b:SetPoint("LEFT", model, "RIGHT");
b:SetText("Set Creature");
b:SetScript("OnClick", function() LoadAndSetCreature(CREATURE_ID) end);