diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index 3cf03adca..389d2eb60 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 563 +local dversion = 565 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -1840,12 +1840,14 @@ function DF:GetAllTalents() local borderTypes = Enum.TraitNodeEntryType if (traitEntryInfo.type) then -- == borderTypes.SpendCircle local definitionId = traitEntryInfo.definitionID - local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) - local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID - local spellName, _, spellTexture = GetSpellInfo(spellId) - if (spellName) then - local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false} - allTalents[#allTalents+1] = talentInfo + if definitionId then + local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) + local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID + local spellName, _, spellTexture = GetSpellInfo(spellId) + if (spellName) then + local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false} + allTalents[#allTalents+1] = talentInfo + end end end end @@ -4889,16 +4891,18 @@ function DF:GetCharacterTalents(bOnlySelected, bOnlySelectedHash) if (traitEntryInfo.type) then -- == borderTypes.SpendCircle local definitionId = traitEntryInfo.definitionID - local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) - local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID - local spellName, _, spellTexture = GetSpellInfo(spellId) - local bIsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false - if (spellName and bIsSelected) then - local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = true} - if (bOnlySelectedHash) then - talentList[spellId] = talentInfo - else - table.insert(talentList, talentInfo) + if definitionId then + local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) + local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID + local spellName, _, spellTexture = GetSpellInfo(spellId) + local bIsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false + if (spellName and bIsSelected) then + local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = true} + if (bOnlySelectedHash) then + talentList[spellId] = talentInfo + else + table.insert(talentList, talentInfo) + end end end end diff --git a/Libs/DF/icon.lua b/Libs/DF/icon.lua index 819c048e4..6c14e4b59 100644 --- a/Libs/DF/icon.lua +++ b/Libs/DF/icon.lua @@ -282,17 +282,19 @@ detailsFramework.IconMixin = { --iconFrame.Border:SetColorTexture(0, 0, 0, 1) if (startTime) then - CooldownFrame_Set(iconFrame.Cooldown, startTime, duration, true, true, modRate) + local now = GetTime() + + iconFrame.timeRemaining = (startTime + duration - now) / (modRate or 1) + iconFrame.expirationTime = startTime + duration + + if iconFrame.timeRemaining > 0 then + CooldownFrame_Set(iconFrame.Cooldown, startTime, duration, true, true, modRate) + end if (self.options.show_text) then iconFrame.CountdownText:Show() - local now = GetTime() - - iconFrame.timeRemaining = (startTime + duration - now) / modRate - iconFrame.expirationTime = startTime + duration - - local formattedTime = (iconFrame.timeRemaining > 0) and self.options.decimal_timer and iconFrame.parentIconRow.FormatCooldownTimeDecimal(iconFrame.timeRemaining) or iconFrame.parentIconRow.FormatCooldownTime(iconFrame.timeRemaining) or "" + local formattedTime = (iconFrame.timeRemaining > 0) and (self.options.decimal_timer and iconFrame.parentIconRow.FormatCooldownTimeDecimal(iconFrame.timeRemaining) or iconFrame.parentIconRow.FormatCooldownTime(iconFrame.timeRemaining)) or "" iconFrame.CountdownText:SetText(formattedTime) iconFrame.CountdownText:SetPoint(self.options.text_anchor or "center", iconFrame, self.options.text_rel_anchor or "center", self.options.text_x_offset or 0, self.options.text_y_offset or 0) diff --git a/Libs/LibOpenRaid/Functions.lua b/Libs/LibOpenRaid/Functions.lua index 6246a073d..b0f95e278 100644 --- a/Libs/LibOpenRaid/Functions.lua +++ b/Libs/LibOpenRaid/Functions.lua @@ -152,6 +152,31 @@ function openRaidLib.IsInGroup() return inParty or inRaid end +---return a table with unitName as keys and true as value +---@return table +function openRaidLib.GetPlayersInTheGroup() + local playersInTheGroup = {} + if (IsInRaid()) then + for i = 1, GetNumGroupMembers() do + local unitName = GetUnitName("raid"..i, true) + if (unitName) then + playersInTheGroup[unitName] = true + end + end + + elseif (IsInGroup()) then + for i = 1, GetNumGroupMembers() - 1 do + local unitName = GetUnitName("party"..i, true) + if (unitName) then + playersInTheGroup[unitName] = true + end + end + playersInTheGroup[UnitName("player")] = true + end + + return playersInTheGroup +end + function openRaidLib.UpdateUnitIDCache() openRaidLib.UnitIDCache = {} if (IsInRaid()) then diff --git a/Libs/LibOpenRaid/LibOpenRaid.lua b/Libs/LibOpenRaid/LibOpenRaid.lua index 4386e315a..de563fb59 100644 --- a/Libs/LibOpenRaid/LibOpenRaid.lua +++ b/Libs/LibOpenRaid/LibOpenRaid.lua @@ -44,7 +44,7 @@ end local major = "LibOpenRaid-1.0" -local CONST_LIB_VERSION = 138 +local CONST_LIB_VERSION = 139 if (LIB_OPEN_RAID_MAX_VERSION) then if (CONST_LIB_VERSION <= LIB_OPEN_RAID_MAX_VERSION) then @@ -110,6 +110,9 @@ end local CONST_COMM_KEYSTONE_DATA_PREFIX = "K" local CONST_COMM_KEYSTONE_DATAREQUEST_PREFIX = "J" + local CONST_COMM_OPENNOTES_RECEIVED_PREFIX = "NR" --when a note is received + local CONST_COMM_OPENNOTES_REQUESTED_PREFIX = "NQ" --when received a request to send your note + local CONST_COMM_SENDTO_PARTY = "0x1" local CONST_COMM_SENDTO_RAID = "0x2" local CONST_COMM_SENDTO_GUILD = "0x4" @@ -466,6 +469,8 @@ end [CONST_COMM_PLAYERINFO_PVPTALENTS_PREFIX] = {}, --pvp talents info [CONST_COMM_KEYSTONE_DATA_PREFIX] = {}, --received keystone data [CONST_COMM_KEYSTONE_DATAREQUEST_PREFIX] = {}, --received a request to send keystone data + [CONST_COMM_OPENNOTES_RECEIVED_PREFIX] = {}, --received notes + [CONST_COMM_OPENNOTES_REQUESTED_PREFIX] = {}, --requested notes } function openRaidLib.commHandler.RegisterComm(prefix, func) @@ -713,6 +718,7 @@ end "PvPTalentUpdate", "KeystoneUpdate", "KeystoneWipe", + "NoteUpdated", } --save build the table to avoid lose registered events on older versions @@ -1826,6 +1832,214 @@ openRaidLib.internalCallback.RegisterCallback("onLeaveCombat", openRaidLib.UnitI end +-------------------------------------------------------------------------------------------------------------------------------- +--~open ~notes ~opennotes + +---type and prototype for the note system, when adding or removeing fields, this is the only place to change + +---@class noteinfo : table +---@field note string +---@field version number + +---@type noteinfo +local notePrototype = { + note = "", + version = 0, +} + +openRaidLib.OpenNotesManager = { + --structure: [playerName] = {note = "note text", lastUpdate = 0} + ---@type table + UnitData = {}, +} + +--the note context saves the context of when the note was last sent, this is to avoid the player sending a note used on other dungeon or group when the a note is request +local noteContext = { + mapId = 0, + difficultyId = 0, + instanceType = "none", + ---@type table + groupMembers = {}, + time = 0, +} + +local checkContext = function() + if (noteContext.time == 0) then + return false + end + + local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceID, instanceGroupSize, LfgDungeonID = GetInstanceInfo() + + if (noteContext.mapId ~= instanceID or noteContext.difficultyId ~= difficultyID or noteContext.instanceType ~= instanceType) then + return false + end + + --if the note context time is more than 25 minutes ago, ignore + if (time() - noteContext.time > 1500) then + return false + end + + --check if the group members are the same + local groupMembers = openRaidLib.GetPlayersInTheGroup() + for unitName in pairs(noteContext.groupMembers) do + if (not groupMembers[unitName]) then + return false + end + end + + return true +end + +--API notes +---return the table where the notes are stored, format: [playerName] = {note = "note text", lastUpdate = time()} +---can return an empty table if no unit sent note yet +---@return table +function openRaidLib.GetAllUnitsNotes() + return openRaidLib.OpenNotesManager.GetAllUnitsNotes() +end + +---return information about a note for a unit, return value is a table of type noteinfo, see the type declaration to know the fields +---always return values, if the note does not exist it'll return an empty string and 0 +---@param unitId string +---@return noteinfo +function openRaidLib.GetUnitNote(unitId) + ---@type string + local unitName = GetUnitName(unitId, true) or unitId + ---@type noteinfo + local noteInfo = openRaidLib.OpenNotesManager.GetUnitNote(unitName) + return noteInfo +end + +---set a note for the player +---@param note string +function openRaidLib.SetPlayerNote(note) + assert(type(note) == "string", "OpenRaid: SetPlayerNote(#1) expect a string.") + assert(note:len() > 3000, "OpenRaid: SetPlayerNote(#1) too long.") + local version = time() + openRaidLib.OpenNotesManager.SetUnitNote(UnitName("player"), note, version) +end + +---send the player note to the group +function openRaidLib.SendPlayerNote() + openRaidLib.OpenNotesManager.SendNote() +end + + + +--INTERNAL notes +function openRaidLib.OpenNotesManager.GetAllUnitsNotes() + return openRaidLib.OpenNotesManager.UnitData +end + +---get a unit note, if it does not exist, create a new one +---@param unitName string +---@return noteinfo +function openRaidLib.OpenNotesManager.GetUnitNote(unitName) + local unitNote = openRaidLib.OpenNotesManager.UnitData[unitName] + + if (not unitNote) then + local newNote = {} + openRaidLib.TCopy(newNote, notePrototype) + openRaidLib.OpenNotesManager.UnitData[unitName] = newNote + end + + return unitNote +end + +---set a note of a unit, this do not send the note yet, just store it +---@param unitName string +---@param note string +---@param version number +function openRaidLib.OpenNotesManager.SetUnitNote(unitName, note, version) + local unitNote = openRaidLib.OpenNotesManager.GetUnitNote(unitName) + unitNote.note = note + unitNote.version = version or time() +end + +---clear all data stored +function openRaidLib.OpenNotesManager.EraseData() + table.wipe(openRaidLib.OpenNotesManager.UnitData) + + --create a note for the local player + local playerName = UnitName("player") + openRaidLib.OpenNotesManager.GetUnitNote(playerName) +end + +---clear all data except the local player +function openRaidLib.OpenNotesManager.EraseDataKeepPlayer() + local playerName = UnitName("player") + local localNote = openRaidLib.OpenNotesManager.UnitData[playerName] + table.wipe(openRaidLib.OpenNotesManager.UnitData) + openRaidLib.OpenNotesManager.UnitData[playerName] = localNote +end + +function openRaidLib.OpenNotesManager.OnPlayerEnterWorld() + --call erase data hence create a note for the local player + openRaidLib.OpenNotesManager.EraseData() +end +openRaidLib.internalCallback.RegisterCallback("onEnterWorld", openRaidLib.OpenNotesManager.OnPlayerEnterWorld) + +function openRaidLib.OpenNotesManager.OnReceiveNoteData(data, unitName) + ---@type string + local note = data[1] + ---@type number + local version = tonumber(data[2]) or 0 + + if (note and version and type(note) == "string" and type(version) == "number") then + openRaidLib.OpenNotesManager.SetUnitNote(unitName, note, version) + ---@type noteinfo + local unitNote = openRaidLib.OpenNotesManager.GetUnitNote(unitName) + --trigger public callback + openRaidLib.publicCallback.TriggerCallback("NoteUpdated", openRaidLib.GetUnitID(unitName), unitNote, openRaidLib.OpenNotesManager.GetAllUnitsNotes()) + end +end +openRaidLib.commHandler.RegisterComm(CONST_COMM_OPENNOTES_RECEIVED_PREFIX, openRaidLib.OpenNotesManager.OnReceiveNoteData) + +function openRaidLib.OpenNotesManager.SendNote() + local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceID, instanceGroupSize, LfgDungeonID = GetInstanceInfo() + + --deny if not in group or if the player is in open world + if (instanceType == "none") then + return + elseif (not openRaidLib.IsInGroup()) then + return + end + + ---@type noteinfo + local playerNote = openRaidLib.OpenNotesManager.GetUnitNote(UnitName("player")) + if (type(playerNote) == "table" and playerNote.note and playerNote.version) then + assert(type(playerNote.note) == "string", "OpenRaid: SendNote() invalid note.") + assert(playerNote.note:len() > 3000, "OpenRaid: SendNote() note too long.") + assert(playerNote.note:len() < 10, "OpenRaid: SendNote() note too short.") + + local dataToSend = "" .. CONST_COMM_OPENNOTES_RECEIVED_PREFIX .. "," .. playerNote.note .. "," .. playerNote.version + --send the data + openRaidLib.commHandler.SendCommData(dataToSend) + diagnosticComm("SendAllNotesData| " .. dataToSend) --debug + + noteContext.time = time() + noteContext.mapId = instanceID + noteContext.difficultyId = difficultyID + noteContext.instanceType = instanceType + noteContext.groupMembers = openRaidLib.GetPlayersInTheGroup() + end +end + +function openRaidLib.OpenNotesManager.OnReceiveNoteRequest() + ---@type noteinfo + local playerNote = openRaidLib.OpenNotesManager.GetUnitNote(UnitName("player")) + + --check if there is text in the note + if (playerNote and playerNote.note and playerNote.version and playerNote.note:len() > 10) then + --check if the context is the same + if (not checkContext()) then + return + end + openRaidLib.Schedules.NewUniqueTimer(2 + math.random(0, 2) + math.random(), openRaidLib.OpenNotesManager.SendNote, "OpenNotesManager", "sendNoteInfo_Schedule") + end +end +openRaidLib.commHandler.RegisterComm(CONST_COMM_OPENNOTES_REQUESTED_PREFIX, openRaidLib.OpenNotesManager.OnReceiveNoteRequest) + -------------------------------------------------------------------------------------------------------------------------------- --~cooldowns openRaidLib.CooldownManager = { diff --git a/boot.lua b/boot.lua index ccecf33fa..eb733ed8e 100644 --- a/boot.lua +++ b/boot.lua @@ -19,12 +19,12 @@ local addonName, Details222 = ... local version, build, date, tvs = GetBuildInfo() - Details.build_counter = 12879 - Details.alpha_build_counter = 12879 --if this is higher than the regular counter, use it instead + Details.build_counter = 12888 + Details.alpha_build_counter = 12888 --if this is higher than the regular counter, use it instead Details.dont_open_news = true Details.game_version = version Details.userversion = version .. " " .. Details.build_counter - Details.realversion = 159 --core version, this is used to check API version for scripts and plugins (see alias below) + Details.realversion = 160 --core version, this is used to check API version for scripts and plugins (see alias below) Details.gametoc = tvs Details.APIVersion = Details.realversion --core version Details.version = Details.userversion .. " (core " .. Details.realversion .. ")" --simple stirng to show to players @@ -42,7 +42,7 @@ Details.BFACORE = 131 --core version on BFA launch Details.SHADOWLANDSCORE = 143 --core version on Shadowlands launch Details.DRAGONFLIGHT = 147 --core version on Dragonflight launch - Details.V11CORE = 158 --core version on V11 launch + Details.V11CORE = 160 --core version on V11 launch Details = Details diff --git a/classes/class_damage.lua b/classes/class_damage.lua index 9557b0a97..121556e47 100644 --- a/classes/class_damage.lua +++ b/classes/class_damage.lua @@ -2581,8 +2581,8 @@ function damageClass:RefreshWindow(instanceObject, combatObject, bForceUpdate, b return Details:EndRefresh(instanceObject, total, combatObject, damageContainer) --retorna a tabela que precisa ganhar o refresh end ---[[exported]] function Details:AutoAlignInLineFontStrings() - +--self is instance +function Details:AutoAlignInLineFontStrings() --if this instance is using in line texts, check the min distance and the length of strings to make them more spread appart if (self.use_multi_fontstrings and self.use_auto_align_multi_fontstrings) then local maxStringLength_StringFour = 0 diff --git a/startup.lua b/startup.lua index 6bbdc9c33..950d699e5 100644 --- a/startup.lua +++ b/startup.lua @@ -77,7 +77,7 @@ function Details222.StartUp.StartMeUp() Details:CreatePluginWindowContainer() Details:InitializeForge() --to install into the container plugin Details:InitializeRaidHistoryWindow() - --Details:InitializeOptionsWindow() + --Details:InitializeOptionsWindow() --debug, uncoment to open options window on startup C_Timer.After(2, function() Details:InitializeAuraCreationWindow() @@ -125,7 +125,7 @@ function Details222.StartUp.StartMeUp() end Details:GetLowerInstanceNumber() - --start time machine + --start time machine, the time machine controls the activity time of players Details222.TimeMachine.Start() --update abbreviation shortcut @@ -135,7 +135,6 @@ function Details222.StartUp.StartMeUp() Details.atributo_misc:UpdateSelectedToKFunction() Details.atributo_custom:UpdateSelectedToKFunction() - --start instances updater Details:CheckSwitchOnLogon() function Details:ScheduledWindowUpdate(bIsForced) @@ -155,6 +154,7 @@ function Details222.StartUp.StartMeUp() Details.scheduled_window_update = Details.Schedules.NewTimer(time or 1, Details.ScheduledWindowUpdate, Details, bIsForced) end + --do the first refresh here, not waiting for the regular refresh schedule to kick in local bForceRefresh = true Details:RefreshMainWindow(-1, bForceRefresh) Details:RefreshUpdater() @@ -485,7 +485,7 @@ function Details222.StartUp.StartMeUp() --restore mythic dungeon state Details:RestoreState_CurrentMythicDungeonRun() - --open profiler + --open profiler (will only open in the first time the character is logged in) Details:OpenProfiler() --start announcers @@ -558,13 +558,6 @@ function Details222.StartUp.StartMeUp() --embed windows on the chat window Details.chat_embed:CheckChatEmbed(true) - if (Details.player_details_window.skin ~= "ElvUI") then --obsolete - local setDefaultSkinOnPlayerBreakdownWindow = function() - Details:ApplyPDWSkin("ElvUI") - end - C_Timer.After(2, setDefaultSkinOnPlayerBreakdownWindow) - end - --coach feature startup Details.Coach.StartUp() @@ -674,25 +667,6 @@ function Details222.StartUp.StartMeUp() Details.time_type = 2 end - --clear overall data on new session - --if (Details.overall_clear_logout) then --this is suppose to be in the load data file - -- Details.tabela_overall = Details.combate:NovaTabela() - --end - - if (not DetailsFramework.IsTimewalkWoW()) then - --wipe overall on torghast - REMOVE ON 10.0 - local torghastTracker = CreateFrame("frame") - torghastTracker:RegisterEvent("JAILERS_TOWER_LEVEL_UPDATE") --shadowlands tower challenge - torghastTracker:SetScript("OnEvent", function(self, event, level, towerType) - if (level == 1) then - if (Details.overall_clear_newtorghast) then - Details.historico:ResetOverallData() - Details:Msg("overall data are now reset.") --localize-me - end - end - end) - end - --hide the panel shown by pressing the right mouse button on the title bar when a cooltip is opened hooksecurefunc(GameCooltip, "SetMyPoint", function() if (DetailsAllAttributesFrame) then @@ -728,20 +702,20 @@ function Details222.StartUp.StartMeUp() if (DetailsFramework.IsWarWow()) then C_Timer.After(1, function() if (SplashFrame) then SplashFrame:Hide() end end) function HelpTip:SetHelpTipsEnabled(flag, enabled) - HelpTip.supressHelpTips[flag] = false + --HelpTip.supressHelpTips[flag] = false end hooksecurefunc(HelpTipTemplateMixin, "OnShow", function(self) - self:Hide() + --self:Hide() end) hooksecurefunc(HelpTipTemplateMixin, "OnUpdate", function(self) - self:Hide() + --self:Hide() end) C_Timer.After(5, function() if (TutorialPointerFrame_1) then - TutorialPointerFrame_1:Hide() + --TutorialPointerFrame_1:Hide() hooksecurefunc(TutorialPointerFrame_1, "Show", function(self) - self:Hide() + --self:Hide() end) end end)