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! :) :) |
About scenes is alot to say:
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:
Secure Render Mode Bug You can take a look to Rare Fish Tracker for fadings > 200ms. |
Quote:
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). Quote:
After all add-ons have been compiled and executed, EVENT_ADD_ON_LOADED events are generated. Quote:
|
@merlight and @votan thank you so much, you already have given me enough to chew on for days! :D
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 ? |
Quote:
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. |
Quote:
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. |
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" /> What are the best practices for building a GUI that scales correctly? |
Quote:
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 :D 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. |
Some great technical answers have already been given, so I tried to list a few more basic answers.
Quote:
Quote:
Quote:
Lua Code:
Lua Code:
Quote:
Quote:
|
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. |
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" ? |
Quote:
Lua Code:
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:
If you want to unregister this function call, use: Lua Code:
|
Quote:
|
Unless I misunderstand what you meant:
Quote:
If you try to register it twice (without unregistering): Lua Code:
|
Am I bugging you guys too much ? I hope not :p
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" } Thanks again! |
Quote:
Lua Code:
The method discussed in that thread is used to get strings for the users client language. As Garkin posted: Lua Code:
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:
This way you do not need to worry about what language the client is using. When you call Lua Code:
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:
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:
|
@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 Code:
-- DE.lua Code:
-- ... 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. |
Quote:
As for the differences in methods, there are also these functions:
GetString does have an extra parameter contextId:
GetString(...) will return "[Empty String]" (literally a string with that text) if the stringId does not exist. |
@circonian Thanks fella! That's clear as it can get, and I'll totally favor ZO standards.
|
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. |
Continuing with localization, I like to have all of my strings in the same file so they are all in the same place when I need to edit them. Then I can use metatables to set a fallback option if I haven't gotten a particular string translated yet.
Lua Code:
After the index metatabe is set, strings["de"] essentially becomes a union of the original strings["de"] and strings["en"] with any matching keys pulled from strings["de"] rather than strings["en"]: Lua Code:
As for exactly why this works or what else you can use metatables for, I couldn't tell you. Metatables are basically magic to me right now :banana: I think making the decision to use this over votan's SafeAddString example really just comes down to personal preference. I suppose my method hogs more memory, but that shouldn't be an issue unless there are a lot of strings. If it did become an issue you could just nil the local strings table after the necessary ones were added to the game. |
@Randactyl that's not how it works.
strings["de"] is still the same table. The metatable's __index provides fallback values for missing keys. But it's only scanned when you explicitly request a missing key, e.g. strings["de"]["SI_MYADDON_GENERAL_OPTIONS_HEADER"]. Iterating over it with next/pairs will only see SI_MYADDON_NAME, because that's the only key in the table itself. To make it work, you need to iterate over the "en" table: Lua Code:
On a positive note, you don't have to clean the local strings table -- it should be garbage-collected afterwards. |
Hmm alrighty then, thanks!
|
I know this thread is old but my problem is quite related to the scene manager. It's acting very funny right know.
What I am doing: Code:
I am using a registered update handler to listen for desired (de-)buffs. This handler simply looks at a specified frequency if the effect is present and sets the boolean variable 'display' to true or false depending on wether the effect is present or not Code:
HUD_SCENE:RemoveFragment(AuraMastery.aura[auraName].sceneFragment); In clearer words, I: 1. create a top level control (TLC) 2. make it a shard 3. assign this shard to HUD_SCENE 4. updating handler (updating every 5frames): check if aura is present => if (not present): remove the shard from HUD_SCENE else add the shard from HUD_SCENE My problem: The control is visible if I start the game. To make it work I have to /reloadui, then everything runs flawlessly. Any ideas? |
All times are GMT -6. The time now is 12:58 AM. |
vBulletin © 2024, Jelsoft Enterprises Ltd
© 2014 - 2022 MMOUI