Skip to content

Getting started ​

Nyx runs inside the WoW 3.3.5a client (build 12340). A loader injects the engine into the running game; the engine removes the client's Lua protection in memory, then reads the framework and your rotations off disk.

The unlock and the engine itself live only in memory and are gone the moment the process exits. One exception: the menu's icons and fonts are written to Interface\Nyx\ inside the game folder, because 3.3.5a can only load textures from there. Nyx.Loader.exe --remove-assets deletes that folder.

It is not tied to any particular server. The patches, offsets and object-manager layout are properties of the 3.3.5a client, so Nyx works against any realm running that build.

What you get that the client does not give you ​

The 3.3.5a Lua API is missing several things a rotation genuinely needs. The engine supplies them by reading the client's own memory:

Missing from 3.3.5aSupplied here
World coordinates (UnitPosition does not exist)Nyx.Objects.Player() and every unit table
Units you have not targetedNyx.Objects.Nearby()
Line of sightNyx.Objects.LineOfSight()
Creature entry IDsentry on every unit table
Hitbox sizes, so melee range is exactcombatReach, Nyx.Objects.InMeleeRange()
Drawing in the worldNyx.Draw

Everything else — auras, cooldowns, casting — goes through the client's own API, wrapped so the awkward parts are handled. See things that bite for where those wrappers differ from what you might expect.

Naming ​

The framework lives in one global, Nyx. A short alias _N is defined too, and script authors who want a single letter should take a file-local one:

lua
local N = Nyx                    -- file-local, collides with nothing
N.Objects.Nearby(8)

Nyx.Objects.Nearby(8)            -- canonical, what this reference uses
_N.Objects.Nearby(8)             -- built-in alias

A bare global N is deliberately not defined: WoW's globals are one shared table across every addon, and a single capital letter is exactly the sort of name something else grabs for a locale or utility table.

Engine natives sit under Nyx.Engine. You rarely need them directly -- the Nyx.* layer wraps them -- but they are documented, and a few (Nyx.Engine.w2s, Nyx.Engine.los, Nyx.Engine.dump) are useful on their own.

Where your code goes ​

rotation-bot/External/
├── init.lua             the framework's single entry point
├── require.lua          the scoped Lua module loader
├── Nyx/                 state, safety, priority engine, drawing, and UI
└── Plugins/             the one root for every plugin
    └── MyPlugin/
        ├── manifest.lua plugin metadata
        └── init.lua     plugin entry point

Put each plugin in its own folder with manifest.lua and init.lua. Its manifest must declare api = 2; its init chunk receives a scoped context as its vararg. Plugin folder order is undefined, so a plugin must not depend on another plugin loading first. /nyx reload re-reads the framework and plugins without restarting the client. See writing a plugin.

If the engine lives somewhere other than the repository, point ZROTATIONS_ROTATION_ROOT at the directory containing Nyx/ and Plugins/.

First run ​

/nyx status      what class and spec it detected, and why it is idle
/nyx list        rotations it found
/nyx             toggle it on

The status frame's bottom line always says what the engine just did, or why it did nothing — no target, pacing, nothing ready, cast Mutilate. That line is the first place to look when a rotation is not doing what you expect.

Safety ​

The engine refuses to act while any of these hold, and /nyx status names the one that is blocking:

  • a loading screen, or not in the world
  • dead or a ghost
  • mounted, on a taxi, or in a vehicle
  • panicked — the panic key, or repeated script errors
  • no attackable target (Nyx.RequireTarget, on by default)
  • out of combat, if Nyx.RequireCombat is on (off by default)

CTRL-SHIFT-X stops it immediately and latches; press again to resume.

Next: writing a plugin.

API reference generated from source.