|
38 | 38 | local eventMap = {} |
39 | 39 | local BGFrame = CreateFrame("Frame", "BGFrame", nil) |
40 | 40 |
|
| 41 | +-- In 12.0+ some UI operations (including event registration on certain frames) can be blocked during combat lockdown. |
| 42 | +local function PVPS_InCombatLockdown() |
| 43 | + return type(InCombatLockdown) == "function" and InCombatLockdown() |
| 44 | +end |
| 45 | + |
| 46 | +function API:_ScheduleDeferredFlush() |
| 47 | + if self._deferredTimer == true then return end |
| 48 | + self._deferredTimer = true |
| 49 | + if type(C_Timer) == "table" and type(C_Timer.After) == "function" then |
| 50 | + C_Timer.After(0.5, function() API:_FlushDeferred() end) |
| 51 | + else |
| 52 | + -- No timer API, try next frame via OnUpdate |
| 53 | + if not self._deferredOnUpdateFrame then |
| 54 | + local f = CreateFrame("Frame") |
| 55 | + f:SetScript("OnUpdate", function() |
| 56 | + f:SetScript("OnUpdate", nil) |
| 57 | + API:_FlushDeferred() |
| 58 | + end) |
| 59 | + self._deferredOnUpdateFrame = f |
| 60 | + end |
| 61 | + end |
| 62 | +end |
| 63 | + |
| 64 | +function API:_FlushDeferred() |
| 65 | + if PVPS_InCombatLockdown() then |
| 66 | + self._deferredTimer = false |
| 67 | + self:_ScheduleDeferredFlush() |
| 68 | + return |
| 69 | + end |
| 70 | + |
| 71 | + self._deferredTimer = false |
| 72 | + if not self._deferred then return end |
| 73 | + local pending = self._deferred |
| 74 | + self._deferred = nil |
| 75 | + |
| 76 | + -- Apply deferred registrations/unregistrations now that combat lockdown is over. |
| 77 | + for _, op in ipairs(pending) do |
| 78 | + if op.action == "reg" then |
| 79 | + pcall(function() BGFrame:RegisterEvent(op.event) end) |
| 80 | + elseif op.action == "unreg" then |
| 81 | + pcall(function() BGFrame:UnregisterEvent(op.event) end) |
| 82 | + end |
| 83 | + end |
| 84 | +end |
| 85 | + |
| 86 | + |
41 | 87 | BGFrame:SetScript("OnEvent", function(frame, event, ...) |
42 | | - for k, v in pairs(eventMap[event]) do |
43 | | - if type(v) == "function" then |
44 | | - v(event, ...) |
45 | | - else |
46 | | - k[v](k, event, ...) |
47 | | - end |
| 88 | + local map = eventMap[event] |
| 89 | + if not map then return end |
| 90 | + for k, v in pairs(map) do |
| 91 | + if type(v) == "function" then |
| 92 | + v(event, ...) |
| 93 | + else |
| 94 | + k[v](k, event, ...) |
48 | 95 | end |
49 | | - end) |
| 96 | + end |
| 97 | +end) |
50 | 98 |
|
51 | 99 |
|
52 | 100 | function API:ShowRegisteredEvents() |
@@ -74,6 +122,14 @@ function API:RegisterEvent(event, func) |
74 | 122 | end |
75 | 123 |
|
76 | 124 | if BGFrame then |
| 125 | + -- Avoid registering events during combat lockdown (can cause ADDON_ACTION_FORBIDDEN in 12.0+). |
| 126 | + if PVPS_InCombatLockdown() then |
| 127 | + API._deferred = API._deferred or {} |
| 128 | + table.insert(API._deferred, { action = "reg", event = event }) |
| 129 | + API:_ScheduleDeferredFlush() |
| 130 | + return true |
| 131 | + end |
| 132 | + |
77 | 133 | BGFrame:RegisterEvent(event) |
78 | 134 | if not eventMap[event] then eventMap[event] = {} end |
79 | 135 | eventMap[event][self] = func or event |
|
87 | 143 | function API:UnregisterEvent(event) |
88 | 144 | if BGFrame and (type(event) == "string") then |
89 | 145 | eventMap[event] = nil |
| 146 | + -- Avoid unregistering events during combat lockdown (can cause UI action blocked/taint warnings). |
| 147 | + if PVPS_InCombatLockdown() then |
| 148 | + API._deferred = API._deferred or {} |
| 149 | + table.insert(API._deferred, { action = "unreg", event = event }) |
| 150 | + API:_ScheduleDeferredFlush() |
| 151 | + -- eventMap cleanup already done below; handler is guarded against nil eventMap[event] |
| 152 | + return true |
| 153 | + end |
| 154 | + |
90 | 155 | BGFrame:UnregisterEvent(event) |
91 | 156 | return true |
92 | 157 | elseif type(event) ~= "string" then |
|
100 | 165 |
|
101 | 166 | function API:UnregisterAllEvents() |
102 | 167 | if BGFrame then |
| 168 | + -- Avoid unregistering events during combat lockdown. |
| 169 | + if PVPS_InCombatLockdown() then |
| 170 | + API._deferred = API._deferred or {} |
| 171 | + for k, _ in pairs(eventMap) do |
| 172 | + table.insert(API._deferred, { action = "unreg", event = k }) |
| 173 | + eventMap[k] = nil |
| 174 | + end |
| 175 | + API:_ScheduleDeferredFlush() |
| 176 | + return true |
| 177 | + end |
| 178 | + |
103 | 179 | for k, v in pairs(eventMap) do |
104 | 180 | BGFrame:UnregisterEvent(k) |
105 | 181 | eventMap[k] = nil |
@@ -187,7 +263,8 @@ function API:LoadModules(CurrentZoneId, InstanceType, CurrentInstId) |
187 | 263 | PVPSound:Debug("alternative loading") |
188 | 264 | for _, mod in pairs(PVPSound.modules) do |
189 | 265 | PVPSound:Debug(" try "..mod.name.." instId: "..tostring(mod.instId).." ;cur instanceId: "..(select(8, GetInstanceInfo()))) |
190 | | - if mod.instId == CurrentInstId and not mod.loaded then |
| 266 | + local curName = select(1, GetInstanceInfo()) |
| 267 | + if ((mod.instId ~= nil and mod.instId == CurrentInstId) or (curName ~= nil and mod.name ~= nil and string.lower(curName) == string.lower(mod.name))) and (mod.type == nil or mod.type == InstanceType) and not mod.loaded then |
191 | 268 | PVPSound:TimerReset() |
192 | 269 | PVPSound:KillersReset() |
193 | 270 | mod:Initialize() |
@@ -232,31 +309,62 @@ end |
232 | 309 | ----------------------------------- |
233 | 310 | -- BG and Arena Team announcer when BG starts |
234 | 311 | function API:Announce(zone) |
235 | | - if zone == "BG" then |
236 | | - local MyFaction |
237 | | - -- 1 for Alliance |
238 | | - -- 0 for Horde |
239 | | - if PS.isRetail then |
240 | | - MyFaction = GetBattlefieldArenaFaction() |
241 | | - else |
242 | | - MyFaction = UnitFactionGroup("player") |
243 | | - if MyFaction == "Horde" then |
244 | | - MyFaction = 0 |
245 | | - elseif MyFaction == "Alliance" then |
246 | | - MyFaction = 1 |
| 312 | + if zone == nil then return end |
| 313 | + if PS_Announce == false then return end |
| 314 | + if AnnouncePlayed == true then return end |
| 315 | + |
| 316 | + -- Determine "effective" faction for the current match. |
| 317 | + -- In 12.0+ (cross-faction / merc mode), UnitFactionGroup("player") may reflect your original faction, |
| 318 | + -- not the team you're currently playing on. |
| 319 | + local MyFaction = nil |
| 320 | + |
| 321 | + if PS.isRetail == true then |
| 322 | + -- 1) Scoreboard faction (most reliable once scores are available) |
| 323 | + local okInfo, info = pcall(function() |
| 324 | + if PVPSound and PVPSound.GetMyScoreInfo then |
| 325 | + return PVPSound:GetMyScoreInfo() |
247 | 326 | end |
| 327 | + return nil |
| 328 | + end) |
| 329 | + if okInfo and info and info.faction ~= nil then |
| 330 | + MyFaction = info.faction |
248 | 331 | end |
249 | 332 |
|
250 | | - if MyFaction == 1 then |
251 | | - PVPSound:AddToQueue(PS.SoundPackDirectory.."\\"..PS_SoundPackLanguage.."\\GameStatus\\PlayYouAreOnBlue.mp3") |
252 | | - elseif MyFaction == 0 then |
253 | | - PVPSound:AddToQueue(PS.SoundPackDirectory.."\\"..PS_SoundPackLanguage.."\\GameStatus\\PlayYouAreOnRed.mp3") |
| 333 | + -- 2) Arena/BG effective faction (can be nil briefly when first zoning in) |
| 334 | + if MyFaction == nil and type(GetBattlefieldArenaFaction) == "function" then |
| 335 | + MyFaction = GetBattlefieldArenaFaction() |
| 336 | + end |
| 337 | + end |
| 338 | + |
| 339 | + -- 3) Fallback to original faction |
| 340 | + if MyFaction == nil then |
| 341 | + _, MyFaction = UnitFactionGroup("player") |
| 342 | + end |
| 343 | + |
| 344 | + -- If we still can't resolve the effective faction yet (common on initial zone-in), |
| 345 | + -- retry a few times before giving up. |
| 346 | + if zone == "BG" and (MyFaction == nil or (UnitIsMercenary and UnitIsMercenary("player") and type(MyFaction) == "string")) then |
| 347 | + API._bgAnnounceRetryCount = (API._bgAnnounceRetryCount or 0) + 1 |
| 348 | + if API._bgAnnounceRetryCount <= 12 then |
| 349 | + if type(C_Timer) == "table" and type(C_Timer.After) == "function" then |
| 350 | + C_Timer.After(0.5, function() API:Announce(zone) end) |
| 351 | + end |
| 352 | + return |
254 | 353 | end |
255 | | - elseif zone == "Arena" then |
256 | | - PVPSound:AddToQueue(PS.SoundPackDirectory.."\\"..PS_SoundPackLanguage.."\\GameStatus\\PrepareForBattle.mp3") |
257 | | - else |
258 | | - return false |
259 | 354 | end |
| 355 | + API._bgAnnounceRetryCount = 0 |
| 356 | + |
| 357 | + -- Alliance (blue) |
| 358 | + if MyFaction == 1 then |
| 359 | + PVPSound:AddToQueue(PS.SoundPackDirectory .. "\\" .. PS_SoundPackLanguage .. "\\Zone_WintergraspBattlefield\\YouAreOnBlueTeam.mp3") |
| 360 | + PVPSound:AddToSct("Blue Team", "You Are On Blue Team", "KILL") |
| 361 | + -- Horde (red) |
| 362 | + elseif MyFaction == 0 then |
| 363 | + PVPSound:AddToQueue(PS.SoundPackDirectory .. "\\" .. PS_SoundPackLanguage .. "\\Zone_WintergraspBattlefield\\YouAreOnRedTeam.mp3") |
| 364 | + PVPSound:AddToSct("Red Team", "You Are On Red Team", "KILL") |
| 365 | + end |
| 366 | + |
| 367 | + AnnouncePlayed = true |
260 | 368 | end |
261 | 369 |
|
262 | 370 | -- winner announcer |
|
0 commit comments