Thread Tools Display Modes
08/14/15, 09:30 AM   #1
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
Arrow What is a Scene, the SceneManager and other concepts

I've been fooling around here fore about 2 weeks now. I even published my very first - and beta - add-on.

I've spent some dozens hours now reading the game UI code base.

Still, I don't grasp most of the concepts here, for instance, what is a Scene ?

And I come from a web development background, so I'm not a layman at all.

I don't mean to sound ungrateful, I know and value all the effort and time put into the wiki, but I think it lacks broader introductions to how things work, and the concepts involved.

Things like:

1. Event and initialization order, for instance, does the GUI is ready when the load event is triggered ?
2. The most prominent ZO_* objects, what they're for and how can you benefit from them
2. Callbacks; I know what they're but what are some actual use cases, besides events I haven't see any asynchrony
3. Other stuff that once you discovered allowed you to write add-ons more efficiently and add more features

I'm willing to expand the wiki once I understand more of all this!

Thanks for everything so far and for everything to come!
  Reply With Quote
08/14/15, 10:07 AM   #2
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
About scenes is alot to say:
  1. All UI (especially in-build) are scenes.
  2. Scenes are groups of FRAGMENTs and FRAGMENTs wrapping Top-Level-Controls.
    One fragment can be part of several scenes.
    e.g. if a fragment is a child of HUD_SCENE and HUD_UI_SCENE (with mouse pointer) it will be visible in both modes.
    If a fragment is child of LOOT_SCENE it is visible while looting, and so on.
    The visibility is automatically handle from build-in (native?) code. So you don't need to.
  3. There are build-in "classes" for fragments, which already handle nice fade-in/fade-outs.
  4. There are fragments automatically handling to enable some backgrounds, showing mouse, turn your avatar (which in opposite can be disabled just by removing the fragment)

Ayantir and Garkin (two of our Grandmasters) already wrote examples and libs:
http://www.esoui.com/downloads/info989-LibMainMenu.html
http://www.esoui.com/portal.php?&id=27&pageid=12

If you use ZO_FadeSceneFragment, always specify a fade-out duration less than 200ms:
Lua Code:
  1. local fragment = ZO_FadeSceneFragment:New(yourTopLevelWindow, true, 150)
See, why:
Secure Render Mode Bug

You can take a look to Rare Fish Tracker for fadings > 200ms.
  Reply With Quote
08/14/15, 10:12 AM   #3
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by haggen View Post
Still, I don't grasp most of the concepts here, for instance, what is a Scene ?
A Scene is like a mode of the UI. When you login, you see the "hud" scene. When you open inventory, the SceneManager makes a transition to the "inventory" scene, and when you close inventory, back to "hud".

Every Scene contains Fragments. A Fragment may be visual -- displaying a TopLevelControl, e.g. the inventory window with buttons and a list of items -- or behavioral -- switching keybinding sets for example. When a Scene is shown, its fragments are shown/activated, and all other fragments are hidden/deactivated. A fragment may be contained in multiple scenes at once, in which case transitions between those scenes keep the fragment shown ("mailInbox" and "mailSend" are two scenes with common interface, and you can't even notice they're different scenes when switching the tab).

Originally Posted by haggen View Post
1. Event and initialization order, for instance, does the GUI is ready when the load event is triggered ?
The order in which you list files in addon manifest.txt matters. The files are interpreted in that order (both Lua and XML). So if your XML defines a (non-virtual) control with an <OnInitialized> handler, the control is created right after the XML has been parsed, and if the handler calls one of your global functions, the Lua file defining that function must precede the XML in the manifest. ZOS Lua and XML sources are run before any add-ons, so most of their controls already exist by the time add-ons load. Not all of them, though, for example Character sheet contents is not created until its Scene is shown for the first time.

After all add-ons have been compiled and executed, EVENT_ADD_ON_LOADED events are generated.

Originally Posted by haggen View Post
2. Callbacks; I know what they're but what are some actual use cases, besides events I haven't see any asynchrony
They're useful for implementing publisher-subscriber pattern. For example SHARED_INVENTORY holds a cache of inventory slot data, and defines callbacks anyone interested in inventory contents updates can subscribe to.
  Reply With Quote
