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.

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