fix channeltime

This commit is contained in:
Jrc13245
2025-11-27 21:01:25 -05:00
parent 5b5d8860c5
commit 1f4781165f
3 changed files with 372 additions and 22 deletions
+41 -3
View File
@@ -1978,18 +1978,56 @@ CleveRoids.Keywords = {
end,
channeltime = function(conditionals)
local playerCast = CleveRoids.spell_tracking[CleveRoids.playerGuid]
-- Try both "player" literal and playerGuid for tracking lookup
local playerCast = CleveRoids.spell_tracking["player"] or CleveRoids.spell_tracking[CleveRoids.playerGuid]
if not playerCast or playerCast.type ~= "CHANNEL" then
if CleveRoids.ChannelTimeDebug then
if not playerCast then
DEFAULT_CHAT_FRAME:AddMessage("|cffffff00[channeltime]|r No tracking data for player or playerGuid: " .. tostring(CleveRoids.playerGuid))
-- Show what keys exist
local keys = ""
for k,v in pairs(CleveRoids.spell_tracking) do
keys = keys .. tostring(k) .. " "
end
if keys ~= "" then
DEFAULT_CHAT_FRAME:AddMessage("|cffffff00[channeltime]|r Tracking keys: " .. keys)
end
else
DEFAULT_CHAT_FRAME:AddMessage("|cffffff00[channeltime]|r Wrong type: " .. tostring(playerCast.type))
end
end
return false
end
-- FOUND TRACKING - Debug this path too!
local timeLeft = playerCast.expires - GetTime()
local check = conditionals.channeltime
if type(check) == "table" and check.operator and check.amount then
return CleveRoids.comparators[check.operator](timeLeft, check.amount)
-- channeltime is stored as an array by the parser, get the first element
if type(check) == "table" and type(check[1]) == "table" then
check = check[1]
end
if CleveRoids.ChannelTimeDebug then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[channeltime FOUND]|r expires=%.2f, timeLeft=%.2f", playerCast.expires, timeLeft))
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[channeltime FOUND]|r check type=" .. type(check) .. ", value=" .. tostring(check))
if type(check) == "table" then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[channeltime FOUND]|r operator=" .. tostring(check.operator) .. ", amount=" .. tostring(check.amount))
end
end
if type(check) == "table" and check.operator and check.amount then
local result = CleveRoids.comparators[check.operator](timeLeft, check.amount)
if CleveRoids.ChannelTimeDebug then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[channeltime RESULT]|r %.2fs %s %.2f = %s",
timeLeft, check.operator, check.amount, result and "TRUE" or "FALSE"))
end
return result
end
if CleveRoids.ChannelTimeDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[channeltime ERROR]|r check structure invalid, returning false")
end
return false
end,
+152 -2
View File
@@ -1693,11 +1693,20 @@ function CleveRoids.DoWithConditionals(msg, hook, fixEmptyTargetFunc, targetBefo
end
function CleveRoids.DoCast(msg)
if CleveRoids.ChannelTimeDebug then
if msg and string.find(msg, "Arcane") then
DEFAULT_CHAT_FRAME:AddMessage("|cffff00ff[/cast BUTTON PRESS]|r " .. msg)
end
end
local handled = false
for k, v in pairs(CleveRoids.splitStringIgnoringQuotes(msg)) do
-- Define a custom action that handles both regular and pet spells
local castAction = function(spellName)
if CleveRoids.ChannelTimeDebug and string.find(v, "channeltime") then
DEFAULT_CHAT_FRAME:AddMessage("|cffff00ff[/cast]|r Processing: " .. v)
end
-- First try regular spell
local spell = CleveRoids.GetSpell(spellName)
if spell then
@@ -3012,11 +3021,11 @@ end
function CleveRoids.Frame:ADDON_LOADED(addon)
-- keep your existing init for CRM:
if addon == "CleveRoidMacros" then
if addon == "CleveRoidMacros" or addon == "SuperCleveRoidMacros" then
CleveRoids.InitializeExtensions()
end
-- (re)attempt hook when either addon arrives
if addon == "SuperMacro" or addon == "CleveRoidMacros" then
if addon == "SuperMacro" or addon == "CleveRoidMacros" or addon == "SuperCleveRoidMacros" then
CRM_SM_InstallHook()
end
end
@@ -3024,17 +3033,54 @@ end
function CleveRoids.Frame:UNIT_CASTEVENT(caster,target,action,spell_id,cast_time)
if action == "MAINHAND" or action == "OFFHAND" then return end
-- Debug channel tracking
if CleveRoids.ChannelTimeDebug then
local spellName = spell_id and SpellInfo and SpellInfo(spell_id) or "Unknown"
if string.find(spellName, "Arcane") then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[UNIT_CASTEVENT]|r %s: %s (ID:%s) caster=%s player=%s",
action, spellName, tostring(spell_id), tostring(caster), tostring(CleveRoids.playerGuid)))
end
end
-- handle cast spell tracking
local cast = CleveRoids.spell_tracking[caster]
if cast_time > 0 and action == "START" or action == "CHANNEL" then
CleveRoids.spell_tracking[caster] = { spell_id = spell_id, expires = GetTime() + cast_time/1000, type = action }
-- ALSO store under "player" literal for easier lookup
if caster == CleveRoids.playerGuid then
CleveRoids.spell_tracking["player"] = CleveRoids.spell_tracking[caster]
end
if CleveRoids.ChannelTimeDebug and caster == CleveRoids.playerGuid then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[Tracking]|r Set spell_tracking[%s] AND [player]: type=%s, expires=%.2f",
tostring(caster), action, GetTime() + cast_time/1000))
end
-- Always show for channels if debug is on
if CleveRoids.ChannelTimeDebug and action == "CHANNEL" then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[Tracking]|r caster=%s, playerGuid=%s, match=%s",
tostring(caster), tostring(CleveRoids.playerGuid), tostring(caster == CleveRoids.playerGuid)))
end
elseif cast
and (
(cast.spell_id == spell_id and (action == "FAIL" or action == "CAST"))
or (GetTime() > cast.expires)
)
then
if CleveRoids.ChannelTimeDebug and caster == CleveRoids.playerGuid then
local reason = ""
if cast.spell_id == spell_id and (action == "FAIL" or action == "CAST") then
reason = string.format("spell_id match (%s) and action=%s", tostring(spell_id), action)
elseif GetTime() > cast.expires then
reason = string.format("expired (%.2f > %.2f)", GetTime(), cast.expires)
end
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffff0000[Tracking]|r CLEARING spell_tracking - %s", reason))
end
CleveRoids.spell_tracking[caster] = nil
-- Also clear "player" literal if this is the player
if caster == CleveRoids.playerGuid then
CleveRoids.spell_tracking["player"] = nil
end
end
-- handle cast sequence (SuperWoW)
@@ -3468,6 +3514,8 @@ SlashCmdList["CLEVEROID"] = function(msg)
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid forget <spellID|all> - Forget learned duration(s)")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid debug [0|1] - Toggle learning debug messages")
end
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrodebug - Toggle macro length warning debug")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrostatus - Check macro length warning status")
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Immunity Tracking:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listimmune [school] - List immunity data')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid addimmune "<NPC>" <school> [buff] - Add immunity')
@@ -3491,6 +3539,8 @@ SlashCmdList["CLEVEROID"] = function(msg)
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearproc [spell|all] - Clear reactive proc(s)')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Casting Detection:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testcasting - Test [selfcasting]/[noselfcasting] conditionals')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testchannel - Test [channeltime] conditional tracking')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid channeldebug - Toggle [channeltime] conditional debug output')
return
end
@@ -3580,6 +3630,106 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- macrodebug (toggle macro length warning debug messages)
if cmd == "macrodebug" then
CleveRoids.MacroLengthDebug = not CleveRoids.MacroLengthDebug
CleveRoids.Print("Macro length warning debug " .. (CleveRoids.MacroLengthDebug and "enabled" or "disabled"))
return
end
-- macrostatus (check macro length warning status)
if cmd == "macrostatus" then
CleveRoids.Print("|cff00ff00=== MacroLengthWarn Status ===|r")
-- Check if file loaded
if CleveRoids.MacroLengthWarnLoaded then
CleveRoids.Print("File: |cff00ff00LOADED|r")
else
CleveRoids.Print("File: |cffff0000NOT LOADED|r - Check for Lua errors!")
end
-- Check if extension is registered
local ext = CleveRoids.Extensions and CleveRoids.Extensions["MacroLengthWarn"]
if ext then
CleveRoids.Print("Extension: |cff00ff00REGISTERED|r")
-- Check if OnLoad was called
if ext.ShowMessages then
CleveRoids.Print("OnLoad: |cff00ff00CALLED|r")
-- Call the status function
ext.ShowMessages()
else
CleveRoids.Print("OnLoad: |cffff0000NOT CALLED|r")
end
else
CleveRoids.Print("Extension: |cffff0000NOT REGISTERED|r")
CleveRoids.Print("The MacroLengthWarn extension failed to register!")
end
-- Check key functions
CleveRoids.Print(" ")
CleveRoids.Print("Function Status:")
CleveRoids.Print(" EditMacro: " .. (EditMacro and "|cff00ff00EXISTS|r" or "|cffff0000MISSING|r"))
CleveRoids.Print(" MacroFrame_SaveMacro: " .. (MacroFrame_SaveMacro and "|cff00ff00EXISTS|r" or "|cffffff00NOT LOADED YET|r"))
return
end
-- channeldebug (toggle channeltime conditional debug)
if cmd == "channeldebug" then
CleveRoids.ChannelTimeDebug = not CleveRoids.ChannelTimeDebug
CleveRoids.Print("Channel time debug " .. (CleveRoids.ChannelTimeDebug and "enabled" or "disabled"))
if CleveRoids.ChannelTimeDebug then
CleveRoids.Print("You will see messages every time [channeltime] is evaluated")
CleveRoids.Print("This shows if your macro is re-evaluating during the channel")
end
return
end
-- testchannel (debug channel time detection)
if cmd == "testchannel" or cmd == "channeltest" then
CleveRoids.Print("|cff00ff00=== Channel Time Test ===|r")
-- Check spell tracking
local playerCast = CleveRoids.spell_tracking[CleveRoids.playerGuid]
if not playerCast then
CleveRoids.Print("|cffffff00No spell tracking data for player|r")
CleveRoids.Print("You must be casting or channeling a spell for this to show data")
else
CleveRoids.Print("Spell tracking found:")
CleveRoids.Print(" Type: " .. tostring(playerCast.type))
CleveRoids.Print(" Spell ID: " .. tostring(playerCast.spell_id))
if playerCast.spell_id and SpellInfo then
local spellName = SpellInfo(playerCast.spell_id)
CleveRoids.Print(" Spell Name: " .. tostring(spellName))
end
if playerCast.expires then
local timeLeft = playerCast.expires - GetTime()
CleveRoids.Print(" Expires at: " .. tostring(playerCast.expires))
CleveRoids.Print(" Time left: " .. string.format("%.2f", timeLeft) .. "s")
-- Test conditionals
CleveRoids.Print(" ")
CleveRoids.Print("Conditional tests:")
CleveRoids.Print(" [channeltime:<0.5]: " .. (timeLeft < 0.5 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
CleveRoids.Print(" [channeltime:<1.0]: " .. (timeLeft < 1.0 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
CleveRoids.Print(" [channeltime:>2.0]: " .. (timeLeft > 2.0 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
else
CleveRoids.Print(" Expires: NOT SET")
end
end
CleveRoids.Print(" ")
CleveRoids.Print("|cff00ffffInstructions:|r")
CleveRoids.Print("1. Start channeling Arcane Missiles")
CleveRoids.Print("2. Run /cleveroid testchannel while channeling")
CleveRoids.Print("3. Check if spell tracking is working")
CleveRoids.Print("|cff00ff00=== End Test ===|r")
return
end
-- testcasting (debug casting state detection)
if cmd == "testcasting" or cmd == "casttest" then
CleveRoids.Print("|cff00ff00=== Casting State Test ===|r")
+179 -17
View File
@@ -4,38 +4,200 @@
]]
local _G = _G or getfenv(0)
local CleveRoids = _G.CleveRoids or {}
-- CleveRoids.mouseoverUnit = CleveRoids.mouseoverUnit or nil
local Extension = CleveRoids.RegisterExtension("MacroLengthWarn")
local edit_orig = EditMacro
-- Set a global flag so we can check if this file loaded
CleveRoids.MacroLengthWarnLoaded = true
function Extension.SafeEditMacro(macro_id, x, y, body)
if SuperMacroFrame ~= nil and x and y and body == nil then
-- super will handle macro
edit_orig(macro_id, x, y, body)
return
end
-- Maximum line length for macros (including spaces)
local MAX_LINE_LENGTH = 261
if not body then -- can't be too long without a body
edit_orig(macro_id, x, y, body)
return
-- Store original functions
local edit_orig = nil
local macroframe_save_orig = nil
-- Validation function - returns true if valid, false if too long
local function ValidateMacroBody(body, macroName)
if not body then
return true -- No body means it's valid
end
for line in string.gfind(body, "([^\n]+)") do
if string.len(line) > 261 then
DEFAULT_CHAT_FRAME:AddMessage("ERROR: A line in the macro < |cffffffff"..GetMacroInfo(macro_id).."|r > is too long and will |cffff0000CRASH|r the client and may |cffff0000DELETE|r all macros on exit! Max line length: |cffffffff261|r",1,1,0)
local lineLen = string.len(line)
if lineLen > MAX_LINE_LENGTH then
local name = macroName or "Unknown"
DEFAULT_CHAT_FRAME:AddMessage(string.format(
"|cffff0000ERROR:|r A line in the macro < |cffffffff%s|r > is |cffff0000%d characters|r long (max: |cffffffff%d|r).",
name, lineLen, MAX_LINE_LENGTH
), 1, 0.82, 0)
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000This will CRASH the client and may DELETE all macros!|r Macro NOT saved.", 1, 0.82, 0)
DEFAULT_CHAT_FRAME:AddMessage("Line: |cffffffff" .. string.sub(line, 1, 100) .. "...|r", 1, 1, 1)
return false
end
end
return true
end
-- Hook for EditMacro API function
function Extension.SafeEditMacro(macro_id, x, y, body)
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r EditMacro called for ID: " .. tostring(macro_id))
end
-- SuperMacro compatibility - bypass validation if SuperMacro is handling it
if SuperMacroFrame ~= nil and x and y and body == nil then
if edit_orig then edit_orig(macro_id, x, y, body) end
return
end
-- Get macro name for error messages
local macroName = GetMacroInfo(macro_id)
-- Validate the macro body
if not ValidateMacroBody(body, macroName) then
-- Validation failed - do NOT save
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r BLOCKED save - line too long")
end
return
end
-- Validation passed - call original
if edit_orig then
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r Validation passed, saving...")
end
edit_orig(macro_id, x, y, body)
end
end
-- Hook for MacroFrame_SaveMacro (Blizzard UI function)
function Extension.SafeMacroFrameSave()
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r MacroFrame_SaveMacro called")
end
-- This is called by the macro UI, so we need to get the text from the edit box
if MacroFrameText and MacroFrame.selectedMacro then
local body = MacroFrameText:GetText()
local macroName = GetMacroInfo(MacroFrame.selectedMacro)
-- Validate before allowing the save
if not ValidateMacroBody(body, macroName) then
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r BLOCKED MacroFrame save")
end
-- Don't call original - block the save
return
end
end
edit_orig(macro_id, x, y, body)
-- Validation passed or no text to validate
if macroframe_save_orig then
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r MacroFrame validation passed")
end
macroframe_save_orig()
end
end
-- Install hooks when macro frame loads
function Extension.OnMacroFrameLoad()
if Extension.macroFrameHooked then
return
end
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r Hooking MacroFrame_SaveMacro")
end
-- Hook MacroFrame_SaveMacro if it exists
if MacroFrame_SaveMacro then
macroframe_save_orig = MacroFrame_SaveMacro
MacroFrame_SaveMacro = function(...)
local success, err = pcall(Extension.SafeMacroFrameSave, unpack(arg))
if not success then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[MacroLengthWarn]|r MacroFrame hook error: " .. tostring(err))
-- Call original on error
if macroframe_save_orig then
return macroframe_save_orig(unpack(arg))
end
end
end
Extension.macroFrameHooked = true
if CleveRoids.MacroLengthDebug then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r MacroFrame_SaveMacro hooked successfully")
end
end
end
function Extension.OnAddonLoaded()
if arg1 == "Blizzard_MacroUI" then
Extension.OnMacroFrameLoad()
end
end
function Extension.OnLoad()
-- how do I use this with a global function?
-- CleveRoids.RegisterMethodHook("MacroLengthWarn", _G, "EditMacro", "SafeEditMacro", true)
EditMacro = Extension.SafeEditMacro
-- Schedule messages to show after UI is ready
local function ShowMessages()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r Extension loaded (Max line length: " .. MAX_LINE_LENGTH .. ")")
if not EditMacro then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[MacroLengthWarn]|r ERROR: EditMacro function not found!")
else
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r EditMacro hook: " .. (edit_orig and "SUCCESS" or "FAILED"))
end
if MacroFrame_SaveMacro then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r MacroFrame_SaveMacro hook: " .. (Extension.macroFrameHooked and "SUCCESS" or "PENDING"))
else
DEFAULT_CHAT_FRAME:AddMessage("|cffffff00[MacroLengthWarn]|r MacroFrame_SaveMacro: Will hook when Blizzard UI loads")
end
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[MacroLengthWarn]|r Use /cleveroid macrodebug to toggle debug output")
end
-- Check if EditMacro exists
if not EditMacro then
CleveRoids.Print("[MacroLengthWarn] ERROR: EditMacro not found!")
return
end
-- Capture and hook EditMacro immediately with error protection
edit_orig = EditMacro
EditMacro = function(...)
local success, err = pcall(Extension.SafeEditMacro, unpack(arg))
if not success then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[MacroLengthWarn]|r Hook error: " .. tostring(err))
-- Call original on error to prevent breaking macros
if edit_orig then
return edit_orig(unpack(arg))
end
end
end
-- Listen for macro UI loading
Extension.RegisterEvent("ADDON_LOADED", "OnAddonLoaded")
-- Also try to hook MacroFrame_SaveMacro if it already exists
if MacroFrame_SaveMacro then
Extension.OnMacroFrameLoad()
end
-- Register PLAYER_LOGIN to show status messages
Extension.RegisterEvent("PLAYER_LOGIN", "OnPlayerLogin")
-- Store the message function for later
Extension.ShowMessages = ShowMessages
end
function Extension.OnPlayerLogin()
-- Status messages disabled by default - use /cleveroid macrostatus to check
-- if Extension.ShowMessages then
-- Extension.ShowMessages()
-- end
end
_G["CleveRoids"] = CleveRoids