Object Tracking
Overview
The object tracking system represents game state as typed objects with declarative field schemas. ObjectTypes define what data is available, Objects are instances, and ObjectTrackers subscribe to changes.
Files
core/objects/objects.lua— Object class + Objects registrycore/objects/ObjectTracker.lua— Tracker with event-based subscriptionscore/objects/types/type.lua— ObjectType, GlobalType, UnitType base classescore/objects/types/unit/— Unit-based types (Health, Power, Aura, PVP)core/objects/types/Cooldown.lua— Cooldown tracking (GlobalType)core/objects/types/PlayerMoney.lua,PlayerXP.lua— Simple types
Type Hierarchy
ObjectType — Base: fields, params, templates. Minimal tracking (single static object).
├── GlobalType — Type-wide tracker/object lifecycle for non-unit types.
│ └── Cooldown — Spell cooldown tracking with event-driven updates.
└── UnitType — Unit-based tracking with GUID change detection.
├── Health — Unit health
├── Power — Unit power (mana/rage/energy/etc.)
├── Aura — Buffs and debuffs
└── PVP — PVP status
Object Class
local obj = WowVision.objects:create("Health", { unit = "player" })
obj.type -- Reference to ObjectType
obj.params -- Identifying params (e.g., {unit = "player"})
obj:get(field) -- Get field value
obj:exists() -- Check existence
obj:getLabel() -- Display label
obj:getFocusString() -- Formatted display string
obj:serialize() -- { type = key, params = {...} }
ObjectTracker
Subscribes to objects matching criteria, emits events on changes:
local tracker = WowVision.objects:track({
type = "Aura",
units = { "target" },
params = {},
})
tracker.events.add:subscribe(self, handler)
tracker.events.modify:subscribe(self, handler)
tracker.events.remove:subscribe(self, handler)
tracker.events.unitsChanged:subscribe(self, handler)
Param Filtering
ObjectTracker:verify(obj) checks trackingInfo.params against obj.params using exact equality. Only params specified in trackingInfo.params are checked — missing keys are ignored (pass-through).
Dynamic Filtering via modify
ObjectTracker:modify(obj) re-verifies the object:
- Verify passes + not tracked → add (emit
addevent) - Verify fails + tracked → remove (emit
removeevent)
This enables dynamic filtering when object params change at runtime (e.g., Cooldown’s onCooldown param flips when a spell becomes ready).
GlobalType
Type-wide tracker/object lifecycle for non-unit types. Objects belong to the type itself rather than to a unit.
local MyType = WowVision.objects:createGlobalType("MyType")
Methods:
addObject(key, data)/removeObject(key)/modifyObject(key, newData)— Object lifecycle, notifies all trackersaddTracker(tracker)/removeTracker(tracker)— Tracker subscriptionstrack(info)/untrack(tracker)— Create/destroy trackers
Subclass hooks:
getObjectParams(key, data)— Return params for new objectsgetObjectKey(params)— Extract key from params (for cache lookup)getCache(params)— Default implementation usesgetObjectKey
Cooldown (GlobalType subclass)
Tracks spell cooldowns. Auto-discovers spells from player casts:
UNIT_SPELLCAST_SENT→ queue pending spellSPELL_UPDATE_COOLDOWN→ if pending spell has real cooldown (not GCD), promote to tracked objectrefreshAll()runs each frame — detects state changes, updatesonCooldownparam, callsmodifyObject
The onCooldown dynamic param enables trackers to filter to only active cooldowns.
UnitType
Unit-based tracking with GUID change detection and per-unit object management:
local Health = WowVision.objects:createUnitType("Health")
Each tracked unit has a unitTable:
{
id = "player",
guid = "0x12345...",
frame = frame, -- For WoW event listening
trackers = {}, -- Active ObjectTrackers
objects = {} -- { key -> { object, data } }
}
GUID detection: onUpdate() polls UnitGUID() each frame. On change, changeUnit() removes all old objects, updates GUID, calls onUnitChange() to load new data, emits unitsChanged.
Event sequence during target change:
- Old objects removed →
tracker.events.remove - GUID updated
onUnitChange→fullUpdateadds new objects →tracker.events.addunitsChangedemitted
Field Caching
Fields can define getCached(cache) for fast reads from unit.objects[key].data, with get(params) as fallback hitting the WoW API live.
Data Flow
WoW event fires (e.g., UNIT_HEALTH)
→ ObjectType:onEvent() on unit's frame
→ modifyObject(unit, key, newData) → tracker:modify(object) for each tracker
→ ObjectTracker:modify() → verify → events.add/modify/remove:emit()
→ Monitor/Buffer subscriber handles the event
Creating a New Object Type
- Choose base:
createObjectType(static),createGlobalType(dynamic lifecycle),createUnitType(unit-based) - Add parameters and fields
- Implement
getCache(params)for cached field access - For GlobalType: implement
getObjectParams,getObjectKey, object lifecycle - For UnitType: implement
onUnitAdd,onUnitChange, event handling - Register a default template for display