chore: hoist plugins to root and move main into Details/

Each Details_* plugin and the main Details addon now lives in its own
repo-root folder, matching the Exiles fork-layout convention.
This commit is contained in:
2026-05-25 10:59:28 +02:00
parent 0b0a5004eb
commit 5bb7be4968
421 changed files with 7 additions and 0 deletions
@@ -0,0 +1,492 @@
--[=[
This file has the functions to get player information
Dumping them here, make the code of the main file smaller
--]=]
if (not LIB_OPEN_RAID_CAN_LOAD) then
return
end
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0")
local CONST_ISITEM_BY_TYPEID = {
[10] = true, --healing items
[11] = true, --attack items
[12] = true, --utility items
}
local GetInventoryItemLink = GetInventoryItemLink
--information about the player character to send, each expansion has its own system and data can be different
--it's always a number
function openRaidLib.UnitInfoManager.GetPlayerInfo1()
return 0
end
--information about the player character to send, each expansion has its own system and data can be different
--it's always a number
function openRaidLib.UnitInfoManager.GetPlayerInfo2()
return 0
end
--creates two tables, one with indexed talents and another with pairs values ([talentId] = true)
function openRaidLib.UnitInfoManager.GetPlayerTalentsAsPairsTable()
local talentsPairs = {}
return talentsPairs
end
function openRaidLib.UnitInfoManager.GetPlayerTalents()
local talents = {}
return talents
end
function openRaidLib.UnitInfoManager.GetPlayerPvPTalents()
-- todo: coa will use these eventually
return {}
-- expected format
-- local talentsPvP = {0, 0, 0}
-- talentsPvP[index] = talentID
end
function openRaidLib.UnitInfoManager.GetPlayerLegendaryEnchant()
return IsHeroClass("player") and MysticEnchantUtil.GetLegendaryEnchantID("player") or 0
end
--return the current specId of the player
function openRaidLib.GetPlayerSpecId()
return GetSpecialization() or 1
end
function openRaidLib.GearManager.GetPlayerItemLevel()
local itemLevel = UnitAverageItemLevel("player")
return floor(itemLevel)
end
--return an integer between zero and one hundret indicating the player gear durability
function openRaidLib.GearManager.GetPlayerGearDurability()
local durabilityTotalPercent, totalItems = 0, 0
--hold the lowest item durability of all the player gear
--this prevent the case where the player has an average of 80% durability but an item with 15% durability
local lowestGearDurability = 100
for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
local durability, maxDurability = GetInventoryItemDurability(i)
if (durability and maxDurability) then
local itemDurability = durability / maxDurability * 100
if (itemDurability < lowestGearDurability) then
lowestGearDurability = itemDurability
end
durabilityTotalPercent = durabilityTotalPercent + itemDurability
totalItems = totalItems + 1
end
end
if (totalItems == 0) then
return 100, lowestGearDurability
end
return floor(durabilityTotalPercent / totalItems), lowestGearDurability
end
function openRaidLib.GearManager.GetPlayerWeaponEnchant()
if not GetWeaponTempEnchantInfo then
return 0, 0, 0
end
local weaponEnchant = 0
local _, mainHandEnchantId = GetWeaponTempEnchantInfo(INVSLOT_MAINHAND)
local _, offHandEnchantId = GetWeaponTempEnchantInfo(INVSLOT_OFFHAND)
if (mainHandEnchantId and LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[mainHandEnchantId]) then
weaponEnchant = 1
elseif( offHandEnchantId and LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[offHandEnchantId]) then
weaponEnchant = 1
end
return weaponEnchant, mainHandEnchantId or 0, offHandEnchantId or 0
end
function openRaidLib.GearManager.GetPlayerRangedWeaponEnchant()
if not GetWeaponTempEnchantInfo then
return 0, 0
end
local weaponEnchant = 0
local _, rangedEnchantId = GetWeaponTempEnchantInfo(INVSLOT_RANGED)
if (rangedEnchantId and LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[rangedEnchantId]) then
weaponEnchant = 1
end
return weaponEnchant, rangedEnchantId or 0
end
function openRaidLib.GearManager.GetPlayerGemsAndEnchantInfo()
--hold equipmentSlotId of equipment with a gem socket but it's empty
local slotsWithoutGems = {}
--hold equipmentSlotId of equipments without an enchant
local slotsWithoutEnchant = {}
local gearWithEnchantIds = {}
for equipmentSlotId = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
if (itemLink) then
--get the information from the item
local _, itemId, enchantId, gemId1, gemId2, gemId3, gemId4 = strsplit(":", itemLink)
local gemsIds = {gemId1, gemId2, gemId3, gemId4}
--enchant
--check if the slot can receive enchat and if the equipment has an enchant
local enchantAttribute = LIB_OPEN_RAID_ENCHANT_SLOTS[equipmentSlotId]
local nEnchantId = 0
if (enchantAttribute) then --this slot can receive an enchant
if (enchantId and enchantId ~= "") then
local number = tonumber(enchantId)
nEnchantId = number
gearWithEnchantIds[#gearWithEnchantIds+1] = nEnchantId
else
gearWithEnchantIds[#gearWithEnchantIds+1] = 0
slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
end
end
--gems
--local itemStatsTable = {}
--fill the table above with information about the item
--GetItemStats(itemLink, itemStatsTable)
local itemStatsTable = GetItemStats(itemLink)
--check if the item has a socket
if (itemStatsTable) then
local numSockets = (itemStatsTable.EMPTY_SOCKET_RED or 0) + (itemStatsTable.EMPTY_SOCKET_YELLOW or 0) + (itemStatsTable.EMPTY_SOCKET_BLUE or 0)
if numSockets > 0 then
--check if the socket is empty
for i = 1, numSockets do
local gemId = tonumber(gemsIds[i])
if (not gemId or gemId == 0) then
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
end
end
end
end
end
end
return slotsWithoutGems, slotsWithoutEnchant
end
function openRaidLib.GearManager.BuildPlayerEquipmentList()
local equipmentList = {}
local debug
for equipmentSlotId = 1, 17 do
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
if (itemLink) then
--local itemStatsTable = {}
local itemID = select(2, strsplit(":", itemLink))
itemID = tonumber(itemID)
local _, _, _, effectiveILvl = GetItemInfo(itemID)
if (not effectiveILvl) then
openRaidLib.mainControl.scheduleUpdatePlayerData()
effectiveILvl = 0
openRaidLib.__errors[#openRaidLib.__errors+1] = "Fail to get Item Level: " .. (itemID or "invalid itemID") .. " " .. (itemLink and itemLink:gsub("|H", "") or "invalid itemLink")
end
local itemStatsTable = GetItemStats(itemLink)
--GetItemStats(itemLink, itemStatsTable)
local gemSlotsAvailable = itemStatsTable and (itemStatsTable.EMPTY_SOCKET_RED or 0) + (itemStatsTable.EMPTY_SOCKET_YELLOW or 0) + (itemStatsTable.EMPTY_SOCKET_BLUE or 0)
local noPrefixItemLink = itemLink : gsub("^|c%x%x%x%x%x%x%x%x|Hitem", "")
local linkTable = {strsplit(":", noPrefixItemLink)}
local numModifiers = linkTable[14]
numModifiers = numModifiers and tonumber(numModifiers) or 0
for i = #linkTable, 14 + numModifiers + 1, -1 do
tremove(linkTable, i)
end
local newItemLink = table.concat(linkTable, ":")
newItemLink = newItemLink
equipmentList[#equipmentList+1] = {equipmentSlotId, gemSlotsAvailable, effectiveILvl, newItemLink}
if (equipmentSlotId == 2) then
debug = {itemLink:gsub("|H", ""), newItemLink}
end
end
end
--[[ debug
local str = ""
for i = 1, #equipmentList do
local t = equipmentList[i]
local s = t[1] .. "," .. t[2] .. "," .. t[3] .. "," .. t[4]
str = str .. s
end
table.insert(debug, str)
dumpt(debug)
--]]
return equipmentList
end
local playerHasPetOfNpcId = function(npcId)
return false -- 3.3.5 cant get if a pet GUID is a specific npc or not.
end
local addCooldownToTable = function(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
local timeLeft, charges, startTimeOffset, duration, auraDuration = openRaidLib.CooldownManager.GetPlayerCooldownStatus(cooldownSpellId)
cooldowns[#cooldowns+1] = cooldownSpellId
cooldowns[#cooldowns+1] = timeLeft
cooldowns[#cooldowns+1] = charges
cooldowns[#cooldowns+1] = startTimeOffset
cooldowns[#cooldowns+1] = duration
cooldowns[#cooldowns+1] = auraDuration
cooldownsHash[cooldownSpellId] = {timeLeft, charges, startTimeOffset, duration, timeNow, auraDuration}
end
local canAddCooldown = function(cooldownInfo)
local petNpcIdNeeded = cooldownInfo.pet
if (petNpcIdNeeded) then
if (not playerHasPetOfNpcId(petNpcIdNeeded)) then
return false
end
end
return true
end
local getSpellListAsHashTableFromSpellBook = function()
local completeListOfSpells = {}
-- find spells in spellbook
for tab = 2, GetNumSpellTabs() do
local name, _, offset, numSpells = GetSpellTabInfo(tab)
if name and name ~= "Internal" and name ~= "Ascension Vanity Items" then
for i = offset + 1, offset + numSpells do
local spellName, rank = GetSpellInfo(i, BOOKTYPE_SPELL)
if spellName then
local link = GetSpellLink(spellName, rank)
if link then
local spellID = tonumber(link:match("spell:(%d*)"))
if spellID and not IsPassiveSpellID(spellID) then
if LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS and LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellID] then
for _, overrideSpellID in pairs(LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellID]) do
completeListOfSpells[overrideSpellID] = true
end
else
completeListOfSpells[spellID] = true
end
end
end
end
end
end
end
--get pet spells from the pet spellbook
local numPetSpells = HasPetSpells()
if (numPetSpells) then
for i = 1, numPetSpells do
local spellName, rank, unmaskedSpellId = GetSpellInfo(i, "pet")
if spellName then
local link = GetSpellLink(spellName, rank)
if link then
local spellID = tonumber(link:match("spell:(%d*)"))
if spellID and not IsPassiveSpellID(spellID) then
if LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS and LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellID] then
for _, overrideSpellID in pairs(LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellID]) do
completeListOfSpells[overrideSpellID] = true
end
else
completeListOfSpells[spellID] = true
end
end
end
end
end
end
return completeListOfSpells
end
local updateCooldownAvailableList = function()
table.wipe(LIB_OPEN_RAID_PLAYERCOOLDOWNS)
local _, playerClass = UnitClass("player")
local locPlayerRace, playerRace, playerRaceId = UnitRace("player")
local spellBookSpellList = getSpellListAsHashTableFromSpellBook()
--build a list of all spells assigned as cooldowns for the player class
for spellID, spellData in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
--type 10 is an item cooldown and does not have a class or race id
local passRaceId = false
local raceId = spellData.raceid
if (raceId) then
if (type(raceId) == "table") then
if (raceId[playerRaceId]) then
passRaceId = true
end
elseif (type(raceId) == "number") then
if (raceId == playerRaceId) then
passRaceId = true
end
end
end
if (spellData.class == playerClass or passRaceId or CONST_ISITEM_BY_TYPEID[spellData.type]) then --need to implement here to get the racial as racial cooldowns does not carry a class
--type 10 is an item cooldown and does not have a spellbook entry
if (spellBookSpellList[spellID] or CONST_ISITEM_BY_TYPEID[spellData.type]) then
LIB_OPEN_RAID_PLAYERCOOLDOWNS[spellID] = spellData
end
end
end
end
--build a list with the local player cooldowns
--called only from SendAllPlayerCooldowns()
function openRaidLib.CooldownManager.GetPlayerCooldownList()
--this fill the global LIB_OPEN_RAID_PLAYERCOOLDOWNS
updateCooldownAvailableList()
--get the player specId
local specId = openRaidLib.GetPlayerSpecId()
if (specId) then
--get the cooldowns for the specializationid
local playerCooldowns = LIB_OPEN_RAID_PLAYERCOOLDOWNS
if (not playerCooldowns) then
openRaidLib.DiagnosticError("CooldownManager|GetPlayerCooldownList|LIB_OPEN_RAID_PLAYERCOOLDOWNS is nil")
return {}, {}
end
local cooldowns = {} --table to ship on comm
local cooldownsHash = {} --table with [spellId] = cooldownInfo
local talentsHash = openRaidLib.UnitInfoManager.GetPlayerTalentsAsPairsTable()
local timeNow = GetTime()
for cooldownSpellId, cooldownInfo in pairs(playerCooldowns) do
--does this cooldown is based on a talent?
local talentId = cooldownInfo.talent
--check if the player has a talent which makes this cooldown unavailable
local ignoredByTalentId = cooldownInfo.ignoredIfTalent
local bIsIgnoredByTalentId = false
if (ignoredByTalentId) then
if (talentsHash[ignoredByTalentId]) then
bIsIgnoredByTalentId = true
end
end
if (not bIsIgnoredByTalentId) then
if (talentId) then
--check if the player has the talent selected
if (talentsHash[talentId]) then
if (canAddCooldown(cooldownInfo)) then
addCooldownToTable(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
end
end
else
if (canAddCooldown(cooldownInfo)) then
addCooldownToTable(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
end
end
end
end
return cooldowns, cooldownsHash
else
return {}, {}
end
end
---check if a player cooldown is ready or if is in cooldown
---@spellId: the spellId to check for cooldown
---@return number timeLeft
---@return number charges
---@return number startTimeOffset
---@return number duration
---@return number buffDuration
function openRaidLib.CooldownManager.GetPlayerCooldownStatus(spellId)
--check if is a charge spell
local spellData = LIB_OPEN_RAID_COOLDOWNS_INFO[spellId]
if (spellData) then
local chargesAvailable, chargesTotal, start, duration = GetSpellCharges(spellId)
if chargesAvailable then
if (chargesAvailable == chargesTotal) then
return 0, chargesTotal, 0, 0, 0 --all charges are ready to use
else
--return the time to the next charge
local timeLeft = start + duration - GetTime()
local startTimeOffset = start - GetTime()
return ceil(timeLeft), chargesAvailable, startTimeOffset, duration
end
else
local start, duration = GetSpellCooldown(spellId)
if (start == 0) then --cooldown is ready
return 0, 1, 0, 0, 0 --time left, charges, startTime
else
local timeLeft = start + duration - GetTime()
local startTimeOffset = start - GetTime()
return ceil(timeLeft), 0, ceil(startTimeOffset), duration --time left, charges, startTime, duration
end
end
else
return openRaidLib.DiagnosticError("CooldownManager|GetPlayerCooldownStatus()|cooldownInfo not found|", spellId)
end
end
do
openRaidLib.AuraTracker = {}
local getUnitName = function(unitId)
local unitName, realmName = UnitName(unitId)
if (unitName) then
if (realmName and realmName ~= "") then
unitName = unitName .. "-" .. realmName
end
return unitName
end
end
local predicateFunc = function(spellIdToFind, casterName, _, name, rank, icon, applications, dispelName, duration, expirationTime, sourceUnitId, isStealable, spellId)
if (spellIdToFind == spellId and UnitExists(sourceUnitId)) then
if (casterName == getUnitName(sourceUnitId)) then
return true
end
end
end
---find the duration of a debuff by passing the spellId and the caster name
---@param unitId unit
---@param spellId spellid
---@param casterName actorname
---@return auraduration|nil auraDuration
---@return number|nil expirationTime
function openRaidLib.AuraTracker.FindBuffDuration(unitId, casterName, spellId)
local name, rank, icon, count, buffType, duration, expirationTime = AuraUtil.FindAura(predicateFunc, unitId, "HELPFUL", spellId, casterName)
if (name) then
return duration, expirationTime
end
end
---find the duration of a buff placed by a unit
---@param targetString string
---@param casterString string
---@param spellId number
function openRaidLib.AuraTracker.FindBuffDurationByUnitName(targetString, casterString, spellId)
local targetName = Ambiguate(targetString, "none")
local casterName = Ambiguate(casterString, "none")
return openRaidLib.AuraTracker.FindBuffDuration(targetName, casterName, spellId)
end
end
openRaidLib.specAttribute = {}
for _, class in ipairs(CLASS_SORT_ORDER) do
local specs = C_ClassInfo.GetAllSpecs(class)
openRaidLib.specAttribute[class] = {}
for index, spec in ipairs(specs) do
local ok, specInfo = pcall(C_ClassInfo.GetSpecInfo, class, spec)
if ok and specInfo then
openRaidLib.specAttribute[class][specInfo.ID] = Enum.PrimaryStat[specInfo.PrimaryStats[1] or "Strength"]
end
end
end