天赋修改更直接展示预览时天赋变更信息

世界地图揭示迷雾全修复
This commit is contained in:
rucky
2026-03-23 18:13:03 +08:00
parent ec9e3c29d6
commit 40d37dc8c4
7 changed files with 1504 additions and 1348 deletions

View File

@@ -2,6 +2,7 @@
-- Nanami-UI: MapReveal -- Reveal unexplored world map areas
-- Adapted from ShaguTweaks-extras worldmap-reveal approach
-- Uses LibMapOverlayData (from !Libs) supplemented with Turtle WoW zones
-- Features persistent overlay discovery via GetMapOverlayInfo() API
--------------------------------------------------------------------------------
SFrames.MapReveal = SFrames.MapReveal or {}
@@ -15,58 +16,14 @@ local errata = {
["Interface\\WorldMap\\Silverpine\\BERENSPERIL"] = { offsetY = { 417, 415 } },
}
-- Turtle WoW new/modified zones not present in LibMapOverlayData
-- Updated for latest Turtle WoW version
-- Zones only in TurtleWoW_Zones: not in patched WorldMapOverlay.dbc but needed for fog reveal
local TurtleWoW_Zones = {
["StonetalonMountains"] = {
"SUNROCKRETREAT:512:256:256:256", "WINDSHEARCRAG:256:256:512:256",
"MIRKFALLONLAKE:512:512:256:0", "THECHARREDVALE:256:512:256:256",
"STONETALONPEAK:256:256:256:0", "WEBWINDERPATH:256:512:512:256",
"AMANIALOR:512:256:0:0", "GRIMTOTEMPOST:512:256:512:512",
"CAMPAPARAJE:512:256:512:512", "MALAKAJIN:512:256:512:512",
"BOULDERSLIDERAVINE:256:256:512:512", "SISHIRCANYON:256:512:512:256",
"VENTURECOMPANYCAMP:256:512:256:0", "BLACKSANDOILFIELDS:512:512:0:0",
"POWDERTOWN:256:256:256:256", "BRAMBLETHORNPASS:512:512:512:256",
"BAELHARDUL:512:256:512:256", "BROKENCLIFFMINE:256:512:256:0",
"THEEARTHENRING:512:256:256:256",
},
["UpperKarazhan2f"] = {
"OUTLAND:1024:768:0:0",
},
["GrimReaches"] = {
"DUNKITHAS:512:256:256:256", "THEGRIMHOLLOW:512:512:256:256",
"LAKEKITHAS:512:256:256:256", "SLATEBEARDSFORGE:512:256:256:256",
"THEHIGHPASS:256:256:256:256", "SALGAZMINES:256:256:512:256",
"EASTRIDGEOUTPOST:512:512:256:0", "BAGGOTHSRAMPART:256:512:256:0",
"RUINSOFSTOLGAZKEEP:256:256:256:0", "GROLDANSEXCAVATION:256:512:512:0",
"ZARMGETHSTRONGHOLD:512:256:256:0", "GETHKAR:512:256:256:0",
"ZARMGETHPOINT:512:256:256:0", "SHATTERBLADEPOST:256:256:512:0",
"BRANGARSFOLLY:256:256:512:0", "BARLEYCRESTFARMSTEAD:512:512:256:0",
},
["Balor"] = {
"GULLWINGWRECKAGE:512:256:0:0", "BILGERATCOMPOUND:256:256:256:0",
"SIOUTPOST:256:512:512:256", "RUINSOFBREEZEHAVEN:512:256:256:256",
"CROAKINGPLATEAU:512:512:256:0", "LANGSTONORCHARD:256:256:256:256",
"SORROWMORELAKE:256:256:256:256", "SCURRYINGTHICKET:256:512:256:0",
"STORMWROUGHTCASTLE:512:256:256:256", "STORMREAVERSPIRE:512:512:256:256",
"WINDROCKCLIFFS:256:512:256:256", "TREACHEROUSCRAGS:512:512:256:256",
"VANDERFARMSTEAD:256:256:256:256", "GRAHANESTATE:256:256:256:256",
"STORMBREAKERPOINT:512:512:512:0",
},
["Northwind"] = {
"MERCHANTSHIGHROAD:512:512:256:256", "AMBERSHIRE:512:256:256:256",
"AMBERWOODKEEP:512:256:0:256", "CRYSTALFALLS:512:512:512:256",
"CRAWFORDWINERY:256:256:512:256", "NORTHWINDLOGGINGCAMP:256:512:256:0",
"WITCHCOVEN:256:256:256:0", "RUINSOFBIRKHAVEN:512:512:512:0",
"SHERWOODQUARRY:512:512:512:0", "BLACKROCKBREACH:512:512:512:0",
"GRIMMENLAKE:256:512:512:256", "ABBEYGARDENS:256:256:512:0",
"STILLHEARTPORT:512:512:0:0", "TOWEROFMAGILOU:512:512:0:0",
"BRISTLEWHISKERCAVERN:256:512:512:0", "NORTHRIDGEPOINT:512:512:256:0",
"CINDERFALLPASS:512:512:512:256",
},
}
-- Runtime-discovered overlay data (populated by ScanAllMaps)
-- Runtime-discovered overlay data (populated by scanning and passive collection)
local scannedOverlays = {}
local function IsTurtleWoW()
@@ -77,6 +34,81 @@ local function GetOverlayDB()
return MapOverlayData or LibMapOverlayData or zMapOverlayData or mapOverlayData
end
--------------------------------------------------------------------------------
-- Persistence: save/load discovered overlay data to SFramesDB
--------------------------------------------------------------------------------
local function GetGlobalDB()
if not SFramesGlobalDB then SFramesGlobalDB = {} end
return SFramesGlobalDB
end
local function LoadPersistedData()
local gdb = GetGlobalDB()
local saved = gdb.MapRevealScanData
if type(saved) ~= "table" then return end
local count = 0
for zone, overlays in pairs(saved) do
if type(overlays) == "table" and table.getn(overlays) > 0 then
if not scannedOverlays[zone] or table.getn(scannedOverlays[zone]) < table.getn(overlays) then
scannedOverlays[zone] = overlays
count = count + 1
end
end
end
return count
end
local function SavePersistedData()
local gdb = GetGlobalDB()
if type(gdb.MapRevealScanData) ~= "table" then
gdb.MapRevealScanData = {}
end
for zone, overlays in pairs(scannedOverlays) do
local existing = gdb.MapRevealScanData[zone]
if not existing or table.getn(existing) < table.getn(overlays) then
gdb.MapRevealScanData[zone] = overlays
end
end
end
--------------------------------------------------------------------------------
-- Overlay name index for deduplication when merging
--------------------------------------------------------------------------------
local function BuildOverlayIndex(overlayList)
local idx = {}
if not overlayList then return idx end
for i = 1, table.getn(overlayList) do
local entry = overlayList[i]
local _, _, name = string.find(entry, "^([^:]+):")
if name then
idx[string.upper(name)] = i
end
end
return idx
end
local function MergeScannedDataIntoDB()
local db = GetOverlayDB()
if not db then return end
for zone, data in pairs(scannedOverlays) do
if not db[zone] then
db[zone] = data
else
local existingIdx = BuildOverlayIndex(db[zone])
for i = 1, table.getn(data) do
local _, _, newName = string.find(data[i], "^([^:]+):")
if newName and not existingIdx[string.upper(newName)] then
table.insert(db[zone], data[i])
existingIdx[string.upper(newName)] = table.getn(db[zone])
end
end
end
end
end
local function PatchOverlayDB()
if overlayDBPatched then return end
overlayDBPatched = true
@@ -87,25 +119,80 @@ local function PatchOverlayDB()
if not db then return end
for zone, data in pairs(TurtleWoW_Zones) do
db[zone] = data
if table.getn(data) > 0 then
db[zone] = data
end
end
for zone, data in pairs(scannedOverlays) do
if not db[zone] then
db[zone] = data
MergeScannedDataIntoDB()
end
local function MergeOverlaysForZone(zone)
local db = GetOverlayDB()
if not db or not scannedOverlays[zone] then return end
if not db[zone] then
db[zone] = scannedOverlays[zone]
return
end
local existingIdx = BuildOverlayIndex(db[zone])
local data = scannedOverlays[zone]
for i = 1, table.getn(data) do
local _, _, newName = string.find(data[i], "^([^:]+):")
if newName and not existingIdx[string.upper(newName)] then
table.insert(db[zone], data[i])
existingIdx[string.upper(newName)] = table.getn(db[zone])
end
end
end
local function MergeScannedData()
local db = GetOverlayDB()
if not db then return end
--------------------------------------------------------------------------------
-- Passive overlay discovery: captures explored overlay data from the API
-- every time the world map updates, discovering new overlays automatically
--------------------------------------------------------------------------------
local function PassiveCollectOverlays()
local mapFile = GetMapInfo and GetMapInfo()
if not mapFile or mapFile == "" or mapFile == "World" then return end
for zone, data in pairs(scannedOverlays) do
if not db[zone] or table.getn(db[zone]) < table.getn(data) then
db[zone] = data
local numOverlays = GetNumMapOverlays and GetNumMapOverlays() or 0
if numOverlays == 0 then return end
local currentOverlays = {}
local hasNew = false
for i = 1, numOverlays do
local texName, texW, texH, offX, offY = GetMapOverlayInfo(i)
if texName and texName ~= "" then
local _, _, name = string.find(texName, "\\([^\\]+)$")
if name then
name = string.upper(name)
table.insert(currentOverlays, name .. ":" .. texW .. ":" .. texH .. ":" .. offX .. ":" .. offY)
end
end
end
if table.getn(currentOverlays) == 0 then return end
if not scannedOverlays[mapFile] then
scannedOverlays[mapFile] = currentOverlays
hasNew = true
else
local existingIdx = BuildOverlayIndex(scannedOverlays[mapFile])
for i = 1, table.getn(currentOverlays) do
local _, _, newName = string.find(currentOverlays[i], "^([^:]+):")
if newName and not existingIdx[string.upper(newName)] then
table.insert(scannedOverlays[mapFile], currentOverlays[i])
existingIdx[string.upper(newName)] = table.getn(scannedOverlays[mapFile])
hasNew = true
end
end
end
if hasNew then
MergeOverlaysForZone(mapFile)
SavePersistedData()
end
end
local function GetConfig()
@@ -251,8 +338,13 @@ function MapReveal:Initialize()
return
end
local loadedCount = LoadPersistedData()
PatchOverlayDB()
if loadedCount and loadedCount > 0 then
MergeScannedDataIntoDB()
end
if not origWorldMapFrame_Update and WorldMapFrame_Update then
origWorldMapFrame_Update = WorldMapFrame_Update
WorldMapFrame_Update = function()
@@ -263,6 +355,8 @@ function MapReveal:Initialize()
origWorldMapFrame_Update()
PassiveCollectOverlays()
local cfg = GetConfig()
if cfg.enabled then
DoMapRevealUpdate()
@@ -358,16 +452,30 @@ local function ProcessScanZone()
if table.getn(overlays) > 0 then
local db = GetOverlayDB()
local existing = db and db[mapFile]
local existingCount = existing and table.getn(existing) or 0
if not existing then
scanNewZones[mapFile] = overlays
scanResults[mapFile] = { overlays = overlays, status = "new", count = table.getn(overlays) }
elseif table.getn(overlays) > existingCount then
scanUpdatedZones[mapFile] = overlays
scanResults[mapFile] = { overlays = overlays, status = "updated", count = table.getn(overlays), oldCount = existingCount }
else
scanResults[mapFile] = { status = "ok", count = existingCount }
local existingIdx = BuildOverlayIndex(existing)
local newEntries = 0
for i = 1, table.getn(overlays) do
local _, _, oName = string.find(overlays[i], "^([^:]+):")
if oName and not existingIdx[string.upper(oName)] then
newEntries = newEntries + 1
end
end
if newEntries > 0 then
scanUpdatedZones[mapFile] = overlays
scanResults[mapFile] = {
overlays = overlays, status = "updated",
count = table.getn(existing) + newEntries,
oldCount = table.getn(existing)
}
else
scanResults[mapFile] = { status = "ok", count = table.getn(existing) }
end
end
end
end
@@ -392,6 +500,7 @@ function MapReveal:FinishScan()
local cf = DEFAULT_CHAT_FRAME
local newCount = 0
local updCount = 0
local newOverlayCount = 0
for zone, overlays in pairs(scanNewZones) do
newCount = newCount + 1
@@ -399,10 +508,23 @@ function MapReveal:FinishScan()
end
for zone, overlays in pairs(scanUpdatedZones) do
updCount = updCount + 1
scannedOverlays[zone] = overlays
if not scannedOverlays[zone] then
scannedOverlays[zone] = overlays
else
local existingIdx = BuildOverlayIndex(scannedOverlays[zone])
for i = 1, table.getn(overlays) do
local _, _, oName = string.find(overlays[i], "^([^:]+):")
if oName and not existingIdx[string.upper(oName)] then
table.insert(scannedOverlays[zone], overlays[i])
existingIdx[string.upper(oName)] = table.getn(scannedOverlays[zone])
newOverlayCount = newOverlayCount + 1
end
end
end
end
MergeScannedData()
MergeScannedDataIntoDB()
SavePersistedData()
cf:AddMessage("|cffffb3d9[Nanami-UI]|r 地图扫描完成!")
cf:AddMessage(string.format(" 扫描了 |cff00ff00%d|r 个区域", table.getn(scanQueue)))
@@ -427,6 +549,7 @@ function MapReveal:FinishScan()
cf:AddMessage(" 所有区域数据已是最新,未发现变动。")
end
cf:AddMessage(" 数据已自动保存,下次登录无需重新扫描。")
cf:AddMessage(" 提示: 新发现的区域仅记录已探索区域的覆盖层,完全探索后再次扫描可获取完整数据。")
if WorldMapFrame and WorldMapFrame:IsShown() then
@@ -510,3 +633,43 @@ function MapReveal:ExportScannedData()
cf:AddMessage("|cffffb3d9[MapReveal]|r 没有扫描到的新数据可导出。先运行 /nui mapscan")
end
end
function MapReveal:ShowStats()
local cf = DEFAULT_CHAT_FRAME
local db = GetOverlayDB()
cf:AddMessage("|cffffb3d9[MapReveal]|r 覆盖层数据统计:")
local dbZones, dbOverlays = 0, 0
if db then
for zone, data in pairs(db) do
dbZones = dbZones + 1
dbOverlays = dbOverlays + table.getn(data)
end
end
cf:AddMessage(string.format(" 数据库: |cff00ff00%d|r 个区域, |cff00ff00%d|r 个覆盖层", dbZones, dbOverlays))
local scanZones, scanOverlays = 0, 0
for zone, data in pairs(scannedOverlays) do
scanZones = scanZones + 1
scanOverlays = scanOverlays + table.getn(data)
end
cf:AddMessage(string.format(" 已发现: |cff00ff00%d|r 个区域, |cff00ff00%d|r 个覆盖层 (通过扫描/浏览)", scanZones, scanOverlays))
local savedZones = 0
local gdb = GetGlobalDB()
if type(gdb.MapRevealScanData) == "table" then
for _ in pairs(gdb.MapRevealScanData) do
savedZones = savedZones + 1
end
end
cf:AddMessage(string.format(" 已持久化: |cff00ff00%d|r 个区域", savedZones))
cf:AddMessage(" 提示: 打开世界地图浏览各区域可自动发现新覆盖层数据")
end
function MapReveal:ClearSavedData()
local gdb = GetGlobalDB()
gdb.MapRevealScanData = nil
scannedOverlays = {}
SFrames:Print("地图扫描数据已清除。重新加载UI后生效。")
end