Files

203 lines
5.4 KiB
Lua

QuestieOcto.Database = QuestieOcto.Database or {}
local D = QuestieOcto.Database
D.ready = false
D.running = false
D.jobs = {}
D.jobIndex = 1
D.stats = { merged=0, jobs=0 }
local DATASETS = {
"items", "quests", "quests-itemreq", "objects", "units",
"zones", "professions", "areatrigger", "refloot", "minimap", "meta"
}
local TEXT_DATASETS = {
"items", "quests", "objects", "units", "zones", "professions"
}
local FIELD_MERGE_DATASETS = { items=true, quests=true, objects=true, units=true }
local function AddMergeJob(target,patch,name,mode)
if target and patch then
table.insert(D.jobs,{ target=target, patch=patch, name=name, mode=mode or "replace" })
end
end
local function BuildMergeJobs()
D.jobs = {}
D.jobIndex = 1
D.stats = { merged=0, jobs=0 }
if not pfDB then return end
-- Locale-independent Turtle patches always merge into the core data first.
for _,name in pairs(DATASETS) do
local bucket=pfDB[name]
if bucket and bucket["data-turtle"] and bucket["data"] then
AddMergeJob(bucket["data"],bucket["data-turtle"],name..".data",FIELD_MERGE_DATASETS[name] and "fields" or "replace")
end
end
-- English is the only packaged presentation database.
for _,name in pairs(TEXT_DATASETS) do
local bucket=pfDB[name]
if bucket then
AddMergeJob(bucket["enUS"],bucket["enUS-turtle"],name..".enUS","locale")
end
end
if pfDB["minimap-turtle"] and pfDB["minimap"] then
AddMergeJob(pfDB["minimap"],pfDB["minimap-turtle"],"minimap")
end
if pfDB["meta-turtle"] and pfDB["meta"] then
AddMergeJob(pfDB["meta"],pfDB["meta-turtle"],"meta")
end
D.stats.jobs=table.getn(D.jobs)
end
local function StartJob(job)
if job.started then return end
-- Never materialize every patch key in one frame. Some Turtle datasets are
-- large enough that the old key-array construction caused a visible startup
-- hitch before the incremental merge even began.
job.started=true
job.cursor=nil
end
local function ProcessJob(job)
StartJob(job)
local count=0
while count<256 do
local key,value=next(job.patch,job.cursor)
if key==nil then return true end
job.cursor=key
if type(value)=="string" and value=="_" then
job.target[key]=nil
elseif (job.mode=="fields" or job.mode=="locale") and type(value)=="table" and type(job.target[key])=="table" then
local base=job.target[key]
for field,fieldValue in pairs(value) do
if type(fieldValue)=="string" and fieldValue=="_" then
base[field]=nil
else
base[field]=fieldValue
end
end
else
job.target[key]=value
end
D.stats.merged=D.stats.merged+1
count=count+1
end
return false
end
local function Finalize()
if pfDB.items then pfDB.items.loc=pfDB.items.enUS end
if pfDB.units then pfDB.units.loc=pfDB.units.enUS end
if pfDB.objects then pfDB.objects.loc=pfDB.objects.enUS end
if pfDB.quests then pfDB.quests.loc=pfDB.quests.enUS end
if pfDB.zones then pfDB.zones.loc=pfDB.zones.enUS end
if pfDB.professions then pfDB.professions.loc=pfDB.professions.enUS end
for _,name in pairs(TEXT_DATASETS) do
local bucket=pfDB[name]
if bucket then bucket["enUS-turtle"]=nil end
end
-- Apply the sparse Tortoise/Octo enrichment only after the base + Turtle
-- field-by-field merge is final. This restores server fields the compact
-- pfQuest runtime database intentionally discarded without replacing the
-- working pfQuest quest records wholesale.
if QuestieOcto.Enrichment then
if not QuestieOcto.Enrichment:Apply() then
D.running=false
D.ready=false
QuestieOcto:Error("quest-truth enrichment could not be applied")
return
end
end
if QuestieOcto.QuestModel and QuestieOcto.QuestModel.Clear then
QuestieOcto.QuestModel:Clear()
end
D.running=false
D.ready=true
QuestieOcto:SendMessage("DATABASE_READY")
end
function D:Start()
if self.ready or self.running then return end
if not pfDB then
QuestieOcto:Error("raw quest database did not load")
return
end
BuildMergeJobs()
self.running=true
local function step()
local job=D.jobs[D.jobIndex]
if not job then
Finalize()
return
end
if ProcessJob(job) then D.jobIndex=D.jobIndex+1 end
QuestieOcto.Scheduler:Enqueue(step,"database-merge")
end
QuestieOcto.Scheduler:Enqueue(step,"database-merge")
end
local function Count(t)
local n=0
if t then for _ in pairs(t) do n=n+1 end end
return n
end
function D:GetActiveLocale()
return "enUS"
end
function D:Counts()
if not pfDB then return 0,0,0,0 end
return
Count(pfDB.quests and pfDB.quests.data),
Count(pfDB.items and pfDB.items.data),
Count(pfDB.units and pfDB.units.data),
Count(pfDB.objects and pfDB.objects.data)
end
function D:GetRawQuest(id)
if not self.ready then return nil end
return pfDB.quests and pfDB.quests.data and pfDB.quests.data[id]
end
function D:GetQuestLocale(id)
if not self.ready then return nil end
return pfDB.quests and pfDB.quests.loc and pfDB.quests.loc[id]
end
function D:GetRawItem(id)
if not self.ready then return nil end
return pfDB.items and pfDB.items.data and pfDB.items.data[id]
end
function D:GetRawUnit(id)
if not self.ready then return nil end
return pfDB.units and pfDB.units.data and pfDB.units.data[id]
end
function D:GetRawObject(id)
if not self.ready then return nil end
return pfDB.objects and pfDB.objects.data and pfDB.objects.data[id]
end