Addon Structure

From ESOUI Wiki

Jump to: navigation, search

An add-on is defined by a folder, containing a manifest file, in the form:

   ExampleAddon\ExampleAddon.txt

The folder and the manifest file (ExampleAddon and ExampleAddon.txt) must have matching names.

The manifest file contains comments, directives, and the metadata that ESO uses to load and display add-ons, and the list of files (*.lua, *.xml, and textures *.dds) that are loaded as part of the addon. Any files not listed in the manifest are ignored and become inaccessible to this add-on from within the game.

Contents

How ESO finds, and loads add-ons

At startup, ESO recursively scans the add-on folder and all of its subordinate (i.e. nested) folders to compile a list of folders that contain a manifest. The recursive scan can be up to three levels deep, so all of the following should be discovered as add-ons:

   TopLevelAddon\TopLevelAddon.txt
   PointlessFolder\StrangeAddon\StrangeAddon.txt
   TopLevelAddon\NestedAddon\NestedAddon.txt
   TopLevelAddon\NestedAddon\EvenDeeper\EvenDeeper.txt

If ESO finds duplicate add-ons in the list, ESO consults the AddOnVersion: directive, that should be present in every manifest, and loads only the add-on with the largest positive integer value in its metadata field. If the directive or its metadata field is missing, the "first" add-on found in the "on-disk order" list is selected. In other words, one of the duplicates is randomly picked and loaded.

Add-ons are defined by their name, not their path, so these add-on paths all define ExampleAddon, and one of them could be chosen to be loaded subject to the AddOnVersion: rule.

   ExampleAddon\ExampleAddon.txt
   NestedFolders\ExampleAddon\ExampleAddon.txt
   DeeplyNestedFolders\MoreFolders\ExampleAddon\ExampleAddon.txt

Once the list of unique add-ons has been determined, ESO uses the folders listed in the DependsOn: and OptionalDependsOn: metadata fields to sort the list. This (topologically) sorted list is used during add-ons initialization.

If an add-on specifies that it DependsOn: another add-on, and that dependency add-on is not present, ESO will not load the requesting add-on. OptionalDependsOn, however, behaves the same way as DependsOn for sort ordering, but this directive will not prevent loading the requesting add-on if a dependency add-on cannot be found.

ESO will then load the *.lua and *.xml files specified in the add-on manifest, in the order they appear in the manifest. You can rely on this order within your individual add-on but you CANNOT depend on any other add-on being loaded before yours -- not even if you specify its folder in the dependency list for your own add-on. You must include .lua code within your add-on to wait until your add-on receives an EVENT_ADD_ON_LOADED event; then, and only then, is your add-on permitted to interact with other add-ons.

Once all of the add-on code has been loaded, ESO runs through the list of sorted add-on names and signals each one that it has been loaded. Every add-on listening for EVENT_ADD_ON_LOADED will receive event signals for every add-on; therefore, whenever you receive an EVENT_ADD_ON_LOADED signal, you should compare its name with your own add-on name before you perform your add-on initialization. If you try to initialize anything prior to receiving this signal, you may wind up with overwritten saved variables and other, random, data corruption issues.

Embedded Directory and SubFolder Nesting

Sometimes add-ons, libraries, dependencies, and/or other modules are embedded within an add-on folder. ESO lets you nest directories and folders up to three levels below its AddOns folder.

Until recently (i.e. 2018), library and dependency add-ons (e.g. any folders in the libs\ directory) were loaded by the add-on manifest (e.g. FooAddon\FooAddon.txt) file by invoking the directory, folder, and dependency add-on names (e.g. libs\FooLibrary\FooLibrary.lua) from within the same FooAddon.txt file text area that loaded the add-on *.lua, *.xml, and *.dds files.

Example 1: Illustrates a typical "old style" directory and folder nesting tree:

Elder Scrolls Online\live\AddOns
  |
  +-- FooAddon\
        |
        +-- FooAddon.txt    (1)(2)
        |
        +-- FooAddon.lua
        |
        +-- BarAddon\
        |     |
        |     +-- BarAddon.txt    (2)
        |     |
        |     +-- BarAddon.lua
        |
        +-- icons\
        |     |
        |    ...
        |
        +-- libs\
              |
              +-- FooLibrary\
                    |
                    +-- FooLibrary.txt    (1)
                    |
                    +-- FooLibrary.lua

