Files
Questie-Octo/Map/CandidateIndex.lua
T
2026-08-16 20:28:28 -05:00

145 lines
3.5 KiB
Lua

QuestieOcto.MapCandidateIndex = QuestieOcto.MapCandidateIndex or {}
local X = QuestieOcto.MapCandidateIndex
X.byMap={}
X.ready=false
X.running=false
X.generation=0
X.stats={scanned=0,maps=0,links=0,currentReady=false,currentMap=nil}
local function Add(mapID,questID)
mapID=tonumber(mapID)
if not mapID then return end
local bucket=X.byMap[mapID]
if not bucket then
bucket={}
X.byMap[mapID]=bucket
X.stats.maps=X.stats.maps+1
end
if not bucket[questID] then
bucket[questID]=true
X.stats.links=X.stats.links+1
end
end
local function IndexCoords(coords,questID)
local seen={}
for _,coord in pairs(coords or {}) do
if type(coord)=="table" and tonumber(coord[3]) then
local mapID=tonumber(coord[3])
if not seen[mapID] then
seen[mapID]=true
Add(mapID,questID)
end
end
end
end
local function StarterCreatureCoords(q,creatureID)
local marker=q and q.conditionalMapMarker or nil
if marker and tonumber(marker.creatureID)==tonumber(creatureID) then
return marker.coords
end
return QuestieOcto.DatabaseAPI:GetCreatureCoords(creatureID)
end
local function IndexQuest(q)
if not q then return end
for _,id in pairs(q.starts.creature or {}) do
IndexCoords(StarterCreatureCoords(q,id),q.id)
end
for _,id in pairs(q.starts.gameObject or {}) do
IndexCoords(QuestieOcto.DatabaseAPI:GetObjectCoords(id),q.id)
end
for _,itemID in pairs(q.starts.item or {}) do
local sources=QuestieOcto.DatabaseAPI:GetItemSources(itemID)
if sources then
for id in pairs(sources.Creature or {}) do
IndexCoords(QuestieOcto.DatabaseAPI:GetCreatureCoords(id),q.id)
end
for id in pairs(sources.GameObject or {}) do
IndexCoords(QuestieOcto.DatabaseAPI:GetObjectCoords(id),q.id)
end
end
end
end
function X:Get(mapID)
local bucket=self.byMap[tonumber(mapID)]
local ids={}
if bucket then
for questID in pairs(bucket) do
table.insert(ids,questID)
end
table.sort(ids)
end
return ids
end
function X:HasMap(mapID)
return self.byMap[tonumber(mapID)] and true or false
end
function X:Build()
if not QuestieOcto.DatabaseAPI:IsReady() then return end
self.generation=self.generation+1
local generation=self.generation
self.byMap={}
self.ready=false
self.running=true
self.stats={scanned=0,maps=0,links=0,currentReady=false,currentMap=QuestieOcto.API:GetBestMapForPlayer()}
local ids=QuestieOcto.DatabaseAPI:GetQuestIDs()
local current=self.stats.currentMap
-- Current map receives a direct synchronous-ish first slice so the initial
-- zone remains fast even before the whole index exists.
local pos=1
local function step()
if generation~=X.generation then return end
local count=0
while pos<=table.getn(ids) and count<256 do
local questID=ids[pos]
pos=pos+1
X.stats.scanned=X.stats.scanned+1
IndexQuest(QuestieOcto.QuestModel:Get(questID))
count=count+1
end
if current and X.byMap[tonumber(current)] then
X.stats.currentReady=true
QuestieOcto:SendMessage("MAP_CANDIDATE_INDEX_CURRENT",current)
end
if pos<=table.getn(ids) then
QuestieOcto.Scheduler:Enqueue(step,"map-candidate-index")
else
X.running=false
X.ready=true
X.stats.currentReady=true
QuestieOcto:SendMessage("MAP_CANDIDATE_INDEX_READY")
end
end
QuestieOcto.Scheduler:Enqueue(step,"map-candidate-index")
end
function X:OnDatabaseReady()
self:Build()
end
QuestieOcto:RegisterMessage("DATABASE_API_READY",X,"OnDatabaseReady")