Thread Tools Display Modes
02-07-17, 08:59 PM   #1
Tuhljin
A Flamescale Wyrmkin
 
Tuhljin's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2008
Posts: 106
Need event when world is loaded, game is playable

My addon needs to display some information to the player when they log in using the alert system, similar to how you get notices about achievements being earned on log in or garrison/order missions being completed. The problem is that all the methods I've found to do this are unreliable.

I'm looking for an event that is called when the game is actually playable: The player sees their character in the world and can now start playing (moving the character around, etc.). It should preferably be called after any loading screen has finished its job, but I will settle for one that triggers A) when the character "enters the world" for the first time from the character selection screen, and B) when the UI is reloaded (as from a /reload command or the "Reload UI" button on the in-game AddOn List).

The events I've been using all trigger too soon, while the game world is still loading. I've tried using C_Timer to add a delay, but this only works sometimes: It never works after a /reload, but it usually does when entering the world from character selection (but not always! the extra long loading screens in Dalaran seem to sometimes break it, for one). Frustratingly, the C_Timer functions apparently start counting down at some point while the loading screen is still visible (and that point seems to happen sooner when you do a /reload than it does when entering from character selection).

For my purposes, the event I'm looking for needn't happen at the exact moment the player character is playable, just so long as it is reliably triggered within a couple of seconds after that point.

Last edited by Tuhljin : 02-07-17 at 09:02 PM.
  Reply With Quote
02-07-17, 09:44 PM   #2
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Neither PLAYER_LOGIN nor PLAYER_ENTERING_WORLD work for you?
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
02-08-17, 12:05 AM   #3
Tuhljin
A Flamescale Wyrmkin
 
Tuhljin's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2008
Posts: 106
I've tried both of them individually and they don't work consistently. It's as described above: Usually on entering the game, never on /reload.

The alerts involve the in-game calendar, so I thought I'd try using OpenCalendar() inside PLAYER_ENTERING_WORLD and watching for CALENDAR_UPDATE_EVENT_LIST, but I end up with mostly the same problem, with one (rather odd) difference: The alerts do appear as intended after the first /reload... but not on any subsequent /reload (until you go back to character selection). I can tell the code that makes the alerts appear is called (since I added print messages), but the frames do not appear unless I put in so many alerts that there are too many to display at once, in which case the first batch are not shown but the rest (which would have gone to the queue) are.

I should note that the alerts I'm using are created using AlertFrame:AddQueuedAlertFrameSubSystem() with a custom template.

If I set the C_Timer to something especially long, the alerts will appear then, as well -- but that's not a good solution because the ideal wait time would vary from PC to PC and also can vary depending on what is being loaded, and we'd have an especially long delay in those cases where C_Timer wasn't counting down early (e.g. when entering the world from character select). (I really don't understand why C_Timer is counting down during the /reload process. This seems like a bug.) It would be much easier if I had an event that reliably triggered when the game world is fully ready.

Last edited by Tuhljin : 02-08-17 at 12:23 AM.
  Reply With Quote
02-08-17, 05:56 AM   #4
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Lua Code:
  1. local addonName, addonTable = ...
  2.  
  3. local EventFrame = CreateFrame('Frame')
  4. EventFrame:RegisterEvent('ADDON_LOADED')
  5. EventFrame:SetScript('OnEvent', function(self, event, ...)
  6.     if self[event] then
  7.         self[event](self, ...)
  8.     end
  9. end)
  10.  
  11. function EventFrame:ADDON_LOADED(name)
  12.     if name == addonName then
  13.         -- do the thing
  14.  
  15.         -- remove event
  16.         self:UnregisterEvent('ADDON_LOADED')
  17.         self.ADDON_LOADED = nil
  18.     end
  19. end

ADDON_LOADED will always fire on login and on reload, but not on loading screens or any subsequent loading in the game. While this might not be the best basis for showing your toast, you can use it as backbone to determine when to start things off.
__________________

Last edited by MunkDev : 02-08-17 at 06:00 AM.
  Reply With Quote
02-08-17, 09:44 AM   #5
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,857
The alerts involve the in-game calendar, so
The calendar is LoadOnDemand so won't actually be loaded and it's functions/data available until after the user clicks the calendar button.

You could try at PLAYER_ENTERING_WORLD:

Code:
if not IsAddOnLoaded("Blizzard_Calendar") then
	UIParentLoadAddOn("Blizzard_Calendar")
end
--- Your code goes here
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 02-08-17 at 11:56 AM.
  Reply With Quote
02-08-17, 10:11 AM   #6
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
In most cases the events prescribed do not load in any significant order. The way I have found, that works for me, is to wait until all three, replacing PLAYER_LOGIN since this occurs only once during a session, have been triggered and most information is available. This should include on ReloadUI but I am unsure if it will work for things like dungeon in/out. However, I am unaware if this will remedy your issue so I apologize in advance if this has wasted your time.