08/14/15, 10:41 AM   #4
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
@merlight and @votan thank you so much, you already have given me enough to chew on for days!

One question though; when developing an add-on with a form-like GUI, should I use an existing scene or scene fragment or should it reside in its own ? And why ?
  Reply With Quote
08/14/15, 11:08 AM   #5
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by haggen View Post
@merlight and @votan thank you so much, you already have given me enough to chew on for days!

One question though; when developing an add-on with a form-like GUI, should I use an existing scene or scene fragment or should it reside in its own ? And why ?
1 Fragment <-> 1 TopLevelControl, so your own fragment. As for scene, that depends on when/where you want to show the fragment.

A) If you wanted to add another tab to the guild interface (the four existing tabs switch scenes), you'd probably create a new scene, add some of the common fragments in there (e.g. the background and the guild selection dropdown), and add your own fragment to that.

B) If you wanted to show your form next to the character sheet, you'd add your fragment to the existing "stats" scene.
  Reply With Quote
08/14/15, 11:19 AM   #6
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
Originally Posted by haggen View Post
@merlight and @votan thank you so much, you already have given me enough to chew on for days!

One question though; when developing an add-on with a form-like GUI, should I use an existing scene or scene fragment or should it reside in its own ? And why ?
For example: In Potion Maker you have a new scene to fade/hide all other elements (if outside crafting station) I reuse the right background fragment, which is the same as at the crafting station or inventory.
It may also helps you to keep a look'n'feel.

And why? Because all controls are created forever and use memory forever. If you can re-use, why not.
Another nice topic: control-pools.
  Reply With Quote
08/14/15, 01:12 PM   #7
Lodur
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 108
I just want to add another topic which I have been wondering about.

- GUI size units and scaling.


What are the units on when you do something like in XML:
Code:
<Dimensions x="750" y="52" />
Is it screen resolution? What is the aspect ratio of the screen. What happens when someone plays in a different screen resolution / aspect ratio?

What are the best practices for building a GUI that scales correctly?
  Reply With Quote
08/14/15, 01:29 PM   #8
Wandamey
Guest
Posts: n/a
Originally Posted by Lodur View Post
What are the best practices for building a GUI that scales correctly?
from what i have experienced, i'd say the less you bother, the better it will look.
Just do thing so they look well proportionned on your screen, it should render the same for everybody.

try to change your UI scale in the UI settings of ESO to see that everything is handled without you having to touch anything.

you can lock/unlock the scaling of controls in special situations (text Inside a preformatted tooltip, etc...) but messing with the maths behind the scale is just asking for problems.

now i'm a bit limited to test things on many resolutions. But from the screenshot/videos i've seen, i'm confident the game looks the same whatever the screen size.

and the units, you answered yourself, they seem to be GUI size units

edit : scale is inherited from parents to children, so that's the only thing you have to care for : placing elements one according to the other (with raw dimensions), then scale the top one if needed.
If you need to do something that looks proportional to the window/screen you can use as raw dimensions something alongside of : width, height = yourproportion * GuiRoot:GetDimensions() -- didn't check the syntax, but you'll get the idea-- knowing that the result will be scalable again with SetScale()
But that may force you to use % for all children dimensions depending on what you're doing
Better start with fixed dimensions (choose it with the default scale UI setting) then later on you'll always be able to add an option to rescale if needed.

rereredit, idk if we can use something similar to $lang to conditionally set dimension of a "sub"ui according to some Guiroot sizes ranges (like bootstrap could do for example) but i don't see why not if you have some very specific needs to do something like that.

Last edited by Wandamey : 08/14/15 at 04:10 PM.
  Reply With Quote
08/14/15, 03:47 PM   #9
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Some great technical answers have already been given, so I tried to list a few more basic answers.

Originally Posted by haggen View Post
Still, I don't grasp most of the concepts here, for instance, what is a Scene ?
A scene is a group of fragments (windows) that are shown/hidden all at once when the scene is shown/hidden. So basically it just shows/hides a group of objects so you don't have to show/hide each individual object.

