LibClassicSwingTimerAPI

LibClassicSwingTimerAPI

73.6k Downloads

Lua Errors with Example Implementation

Snoogens101 opened this issue ยท 6 comments

commented

Am I doing something wrong?
Playing on Official Classic, WotLK Pre-Patch

    local SwingTimerLib = LibStub("LibClassicSwingTimerAPI", true)
    if not SwingTimerLib then return end
    
    local f = CreateFrame("Frame", nil)
    
    local SwingTimerInfo = function(hand)
        return SwingTimerLib:SwingTimerInfo(hand)
    end
    
    local SwingTimerEventHandler = function(event, ...)
        return f[event](f, event, ...)
    end
    
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_START", SwingTimerEventHandler)
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_UPDATE", SwingTimerEventHandler)
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_CLIPPED", SwingTimerEventHandler)
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_PAUSED", SwingTimerEventHandler)
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_STOP", SwingTimerEventHandler)
    SwingTimerLib.RegisterCallback(f, "SWING_TIMER_DELTA", SwingTimerEventHandler)

If I fix the Lua errors below with guards, I only get nil, nil, nil as a return to SwingTimerInfo("mainhand").
However if I mount, funnily enough, I get a proper value for all three returns - but it also results in a Lua error for the line return f[event](f, event, ...) (attempt to call field '?' (a nil value)).

Lua Errors before manual guards added:

attempt to perform arithmetic on field 'offSpeed' (a nil value)

function lib:PLAYER_ENTER_COMBAT()
	local now = GetTime()
	self.isAttacking = true
	if now > (self.offExpirationTime - (self.offSpeed / 2)) then -- THIS LINE (self.offSpeed)
		if self.offTimer then
			self.offTimer:Cancel()
		end
		self:SwingStart("offhand", now, true)
	end
end

attempt to compare number with nil

function lib:UNIT_ATTACK_SPEED()
	if isClassic and self.class == "PALADIN" then return end -- Ignore UNIT_ATTACK_SPEED on Classic for Paladin. Seal of the Crusader snapshot. No other dynamic speed change.
	local now = GetTime()
	if
		self.skipNextAttackSpeedUpdate
		and tonumber(self.skipNextAttackSpeedUpdate)
		and (now - self.skipNextAttackSpeedUpdate) < 0.04
		and tonumber(self.skipNextAttackSpeedUpdateCount)
	then
		self.skipNextAttackSpeedUpdateCount = self.skipNextAttackSpeedUpdateCount - 1
		return
	end
	if self.mainTimer then
		self.mainTimer:Cancel()
	end
	if self.offTimer then
		self.offTimer:Cancel()
	end
	local mainSpeedNew, offSpeedNew = UnitAttackSpeed("player")
	offSpeedNew = offSpeedNew or 0
	if mainSpeedNew > 0 and self.mainSpeed > 0 and mainSpeedNew ~= self.mainSpeed then -- THIS LINE (self.mainSpeed)
		local multiplier = mainSpeedNew / self.mainSpeed
		local timeLeft = (self.lastMainSwing + self.mainSpeed - now) * multiplier
		self.mainSpeed = mainSpeedNew
		self.mainExpirationTime = now + timeLeft
		self:Fire("SWING_TIMER_UPDATE", self.mainSpeed, self.mainExpirationTime, "mainhand")
		if self.mainSpeed > 0 and self.mainExpirationTime - GetTime() > 0 then
			self.mainTimer = C_Timer.NewTimer(self.mainExpirationTime - GetTime(), function()
				self:SwingEnd("mainhand")
			end)
		end
	end
	if offSpeedNew > 0 and self.offSpeed > 0 and offSpeedNew ~= self.offSpeed then -- THIS LINE (self.offSpeed)
		local multiplier = offSpeedNew / self.offSpeed
		local timeLeft = (self.lastOffSwing + self.offSpeed - now) * multiplier
		self.offSpeed = offSpeedNew
		self.offExpirationTime = now + timeLeft
		if self.calculaDeltaTimer ~= nil then
			self.calculaDeltaTimer:Cancel()
		end
		self:Fire("SWING_TIMER_UPDATE", self.offSpeed, self.offExpirationTime, "offhand")
		if self.offSpeed > 0 and self.offExpirationTime - GetTime() > 0 then
			self.offTimer = C_Timer.NewTimer(self.offExpirationTime - GetTime(), function()
				self:SwingEnd("offhand")
			end)
		end
	end
end
commented

I think @hypernormalisation had a similar issue during it's addon implementation. On the next release we are adding a new event to the lib SWING_TIMER_INFO_INITIALIZED. This event give the possibility for addon implementation to know when the lib is initialized and all method/EVENT can be used.

commented

@Ralgathor , I see the new event is now added, but I get the exact same issues with the latest version. Is there any special thing that needs to be done for it to work properly? It passively fails, I'm not even calling any function, I just have the lib initialized.

commented

Well after a lot of messing around I got it to work. First problem was initialising. You only seem to do it on PLAYER_ENTER_WORLD, but so I had to add that it also inits on load.
Then the next problem is this function, no idea what it does but whatever it tries to process is always nil. I had to make it just return true to get it work.

local SwingTimerEventHandler = function(event, ...)
    return f[event](f, event, ...)
end
commented

@Snoogens101 What your exact use of the lib? If you can provide some code example maybe It can hehp to better understand your issue.

commented

It's OK, I've managed to get it to work, I'm not sure what the purpose is of the function above but it doesn't work with it - works well without, as the function will always return nil.
Then I recommend you add some nil checks for your self.nTimer:Cancel(), was missing in one part for all of them so had to add that to avoid Lua errors when zoning. Works great tho with some tweaks!

commented

It's OK, I've managed to get it to work, I'm not sure what the purpose is of the function above but it doesn't work with it - works well without, as the function will always return nil. Then I recommend you add some nil checks for your self.nTimer:Cancel(), was missing in one part for all of them so had to add that to avoid Lua errors when zoning. Works great tho with some tweaks!

@Snoogens101

local SwingTimerEventHandler = function(event, ...)
    return f[event](f, event, ...)
end

That an exampe of an event handler you need to adapt it to your addon implementation. f is a frame you need to declare the event handled on the frame to avoid the nil like:

function f:SWING_TIMER_START()
// Whatever your addon need to do with this event
end