87617c4eed
Added LibMapData and began transitioning map data needs to use LibMapData. Began changing the data collection, yet again. Once this goes beta, the new collection system will be in place... My hope is to allow QH to "learn" as you play, eliminating any need for data compilation, though I will still make attempts to compile said data into a full on db. Added some code that will eventually be usable to get data from LightHeaded. This is not yet implemented in full, but will be the preferred method of QH doesn't know about a quest. Order of preference will eventually be: 1) Learned data, 2) Internal DB, 3) LightHeaded, 4) WoW client. NOTE: THIS COMMIT IS ON THE WOW-DB-GET BRANCH. An alpha release will be up on the downloads page by 6:30 US EST on February 29, 2012 (tomorrow). I THINK I have covered all the changes in this, but I have done so much since my last commit, I cannot be sure.
455 lignes
13 Kio
Lua
455 lignes
13 Kio
Lua
|
|
local GetTime = QuestHelper_GetTime
|
|
|
|
QuestHelper_File["db_get.lua"] = "4.0.1.$svnversion$"
|
|
QuestHelper_Loadtime["db_get.lua"] = GetTime()
|
|
|
|
local dev_mode = (QuestHelper_File["db_get.lua"] == "Development Version")
|
|
QHDB_Export = {}
|
|
local export = false
|
|
-- yoink
|
|
--[[
|
|
local QHDB_temp = QHDB
|
|
QHDB = nil
|
|
local QHDB = QHDB_temp]]
|
|
QuestHelper: Assert(#QHDB == 4, "Please make sure that you are loading a locale.")
|
|
|
|
local weak_v = { __mode = 'v' }
|
|
local weak_k = { __mode = 'k' }
|
|
|
|
local cache = {}
|
|
|
|
local frequencies = setmetatable({}, weak_k)
|
|
|
|
-- guhhh just want this to work
|
|
local freq_group = setmetatable({}, weak_k)
|
|
local freq_id = setmetatable({}, weak_k)
|
|
|
|
local function DBC_Get(group, id)
|
|
if not cache[group] then return end
|
|
return cache[group][id]
|
|
end
|
|
|
|
local function DBC_Put(group, id, item)
|
|
if not cache[group] then cache[group] = setmetatable({}, weak_v) end
|
|
QuestHelper: Assert(not cache[group][id])
|
|
cache[group][id] = item
|
|
|
|
--DB_how_many_are_used()
|
|
end
|
|
|
|
local function mark(tab, tomark)
|
|
for k, v in pairs(tab) do
|
|
if k ~= "__owner" and type(v) == "table" then
|
|
mark(v, tomark)
|
|
end
|
|
end
|
|
tab.__owner = tomark
|
|
end
|
|
|
|
local function read_adaptint(data, offset)
|
|
local stx = 0
|
|
local acu = 1
|
|
while true do
|
|
local v = strbyte(data, offset)
|
|
QuestHelper: Assert(v, string.format("%d %d", #data, offset))
|
|
stx = stx + acu * math.floor(v / 2)
|
|
offset = offset + 1
|
|
acu = acu * 128
|
|
if mod(v, 2) == 0 then break end
|
|
end
|
|
return stx, offset
|
|
end
|
|
|
|
local function search_index(index, data, item)
|
|
--[[Header format:
|
|
|
|
Itemid (0 for endnode)
|
|
Offset
|
|
Length
|
|
Rightlink]]
|
|
|
|
local cofs = 1
|
|
--[[ assert(index and type(index) == "string") ]]
|
|
--[[ assert(data and type(data) == "string") ]]
|
|
|
|
while true do
|
|
local idx, ofs, len, rlink
|
|
idx, cofs = read_adaptint(index, cofs)
|
|
if idx == 0 then return end
|
|
ofs, cofs = read_adaptint(index, cofs)
|
|
len, cofs = read_adaptint(index, cofs)
|
|
rlink, cofs = read_adaptint(index, cofs)
|
|
|
|
if idx == item then
|
|
return strsub(data, ofs, ofs + len)
|
|
end
|
|
|
|
if idx < item then cofs = cofs + rlink end
|
|
end
|
|
end
|
|
|
|
local initted = false
|
|
function DB_Init()
|
|
QuestHelper: Assert(not initted)
|
|
for _, db in ipairs(QHDB) do
|
|
for _, v in pairs(db) do
|
|
--print("db", not not v.__dictionary, not not v.__tokens)
|
|
if v.__dictionary and v.__tokens then
|
|
local redictix = v.__dictionary
|
|
if not redictix:find("\"") then redictix = redictix .. "\"" end
|
|
if not redictix:find(",") then redictix = redictix .. "," end
|
|
if not redictix:find("\\") then redictix = redictix .. "\\" end
|
|
local tokens = loadstring("return {" .. QH_LZW_Decompress_Dicts_Arghhacky(v.__tokens, redictix) .. "}")()
|
|
QuestHelper: Assert(tokens)
|
|
|
|
local _, _, prep = QH_LZW_Prepare_Arghhacky(v.__dictionary, tokens)
|
|
QuestHelper: Assert(prep)
|
|
|
|
QuestHelper: Assert(type(prep) == "table")
|
|
|
|
v.__tokens = prep
|
|
end
|
|
end
|
|
end
|
|
initted = true
|
|
QH_UpdateQuests() -- just in case it's been waiting on us (it has almost certainly been waiting on us)
|
|
end
|
|
|
|
function DB_Ready()
|
|
return initted
|
|
end
|
|
|
|
function DB_HasItem(group, id)
|
|
QuestHelper: Assert(initted)
|
|
|
|
if group == "quest" then
|
|
if type(id) == "number" and id > 0 then return true
|
|
else return false
|
|
end
|
|
end
|
|
|
|
for _, db in ipairs(QHDB) do
|
|
if db[group] then
|
|
if db[group][id] then
|
|
return true
|
|
end
|
|
|
|
if type(id) == "number" and id > 0 and db[group].__serialize_index and db[group].__serialize_data and search_index(db[group].__serialize_index, db[group].__serialize_data, id) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
local function GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
local POIFrame, questFrame
|
|
QuestMapUpdateAllQuests()
|
|
QuestPOIUpdateIcons()
|
|
WorldMapFrame_UpdateQuests()
|
|
|
|
for i = 1, MAX_NUM_QUESTS do
|
|
questFrame = _G["WorldMapQuestFrame" .. i]
|
|
if questFrame then
|
|
if questFrame.questId == qid then
|
|
POIFrame = questFrame.poiIcon
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
return questFrame, POIFrame
|
|
end
|
|
|
|
local function GetBlizzardQuestInfoFrame(qid, map)
|
|
if map then SetMapByID(map) end
|
|
QuestMapUpdateAllQuests()
|
|
QuestPOIUpdateIcons()
|
|
WorldMapFrame_UpdateQuests()
|
|
|
|
local POIFrame
|
|
local questFrame
|
|
local dLvl
|
|
|
|
if map and GetNumDungeonMapLevels() > 0 then -- Suspicion is that each dungeon level has to be iterated.
|
|
for i = 1, GetNumDungeonMapLevels() do
|
|
SetDungeonMapLevel(i)
|
|
questFrame, POIFrame = GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
if POIFrame then
|
|
dLvl = i
|
|
break
|
|
end
|
|
end
|
|
else -- Only need to call once
|
|
questFrame, POIFrame = GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
end
|
|
|
|
return questFrame, POIFrame, dLvl or 0
|
|
end
|
|
|
|
local function GetBlizzardQuestInfo(qid)
|
|
local questFrame, POIFrame, qdLvl = GetBlizzardQuestInfoFrame(qid)
|
|
local mapId = GetCurrentMapAreaID()
|
|
local c, z
|
|
local dLvl = false
|
|
local qMapId
|
|
|
|
if GetNumDungeonMapLevels() > 0 then dLvl = GetCurrentMapDungeonLevel() end
|
|
|
|
if not POIFrame then
|
|
-- Iterate over all maps to try and find it (we are of course assuming that the player has the quest, otherwise we will be SOL.
|
|
local maps = QuestHelper.LibMapData:GetAllMapIDs()
|
|
for _, map in pairs(maps) do
|
|
if map >= 0 and not QuestHelper.LibMapData:IsContinentMap(map) then
|
|
|
|
questFrame, POIFrame, qdLvl = GetBlizzardQuestInfoFrame(qid, map)
|
|
|
|
if POIFrame then
|
|
qMapId = map
|
|
break
|
|
end
|
|
end
|
|
end
|
|
c, z = GetCurrentMapContinent(), GetCurrentMapZone()
|
|
SetMapByID(mapId)
|
|
if not POIFrame then return nil end -- At this point we either have the quest or we are SOL.
|
|
else
|
|
qMapId = mapId
|
|
c, z = GetCurrentMapContinent(), GetCurrentMapZone()
|
|
end
|
|
|
|
local _, _, _, x, y = POIFrame:GetPoint()
|
|
|
|
if not x or not y then return nil end
|
|
|
|
local frame = WorldMapDetailFrame
|
|
local width, height = frame:GetWidth(), frame:GetHeight()
|
|
local wm_scale, poi_scale = frame:GetScale(), POIFrame:GetScale()
|
|
|
|
-- Convert from yards to %
|
|
local cx = ((x / (wm_scale / poi_scale)) / width)
|
|
local cy = ((-y / (wm_scale / poi_scale)) / height)
|
|
|
|
|
|
if cx < 0 or cx > 1 or cy < 0 or cy > 1 then return nil end
|
|
|
|
-- Now we want to convert to proper format for QH.
|
|
-- Look at WoWPro:findBlizzCoords(qid) for remainder
|
|
local _, contX, contY = QuestHelper.Astrolabe:GetAbsoluteContinentPosition(c, z, cx, cy)
|
|
--contX, contY = contX / QuestHelper.Astrolabe:GetZoneWidth(c, 0), contY / QuestHelper.Astrolabe:GetZoneHeight(c, 0)
|
|
|
|
local solid = { ["continent"] = c, contX - 10, contY - 10, contX + 10, contY - 10, contX + 10, contY + 10, contX - 10, contY + 10 }
|
|
local ret = {}
|
|
|
|
ret.solid = solid
|
|
ret.criteria = {}
|
|
|
|
local questIdx = GetQuestLogIndexByID(qid)
|
|
local numCrit = GetNumQuestLeaderBoards(questIdx)
|
|
local loc = { ["loc"] = { { ["p"] = qMapId, ["x"] = contX, ["y"] = contY} } }
|
|
for i = 1, numCrit do
|
|
table.insert(ret.criteria, loc)
|
|
end
|
|
|
|
ret.name = GetQuestLogTitle(questIdx)
|
|
ret.Blizzard = true
|
|
return ret
|
|
end
|
|
|
|
local function GetLightHeadedQuestInfo(qid)
|
|
if not LightHeaded or type(LightHeaded) ~= "table" then return nil end -- LH not loaded
|
|
|
|
local npcid, npcname, stype
|
|
local coords = {}
|
|
|
|
_, _, _, _, _, _, _, stype, npcname, npcid = LightHeaded:GetQuestInfo(qid)
|
|
|
|
-- Note: If we want the quest giver, we need fields 5, 6 and 7 above, rather than what we have gotten.
|
|
--
|
|
if stype == "npc" then
|
|
local data = LightHeaded:LoadNPCData(tonumber(npcid))
|
|
if not data then return end -- LightHeaded has no clue about the given NPC, despite giving us the id.
|
|
for zid,x,y in data:gmatch("([^,]+),([^,]+),([^:]+):") do
|
|
table.insert(coords, {["p"] = zid, ["x"] = x, ["y"] = y})
|
|
end
|
|
end
|
|
|
|
--can't return coordinates until we know more about what we are getting and then convert accordingly.
|
|
for k, v in pairs(coords) do for k1, v1 in pairs(v) do print(k, k1, v1) end end
|
|
--return coords
|
|
return nil
|
|
end
|
|
|
|
local function GetSelfQuestInfo(qid)
|
|
return nil
|
|
end
|
|
|
|
-- Returns x and y in yards relative to something... Continent?
|
|
local function GetQuestInfo(qid)
|
|
assert(type(qid) == "number")
|
|
local coords = GetSelfQuestInfo(qid)
|
|
--if not coords then coords = GetLightHeadedQuestInfo(qid) end
|
|
if not coords then
|
|
coords = GetBlizzardQuestInfo(qid)
|
|
end
|
|
|
|
return coords -- Might still be nil, but if we don't have anything from Blizz, prolly nothing can be done.
|
|
end
|
|
|
|
function DB_GetItem(group, id, silent, register)
|
|
QuestHelper: Assert(initted)
|
|
|
|
QuestHelper: Assert(group, string.format("%s %s", tostring(group), tostring(id)))
|
|
QuestHelper: Assert(id, string.format("%s %s", tostring(group), tostring(id)))
|
|
local ite = DBC_Get(group, id)
|
|
|
|
if not ite and group == "flightpaths" then return nil end
|
|
|
|
if not ite and group == "quest" then
|
|
-- Loop over zones AND floors
|
|
-- see QuestRouterLite.lua for specific calls.
|
|
-- In the end, the item returned MUST be "formatted" the same as a true QHDB item.
|
|
ite = GetQuestInfo(id)
|
|
end
|
|
|
|
if not ite then
|
|
if type(id) == "string" then QuestHelper: Assert(not id:match("__.*")) end
|
|
|
|
--QuestHelper:TextOut(string.format("%s %d", group, id))
|
|
|
|
for _, db in ipairs(QHDB) do
|
|
--print(db, db[group], db[group] and db[group][id], type(group), type(id))
|
|
if db[group] then
|
|
local dat
|
|
if db[group][id] then
|
|
dat = db[group][id]
|
|
end
|
|
|
|
--print(not dat, type(id), id, not not db[group].__serialize_index, not not db[group].__serialize_index)
|
|
if not dat and type(id) == "number" and id > 0 and db[group].__serialize_index and db[group].__serialize_data then
|
|
dat = search_index(db[group].__serialize_index, db[group].__serialize_data, id)
|
|
end
|
|
|
|
if dat then
|
|
if not ite then ite = QuestHelper:CreateTable("db") end
|
|
|
|
local srctab
|
|
|
|
if type(dat) == "string" then
|
|
QuestHelper: Assert(db[group].__tokens == nil or type(db[group].__tokens) == "table")
|
|
srctab = loadstring("return {" .. (db[group].__prefix or "") .. QH_LZW_Decompress_Dicts_Prepared_Arghhacky(dat, db[group].__dictionary, nil, db[group].__tokens) .. (db[group].__suffix or "") .. "}")()
|
|
elseif type(dat) == "table" then
|
|
srctab = dat
|
|
else
|
|
QuestHelper: Assert()
|
|
end
|
|
|
|
for k, v in pairs(srctab) do
|
|
QuestHelper: Assert(not ite[k] or k == "used")
|
|
ite[k] = v
|
|
if export then
|
|
if not QHDB_Export[group] then QHDB_Export[group] = {} end
|
|
if not QHDB_Export[group][id] then QHDB_Export[group][id] = {} end
|
|
QHDB_Export[group][id][k] = v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if ite then
|
|
--print("marking", group, id, silent, register)
|
|
mark(ite, ite)
|
|
--print("done marking")
|
|
|
|
DBC_Put(group, id, ite)
|
|
|
|
freq_group[ite] = group
|
|
freq_id[ite] = id
|
|
else
|
|
if not silent then
|
|
QuestHelper:TextOut(string.format("Tried to get %s/%s, failed", tostring(group), tostring(id)))
|
|
end
|
|
end
|
|
end
|
|
|
|
if ite then
|
|
frequencies[ite] = (frequencies[ite] or 0) + (register and 1 or 1000000000) -- effectively infinity
|
|
end
|
|
|
|
return ite
|
|
end
|
|
|
|
local function incinerate(ite, crunchy)
|
|
if dev_mode then return end -- wellllp
|
|
|
|
if not crunchy[ite] then
|
|
crunchy[ite] = true
|
|
|
|
for k, v in pairs(ite) do
|
|
if type(k) == "table" then incinerate(k, crunchy) end
|
|
if type(v) == "table" then incinerate(v, crunchy) end
|
|
end
|
|
end
|
|
end
|
|
|
|
function DB_ReleaseItem(ite)
|
|
QuestHelper: Assert(ite)
|
|
frequencies[ite] = frequencies[ite] - 1
|
|
|
|
if frequencies[ite] == 0 then
|
|
--print("incinerating", freq_group[ite], freq_id[ite])
|
|
if cache[freq_group[ite]] then
|
|
cache[freq_group[ite]][freq_id[ite]] = nil
|
|
end
|
|
freq_group[ite] = nil
|
|
freq_id[ite] = nil
|
|
|
|
local incin = QuestHelper:CreateTable("incinerate")
|
|
incinerate(ite, incin)
|
|
for k, _ in pairs(incin) do
|
|
QuestHelper:ReleaseTable(k)
|
|
end -- burn baby burn
|
|
QuestHelper:ReleaseTable(incin)
|
|
end
|
|
end
|
|
|
|
function DB_ListItems(group)
|
|
local tab = {}
|
|
for _, db in ipairs(QHDB) do
|
|
if db[group] then
|
|
QuestHelper: Assert(not db.__serialize_index and not db.__serialize_data)
|
|
for k, _ in pairs(db[group]) do
|
|
if type(k) ~= "string" or not k:match("__.*") then
|
|
tab[k] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local rv = {}
|
|
for k, _ in pairs(tab) do
|
|
table.insert(rv, k)
|
|
end
|
|
|
|
return rv
|
|
end
|
|
|
|
function DB_how_many_are_used()
|
|
local count = 0
|
|
for k, v in pairs(cache) do
|
|
for k2, v2 in pairs(v) do
|
|
count = count + 1
|
|
end
|
|
end
|
|
print(count)
|
|
end
|
|
|
|
function DB_DumpItems()
|
|
local dt = {}
|
|
for k, v in pairs(freq_group) do
|
|
dt[string.format("%s/%s", freq_group[k], tostring(freq_id[k]))] = true
|
|
end
|
|
return dt
|
|
end
|