Repository navigation
Expand file tree
/
Copy pathcore.lua
More file actions
executable file
·170 lines (152 loc) · 6.13 KB
/
Copy pathcore.lua
File metadata and controls
executable file
·170 lines (152 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
if not Cursive.superwow then
return
end
-- Local-cache frequently used globals
local UnitExists = UnitExists
local UnitIsDead = UnitIsDead
local GetTime = GetTime
local GetRaidTargetIndex = GetRaidTargetIndex
local strsub = string.sub
local pairs = pairs
-- add (1) for first stack of buffs/debuffs
-- other addons already do this, avoid having to parse both formats
AURAADDEDOTHERHELPFUL = "%s gains %s (1)."
AURAADDEDOTHERHARMFUL = "%s is afflicted by %s (1)."
AURAADDEDSELFHARMFUL = "You are afflicted by %s (1)."
AURAADDEDSELFHELPFUL = "You gain %s (1)."
Cursive.core = CreateFrame("Frame", "Cursive", UIParent)
Cursive.core.tooltipScan = CreateFrame("GameTooltip", "CursiveTooltipScan", UIParent, "GameTooltipTemplate")
Cursive.core.guids = {}
Cursive.core._guidCount = 0
-- v4.0.6: GUID cap to prevent O(N) explosion in BGs (AV = 80+ units)
local GUID_CAP = 60
-- v4.1.2: Long-TTL safety-valve (seconds). Primary stale-check is UnitExists-based
-- in evictStale(); this TTL only catches edge cases where UnitExists lies.
-- Raised from 30s (v4.1.1) → 300s because the old TTL removed mobs that were
-- still visible just because no UNIT_COMBAT event fired (regression at standstill).
local LRU_TTL = 300
-- v4.1.3: Hard cap on tracking distance. The Within Range filter is 120y, but
-- without it Cursive tracked mobs up to ~300-700y via UNIT_COMBAT events from
-- other raid members attacking distant units. 300y is the overall max so passive
-- acquisition from cross-map events still gets evicted promptly.
local MAX_TRACK_RANGE = 300
-- v4.0.6: Check if GUID is high-priority (target, raid-marked, or has our curses)
-- v4.1.1: Moved above add() so both add() and addGuid() can enforce the cap.
local function isHighPriorityGuid(guid)
local _, targetGuid = UnitExists("target")
if targetGuid and targetGuid == guid then return true end
if GetRaidTargetIndex(guid) then return true end
if Cursive.curses and Cursive.curses.guids and Cursive.curses.guids[guid] then return true end
return false
end
Cursive.core.add = function(unit)
local _, guid = UnitExists(unit)
if guid and not UnitIsDead(unit) then
if not Cursive.core.guids[guid] then
-- v4.1.1: Enforce cap for passive UNIT_COMBAT adds as well.
-- Previously only addGuid() enforced the cap; add() was a cap-bypass
-- once we routed UNIT_COMBAT tokens here (Bug #1 fix).
if Cursive.core._guidCount >= GUID_CAP and not isHighPriorityGuid(guid) then
return
end
Cursive.core._guidCount = Cursive.core._guidCount + 1
end
Cursive.core.guids[guid] = GetTime()
end
end
Cursive.core.addGuid = function(guid)
-- Already tracked -- just refresh timestamp
if Cursive.core.guids[guid] then
Cursive.core.guids[guid] = GetTime()
return
end
-- check if first two characters are 0x
if strsub(guid, 1, 2) ~= "0x" then
return
end
-- v4.0.6: Enforce GUID cap -- drop low-priority adds (UNIT_COMBAT spam in AV)
if Cursive.core._guidCount >= GUID_CAP then
if not isHighPriorityGuid(guid) then
return
end
end
if UnitExists(guid) and not UnitIsDead(guid) then
Cursive.core._guidCount = Cursive.core._guidCount + 1
Cursive.core.guids[guid] = GetTime()
end
end
Cursive.core.remove = function(guid)
if Cursive.core.guids[guid] then
Cursive.core.guids[guid] = nil
Cursive.core._guidCount = Cursive.core._guidCount - 1
if Cursive.core._guidCount < 0 then Cursive.core._guidCount = 0 end
end
end
-- v4.1.2: Evict non-priority GUIDs. Primary check is UnitExists(guid) which
-- uses SuperWoW's GUID-based lookup — a mob that's physically gone from the
-- server-range will return false. The 30s TTL from v4.1.1 was wrong: it
-- removed mobs that were still visible just because no UNIT_COMBAT event
-- fired to refresh the timestamp (Rob's standstill regression).
-- LRU_TTL (5 min) remains as a safety-valve for edge cases where UnitExists lies.
Cursive.core.evictStale = function()
local now = GetTime()
for guid, lastSeen in pairs(Cursive.core.guids) do
if not isHighPriorityGuid(guid) then
local exists = UnitExists(guid)
local dead = exists and UnitIsDead(guid)
-- v4.1.3: Also evict if mob drifted beyond the 300y overall max track range.
-- UnitXP distance is only checked when the unit exists — no point probing
-- a GUID that's already gone from the client.
local farAway = false
if exists and not dead and UnitXP then
local ok, dist = pcall(UnitXP, "distanceBetween", "player", guid)
if ok and type(dist) == "number" and dist > MAX_TRACK_RANGE then
farAway = true
end
end
if (not exists) or dead or farAway or ((now - lastSeen) > LRU_TTL) then
Cursive.core.guids[guid] = nil
Cursive.core._guidCount = Cursive.core._guidCount - 1
if Cursive.core._guidCount < 0 then Cursive.core._guidCount = 0 end
end
end
end
end
Cursive.core.disable = function()
Cursive.core:UnregisterAllEvents()
Cursive.core.guids = {}
Cursive.core._guidCount = 0
end
Cursive.core.enable = function()
-- unitstr
Cursive.core:RegisterEvent("PLAYER_TARGET_CHANGED")
-- arg1
Cursive.core:RegisterEvent("UNIT_COMBAT") -- this can get called with player/target/raid1 etc
Cursive.core:RegisterEvent("UNIT_MODEL_CHANGED")
end
Cursive.core:SetScript("OnEvent", function()
-- v4.1.1 FIX: Localize event/arg globals immediately (volatile in Vanilla 1.12).
local evt = event
local a1 = arg1
if evt == "PLAYER_TARGET_CHANGED" then
this.add("target")
elseif evt == "UNIT_COMBAT" then
-- v4.1.1 FIX (Bug #1): arg1 is a unit token (e.g. "raid5target"), not a GUID.
-- The 0x-prefix guard in addGuid() rejected tokens silently, making
-- UNIT_COMBAT a dead passive-acquisition path since v4.0.6. Route through
-- add() which resolves the token via UnitExists().
this.add(a1)
else
-- UNIT_MODEL_CHANGED — arg1 IS a GUID here (SuperWoW semantics)
this.addGuid(a1)
end
end)
-- v4.1.1: Drive LRU-Evict from core frame's OnUpdate, throttled to 2Hz.
local _lruTick = 0
Cursive.core:SetScript("OnUpdate", function()
local now = GetTime()
if now >= _lruTick then
_lruTick = now + 0.5
Cursive.core.evictStale()
end
end)