feat: Questie-X v1.1.4 - plugin architecture, monorepo, rebranding
- Repoint remote to Xurkon/Questie-X - Add QuestiePluginAPI, QuestieServer, QuestieLearnerComms modules - Add Questie-X.toc, Questie-X-Classic.toc, Questie-X-TBC.toc, Questie-X-Turtle.toc - Remove embedded Database/Ascension and Database/Ebonhold (migrated to plugins) - Add Plugins/ directory with NTFS junctions for Questie-X-AscensionDB and Questie-X-EbonholdDB - Add LibDeflate, XXH_Lua_Lib, LibDBIcon-1.0, LibDataBroker-1.1 - Update README: Questie-X branding, logo, plugin install guide, plugin API docs - Update CHANGELOG: v1.1.4 entry documenting all architectural changes - Update .gitignore: exclude plugin junctions, __pycache__, .agents, debug files - Various module updates: corrections, map, tracker, tooltips, quest, options
This commit is contained in:
@@ -9,8 +9,9 @@ local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
||||
local Sounds = QuestieLoader:ImportModule("Sounds")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local QuestieCompat = QuestieCompat -- Ensure it's loaded
|
||||
local GetQuestLogTitle = QuestieCompat.GetQuestLogTitle
|
||||
local C_QuestLog_GetQuestObjectives = QuestieCompat.C_QuestLog.GetQuestObjectives
|
||||
local C_QuestLog_GetQuestObjectives = QuestieCompat.C_QuestLog and QuestieCompat.C_QuestLog.GetQuestObjectives
|
||||
local HaveQuestData = QuestieCompat.HaveQuestData
|
||||
|
||||
local stringByte = string.byte
|
||||
@@ -88,7 +89,7 @@ local function GetNewObjectives(questId, oldObjectives, questLogIndex)
|
||||
local changedObjIds -- not assigning {} for easier nil when nothing changed
|
||||
local objectives = C_QuestLog_GetQuestObjectives(questId, questLogIndex)
|
||||
|
||||
for objIndex = 1, #objectives do -- iterate manually to be sure getting those in order
|
||||
for objIndex = 1, table.getn(objectives) do -- iterate manually to be sure getting those in order
|
||||
local oldObj = oldObjectives[objIndex]
|
||||
local newObj = objectives[objIndex]
|
||||
-- Check if objective.text is in game's cache
|
||||
@@ -102,7 +103,7 @@ local function GetNewObjectives(questId, oldObjectives, questLogIndex)
|
||||
if (not changedObjIds) then
|
||||
changedObjIds = { objIndex }
|
||||
else
|
||||
changedObjIds[#changedObjIds + 1] = objIndex
|
||||
changedObjIds[table.getn(changedObjIds) + 1] = objIndex
|
||||
end
|
||||
|
||||
if oldObj and newObj and oldObj.numRequired ~= oldObj.numFulfilled and newObj.numRequired == newObj.numFulfilled then
|
||||
@@ -177,15 +178,15 @@ function QuestLogCache.CheckForChanges(questIdsToCheck)
|
||||
local newObjectives, changedObjIds = GetNewObjectives(questId, cachedObjectives, questLogIndex)
|
||||
|
||||
if newObjectives then
|
||||
if (not cachedQuest) or (#cachedObjectives == #newObjectives and #cachedObjectives > 0 and
|
||||
if (not cachedQuest) or (table.getn(cachedObjectives) == table.getn(newObjectives) and table.getn(cachedObjectives) > 0 and
|
||||
(cachedQuest.title ~= title or cachedQuest.questTag ~= questTag or cachedQuest.isComplete ~= isComplete)) then
|
||||
changedObjIds = {}
|
||||
for i = 1, #newObjectives do
|
||||
for i = 1, table.getn(newObjectives) do
|
||||
changedObjIds[i] = i
|
||||
end
|
||||
|
||||
if isComplete == 1 then
|
||||
for i = 1, #newObjectives do
|
||||
for i = 1, table.getn(newObjectives) do
|
||||
local o = newObjectives[i]
|
||||
o.finished = true
|
||||
o.numFulfilled = o.numRequired
|
||||
@@ -235,6 +236,11 @@ end
|
||||
function QuestLogCache.RemoveQuest(questId)
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestLogCache.RemoveQuest] remove questId:", questId)
|
||||
cache[questId] = nil
|
||||
-- Also evict any live fallback object so stale tracker entries don't persist.
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
if QuestieDB and QuestieDB.InvalidateLiveQuest then
|
||||
QuestieDB.InvalidateLiveQuest(questId)
|
||||
end
|
||||
end
|
||||
|
||||
--- Tests if game client's cache has all quest log quests and objectives cached.
|
||||
@@ -249,7 +255,7 @@ function QuestLogCache.TestGameCache()
|
||||
if HaveQuestData(questId) then
|
||||
local objectives = C_QuestLog_GetQuestObjectives(questId, questLogIndex)
|
||||
|
||||
for objIndex = 1, #objectives do
|
||||
for objIndex = 1, table.getn(objectives) do
|
||||
local text = objectives[objIndex].text
|
||||
-- Check if objective.text is not in game's cache
|
||||
if (not text) or (stringByte(text, 1) == 32) then
|
||||
@@ -298,12 +304,12 @@ end
|
||||
---@param o table @objective
|
||||
local function DebugPrintObjective(q, i, o)
|
||||
if (o.raw_numFulfilled == o.numFulfilled) and (o.raw_finished == o.finished) then
|
||||
print(" ", i .. "/" .. #q.objectives .. ":",
|
||||
print(" ", i .. "/" .. table.getn(q.objectives) .. ":",
|
||||
o.numFulfilled .. "/" .. o.numRequired .. "=" .. tostring(o.finished),
|
||||
o.type,
|
||||
"\"" .. o.raw_text .. "\" \"" .. o.text .. "\"")
|
||||
else
|
||||
print(" ", i .. "/" .. #q.objectives .. ":",
|
||||
print(" ", i .. "/" .. table.getn(q.objectives) .. ":",
|
||||
o.raw_numFulfilled .. "/" .. o.numRequired .. "=" .. tostring(o.raw_finished),
|
||||
"FIX:", o.numFulfilled .. "/" .. o.numRequired .. "=" .. tostring(o.finished),
|
||||
o.type,
|
||||
|
||||
@@ -1636,14 +1636,68 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
quest.isComplete = true
|
||||
end
|
||||
|
||||
-- Live fallback quests (no static DB entry) manage their own Objectives.
|
||||
-- Their per-objective Update() functions read directly from QuestLogCache.
|
||||
if quest._isLogFallback then
|
||||
for _, obj in pairs(quest.Objectives) do
|
||||
obj:Update()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--Uses the category order to draw the quests and trusts the database order.
|
||||
|
||||
local questObjectives = QuestieQuest:GetAllLeaderBoardDetails(quest.Id) or {} -- DO NOT MODIFY THE RETURNED TABLE
|
||||
|
||||
|
||||
for objectiveIndex, objective in pairs(questObjectives) do
|
||||
if objective.type and string.len(objective.type) > 1 then
|
||||
if (not quest.ObjectiveData) or (not quest.ObjectiveData[objectiveIndex]) then
|
||||
Questie:Error(l10n("Missing objective data for quest "), quest.Id, " ", objective.text)
|
||||
if (not quest.ObjectiveData) or (not quest.ObjectiveData[objectiveIndex]) or (not quest.ObjectiveData[objectiveIndex].Id) then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Missing objective data for quest", quest.Id, objective.text, "creating fallback objective")
|
||||
if not quest.Objectives[objectiveIndex] then
|
||||
local fallbackSpawnList = {}
|
||||
local objType = objective.type or "monster"
|
||||
|
||||
if objType == "monster" then
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
local zoneId = quest.zoneOrSort and quest.zoneOrSort > 0 and quest.zoneOrSort or nil
|
||||
if zoneId and l10n and l10n.raresByZone and l10n.raresByZone[zoneId] then
|
||||
local function _GetIconScaleForMonster()
|
||||
return Questie.db.profile.monsterScale or 1
|
||||
end
|
||||
for _, npcId in ipairs(l10n.raresByZone[zoneId]) do
|
||||
local npcName = QuestieDB.QueryNPCSingle(npcId, "name")
|
||||
local npcSpawns = QuestieDB.QueryNPCSingle(npcId, "spawns")
|
||||
if npcName and npcSpawns and npcSpawns[zoneId] then
|
||||
fallbackSpawnList[npcId] = {
|
||||
Id = npcId,
|
||||
Name = npcName,
|
||||
Spawns = { [zoneId] = npcSpawns[zoneId] },
|
||||
Waypoints = {},
|
||||
Hostile = true,
|
||||
Icon = Questie.ICON_TYPE_SLAY,
|
||||
GetIconScale = _GetIconScaleForMonster,
|
||||
IconScale = _GetIconScaleForMonster(),
|
||||
TooltipKey = "m_" .. npcId,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
quest.Objectives[objectiveIndex] = {
|
||||
Id = 0, -- Dynamic fallback, no static DB ID known
|
||||
Index = objectiveIndex,
|
||||
questId = quest.Id,
|
||||
_lastUpdate = 0,
|
||||
Description = objective.text,
|
||||
spawnList = fallbackSpawnList,
|
||||
AlreadySpawned = {},
|
||||
Update = _QuestieQuest.ObjectiveUpdate,
|
||||
Type = objType,
|
||||
}
|
||||
end
|
||||
quest.Objectives[objectiveIndex]:Update()
|
||||
else
|
||||
if not quest.Objectives[objectiveIndex] then
|
||||
quest.Objectives[objectiveIndex] = {
|
||||
@@ -1651,7 +1705,7 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
Index = objectiveIndex,
|
||||
questId = quest.Id,
|
||||
_lastUpdate = 0,
|
||||
Description = objective.text,
|
||||
Description = (objective.text and objective.text ~= "") and objective.text or (quest.ObjectiveData and quest.ObjectiveData[objectiveIndex] and quest.ObjectiveData[objectiveIndex].Text) or "",
|
||||
spawnList = {},
|
||||
AlreadySpawned = {},
|
||||
Update = _QuestieQuest.ObjectiveUpdate,
|
||||
@@ -1731,7 +1785,9 @@ function _QuestieQuest.ObjectiveUpdate(self)
|
||||
local finished = obj.finished or false -- ensure its boolean false and not nil (hack)
|
||||
|
||||
self.Type = obj.type;
|
||||
self.Description = obj.text
|
||||
local quest = QuestieDB.GetQuest(self.questId)
|
||||
local fallbackText = quest and quest.ObjectiveData and quest.ObjectiveData[self.Index] and quest.ObjectiveData[self.Index].Text or ""
|
||||
self.Description = (obj.text and obj.text ~= "") and obj.text or fallbackText
|
||||
self.Collected = tonumber(numFulfilled);
|
||||
self.Needed = tonumber(numRequired);
|
||||
self.Completed = (self.Needed == self.Collected and self.Needed > 0) or
|
||||
|
||||
Reference in New Issue
Block a user