Originally Posted by haggen View Post
2. The most prominent ZO_* objects, what they're for and how can you benefit from them
Heres a thread where it was discussed: zo_objects

Originally Posted by haggen View Post
2. Callbacks; I know what they're but what are some actual use cases, besides events I haven't see any asynchrony
They are used when you need to run code after something happens, typically used when there is not a pre-defined event for something. Merlights example of using callbacks with the inventory is a great example. Some others might be if you need to run some code when the fence "Sell" panel or the fence "Luander" panel opens. There is an event for when the fence window opens or closes, but not for the invididual "sell" & "launder" panels. You could register a callback
Lua Code:
  1. FENCE_MANAGER:RegisterCallback("FenceEnterSell", OnFenceEnterSell)
  2. FENCE_MANAGER:RegisterCallback("FenceEnterLaunder", OnFenceEnterLaunder)
And then whenever that window/panel is shown it will run your function. Other useful ones might be when the map changes, or when a scenes state changes (when it is shown/hidden).
Lua Code:
  1. WORLD_MAP_SCENE:RegisterCallback("StateChange", OnMapStateChange)
  2. CALLBACK_MANAGER:RegisterCallback("OnWorldMapChanged", OnWorldMapChanged)

Originally Posted by haggen View Post
One question though; when developing an add-on with a form-like GUI, should I use an existing scene or scene fragment or should it reside in its own ? And why ?
It depends on when you want it shown. If you want your GUI to show "with" the other fragments in a scene, then you would put it into that scene. For example if you created something that was related to the world map, you may only want it to show when the world map is shown, so put it in that scene. If your GUI is unrelated to, or not strictly tied to, the fragments in any given scene then you probably want to create your own scene for it.


Originally Posted by haggen View Post
3. Other stuff that once you discovered allowed you to write add-ons more efficiently and add more features
  1. Using the free program "Total Commander" that allows you to search multiple files at once to search the eso lua code for functions/constants to allow me to see an example of how it is used. I'm sure there are other programs that do this, but this is one Garkin told me about & I would not have been able to do a fraction of what I have done without it.
  2. Knowing how to look up functions, constants, & their values in game. You can look them up on the wiki, but this has saved me a lot of time. There are at least 2 addons that I know of that do the work for you Click4Info and Mer Torchbug
  3. Learning how to use zgoo or merlights new Mer Torchbug
  4. Using some type of ingame notepad that allows you to write & run code from within the game so you don't have to alt+tab out, write some code, go back to the game, & reload the ui to test something. Addons that do that: Click4Info and ZAM Notebook
  Reply With Quote
08/15/15, 04:28 PM   #10
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
This is real gold, thank you so much guys!

My schedule's kinda tight but I'll definitely take some time to organize the content and write it down.
  Reply With Quote
08/15/15, 04:37 PM   #11
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
Look at this http://esodata.uesp.net/100011/data/...ForUpdate.html

You'll see a bunch of cases where the game code calls RegisterForUpdate function on a control. I'm only 90% sure of what it does, do you guys know ?

What I got from it is that it registers a callback for when a given UI is updated (more like a tick, and many times per second actually, maybe the same as frames per second) but I'm not sure about the second argument, which looks like a delay. Maybe it's something like, "on update call this, but only once every X milliseconds" ?

Last edited by haggen : 08/15/15 at 04:50 PM.
  Reply With Quote
08/15/15, 05:01 PM   #12
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
Originally Posted by haggen View Post
Look at this http://esodata.uesp.net/100011/data/...ForUpdate.html

You'll see a bunch of cases where the game code calls RegisterForUpdate function on a control. I'm only 90% sure of what it does, do you guys know ?

What I got from it is that it registers a callback for when a given UI is updated (more like a tick, and many times per second actually, maybe the same as frames per second) but I'm not sure about the second argument, which looks like a delay. Maybe it's something like, "on update call this, but only once every X seconds" ?
RegisterForUpdate is one of EVENT_MANAGER's methods which calls function in specified intervals.
Lua Code:
  1. EVENT_MANAGER:RegisterForUpdate(identifier, interval, function)

