State Registrar
The State Registrar provides a robust system for tracking and managing state in your Aurora modules. It's particularly useful for tracking time-windowed events and maintaining state access.
Core Implementation
The state registrar consists of two main components:
StateExpression
: The core class for managing individual statesStateManager
: A global manager for all state expressions
Creating a State Expression
local myState = Aurora.StateExpression:New("my_state", 0)
The New
method accepts:
name
: Unique identifier for the statedefault
: Initial value (defaults to 0)
State Expression Properties
Each state expression contains:
{
name = "string", -- Unique identifier
value = any, -- Current state value
lastUpdate = number, -- Last update timestamp
window = number -- Time window in seconds (default: 5)
}
Core Methods
-- Register an event handler
myState:RegisterHandler("EVENT_NAME", function(self, now, ...)
-- Handle the event
end)
-- Update state based on an event
myState:Update("EVENT_NAME", ...)
-- Set the time window
myState:SetWindow(10) -- 10 seconds
Accessing State Values
-- Using __call metamethod
local value = myState()
-- Direct access
local directValue = myState.value
Advanced Example: Damage Tracker
Here's a comprehensive example that demonstrates the power of the state registrar by implementing a damage tracking system:
local StateExpression = Aurora.StateExpression
-- Create damage tracking state
local damageTaken = StateExpression:New("damage_taken")
damageTaken.hits = {} -- Store individual hits
-- Cleanup function for managing the hit window
local function cleanupOldHits(self, now)
local windowStart = now - self.window
local removed = 0
-- Remove old hits
while self.hits[1] and self.hits[1].time < windowStart do
table.remove(self.hits, 1)
removed = removed + 1
end
-- Recalculate total
local total = 0
for _, hit in ipairs(self.hits) do
total = total + (tonumber(hit.amount) or 0)
end
-- Update only if changed
if total ~= self.value then
self.value = total
end
return removed
end
-- Setup event handling
local f = CreateFrame("Frame")
f:RegisterEvent("UNIT_COMBAT")
-- Periodic cleanup
local timerFrame = CreateFrame("Frame")
timerFrame:SetScript("OnUpdate", function(self, elapsed)
if #damageTaken.hits > 0 then
cleanupOldHits(damageTaken, GetTime())
end
end)
-- Event forwarding
f:SetScript("OnEvent", function(self, event, ...)
damageTaken:Update(event, ...)
end)
-- Register damage handler
damageTaken:RegisterHandler("UNIT_COMBAT", function(self, now, unitTarget, event, flagText, amount, schoolMask)
if unitTarget ~= "player" then return end
-- Process damage amount and type
local damageAmount = tonumber(amount) or 0
local damageType = "Unknown"
-- Map damage school types
local schoolTypes = {
[1] = "Physical",
[2] = "Holy",
[4] = "Fire",
[8] = "Nature",
[16] = "Frost",
[32] = "Shadow",
[64] = "Arcane"
}
damageType = schoolTypes[schoolMask] or "Unknown"
-- Record hit details
table.insert(self.hits, {
time = now,
amount = damageAmount,
type = damageType,
isCrit = flagText == "CRITICAL",
isCrushing = flagText == "CRUSHING",
isGlancing = flagText == "GLANCING"
})
cleanupOldHits(self, now)
end)
-- Register in global state
Aurora.state.damage_taken = damageTaken
Using the Damage Tracker
-- Get total damage in current window
local totalDamage = damageTaken()
-- Analyze recent hits
for _, hit in ipairs(damageTaken.hits) do
if hit.isCrit then
print(string.format("%s critical hit for %d!",
hit.type, hit.amount))
end
end
-- Get damage by type
local function getDamageByType(type)
local total = 0
for _, hit in ipairs(damageTaken.hits) do
if hit.type == type then
total = total + hit.amount
end
end
return total
end
local physicalDamage = getDamageByType("Physical")