天赋修改更直接展示预览时天赋变更信息
世界地图揭示迷雾全修复
This commit is contained in:
289
MapReveal.lua
289
MapReveal.lua
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user