修复拾取问题 修复其他已知问题 修复自动下马问题以及带来的猎人守护自动关闭问题 彻底修复拾取界面问题 修复目标框架的施法条监控 修复其他已知问题 调整dps插件对仇恨的估算方式 优化dps插件 修复远程攻击条问题
721 lines
31 KiB
Lua
721 lines
31 KiB
Lua
-- S-Frames Core Initialize
|
||
SFrames = {}
|
||
DEFAULT_CHAT_FRAME:AddMessage("SF: Loading Core.lua...")
|
||
|
||
do
|
||
local _orig_wipe = wipe
|
||
if _orig_wipe then
|
||
wipe = function(t)
|
||
if t == nil then return end
|
||
return _orig_wipe(t)
|
||
end
|
||
end
|
||
local _orig_tinsert = tinsert
|
||
if _orig_tinsert then
|
||
tinsert = function(t, a2, a3)
|
||
if type(t) ~= "table" then return end
|
||
if a3 ~= nil then
|
||
return _orig_tinsert(t, a2, a3)
|
||
else
|
||
return _orig_tinsert(t, a2)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
do
|
||
local _orig_UIFrameFade = UIFrameFade
|
||
if _orig_UIFrameFade then
|
||
UIFrameFade = function(frame, fadeInfo)
|
||
if not frame or not fadeInfo then return end
|
||
return _orig_UIFrameFade(frame, fadeInfo)
|
||
end
|
||
end
|
||
|
||
local origOnUpdate = UIParent and UIParent.GetScript and UIParent:GetScript("OnUpdate")
|
||
if origOnUpdate then
|
||
UIParent:SetScript("OnUpdate", function()
|
||
pcall(origOnUpdate)
|
||
end)
|
||
end
|
||
end
|
||
|
||
BINDING_HEADER_NANAMI_UI = "Nanami-UI"
|
||
BINDING_NAME_NANAMI_TOGGLE_NAV = "切换导航地图"
|
||
|
||
SFrames.eventFrame = CreateFrame("Frame", "SFramesEventFrame", UIParent)
|
||
SFrames.events = {}
|
||
|
||
function SFrames:GetIncomingHeals(unit)
|
||
-- Source 1: ShaguTweaks libpredict
|
||
if ShaguTweaks and ShaguTweaks.libpredict and ShaguTweaks.libpredict.UnitGetIncomingHeals then
|
||
local lp = ShaguTweaks.libpredict
|
||
if lp.UnitGetIncomingHealsBreakdown then
|
||
local ok, total, mine, others = pcall(function()
|
||
return lp:UnitGetIncomingHealsBreakdown(unit, UnitName("player"))
|
||
end)
|
||
if ok then
|
||
return math.max(0, tonumber(total) or 0),
|
||
math.max(0, tonumber(mine) or 0),
|
||
math.max(0, tonumber(others) or 0)
|
||
end
|
||
end
|
||
local ok, amount = pcall(function() return lp:UnitGetIncomingHeals(unit) end)
|
||
if ok then
|
||
amount = math.max(0, tonumber(amount) or 0)
|
||
return amount, 0, amount
|
||
end
|
||
end
|
||
-- Source 2: HealComm-1.0 (AceLibrary)
|
||
if AceLibrary and AceLibrary.HasInstance and AceLibrary:HasInstance("HealComm-1.0") then
|
||
local ok, HC = pcall(function() return AceLibrary("HealComm-1.0") end)
|
||
if ok and HC and HC.getHeal then
|
||
local name = UnitName(unit)
|
||
if name then
|
||
local total = HC:getHeal(name) or 0
|
||
total = math.max(0, tonumber(total) or 0)
|
||
return total, 0, total
|
||
end
|
||
end
|
||
end
|
||
return 0, 0, 0
|
||
end
|
||
|
||
-- Event Dispatcher
|
||
SFrames.eventFrame:SetScript("OnEvent", function()
|
||
local handlers = SFrames.events[event]
|
||
if handlers then
|
||
local n = table.getn(handlers)
|
||
for i = 1, n do
|
||
handlers[i](event)
|
||
end
|
||
end
|
||
end)
|
||
|
||
function SFrames:RegisterEvent(event, func)
|
||
if not self.events[event] then
|
||
self.events[event] = {}
|
||
self.eventFrame:RegisterEvent(event)
|
||
end
|
||
table.insert(self.events[event], func)
|
||
end
|
||
|
||
function SFrames:UnregisterEvent(event, func)
|
||
if self.events[event] then
|
||
for i = 1, table.getn(self.events[event]) do
|
||
if self.events[event][i] == func then
|
||
table.remove(self.events[event], i)
|
||
break
|
||
end
|
||
end
|
||
if table.getn(self.events[event]) == 0 then
|
||
self.events[event] = nil
|
||
self.eventFrame:UnregisterEvent(event)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Print Helper
|
||
function SFrames:Print(msg)
|
||
local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
|
||
DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r " .. tostring(msg))
|
||
end
|
||
|
||
-- Addon Loaded Initializer
|
||
SFrames:RegisterEvent("PLAYER_LOGIN", function()
|
||
SFrames:Initialize()
|
||
end)
|
||
|
||
function SFrames:SafeInit(name, initFn)
|
||
local ok, err = pcall(initFn)
|
||
if not ok then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444Nanami-UI: " .. name .. " init failed: " .. tostring(err) .. "|r")
|
||
end
|
||
end
|
||
|
||
function SFrames:Initialize()
|
||
if not SFramesDB then SFramesDB = {} end
|
||
|
||
if not SFramesDB.setupComplete then
|
||
if SFrames.SetupWizard and SFrames.SetupWizard.Show then
|
||
SFrames.SetupWizard:Show(function()
|
||
SFrames:DoFullInitialize()
|
||
end, "firstrun")
|
||
else
|
||
SFramesDB.setupComplete = true
|
||
self:DoFullInitialize()
|
||
end
|
||
return
|
||
end
|
||
|
||
self:DoFullInitialize()
|
||
end
|
||
|
||
function SFrames:DoFullInitialize()
|
||
self:Print("Nanami-UI 正在加载,喵呜~ =^_^=")
|
||
|
||
self:HideBlizzardFrames()
|
||
|
||
SFrames.Tooltip = CreateFrame("GameTooltip", "SFramesScanTooltip", nil, "GameTooltipTemplate")
|
||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||
SFrames.Tooltip:SetAlpha(0)
|
||
SFrames.Tooltip:Hide()
|
||
|
||
-- Phase 1: Critical modules (unit frames, action bars) — must load immediately
|
||
if SFramesDB.enableUnitFrames ~= false then
|
||
if SFramesDB.enablePlayerFrame ~= false then
|
||
if SFrames.Player and SFrames.Player.Initialize then SFrames.Player:Initialize() end
|
||
if SFrames.Pet and SFrames.Pet.Initialize then SFrames.Pet:Initialize() end
|
||
end
|
||
if SFramesDB.enableTargetFrame ~= false then
|
||
if SFrames.Target and SFrames.Target.Initialize then SFrames.Target:Initialize() end
|
||
if SFrames.ToT and SFrames.ToT.Initialize then SFrames.ToT:Initialize() end
|
||
end
|
||
if SFramesDB.enablePartyFrame ~= false then
|
||
if SFrames.Party and SFrames.Party.Initialize then SFrames.Party:Initialize() end
|
||
end
|
||
end
|
||
if SFrames.FloatingTooltip and SFrames.FloatingTooltip.Initialize then SFrames.FloatingTooltip:Initialize() end
|
||
|
||
if SFrames.ActionBars and SFrames.ActionBars.Initialize then
|
||
SFrames.ActionBars:Initialize()
|
||
end
|
||
|
||
self:InitSlashCommands()
|
||
|
||
-- Phase 2: Deferred modules — spread across multiple frames to avoid memory spike
|
||
local deferred = {
|
||
{ "Raid", function() if SFramesDB.enableUnitFrames ~= false and SFrames.Raid and SFrames.Raid.Initialize then SFrames.Raid:Initialize() end end },
|
||
{ "Bags", function() if SFrames.Bags and SFrames.Bags.Core and SFrames.Bags.Core.Initialize then SFrames.Bags.Core:Initialize() end end },
|
||
{ "Focus", function() if SFrames.Focus and SFrames.Focus.Initialize then SFrames.Focus:Initialize() end end },
|
||
{ "TalentTree", function() if SFrames.TalentTree and SFrames.TalentTree.Initialize then SFrames.TalentTree:Initialize() end end },
|
||
{ "Minimap", function() if SFrames.Minimap and SFrames.Minimap.Initialize then SFrames.Minimap:Initialize() end end },
|
||
{ "MinimapBuffs",function() if SFrames.MinimapBuffs and SFrames.MinimapBuffs.Initialize then SFrames.MinimapBuffs:Initialize() end end },
|
||
{ "MinimapButton",function() if SFrames.MinimapButton and SFrames.MinimapButton.Initialize then SFrames.MinimapButton:Initialize() end end },
|
||
{ "Chat", function() if SFramesDB.enableChat ~= false and SFrames.Chat and SFrames.Chat.Initialize then SFrames.Chat:Initialize() end end },
|
||
{ "MapReveal", function() if SFrames.MapReveal and SFrames.MapReveal.Initialize then SFrames.MapReveal:Initialize() end end },
|
||
{ "WorldMap", function() if SFrames.WorldMap and SFrames.WorldMap.Initialize then SFrames.WorldMap:Initialize() end end },
|
||
{ "ZoneLevelRange", function() if SFrames.ZoneLevelRange and SFrames.ZoneLevelRange.Initialize then SFrames.ZoneLevelRange:Initialize() end end },
|
||
{ "MapIcons", function() if SFrames.MapIcons and SFrames.MapIcons.Initialize then SFrames.MapIcons:Initialize() end end },
|
||
{ "Tweaks", function() if SFrames.Tweaks and SFrames.Tweaks.Initialize then SFrames.Tweaks:Initialize() end end },
|
||
{ "AFKScreen", function() if SFrames.AFKScreen and SFrames.AFKScreen.Initialize then SFrames.AFKScreen:Initialize() end end },
|
||
{ "LootDisplay", function() if SFrames.LootDisplay and SFrames.LootDisplay.Initialize then SFrames.LootDisplay:Initialize() end end },
|
||
}
|
||
|
||
local idx = 1
|
||
local batchSize = 3
|
||
local deferFrame = CreateFrame("Frame")
|
||
deferFrame:SetScript("OnUpdate", function()
|
||
if idx > table.getn(deferred) then
|
||
this:SetScript("OnUpdate", nil)
|
||
SFrames:Print("所有模块加载完成 =^_^=")
|
||
return
|
||
end
|
||
local batchEnd = idx + batchSize - 1
|
||
if batchEnd > table.getn(deferred) then batchEnd = table.getn(deferred) end
|
||
for i = idx, batchEnd do
|
||
SFrames:SafeInit(deferred[i][1], deferred[i][2])
|
||
end
|
||
idx = batchEnd + 1
|
||
end)
|
||
end
|
||
|
||
function SFrames:GetAuraTimeLeft(unit, index, isBuff)
|
||
-- If the unit is the player (e.g. you target yourself), Vanilla API CAN give us exact times
|
||
if UnitIsUnit(unit, "player") then
|
||
local texture = isBuff and UnitBuff(unit, index) or UnitDebuff(unit, index)
|
||
if texture then
|
||
local filter = isBuff and "HELPFUL" or "HARMFUL"
|
||
for i = 0, 31 do
|
||
local buffIndex = GetPlayerBuff(i, filter)
|
||
if buffIndex and buffIndex >= 0 then
|
||
if GetPlayerBuffTexture(buffIndex) == texture then
|
||
local t = GetPlayerBuffTimeLeft(buffIndex)
|
||
if t and t > 0 then return t end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Nanami-Plates SpellDB: combat log + spell DB tracking (most accurate for debuffs)
|
||
if not isBuff and NanamiPlates_SpellDB and NanamiPlates_SpellDB.UnitDebuff then
|
||
local effect, rank, tex, stacks, dtype, duration, timeleft, isOwn = NanamiPlates_SpellDB:UnitDebuff(unit, index)
|
||
if timeleft and timeleft > 0 then
|
||
return timeleft, effect
|
||
end
|
||
if effect and effect ~= "" and duration and duration > 0
|
||
and NanamiPlates_Auras and NanamiPlates_Auras.timers then
|
||
local unitKey = (UnitGUID and UnitGUID(unit)) or UnitName(unit) or ""
|
||
local cached = NanamiPlates_Auras.timers[unitKey .. "_" .. effect]
|
||
if not cached and UnitName(unit) then
|
||
cached = NanamiPlates_Auras.timers[UnitName(unit) .. "_" .. effect]
|
||
end
|
||
if cached and cached.startTime and cached.duration then
|
||
local remaining = cached.duration - (GetTime() - cached.startTime)
|
||
if remaining > 0 then
|
||
return remaining, effect
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Fallback to ShaguTweaks libdebuff if available (Debuffs only usually)
|
||
if ShaguTweaks and ShaguTweaks.libdebuff then
|
||
if not isBuff then
|
||
local effect, rank, texture, stacks, dtype, duration, libTimeLeft = ShaguTweaks.libdebuff:UnitDebuff(unit, index)
|
||
if libTimeLeft and libTimeLeft > 0 then
|
||
return libTimeLeft
|
||
end
|
||
end
|
||
end
|
||
return 0
|
||
end
|
||
|
||
function SFrames:FormatTime(seconds)
|
||
if not seconds then return "" end
|
||
if seconds >= 3600 then
|
||
return math.floor(seconds / 3600) .. "h"
|
||
elseif seconds >= 60 then
|
||
return math.floor(seconds / 60) .. "m"
|
||
else
|
||
return math.floor(seconds) .. "s"
|
||
end
|
||
end
|
||
|
||
function SFrames:InitSlashCommands()
|
||
DEFAULT_CHAT_FRAME:AddMessage("SF: InitSlashCommands called.")
|
||
SLASH_SFRAMES1 = "/nanami"
|
||
SLASH_SFRAMES2 = "/nui"
|
||
SlashCmdList["SFRAMES"] = function(msg)
|
||
local text = msg or ""
|
||
text = string.gsub(text, "^%s+", "")
|
||
text = string.gsub(text, "%s+$", "")
|
||
local _, _, cmd, args = string.find(text, "^(%S+)%s*(.-)$")
|
||
cmd = string.lower(cmd or "")
|
||
args = args or ""
|
||
|
||
if cmd == "unlock" or cmd == "move" then
|
||
SFrames:UnlockFrames()
|
||
elseif cmd == "lock" then
|
||
SFrames:LockFrames()
|
||
elseif cmd == "chatreset" then
|
||
if SFrames.Chat and SFrames.Chat.ResetPosition then
|
||
SFrames.Chat:ResetPosition()
|
||
end
|
||
elseif cmd == "test" then
|
||
if SFrames.Party and SFrames.Party.TestMode then SFrames.Party:TestMode() end
|
||
elseif cmd == "partyh" then
|
||
if SFrames.Party and SFrames.Party.SetLayout then
|
||
SFrames.Party:SetLayout("horizontal")
|
||
SFrames:Print("Party layout set to horizontal.")
|
||
end
|
||
elseif cmd == "partyv" then
|
||
if SFrames.Party and SFrames.Party.SetLayout then
|
||
SFrames.Party:SetLayout("vertical")
|
||
SFrames:Print("Party layout set to vertical.")
|
||
end
|
||
elseif cmd == "partylayout" or cmd == "playout" then
|
||
local mode = string.lower(args or "")
|
||
if mode == "h" or mode == "horizontal" then
|
||
if SFrames.Party and SFrames.Party.SetLayout then
|
||
SFrames.Party:SetLayout("horizontal")
|
||
SFrames:Print("Party layout set to horizontal.")
|
||
end
|
||
elseif mode == "v" or mode == "vertical" then
|
||
if SFrames.Party and SFrames.Party.SetLayout then
|
||
SFrames.Party:SetLayout("vertical")
|
||
SFrames:Print("Party layout set to vertical.")
|
||
end
|
||
else
|
||
local current = (SFramesDB and SFramesDB.partyLayout) or "vertical"
|
||
SFrames:Print("Usage: /nui partylayout horizontal|vertical (current: " .. current .. ")")
|
||
end
|
||
elseif cmd == "focus" then
|
||
if not SFrames.Focus then
|
||
SFrames:Print("Focus module unavailable.")
|
||
return
|
||
end
|
||
local ok, name, usedNative = SFrames.Focus:SetFromTarget()
|
||
if ok then
|
||
if usedNative then
|
||
SFrames:Print("Focus set: " .. tostring(name) .. " (native)")
|
||
else
|
||
SFrames:Print("Focus set: " .. tostring(name))
|
||
end
|
||
else
|
||
SFrames:Print("No valid target to set focus.")
|
||
end
|
||
elseif cmd == "clearfocus" or cmd == "cf" then
|
||
if not SFrames.Focus then
|
||
SFrames:Print("Focus module unavailable.")
|
||
return
|
||
end
|
||
SFrames.Focus:Clear()
|
||
SFrames:Print("Focus cleared.")
|
||
elseif cmd == "targetfocus" or cmd == "tf" then
|
||
if not SFrames.Focus then
|
||
SFrames:Print("Focus module unavailable.")
|
||
return
|
||
end
|
||
local ok = SFrames.Focus:Target()
|
||
if not ok then
|
||
SFrames:Print("Focus target not found.")
|
||
end
|
||
elseif cmd == "fcast" or cmd == "focuscast" then
|
||
if not SFrames.Focus then
|
||
SFrames:Print("Focus module unavailable.")
|
||
return
|
||
end
|
||
local ok, reason = SFrames.Focus:Cast(args)
|
||
if not ok then
|
||
if reason == "NO_SPELL" then
|
||
SFrames:Print("Usage: /nui fcast <spell name>")
|
||
elseif reason == "NO_FOCUS" then
|
||
SFrames:Print("No focus set.")
|
||
elseif reason == "FOCUS_NOT_FOUND" then
|
||
SFrames:Print("Focus not found in range/scene.")
|
||
else
|
||
SFrames:Print("Focus cast failed.")
|
||
end
|
||
end
|
||
elseif cmd == "focushelp" then
|
||
SFrames:Print("/nui focus - set current target as focus")
|
||
SFrames:Print("/nui clearfocus - clear focus")
|
||
SFrames:Print("/nui targetfocus - target focus")
|
||
SFrames:Print("/nui fcast <spell> - cast spell on focus")
|
||
SFrames:Print("/nui partyh / partyv - switch party layout")
|
||
SFrames:Print("/nui partylayout h|v - switch party layout")
|
||
SFrames:Print("/nui ui - open UI settings")
|
||
SFrames:Print("/nui bags - open bag settings")
|
||
SFrames:Print("/nui chat - open chat settings panel")
|
||
SFrames:Print("/nui chat help - chat command help")
|
||
SFrames:Print("/nui chatreset - reset chat frame position")
|
||
SFrames:Print("/nui afk - toggle AFK screen")
|
||
SFrames:Print("/nui pin - 地图标记 (clear/share)")
|
||
SFrames:Print("/nui nav - 切换导航地图")
|
||
SFrames:Print("/nui mapscan - 扫描所有地图更新迷雾揭示数据")
|
||
SFrames:Print("/nui mapstats - 查看地图覆盖层数据统计")
|
||
SFrames:Print("/nui mapexport - 导出扫描到的地图数据")
|
||
SFrames:Print("/nui mapclear - 清除已保存的扫描数据")
|
||
SFrames:Print("/nui layout - 布局模式(拖拽调整所有框体位置)")
|
||
SFrames:Print("/nui bind - 按键绑定模式(悬停按钮+按键)")
|
||
SFrames:Print("/nui talentdb - 天赋默认数据库管理/导出")
|
||
elseif cmd == "ui" or cmd == "uiconfig" then
|
||
if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("ui") end
|
||
elseif cmd == "chat" or cmd == "chatconfig" then
|
||
if SFrames.Chat and SFrames.Chat.HandleSlash then
|
||
SFrames.Chat:HandleSlash(args)
|
||
end
|
||
elseif cmd == "bags" or cmd == "bag" or cmd == "bagconfig" then
|
||
if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("bags") end
|
||
elseif cmd == "mapreveal" or cmd == "mr" then
|
||
if SFrames.MapReveal and SFrames.MapReveal.Toggle then
|
||
SFrames.MapReveal:Toggle()
|
||
else
|
||
SFrames:Print("MapReveal module unavailable.")
|
||
end
|
||
elseif cmd == "stats" or cmd == "stat" or cmd == "ss" then
|
||
if SFrames.StatSummary and SFrames.StatSummary.Toggle then
|
||
SFrames.StatSummary:Toggle()
|
||
else
|
||
SFrames:Print("StatSummary module unavailable.")
|
||
end
|
||
elseif cmd == "afk" then
|
||
if SFrames.AFKScreen and SFrames.AFKScreen.Toggle then
|
||
SFrames.AFKScreen:Toggle()
|
||
else
|
||
SFrames:Print("AFKScreen module unavailable.")
|
||
end
|
||
elseif cmd == "pin" or cmd == "wp" or cmd == "waypoint" then
|
||
if not SFrames.WorldMap then
|
||
SFrames:Print("WorldMap module unavailable.")
|
||
elseif args == "clear" or args == "remove" then
|
||
SFrames.WorldMap:ClearWaypoint()
|
||
SFrames:Print("地图标记已清除")
|
||
elseif args == "share" then
|
||
SFrames.WorldMap:ShareWaypoint()
|
||
else
|
||
SFrames:Print("/nui pin clear - 清除地图标记")
|
||
SFrames:Print("/nui pin share - 分享当前标记到聊天")
|
||
SFrames:Print("在世界地图中 Ctrl+左键 可放置标记")
|
||
end
|
||
elseif cmd == "nav" or cmd == "navigation" then
|
||
if SFrames.WorldMap and SFrames.WorldMap.ToggleNav then
|
||
SFrames.WorldMap:ToggleNav()
|
||
else
|
||
SFrames:Print("WorldMap module unavailable.")
|
||
end
|
||
elseif cmd == "mapscan" or cmd == "scanmap" then
|
||
if SFrames.MapReveal and SFrames.MapReveal.ScanAllMaps then
|
||
SFrames.MapReveal:ScanAllMaps()
|
||
else
|
||
SFrames:Print("MapReveal module unavailable.")
|
||
end
|
||
elseif cmd == "mapexport" then
|
||
if SFrames.MapReveal and SFrames.MapReveal.ExportScannedData then
|
||
SFrames.MapReveal:ExportScannedData()
|
||
else
|
||
SFrames:Print("MapReveal module unavailable.")
|
||
end
|
||
elseif cmd == "mapstats" then
|
||
if SFrames.MapReveal and SFrames.MapReveal.ShowStats then
|
||
SFrames.MapReveal:ShowStats()
|
||
else
|
||
SFrames:Print("MapReveal module unavailable.")
|
||
end
|
||
elseif cmd == "mapclear" then
|
||
if SFrames.MapReveal and SFrames.MapReveal.ClearSavedData then
|
||
SFrames.MapReveal:ClearSavedData()
|
||
else
|
||
SFrames:Print("MapReveal module unavailable.")
|
||
end
|
||
elseif cmd == "layout" or cmd == "movers" then
|
||
if SFrames.Movers and SFrames.Movers.ToggleLayoutMode then
|
||
SFrames.Movers:ToggleLayoutMode()
|
||
else
|
||
SFrames:Print("Layout mode unavailable.")
|
||
end
|
||
elseif cmd == "bind" or cmd == "keybind" then
|
||
if SFrames.ActionBars and SFrames.ActionBars.ToggleKeyBindMode then
|
||
SFrames.ActionBars:ToggleKeyBindMode()
|
||
else
|
||
SFrames:Print("ActionBars module unavailable.")
|
||
end
|
||
elseif cmd == "keybinds" or cmd == "kb" then
|
||
local KBM = SFrames.KeyBindManager
|
||
if not KBM then
|
||
SFrames:Print("KeyBindManager module unavailable.")
|
||
elseif args == "" then
|
||
if SFrames.ConfigUI and SFrames.ConfigUI.Build then
|
||
SFrames.ConfigUI:Build("keybinds")
|
||
end
|
||
elseif string.find(args, "^save ") then
|
||
local name = string.gsub(args, "^save ", "")
|
||
if name ~= "" then KBM:SaveProfile(name) end
|
||
elseif string.find(args, "^load ") then
|
||
local name = string.gsub(args, "^load ", "")
|
||
if name ~= "" then KBM:LoadProfile(name) end
|
||
elseif string.find(args, "^delete ") then
|
||
local name = string.gsub(args, "^delete ", "")
|
||
if name ~= "" then KBM:DeleteProfile(name) end
|
||
elseif args == "list" then
|
||
local list = KBM:GetProfileList()
|
||
if table.getn(list) == 0 then
|
||
SFrames:Print("没有保存的按键绑定方案")
|
||
else
|
||
SFrames:Print("按键绑定方案列表:")
|
||
for _, name in ipairs(list) do
|
||
local info = KBM:GetProfileInfo(name)
|
||
local desc = info and (info.charName .. ", " .. info.count .. " 条") or ""
|
||
SFrames:Print(" |cffffd100" .. name .. "|r " .. desc)
|
||
end
|
||
end
|
||
elseif args == "export" then
|
||
KBM:ShowExportDialog()
|
||
elseif args == "import" then
|
||
KBM:ShowImportDialog()
|
||
else
|
||
SFrames:Print("/nui keybinds - 打开设置面板")
|
||
SFrames:Print("/nui keybinds save <名称> - 保存当前绑定为方案")
|
||
SFrames:Print("/nui keybinds load <名称> - 加载方案")
|
||
SFrames:Print("/nui keybinds delete <名称> - 删除方案")
|
||
SFrames:Print("/nui keybinds list - 列出所有方案")
|
||
SFrames:Print("/nui keybinds export - 导出当前绑定")
|
||
SFrames:Print("/nui keybinds import - 导入绑定")
|
||
end
|
||
elseif cmd == "talentdb" or cmd == "tdb" then
|
||
if SFrames.TalentTree and SFrames.TalentTree.HandleTalentDBCommand then
|
||
SFrames.TalentTree:HandleTalentDBCommand(args)
|
||
else
|
||
SFrames:Print("TalentTree module unavailable.")
|
||
end
|
||
elseif cmd == "debugbuffs" or cmd == "db" then
|
||
local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
|
||
DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r 当前所有 Buff:")
|
||
for i = 0, 31 do
|
||
local buffIndex = GetPlayerBuff(i, "HELPFUL")
|
||
if buffIndex and buffIndex >= 0 then
|
||
local name = SFrames:GetBuffName(buffIndex)
|
||
local tex = GetPlayerBuffTexture(buffIndex) or "?"
|
||
local tl = GetPlayerBuffTimeLeft(buffIndex)
|
||
local timeStr = (tl and tl > 0 and tl < 99999) and string.format("%.1fs", tl) or "N/A"
|
||
local hidden = SFrames:IsBuffHidden(buffIndex) and "|cffff4444[隐藏]|r" or ""
|
||
DEFAULT_CHAT_FRAME:AddMessage(string.format(" #%d: |cffffd100%s|r %s %s", i, name or "(nil)", timeStr, hidden))
|
||
end
|
||
end
|
||
elseif cmd == "hidebuff" or cmd == "hb" then
|
||
if args == "" then
|
||
SFrames:Print("用法: /nui hidebuff <buff名称>")
|
||
else
|
||
if not SFramesDB.hiddenBuffs then SFramesDB.hiddenBuffs = {} end
|
||
SFramesDB.hiddenBuffs[args] = true
|
||
SFrames:Print("已隐藏 Buff: |cffffd100" .. args .. "|r")
|
||
end
|
||
elseif cmd == "unhidebuff" or cmd == "uhb" then
|
||
if args == "" then
|
||
SFrames:Print("用法: /nui unhidebuff <buff名称>")
|
||
else
|
||
if SFramesDB.hiddenBuffs then SFramesDB.hiddenBuffs[args] = nil end
|
||
SFrames:Print("已取消隐藏 Buff: |cffffd100" .. args .. "|r")
|
||
end
|
||
elseif cmd == "listhidden" or cmd == "lh" then
|
||
local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
|
||
DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r 已隐藏的 Buff 列表:")
|
||
if SFramesDB.hiddenBuffs then
|
||
for name, _ in pairs(SFramesDB.hiddenBuffs) do
|
||
DEFAULT_CHAT_FRAME:AddMessage(" |cffffd100" .. name .. "|r (用户自定义)")
|
||
end
|
||
end
|
||
elseif cmd == "config" or cmd == "" then
|
||
if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("ui") end
|
||
else
|
||
local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
|
||
DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r Commands: /nui, /nui ui, /nui bags, /nui chat, /nui layout, /nui unlock, /nui lock, /nui test, /nui partyh, /nui partyv, /nui focushelp, /nui mapreveal, /nui mapscan, /nui stats, /nui afk, /nui pin, /nui bind, /nui keybinds")
|
||
end
|
||
end
|
||
end
|
||
|
||
function SFrames:UnlockFrames()
|
||
self.isUnlocked = true
|
||
self:Print("Frames Unlocked. Drag to move.")
|
||
-- Show overlays or just let them be dragged if they are always movable
|
||
if SFramesPlayerFrame then SFramesPlayerFrame:EnableMouse(true) end
|
||
if SFramesPetFrame then SFramesPetFrame:EnableMouse(true) end
|
||
if SFramesTargetFrame then SFramesTargetFrame:EnableMouse(true) end
|
||
if SFrames.Chat and SFrames.Chat.SetUnlocked then
|
||
SFrames.Chat:SetUnlocked(true)
|
||
end
|
||
end
|
||
|
||
function SFrames:LockFrames()
|
||
self.isUnlocked = false
|
||
self:Print("Frames Locked.")
|
||
if SFrames.Chat and SFrames.Chat.SetUnlocked then
|
||
SFrames.Chat:SetUnlocked(false)
|
||
end
|
||
end
|
||
|
||
function SFrames:HideBlizzardFrames()
|
||
-- Hide Character Frame (replaced by CharacterPanel.lua)
|
||
-- Only suppress if the custom character panel is enabled
|
||
if (not SFramesDB) or (SFramesDB.charPanelEnable ~= false) then
|
||
if CharacterFrame then
|
||
CharacterFrame:UnregisterAllEvents()
|
||
CharacterFrame:Hide()
|
||
CharacterFrame.Show = function() end
|
||
end
|
||
if PaperDollFrame then PaperDollFrame:Hide() end
|
||
if ReputationFrame then ReputationFrame:Hide() end
|
||
if SkillFrame then SkillFrame:Hide() end
|
||
if HonorFrame then HonorFrame:Hide() end
|
||
end
|
||
|
||
if SFramesDB and SFramesDB.enableUnitFrames == false then
|
||
-- Keep Blizzard unit frames when Nanami frames are disabled
|
||
else
|
||
if not SFramesDB or SFramesDB.enablePlayerFrame ~= false then
|
||
if PlayerFrame then
|
||
PlayerFrame:UnregisterAllEvents()
|
||
PlayerFrame:Hide()
|
||
PlayerFrame.Show = function() end
|
||
end
|
||
if PetFrame then
|
||
PetFrame:UnregisterAllEvents()
|
||
PetFrame:Hide()
|
||
PetFrame.Show = function() end
|
||
end
|
||
end
|
||
|
||
if not SFramesDB or SFramesDB.enableTargetFrame ~= false then
|
||
if TargetFrame then
|
||
TargetFrame:UnregisterAllEvents()
|
||
TargetFrame:Hide()
|
||
TargetFrame.Show = function() end
|
||
end
|
||
if ComboFrame then
|
||
ComboFrame:UnregisterAllEvents()
|
||
ComboFrame:Hide()
|
||
ComboFrame.Show = function() end
|
||
ComboFrame.fadeInfo = ComboFrame.fadeInfo or {}
|
||
if ComboFrame_Update then
|
||
ComboFrame_Update = function() end
|
||
end
|
||
end
|
||
end
|
||
|
||
if not SFramesDB or SFramesDB.enablePartyFrame ~= false then
|
||
for i = 1, 4 do
|
||
local pf = _G["PartyMemberFrame"..i]
|
||
if pf then
|
||
pf:UnregisterAllEvents()
|
||
pf:Hide()
|
||
pf.Show = function() end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Hide Native Raid Frames if SFrames raid is enabled
|
||
if (not SFramesDB) or (SFramesDB.enableRaidFrames ~= false) then
|
||
|
||
local function NeuterBlizzardRaidUI()
|
||
if RaidFrame then
|
||
RaidFrame:UnregisterAllEvents()
|
||
RaidFrame:SetScript("OnEvent", nil)
|
||
RaidFrame:SetScript("OnUpdate", nil)
|
||
end
|
||
|
||
for i = 1, NUM_RAID_GROUPS or 8 do
|
||
local rgf = _G["RaidGroupButton"..i]
|
||
if rgf then
|
||
rgf:UnregisterAllEvents()
|
||
end
|
||
end
|
||
|
||
RaidPullout_Update = function() return {} end
|
||
RaidPullout_OnEvent = function() return {} end
|
||
RaidGroupFrame_OnEvent = function() return {} end
|
||
RaidGroupFrame_Update = RaidGroupFrame_Update or function() end
|
||
|
||
if not RAID_SUBGROUP_LISTS then RAID_SUBGROUP_LISTS = {} end
|
||
for i = 1, NUM_RAID_GROUPS or 8 do
|
||
if not RAID_SUBGROUP_LISTS[i] then
|
||
RAID_SUBGROUP_LISTS[i] = {}
|
||
end
|
||
end
|
||
|
||
for i = 1, 40 do
|
||
local pf = _G["RaidPullout"..i]
|
||
if pf then
|
||
pf:UnregisterAllEvents()
|
||
pf:Hide()
|
||
pf.Show = function() end
|
||
end
|
||
end
|
||
|
||
if CompactRaidFrameManager then
|
||
CompactRaidFrameManager:UnregisterAllEvents()
|
||
CompactRaidFrameManager:Hide()
|
||
CompactRaidFrameManager.Show = function() end
|
||
end
|
||
if CompactRaidFrameContainer then
|
||
CompactRaidFrameContainer:UnregisterAllEvents()
|
||
CompactRaidFrameContainer:Hide()
|
||
CompactRaidFrameContainer.Show = function() end
|
||
end
|
||
end
|
||
|
||
NeuterBlizzardRaidUI()
|
||
|
||
local raidHook = CreateFrame("Frame")
|
||
raidHook:RegisterEvent("ADDON_LOADED")
|
||
raidHook:SetScript("OnEvent", function()
|
||
if arg1 == "Blizzard_RaidUI" then
|
||
NeuterBlizzardRaidUI()
|
||
end
|
||
end)
|
||
end
|
||
|
||
end
|