Lua Code:
  1. local frame = CreateFrame('Frame')
  2. local VariableLoadCount = 0
  3. local function LoadVariables()
  4.     VariableLoadCount = VariableLoadCount +1
  5.     if VariableLoadCount == 3 then
  6.         --you have reached the point where most information is now available
  7.         --safest place to create and populate frames
  8.         --unregister the events if no longer needed
  9.     end
  10. end
  11.  
  12. frame:RegisterEvent('PLAYER_ENTERING_WORLD')
  13. local function PLAYER_ENTERING_WORLD()
  14.     LoadVariables()
  15.     --self:UnregisterEvent('PLAYER_ENTERING_WORLD')
  16. end
  17.  
  18. frame:RegisterEvent('ADDON_LOADED')
  19. local function ADDON_LOADED(addon, ...)
  20.     if addon == addonName then
  21.         --safe place to create frames
  22.         LoadVariables()
  23.     end
  24. end
  25.  
  26. frame:RegisterEvent('VARIABLES_LOADED')
  27. local function VARIABLES_LOADED()
  28.     --safe place to populate frames
  29.     LoadVariables()
  30. end
  31.  
  32. frame:HookScript('OnEvent', function(self, event, ...)
  33.     if event == 'VARIABLES_LOADED' then
  34.         VARIABLES_LOADED()
  35.     elseif event == 'ADDON_LOADED' then
  36.         ADDON_LOADED(...)
  37.     elseif event == 'PLAYER_ENTERING_WORLD' then
  38.         PLAYER_ENTERING_WORLD()
  39.     end
  40. end)
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
02-08-17, 03:58 PM   #7
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Ah, getting info from the calendar. That's helpful to know.

In my Bear in Mind addon, I have the Blizzard_Calendar listed as a dependency. I then looked through the UI source code and found how they update and gather calendar info.

You can look in BiM.lua if you like to see how I gather the day's events (just don't straight up copy it ). The relevant code is at the end of the BiM.PlayerLogin function, which then also calls the CheckForCalendarEvents function above that.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
02-08-17, 04:13 PM   #8
Tuhljin
A Flamescale Wyrmkin
 
Tuhljin's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2008
Posts: 106
I already successfully grab the information I need from the calendar, and did so even if I was using only PLAYER_LOGIN or PLAYER_ENTERING_WORLD, so I don't think that's the problem.

According to this, PLAYER_ENTERING_WORLD fires after ADDON_LOADED and is considered the last startup event. But C_Timer starts ticking down while the loading screen is still visible when you do /reload (again, I think this is a bug), so it doesn't work properly with alert frames.

Is there not an event that fires when the game is actually playable, player in the world? Maybe one that actually signifies something besides "game now playable" but will reliably occur at that point? It could be one that triggers many times, even, just so long as the first time it triggers after PLAYER_ENTERING_WORLD is when the game world is shown.
  Reply With Quote
02-08-17, 05:03 PM   #9
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
I had a long seach for this as well and the best I could do was this:

Lua Code:
  1. local f = CreateFrame("Frame")
  2.  
  3. f:SetScript("OnEvent",function(self,event,...)
  4.     if event=="PLAYER_LOGIN" then
  5.         self:RegisterEvent("PET_JOURNAL_LIST_UPDATE")
  6.     elseif event=="PET_JOURNAL_LIST_UPDATE" then
  7.         self:UnregisterEvent("PET_JOURNAL_LIST_UPDATE")
  8.         --CALL YOUR STUFF HERE
  9.     end
  10. end)
  11. f:RegisterEvent("PLAYER_LOGIN")
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
02-08-17, 11:07 PM   #10
Tuhljin
A Flamescale Wyrmkin
 
Tuhljin's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2008
Posts: 106
I just tried PET_JOURNAL_LIST_UPDATE and it was still called too soon. Any other ideas?
  Reply With Quote
02-09-17, 12:30 AM   #11
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,857
As far as I know, noone has found a silver bullet event after PLAYER_ENERING_WORLD to cover all situations. Even Blizzard uses multiple events to cover login, logout/login and /reload scenarios for different parts of the game.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 02-09-17 at 01:05 AM.
  Reply With Quote
02-09-17, 12:30 AM   #12
Tuhljin
A Flamescale Wyrmkin
 
Tuhljin's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2008
Posts: 106
Sorry for the double post, but I seem to have found a workaround.

This doesn't work reliably:

Code:
C_Timer.After(3, function()
  ToastForEvents()
end)
... but this seemingly does:

Code:
C_Timer.After(0, function()
  C_Timer.After(3, function()
    ToastForEvents()
  end)
end)
Weird. I have a theory as to why it works, and it makes some sense as a programmer, but that doesn't make it any less unintuitive -- and I still think it would be considered buggy that /reload handles this so differently.

Edit: Turns out it wasn't a double post. Thanks, Fizzlemizz!

Last edited by Tuhljin : 02-09-17 at 12:36 AM.
  Reply With Quote
02-09-17, 01:24 AM   #13
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,308
Originally Posted by Tuhljin View Post
... but this seemingly does:

Code:
C_Timer.After(0, function()
  C_Timer.After(3, function()
    ToastForEvents()
  end)
end)
The first call is basically telling C_Timer to run it when it can. After the game has loaded, it actually runs and the second one schedules the final function for 3 additional seconds from then. The first example would vary depending if it took 3 seconds or longer to finish loading and push out the first rendered frame.

Trying to support /reload is a niche case and you should just make sure your code doesn't throw any errors. Ideally, nobody should need to use it in a normal session. It only exists because sometimes mistakes happen. You shouldn't need to complicate your code more covering other addons' problems.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 02-09-17 at 01:30 AM.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Need event when world is loaded, game is playable

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off