From a24e00608bb23b3859e5bbcefe048dd0c4c41dc7 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Mon, 12 May 2014 16:08:16 +0000 Subject: [PATCH] Add additional phase of tracking to spellcasts: "after hit". ApplySpellAfterHit() is called after the three previous phases: ApplySpellStartCast ApplySpellAfterCast ApplySpellOnHit ApplySpellAfterHit Apply spell auras to the target during ApplySpellAfterHit(). Only remove a spellcast from the spells-in-flight after it has applied any auras to the target, which can take a bit of time due to server event lag. The simulator will continue to apply spells until it sees their aura effects appear on the target in reality. Remove the previous workaround for aura lag added to OvaleAura in r1411 and r1413. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1426 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- OvaleAura.lua | 40 ++++----------------------- OvaleFuture.lua | 81 +++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/OvaleAura.lua b/OvaleAura.lua index df7bc0a..c55ab53 100644 --- a/OvaleAura.lua +++ b/OvaleAura.lua @@ -647,39 +647,9 @@ function OvaleAura:ResetState(state) for guid, auraTable in pairs(state.aura) do for auraId, whoseTable in pairs(auraTable) do for casterGUID, aura in pairs(whoseTable) do - local keepAura = false - local auraFound = GetAura(self.aura, guid, auraId, casterGUID) - if auraFound and aura.lastUpdated <= auraFound.lastUpdated then - Ovale:Logf(" Aura %d on %s more recently updated outside simulator.", auraId, guid) - elseif state.lastSpellId and state.endCast and state.endCast < state.currentTime then - local si = OvaleData.spellInfo[state.lastSpellId] - if si and si.aura then - if guid == self_guid then - -- Check for auras that start within aura lag if they are auras applied onto the player. - if (si.aura.player and si.aura.player[aura.filter] and si.aura.player[aura.filter][auraId]) - or (si.aura.target and si.aura.target[aura.filter] and si.aura.target[aura.filter][auraId]) then - if IsWithinAuraLag(aura.start, state.currentTime) then - keepAura = true - end - end - elseif si.aura.target and si.aura.target[aura.filter] and si.aura.target[aura.filter][auraId] then - -- Check for auras that start within twice the aura lag if they are auras applied onto a target. - if IsWithinAuraLag(aura.start, state.currentTime, 2) then - keepAura = true - end - end - end - if keepAura then - -- Reset the aura age relative to the state of the simulator. - aura.serial = state.serial - Ovale:Logf(" Aura %d on %s preserved in simulator for aura lag, start=%f, now=%f.", auraId, guid, aura.start, state.currentTime) - end - end - if not keepAura then - self_pool:Release(aura) - whoseTable[casterGUID] = nil - Ovale:Logf(" Aura %d on %s removed, now=%f.", auraId, guid, state.currentTime) - end + self_pool:Release(aura) + whoseTable[casterGUID] = nil + Ovale:Logf(" Aura %d on %s removed, now=%f.", auraId, guid, state.currentTime) end if not next(whoseTable) then self_pool:Release(whoseTable) @@ -709,8 +679,8 @@ function OvaleAura:ApplySpellAfterCast(state, spellId, targetGUID, startCast, en end end --- Apply the effects of the spell on the target's state when it lands on the target. -function OvaleAura:ApplySpellOnHit(state, spellId, targetGUID, startCast, endCast, nextCast, isChanneled, nocd, spellcast) +-- Apply the effects of the spell on the target's state after it lands on the target. +function OvaleAura:ApplySpellAfterHit(state, spellId, targetGUID, startCast, endCast, nextCast, isChanneled, nocd, spellcast) local si = OvaleData.spellInfo[spellId] -- Apply the auras on the target. if si and si.aura and si.aura.target then diff --git a/OvaleFuture.lua b/OvaleFuture.lua index 4717a20..be82ea7 100644 --- a/OvaleFuture.lua +++ b/OvaleFuture.lua @@ -68,16 +68,32 @@ local self_timeAuraAdded = nil local OVALE_UNKNOWN_GUID = 0 -- These CLEU events are eventually received after a successful spellcast. -local OVALE_CLEU_SPELLCAST_RESULTS = { - SPELL_AURA_APPLIED = true, - SPELL_AURA_APPLIED_DOSE = true, - SPELL_AURA_REFRESH = true, - SPELL_AURA_REMOVED_DOSE = true, - SPELL_CAST_SUCCESS = true, - SPELL_CAST_FAILED = true, - SPELL_DAMAGE = true, - SPELL_MISSED = true, +local CLEU_AURA_EVENT = { + SPELL_AURA_APPLIED = "hit", + SPELL_AURA_APPLIED_DOSE = "hit", + SPELL_AURA_BROKEN = "hit", + SPELL_AURA_BROKEN_SPELL = "hit", + SPELL_AURA_REFRESH = "hit", + SPELL_AURA_REMOVED = "hit", + SPELL_AURA_REMOVED_DOSE = "hit", } +local CLEU_SUCCESSFUL_SPELLCAST_EVENT = { +-- SPELL_CAST_SUCCESS = "hit", + SPELL_CAST_FAILED = "miss", + SPELL_DAMAGE = "hit", + SPELL_DISPEL = "hit", + SPELL_DISPEL_FAILED = "miss", + SPELL_HEAL = "hit", + SPELL_INTERRUPT = "hit", + SPELL_MISSED = "miss", + SPELL_STOLEN = "hit", +} +do + -- All aura events are also successful spellcast events. + for cleuEvent, v in pairs(CLEU_AURA_EVENT) do + CLEU_SUCCESSFUL_SPELLCAST_EVENT[cleuEvent] = v + end +end -- -- @@ -209,19 +225,30 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a -- This helps to later identify whether the spellcast succeeded by noting when -- the aura is applied or refreshed. if si.aura then - for target, auraTable in pairs(si.aura) do - for filter, auraList in pairs(auraTable) do + -- Look for target auras before player auras applied by the spell. + if not spellcast.auraId and si.aura.target then + for filter, auraList in pairs(si.aura.target) do for auraId, spellData in pairs(auraList) do if spellData and (spellData == "refresh" or (type(spellData) == "number" and spellData > 0)) then spellcast.auraId = auraId - if target == "player" or (target == "target" and spellcast.target == self_guid) then - spellcast.removeOnSuccess = true + if spellcast.target ~= self_guid then + spellcast.removeOnAuraSuccess = true end break end end end end + if not spellcast.auraId and si.aura.player then + for filter, auraList in pairs(si.aura.player) do + for auraId, spellData in pairs(auraList) do + if spellData and (spellData == "refresh" or (type(spellData) == "number" and spellData > 0)) then + spellcast.auraId = auraId + break + end + end + end + end end -- Increase or reset any counters used by the Counter() condition. @@ -232,9 +259,13 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a local prev = self.counter[si.inccounter] or 0 self.counter[si.inccounter] = prev + 1 end - else + end + + -- Set the condition for detecting a successful spellcast. + if not spellcast.removeOnAuraSuccess then spellcast.removeOnSuccess = true end + tinsert(self_activeSpellcast, spellcast) OvaleScore:ScoreSpell(spellId) @@ -254,7 +285,7 @@ local function RemoveSpellFromQueue(spellId, lineId) Ovale.refreshNeeded["player"] = true end --- UpdateLastSpellcast() is called at the end of the event handler for OVALE_CLEU_SPELLCAST_RESULTS[]. +-- UpdateLastSpellcast() is called at the end of the event handler for CLEU_SUCCESSFUL_SPELLCAST_EVENT[]. -- It saves the given spellcast as the most recent one on its target and ensures that the spellcast -- snapshot values are correctly adjusted for buffs that are added or cleared simultaneously with the -- spellcast. @@ -510,15 +541,19 @@ function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, cleuEvent, hi -- Called when a missile reaches or misses its target if sourceGUID == self_guid then - if OVALE_CLEU_SPELLCAST_RESULTS[cleuEvent] then + local success = CLEU_SUCCESSFUL_SPELLCAST_EVENT[cleuEvent] + if success then local spellId, spellName = arg12, arg13 TracePrintf(spellId, "%s: %s (%d)", cleuEvent, spellName, spellId) for index, spellcast in ipairs(self_activeSpellcast) do - if spellcast.allowRemove and (spellcast.spellId == spellId or spellcast.auraId == spellId) then - if not spellcast.channeled and (spellcast.removeOnSuccess or cleuEvent ~= "SPELL_CAST_SUCCESS") then + if spellcast.allowRemove and not spellcast.channeled and (spellcast.spellId == spellId or spellcast.auraId == spellId) then + spellcast.success = success + if spellcast.removeOnSuccess or (spellcast.removeOnAuraSuccess and CLEU_AURA_EVENT[cleuEvent]) then TracePrintf(spellId, " Spell finished: %s (%d)", spellName, spellId) tremove(self_activeSpellcast, index) UpdateLastSpellcast(spellcast) + local unitId = spellcast.target and OvaleGUID:GetUnitId(spellcast.target) or "player" + Ovale.refreshNeeded[unitId] = true Ovale.refreshNeeded["player"] = true end break @@ -751,10 +786,11 @@ statePrototype.ApplySpell = function(state, ...) Ovale:Logf("Apply spell %d at %f currentTime=%f nextCast=%f endCast=%f targetGUID=%s", spellId, startCast, state.currentTime, nextCast, endCast, targetGUID) --[[ - Apply the effects of the spellcast in three phases. + Apply the effects of the spellcast in four phases. 1. Effects at the beginning of the spellcast. 2. Effects when the spell has been cast. 3. Effects when the spellcast hits the target. + 4. Effects after the spellcast hits the target (possibly due to server lag). --]] -- If the spellcast has already started, then the effects have already occurred. if startCast >= now then @@ -764,6 +800,11 @@ statePrototype.ApplySpell = function(state, ...) if endCast > now then OvaleState:InvokeMethod("ApplySpellAfterCast", state, ...) end - OvaleState:InvokeMethod("ApplySpellOnHit", state, ...) + if not spellcast or not spellcast.success then + OvaleState:InvokeMethod("ApplySpellOnHit", state, ...) + end + if not spellcast or not spellcast.success or spellcast.success == "hit" then + OvaleState:InvokeMethod("ApplySpellAfterHit", state, ...) + end end -- -- 1.7.9.5