identifier (string) - unique identifier, you can use for example name of your addon or some kind of description. If you register the same identifier again, it will overwrite previous function call.
interval (integer) - interval in milliseconds between function calls
function (function) - function which will be called


Example - function OnUpdate is called every 5 seconds (5000ms):
Lua Code:
  1. EVENT_MANAGER:RegisterForUpdate("DurabilityWarner", 5000, OnUpdate)

If you want to unregister this function call, use:
Lua Code:
  1. EVENT_MANAGER:UnregisterForUpdate(identifier)

Last edited by Garkin : 08/15/15 at 05:05 PM.
  Reply With Quote
08/15/15, 06:56 PM   #13
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
Originally Posted by Garkin View Post
RegisterForUpdate is one of EVENT_MANAGER's ...
Thanks a lot! That was exactly what I thought
  Reply With Quote
08/15/15, 07:02 PM   #14
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Unless I misunderstand what you meant:
Originally Posted by Garkin View Post
identifier (string) - unique identifier, you can use for example name of your addon or some kind of description. If you register the same identifier again, it will overwrite previous function call.
It does not overwrite the previously registered update.

If you try to register it twice (without unregistering):
Lua Code:
  1. EVENT_MANAGER:RegisterForUpdate("DurabilityWarner", 5000, OnUpdate)
  2. EVENT_MANAGER:RegisterForUpdate("DurabilityWarner", 1000, SomeOtherUpdate)
It will still call OnUpdate, every 5000 ms. The second register does nothing.
  Reply With Quote
08/15/15, 07:44 PM   #15
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
Am I bugging you guys too much ? I hope not

Another question: I just found this post http://www.esoui.com/forums/showthread.php?t=2136 about localization/internationalization strings.

But why should I bother to learn that, when I could simply do something like...

Code:
GetMyString = { ["Hello"] = "Hello" }
GetMyString["Hello"]
What's the benefit here of following the ZO standard ?

Thanks again!
  Reply With Quote
08/15/15, 08:00 PM   #16
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by haggen View Post
Am I bugging you guys too much ? I hope not

Another question: I just found this post http://www.esoui.com/forums/showthread.php?t=2136 about localization/internationalization strings.

But why should I bother to learn that, when I could simply do something like...

Code:
GetMyString = { ["Hello"] = "Hello" }
GetMyString["Hello"]
What's the benefit here of following the ZO standard ?

Thanks again!
Because in your example no matter what language the user is using
Lua Code:
  1. GetMyString["Hello"]
  2. -- would give you "Hello"
So it would always be in English.


The method discussed in that thread is used to get strings for the users client language.
As Garkin posted:
Lua Code:
  1. ## Title: My Addon
  2. ## Version: 1.0
  3. ## Author: Garkin
  4. ## APIVersion: 100008
  5.  
  6. Lang/$(language).lua
  7. addon.lua

The Lang/$(language).lua line would automatically load the correct language file (see code below) for the users current language. Each language file you create would have different definitions in it.

Lua Code:
  1. -- Lang/en.lua (english language file):
  2. ZO_CreateStringId("STRING_JEWELRY", "Jewelry")
  3.  
  4. -- Lang/de.lua (german language file):
  5. ZO_CreateStringId("STRING_JEWELRY", "Schmuck")
  6.  
  7. -- Lang/fr.lua (french language file):
  8. ZO_CreateStringId("STRING_JEWELRY", "Bijoux")

This way you do not need to worry about what language the client is using. When you call
Lua Code:
  1. GetString(STRING_JEWELRY)
If the users client is in english it will return "Jewelry", if the client is in german it will return "Schmuck", if it is in french it will return "Bijoux", exc...

It frees you from having to worry about what language the users client is in. Otherwise every time you wanted to do your version of GetMyString, you would have to have something like this:

Lua Code:
  1. GetMyString = { ["EnJewelry"] = "Jewelry", ["DeJewelry"] = "Schmuch", ["FrJewelry"] = "Bijoux" }
  2. -- Then you would have to determine what language the client
  3. -- was in and then get the appropriate string for that language:
  4. GetMyString["EnJewelry"]

