Event Handler Priority System

From GECK
Jump to: navigation, search

Since xNVSE 6.2.9, a new priority system was established to determine which event handlers will be run first/second/.../last and easily detect priority conflicts. This primarily concerns SetEventHandler and SetEventHandlerAlt.

For example, a mod might need their OnHit UDF to run after most other OnHit events, to account for their scripted effects to a target's health.
This is what the priority system aims to streamline.

Note that this only applies to event handlers managed by xNVSE.

Prior Issues

Before, some mods resorted to modifying the load order for mods and using fast/slow Quest Script processing times in order to get their event handlers registered before/after handlers from other mods, to ensure their handlers would run when needed.

However, this approach has its flaws:

  1. It requires forcing users to shift their load orders according to vague guidelines to avoid priority conflicts
  2. It cannot account for events that are registered instantly with the JIP Script Runner.
  3. A single mod cannot have one handler that runs before all others, and another that runs after all others.

Advantages

To overcome this, the expanded priority system now allows users to define their handlers with a priority value.
Highest (greatest) priority value means the handler will run first before other handlers, lowest means it will run last.

Thanks to this, mods are no longer beholden to the registration order of an event handler to determine its priority.
However, priority conflicts may still happen, and cooperation between modmakers is key to preventing these. More details are in the Preventing & Handling Priority Conflicts section.

Details

Priority for handlers can now be specified when registering the handler via SetEventHandler and SetEventHandlerAlt. Syntax details are on those pages, but as an example, one can do:

SetEventHandlerAlt "SomeEvent" SomeUDF "priority"::2

This will set a handler with priority 2.

RemoveEventHandler also accepts a priority specifier as a filter for what handler to remove, and if it is omitted, then handlers will be removed regardless of priority.

If multiple handlers register with the same priority, then the handler registration order will determine which one will run first. Evidently, it isn't ideal to rely on registration order to get handlers from different mods to work together as intended, so working out a priority range to avoid conflicts is the best solution.

Priority Values

There are a few special priority values to take note of:

  • 1 is the default priority, for handlers that do not have a specified priority.
  • 0 is reserved as an invalid priority, for use in other functions where we don't want to filter by priority.

All other numbers, including negative numbers, can be picked as priorities.

  • 9999 is the max priority value.
  • -9999 is the min priority value.

Preventing & Handling Priority Conflicts

Modmakers get runtime tools to detect priority conflicts via IsEventHandlerFirst and IsEventHandlerLast.

However, mods should never report a priority-based issue unless absolutely necessary; the above are more for debugging.
Instead, they should use a priority value within a community-defined range, to allow some handlers to run before/after it, depending on the mod's needs.

For example, if we want to have an OnHit UDF that modifies all incoming damage, including damage dealt by other OnHit UDFs, then we can register it in a range between 7000-8000. We should do this because it would leave priorities 8000-9999 for other handlers that want to know how much total damage has been dealt without modifying that amount, so that those handlers could account for the damage changes our handler does.

Examples

SetEventHandlerAlt "OnHit" OnHitUDF

This will register OnHitUDF as a handler for the OnHit event with default priority (1)

SetEventHandlerAlt "OnHit" OnHitUDF "priority"::1000

This will register OnHitUDF as a handler for the OnHit event with priority 1000, so it will run before any handlers with a lower priority value (999 and below).

SetEventHandlerAlt "OnHit" OnHitUDF "priority"::0

This is invalid and will report an error; priority 0 is reserved as an invalid priority, for functions where we don't want to filter by priority.

SetEventHandlerAlt "OnHit" OnHitUDF "priority"::-999

This will register OnHitUDF as a handler for the OnHit event with priority -999, so it will run after any handlers with a higher priority value (-998 and above).

See Also