When ESO added the capability to track add-on versions (see the AddOnVersion: directive), library add-on versioning (e.g. the LibStub add-on) became redundant because ESO could now treat all add-ons, libraries, and dependencies as versioned, stand-alone add-ons.

Just like stand-alone add-ons (e.g. LUI Extended, SkyShards, LoreBooks, The Elder Bar, Votan's MiniMap, etc.), stand-alone library add-ons and stand-alone dependency add-ons MUST have manifest files within their folders. This change means library and dependency addons get the option to specify and use saved variables file(s) and all add-ons get improved loading options as defined by the AddOnVersion:, DependsOn:, and OptionalDependsOn: directives.

Example 2: illustrates a revised "new style" folder and directory nesting tree:

Elder Scrolls Online\live\AddOns
  |
  +-- LibStub\             (3a)
  |     |
  |     +-- LibStub.txt
  |     |
  |     +-- LibStub.lua
  |
  +-- FooAddon\
        |
        +-- FooAddon.txt    (1)(2)
        |
        +-- FooAddon.lua
        |
        +-- FooLibrary\
        |     |
        |     +-- FooLibrary.txt    (1)
        |     |
        |     +-- FooLibrary.lua
        |     |
        |     +-- LibStub\             (3b)
        |           |
        |           +-- LibStub.txt
        |           |
        |           +-- LibStub.lua
        |
        +-- BarAddon\
        |     |
        |     +-- BarAddon.txt    (2)
        |     |
        |     +-- BarAddon.lua
        |
        +-- icons\
        |     |
        |    ...
        |
       ...

Testing

The keyed paragraphs link their numbered descriptions to their equivalent numbered areas in the two nesting tree examples. The keyed paragraphs describe what the testers observed while testing the revised nesting structure and its impact on the ESO loading directives.

(1) The DependsOn: FooLibrary directive in the FooAddon\FooAddOn.txt manifest file tells ESO to look for a FooLibrary folder within its (i.e. FooAddon) folder. ESO looks for a newer version of FooLibrary.lua as defined by the AddOnVersion: directive in the FooLibrary.txt file. If ESO finds one, it tries to load it; otherwise, ESO loads the FooLibrary.lua file from its add-on catalog. If there is no FooLibrary.lua file in the FooLibrary folder or in the ESO catalog, or if ESO cannot load the FooLibrary.lua file, ESO notes the error and refuses to load the FooAddon.lua file.

(2) The OptionalDependsOn: BarAddon directive in the FooAddon\FooAddOn.txt manifest file tells ESO to look for a BarAddon folder within its (i.e. FooAddon) folder. The ESO loader looks for a newer version of BarAddon.lua as defined by the AddOnVersion: value in the BarAddon.txt file. If ESO finds one, it tries to load it; otherwise, ESO loads the BarAddon.lua file from its add-on catalog. If there is no BarAddon.lua file in a BarAddon folder or in the ESO catalog, or if ESO cannot load the BarAddon.lua file, ESO notes the error but loads the FooAddon.lua file anyway.

Note: The ESO actions for (1) and (2) were identical in both nesting tree examples. ESO took the same actions to load the add-ons regardless of which nesting tree was used. Whenever an add-on failed to load, the reason for the failure was traced back to one or more packaging mistakes (e.g. something was missing or incorrectly entered; a manifest, a directive, a nested folder, etc.). 99% of the time, the addon loaded successfully after its packaging mistakes were corrected.

(3a) When you load any library add-on (e.g. LibStub) directly into your .../AddOns/... folder as a stand-alone, "new style" library, you should remove all references to its folder name in all DependsOn: or OptionalDependsOn: directives within any subordinate manifests and you should remove all its folders from within any subordinate folders. For example, (3b) is wrong; the LibStub folder should not be there.

(3b) Is very similar to the embedded example (1) in both nesting trees above with two exceptions. When you load any library add-on (e.g. LibStub) as a dependent, "old style" library, you cannot force it to load by putting a LibStub/LibStub.lua command into the manifest file text area; you MUST add its folder name into a DependsOn: directive in the add-on manifest, and you MUST embed its folder (and manifest file) within that add-on. For example, the LibStub folder (3b) has to be there.

Note: You can change packaging styles for add-ons on an individual basis, but you must coordinate internal changes to its subordinate add-on folders at the same time.

Observations

The paragraphs in this section contain personal observations and comments from testers so be aware that these paragraphs may disappear at some point in the future because personal comments have no place within reference material; however, some testers felt that their comments might help newcomers to the wiki discover why their add-on(s) were not loading or were displaying run-time errors after they appeared to load correctly.

(3) The reason for testing revised nesting trees with LibStub was to prove that we could remove obsolescent, embedded, "old style" library add-ons like LibStub from their respective host folders without impacting "old style" add-on nesting trees provided the "old style" add-ons were properly packaged to contain manifest files, and the manifests contained accurate and current metadata. This was proven to be successful on, 8 November, 2018, by successfully using Baertrams FCO Item Saver to test "new style" add-ons and Blagbird's QuestMap 2.0.2 to test "old style" add-ons. At least two Libstub folders, one stand-alone (3a) and many embedded (3b), were present within our testing environments (i.e. ...Live/Addons/ directory) during all tests.

Two reasons for selecting the obsolescent LibStub library loader as the test example for the revised nesting tree (3) are that LibStub is embedded within almost every stand-alone add-on (e.g. Skyshards) and more often than not, it is embedded within multiple "old style" libraries (e.g. LibAddonMenu-2.0, LibGPS2, LibMapPing, LibMapPins-1.0, and many, many more). One possible benefit of starting with a move to a stand-alone, LibStub add-on, is that we can remove many, many redundant and possibly obsolete, Libstub folders from the existing ESOUI library add-ons catalog. Another possible benefit is that we can make library manifest files look and operate more like "new style" library manifest files that do not use LibStub at all.

The advantages to using stand-alone library add-ons for you, the user, is that you only have to load one add-on, library, or dependency folder, and when downloaded from ESOUI (or Minion), that folder is usually the latest one. Fewer addon folders make the game and your character(s) load and zone faster.

The advantage to us, the developers, is that we spend less time maintaining our add-ons because we have fewer add-on, library, or dependency folders to include in our own updates, which means we have fewer add-ons to check, update, and repackage.

A possible developer benefit is our not having to perform folder maintenance every time ESO issues a new API. This is an unknown benefit at this time because ESO has not published what the interactions between the AddOnVersion: and the APIVersion: directives will be. Hopefully, the former will determine when an add-on goes "Out-of-Date" and the latter will be checked only when an add-on is updated. This is all speculation but one can always hope for the best.

Some testers did experience stand-alone add-ons that refused to load during testing and stand-alone add-ons that loaded but then got run-time errors when characters entered the game; however, every failure and every error was traced back to packaging mistakes such as missing manifest files or manifest files that did not contain all of their basic directives. This was particularly true of those add-ons whose manifests did not contain an AddOnVersion: directive.

Missing Folders and Files

This "helpful hints" section may disappear at some point in the future because it contains opinions rather than fact.

If your add-on fails to load due to missing folders or files, you need not make changes to your add-on manifest file. All you need do is to include the missing folders within the same .zip file as your addon folder. This should make ESO create stand-alone add-ons (3a) that your add-on can reference provided the proper code and manifest content (.lua and .txt) files are present. But be aware that doing this may cause other add-on loads to fail because of idiosyncrasies and inconsistencies within their add-on folders.

If you did not create the failed add-on, the optimum solution is to use the ESOUI Comments page for the problem add-on to let its Author know you experienced a problem and to describe the problem in sufficient detail that the author can fix it.

If the problem is a missing manifest file, use the same ESOUI Comments page method to report the missing manifest to the Author.

As a last resort, and only as a temporary fix, you can check the infamous "Out Of Date" (OOD) box in the Addons List window to see if that solves the problem. Please refer to the APIVersion: directive for more information about the impact of using this option.

Personal tools
Namespaces
Variants
Actions
Menu
Wiki
Toolbox