I should point out this is not something you have to do. This is only done if you are concerned with translating/displaying the strings in the users client language. If you are not concerned with that, then there would be nothing wrong with just defining the strings in normal variables & just using them when you need them:
Lua Code:
  1. local lootMsg = "You looted something!"
  2. ...
  3. local function OnLoot()
  4.    d(lootMsg)
  5. end

Last edited by circonian : 08/15/15 at 09:34 PM.
  Reply With Quote
08/15/15, 08:08 PM   #17
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
Question

@circonian now I see that my example was bad.

Say you use $(language) to include the correct file, and in each locale file you put something simpler, like:

Code:
-- EN.lua
STRING_JEWELRY = "Jewelry"
Code:
-- DE.lua
STRING_JEWELRY = "Schmuch"
Then in your add-on you simply use:

Code:
-- ...
STRING_JEWELRY
Is it worse than the ZO standard of using CreateString and GetString ? And why ?

Thanks

Edit. I ask because the concept I illustrated above is clear enough and seems to work pretty well: you use the same variable name but load different files and bingo it all works. But maybe the localization API provided (GetString, etc.) has more implications than what meets the eye.

Last edited by haggen : 08/15/15 at 08:13 PM.
  Reply With Quote
08/15/15, 09:18 PM   #18
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by haggen View Post
Is it worse than the ZO standard of using CreateString and GetString ? And why ?
What you did would work. Is it worse, I'm no expert on this, but I can't think of a reason why it would be for most addons. Either way STRING_JEWELRY gets defined as a global & your way it would not have to look up the index in the EsoStrings table. You would just loose some extra functionality.

As for the differences in methods, there are also these functions:
Lua Code:
  1. SafeAddVersion(stringId, stringVersion)
  2. SafeAddString(stringId, stringValue, stringVersion)
SafeAddVersion(...) can be used to assign a version number to a stringId. SafeAddString(...) can be used to update a stringId's corresponding string, while at the same time checking the version numbers to ensure that you are not overwriting a newer version of the string with an older version of the string.
This would not be possible using the method you implemented without writing your own versioning code (which would probably be just copying the games code), but since its already available using ZO_CreateStringId that would be pointless. Although to you, creating an addon, this would make no difference because I highly doubt you would need this functionality.

GetString does have an extra parameter contextId:
Lua Code:
  1. GetString(string stringVariablePrefix, integer contextId)
  2.    Returns: string stringValue

This allows you to do things like:
Lua Code:
  1. equipTypeName = GetString("SI_EQUIPTYPE", equipType)
and if, for example, equipType == 8, then it would return "Waist" which is "SI_EQUIPTYPE8"
Your way you would probably end up doing several if statements:
Lua Code:
  1. if equipType == 8 then d(MY_EQUIPTYPE_WAIST)
  2. elseif equipType == 9 then d(MY_EQUIPTYPE_LEGS)
  3. ...
Although there are ways around that, you could write your own GetString(...) func to mimic that functionality of GetString(...) and it would work the same with your method. Of course once again you would just be rewriting code/functions that are already available to us.

GetString(...) will return "[Empty String]" (literally a string with that text) if the stringId does not exist.

Last edited by circonian : 08/15/15 at 09:43 PM.
  Reply With Quote
08/15/15, 09:29 PM   #19
haggen
 
haggen's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2015
Posts: 137
@circonian Thanks fella! That's clear as it can get, and I'll totally favor ZO standards.
  Reply With Quote
08/16/15, 02:22 AM   #20
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
There is another use of ZO_CreateStringId and SafeAddString:
In your manifest file you could do:
...
lang\strings.lua
lang\$(language).lua
...


in strings.lua you define the id with default text (english)
ZO_CreateStringId("SI_ADDONNAME_TEXT1", "what ever")
...

and in the other files you do, e.g. de.lua:
SafeAddString(SI_ADDONNAME_TEXT1, "was auch immer")
...

This way strings default to english if:
1. The language is not translated at all. (language file missing)
2. You have new, yet not translated, strings.
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » What is a Scene, the SceneManager and other concepts

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