From 1ba0cd711540459e98c2b011a8c26df9e0e68d1c Mon Sep 17 00:00:00 2001 From: 4n0n <4n0n@tinkr.site> Date: Wed, 11 Jan 2023 12:49:18 -0600 Subject: [PATCH] Possibly massive improvements to performance in raid, start on notification system --- scripts/restodruid.lua | 68 +++--- src/AuraTable/AuraTable.lua | 223 ++++++-------------- src/NotificationsList/NotificationsList.lua | 124 +++++++++++ src/Spell/Spell.lua | 43 ++-- src/Unit/Unit.lua | 52 ++--- src/UnitManager/UnitManager.lua | 24 ++- src/_bastion.lua | 8 + 7 files changed, 292 insertions(+), 250 deletions(-) create mode 100644 src/NotificationsList/NotificationsList.lua diff --git a/scripts/restodruid.lua b/scripts/restodruid.lua index 83e84d4..564a9dc 100644 --- a/scripts/restodruid.lua +++ b/scripts/restodruid.lua @@ -139,7 +139,7 @@ local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) return lowest end) -local DispelTarget = Bastion.UnitManager:CreateCustomUnit('rejuv', function(unit) +local DispelTarget = Bastion.UnitManager:CreateCustomUnit('dispel', function(unit) local lowest = nil local lowestHP = math.huge @@ -366,7 +366,7 @@ local PLACE_EFFLO = false RestoCommands:Register('efflo', 'Request the engine to place an Efflorescence', function() PLACE_EFFLO = true - Bastion:Print('Efflorescence will be placed on next cast') + Bastion.Notifications:AddNotification(Efflorescence:GetIcon(), "Efflorescence requested") end) local DefaultAPL = Bastion.APL:New('default') @@ -515,18 +515,6 @@ DefaultAPL:AddSpell( end):SetTarget(RejuvUnit) ) -DefaultAPL:AddSpell( - Regrowth:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and - ( - not Player:GetAuras():FindMy(Regrowth):IsUp() and Lowest:GetHP() < 70 or - (Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and - not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and - not Player:IsMoving() - end):SetTarget(Lowest) -) - DefaultAPL:AddSpell( Lifebloom:CastableIf(function(self) return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() @@ -547,42 +535,54 @@ DefaultAPL:AddSpell( end):SetTarget(Tank) ) +DefaultAPL:AddSpell( + Regrowth:CastableIf(function(self) + return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Lowest) and + ( + not Player:GetAuras():FindMy(Regrowth):IsUp() and Lowest:GetHP() < 70 or + (Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and + not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and + not Player:IsMoving() + end):SetTarget(Lowest) +) + DefaultAPL:AddSpell( Sunfire:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Target) and + return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Bastion.UnitManager['target']) and ( - not Target:GetAuras():FindMy(SunfireAura):IsUp() or - Target:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and Target:IsHostile() and - Target:IsAffectingCombat() - end):SetTarget(Target) + not Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):IsUp() or + Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and Bastion.UnitManager['target']:IsHostile() and + Bastion.UnitManager['target']:IsAffectingCombat() + end):SetTarget(Bastion.UnitManager['target']) ) DefaultAPL:AddSpell( Moonfire:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Target) and + return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Bastion.UnitManager['target']) and ( - not Target:GetAuras():FindMy(MoonfireAura):IsUp() or - Target:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and Target:IsHostile() and - Target:IsAffectingCombat() - end):SetTarget(Target) + not Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):IsUp() or + Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and Bastion.UnitManager['target']:IsHostile() and + Bastion.UnitManager['target']:IsAffectingCombat() + end):SetTarget(Bastion.UnitManager['target']) ) DefaultAPL:AddSpell( Starsurge:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Target) and Target:IsHostile() and - Target:IsAffectingCombat() - end):SetTarget(Target) + return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Bastion.UnitManager['target']) and Bastion.UnitManager['target']:IsHostile() and + Bastion.UnitManager['target']:IsAffectingCombat() + end):SetTarget(Bastion.UnitManager['target']) ) DefaultAPL:AddSpell( Wrath:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Target) and not Player:IsMoving() and Target:IsHostile() and - Target:IsAffectingCombat() - end):SetTarget(Target) + return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Bastion.UnitManager['target']) and not Player:IsMoving() and Bastion.UnitManager['target']:IsHostile() and + Bastion.UnitManager['target']:IsAffectingCombat() + end):SetTarget(Bastion.UnitManager['target']) ) RestoModule:Sync(function() diff --git a/src/AuraTable/AuraTable.lua b/src/AuraTable/AuraTable.lua index 9ec4cf6..ea82d2b 100644 --- a/src/AuraTable/AuraTable.lua +++ b/src/AuraTable/AuraTable.lua @@ -17,100 +17,54 @@ function AuraTable:New(unit) local self = setmetatable({}, AuraTable) self.unit = unit - self.buffs = {} - self.debuffs = {} self.auras = {} - -- Our player is usually the most important unit, so we cache the auras for it - self.playerAppliedBuffs = {} - self.playerAppliedDebuffs = {} self.playerAuras = {} self.guid = unit:GetGUID() self.instanceIDLookup = {} - Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) - local u = Bastion.UnitManager[unit] + return self +end - if not self.unit:IsUnit(u) then - return - end +function AuraTable:OnUpdate(auras) + local isFullUpdate = auras.isFullUpdate + if isFullUpdate then + self:Update() + return + end - local isFullUpdate = auras.isFullUpdate + local removedAuras = auras.removedAuraInstanceIDs + local addedAuras = auras.addedAuras + local updatedAuras = auras.updatedAuraInstanceIDs - if isFullUpdate then - self:Update() - print("Full update requested for " .. unit) - return - end + -- Add auras + if addedAuras and #addedAuras > 0 then + for i = 1, #addedAuras do + local aura = Bastion.Aura:CreateFromUnitAuraInfo(addedAuras[i]) - local addedAuras = auras.addedAuras - local removedAuras = auras.removedAuraInstanceIDs - local updatedAuras = auras.updatedAuraInstanceIDs - - -- DevTools_Dump(addedAuras) - if updatedAuras and #updatedAuras > 0 then - for i = 1, #updatedAuras do - local id = updatedAuras[i] - local newAura = C_UnitAuras.GetAuraDataByAuraInstanceID(unit, id); - if newAura then - local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura) - self:UpdateInstanceID(id, aura) - else - print("Instance ID " .. id .. " not found" .. " for unit " .. unit) - end - end + self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) end + end - -- Remove auras - if removedAuras and #removedAuras > 0 then - for i = 1, #removedAuras do - self:RemoveInstanceID(removedAuras[i]) + -- DevTools_Dump(addedAuras) + if updatedAuras and #updatedAuras > 0 then + for i = 1, #updatedAuras do + local id = updatedAuras[i] + local newAura = C_UnitAuras_GetAuraDataByAuraInstanceID(self.unit.unit, id); + if newAura then + local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura) + self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) end end + end - -- Add auras - if addedAuras and #addedAuras > 0 then - for i = 1, #addedAuras do - local aura = Bastion.Aura:CreateFromUnitAuraInfo(addedAuras[i]) - - if aura:IsBuff() then - if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then - if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then - self.playerAppliedBuffs[aura:GetSpell():GetID()] = {} - end - self.playerAppliedBuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedBuffs', - aura:GetSpell():GetID() } - else - if not self.buffs[aura:GetSpell():GetID()] then - self.buffs[aura:GetSpell():GetID()] = {} - end - self.buffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'buffs', - aura:GetSpell():GetID() } - end - else - if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then - if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then - self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {} - end - self.playerAppliedDebuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedDebuffs', - aura:GetSpell():GetID() } - else - if not self.debuffs[aura:GetSpell():GetID()] then - self.debuffs[aura:GetSpell():GetID()] = {} - end - self.debuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'debuffs', aura:GetSpell():GetID() } - end - end - end + -- Remove auras + if removedAuras and #removedAuras > 0 then + for i = 1, #removedAuras do + self:RemoveInstanceID(removedAuras[i]) end - end) - - return self + end end function AuraTable:RemoveInstanceID(instanceID) @@ -118,106 +72,74 @@ function AuraTable:RemoveInstanceID(instanceID) return end - local t, id = unpack(self.instanceIDLookup[instanceID]) + local id = self.instanceIDLookup[instanceID] - -- print("Removing aura from table: " .. t .. " " .. id .. " " .. index .. "") - local a = self[t][id][instanceID] - - if a:GetAuraInstanceID() ~= instanceID then - print("Instance ID mismatch: " .. a:GetAuraInstanceID() .. " " .. instanceID) + if self.playerAuras[id] and self.playerAuras[id][instanceID] then + self.playerAuras[id][instanceID] = nil + self.instanceIDLookup[instanceID] = nil + return end - self[t][id][instanceID] = nil - self.instanceIDLookup[instanceID] = nil -end - -function AuraTable:UpdateInstanceID(instanceID, newAura) - if not self.instanceIDLookup[instanceID] then + if self.auras[id] and self.auras[id][instanceID] then + self.auras[id][instanceID] = nil + self.instanceIDLookup[instanceID] = nil return end +end + +function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura) + local spellId = aura:GetSpell():GetID() + + self.instanceIDLookup[instanceID] = spellId - local t, id = unpack(self.instanceIDLookup[instanceID]) + if Bastion.UnitManager['player']:IsUnit(aura:GetSource()) then + if not self.playerAuras[spellId] then + self.playerAuras[spellId] = {} + end - -- print("Updating aura in table: " .. t .. " " .. id .. " " .. index .. "") + self.playerAuras[spellId][instanceID] = aura + else + if not self.auras[spellId] then + self.auras[spellId] = {} + end - self[t][id][instanceID] = newAura + self.auras[spellId][instanceID] = aura + end end -- Get a units buffs function AuraTable:GetUnitBuffs() - AuraUtil.ForEachAura(self.unit.unit, 'HELPFUL', nil, function(a) + AuraUtil_ForEachAura(self.unit.unit, 'HELPFUL', nil, function(a) local aura = Bastion.Aura:CreateFromUnitAuraInfo(a) if aura:IsValid() then - if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then - if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then - self.playerAppliedBuffs[aura:GetSpell():GetID()] = {} - end - self.playerAppliedBuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedBuffs', - aura:GetSpell():GetID() } - else - if not self.buffs[aura:GetSpell():GetID()] then - self.buffs[aura:GetSpell():GetID()] = {} - end - self.buffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'buffs', - aura:GetSpell():GetID() } - end + self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) end end, true) end -- Get a units debuffs function AuraTable:GetUnitDebuffs() - AuraUtil.ForEachAura(self.unit.unit, 'HARMFUL', nil, function(a) + AuraUtil_ForEachAura(self.unit.unit, 'HARMFUL', nil, function(a) local aura = Bastion.Aura:CreateFromUnitAuraInfo(a) if aura:IsValid() then - if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then - if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then - self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {} - end - self.playerAppliedDebuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedDebuffs', - aura:GetSpell():GetID() } - else - if not self.debuffs[aura:GetSpell():GetID()] then - self.debuffs[aura:GetSpell():GetID()] = {} - end - self.debuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura - self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'debuffs', - aura:GetSpell():GetID() } - end + self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) end end, true) end -local function merge(t1, t2) - for k, v in pairs(t2) do - if type(v) == "table" then - if type(t1[k] or false) == "table" then - merge(t1[k] or {}, t2[k] or {}) - else - t1[k] = v - end - else - t1[k] = v - end - end - return t1 -end - -- Update auras function AuraTable:Update() + print("Updating auras for " .. tostring(self.unit)) self:Clear() -- self.lastUpdate = GetTime() self:GetUnitBuffs() self:GetUnitDebuffs() - -- self.auras = merge(self.buffs, self.debuffs) - -- self.playerAuras = merge(self.playerAppliedBuffs, self.playerAppliedDebuffs) + -- self.auras = self.auras + -- self.playerAuras = self.playerAuras end -- Get a units auras @@ -230,17 +152,17 @@ function AuraTable:GetUnitAuras() if self.unit:GetGUID() ~= self.guid then self.guid = self.unit:GetGUID() self:Update() - return merge(self.buffs, self.debuffs) + return self.auras end -- -- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not -- -- If it's less than .4 seconds since the last time we queried the API, return the cached auras -- if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then - -- return merge(self.buffs, self.debuffs) + -- return self.auras -- end -- self:Update() - return merge(self.buffs, self.debuffs) + return self.auras end -- Get a units auras @@ -253,26 +175,22 @@ function AuraTable:GetMyUnitAuras() if self.unit:GetGUID() ~= self.guid then self.guid = self.unit:GetGUID() self:Update() - return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs) + return self.playerAuras end -- -- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not -- -- If it's less than .4 seconds since the last time we queried the API, return the cached auras -- if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then - -- return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs) + -- return self.playerAuras -- end -- self:Update() - return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs) + return self.playerAuras end -- Clear the aura table function AuraTable:Clear() - self.buffs = {} - self.debuffs = {} self.auras = {} - self.playerAppliedBuffs = {} - self.playerAppliedDebuffs = {} self.playerAuras = {} self.instanceIDLookup = {} end @@ -300,8 +218,7 @@ function AuraTable:Find(spell) end function AuraTable:FindMy(spell) - local auras = self:GetMyUnitAuras() - local aurasub = auras[spell:GetID()] + local aurasub = self.playerAuras[spell:GetID()] if not aurasub then return Bastion.Aura:New() diff --git a/src/NotificationsList/NotificationsList.lua b/src/NotificationsList/NotificationsList.lua new file mode 100644 index 0000000..7572d07 --- /dev/null +++ b/src/NotificationsList/NotificationsList.lua @@ -0,0 +1,124 @@ +-- Create a NotificationsList class + +local NotificationsList = { + notifications = {} +} +NotificationsList.__index = NotificationsList + +-- Constructor +function NotificationsList:New() + local self = setmetatable({}, NotificationsList) + + -- Create a frame for the notifications + self.frame = CreateFrame("Frame", "BastionNotificationsList", UIParent) + self.frame:SetSize(300, 100) + self.frame:SetPoint("TOP", UIParent, "TOP", 0, -100) + self.frame:SetFrameStrata("HIGH") + + -- Remove notifications after 5 seconds + C_Timer.NewTicker(0.1, function() + for i, notification in ipairs(self.notifications) do + if GetTime() - notification.addedAt > 2 then + notification:Remove() + table.remove(self.notifications, i) + end + end + end) + + return self +end + +-- Create a notification class for the notifications list (takes icon and text) +local Notification = { +} +Notification.__index = Notification + +-- Constructor +function Notification:New(list, icon, text) + local self = setmetatable({}, Notification) + + -- Create a frame for the notification + self.frame = CreateFrame("Frame", nil, list.frame) + self.frame:SetSize(300, 100) + self.frame:SetPoint("TOP", list.frame, "TOP", 0, 0) + self.frame:SetFrameStrata("HIGH") + + -- Create a texture for the icon + self.icon = self.frame:CreateTexture(nil, "ARTWORK") + self.icon:SetSize(32, 32) + self.icon:SetPoint("LEFT", self.frame, "LEFT", 0, 0) + self.icon:SetTexture(icon) + + -- Create a fontstring for the text + self.text = self.frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal") + self.text:SetPoint("CENTER", self.frame, "CENTER", 10, 0) + self.text:SetText(text) + self.text:SetFont("Fonts\\FRIZQT__.TTF", 14) + + self.addedAt = GetTime() + self.list = list + + return self +end + +-- Remove notification +function Notification:Remove() + -- Fade out the notification frame and remove it after the fade + UIFrameFadeOut(self.frame, 0.2, 1, 0) + C_Timer.After(0.5, function() + self.frame:Hide() + self.frame:ClearAllPoints() + self.frame:SetParent(nil) + self.frame = nil + self.list:Update() + end) +end + +-- Add a notification to the list +function NotificationsList:AddNotification(icon, text) + -- Create a new notification + local notification = Notification:New(self, icon, text) + + -- Add the notification to the list + table.insert(self.notifications, notification) + UIFrameFadeIn(notification.frame, 0.2, 0, 1) + + -- Update the notifications + self:Update() +end + +-- Update the notifications +function NotificationsList:Update() + -- Loop through the notifications + for i, notification in ipairs(self.notifications) do + -- Set the position of the notification + notification.frame:SetPoint("TOP", self.frame, "TOP", 0, -50 * (i - 1)) + end +end + +-- Remove a notification from the list +function NotificationsList:RemoveNotification(notification) + -- Loop through the notifications + for i, v in ipairs(self.notifications) do + -- Check if the notification is the one we want to remove + if v == notification then + -- Remove the notification from the list + table.remove(self.notifications, i) + notification:Remove() + break + end + end +end + +-- Remove all notifications from the list +function NotificationsList:RemoveAllNotifications() + -- Loop through the notifications + for i, v in ipairs(self.notifications) do + -- Remove the notification from the list + table.remove(self.notifications, i) + self.notifications[i]:Remove() + end +end + +-- Remove all notifications +return NotificationsList, Notification diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index 7042f14..ae06614 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -40,6 +40,13 @@ function Spell:New(id) self.spellID = id + Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) + local unit, castGUID, spellID = ... + if unit == "player" and spellID == self:GetID() then + self.lastCastAt = GetTime() + end + end) + return self end @@ -104,7 +111,7 @@ function Spell:Cast(unit, condition) -- if unit.unit contains 'nameplate' then we need to use Object wrapper to cast local u = unit.unit - if string.find(u, 'nameplate') then + if type(u) == "string" and string.find(u, 'nameplate') then u = Object(u) end @@ -114,7 +121,7 @@ function Spell:Cast(unit, condition) Bastion:Debug("Casting", self) -- Set the last cast time - self.lastCastAt = GetTime() + self.lastCastAttempt = GetTime() -- Call post cast function if self:GetOnCastFunction() then @@ -202,36 +209,20 @@ function Spell:Call(unit) return false end +function Spell:HasRange() + return SpellHasRange(self:GetName()) +end + -- Check if the spell is in range of the unit function Spell:IsInRange(unit) - local name, rank, icon, castTime, spellmin, spellmax, spellID = GetSpellInfo(self:GetID()) - - local them = Object(unit.unit) - - local tx, ty, tz = ObjectPosition(unit.unit) - local px, py, pz = ObjectPosition('player') - - if not them then - return false - end + local hasRange = self:HasRange() + local inRange = IsSpellInRange(self:GetName(), unit.unit) - if tx == 0 and ty == 0 and tz == 0 then + if not hasRange then return true end - local combatReach = ObjectCombatReach("player") - local themCombatReach = ObjectCombatReach(unit.unit) - - if Bastion.UnitManager['player']:InMelee(unit) and spellmin == 0 then - return true - end - - local distance = FastDistance(px, py, pz, tx, ty, tz) - - if spellmax - and distance >= spellmin - and distance <= combatReach + themCombatReach + spellmax - then + if hasRange and inRange == 1 then return true end diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index 79a9a0f..f5a225d 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -23,11 +23,15 @@ end -- tostring function Unit:__tostring() - return "Bastion.__Unit(" .. self.unit .. ")" .. " - " .. (self:GetName() or '') + return "Bastion.__Unit(" .. tostring(self.unit) .. ")" .. " - " .. (self:GetName() or '') end -- Constructor function Unit:New(unit) + if UnitIsUnit(unit, "player") then + print("Created unit for player") + end + local self = setmetatable({}, Unit) self.unit = unit self.cache = Bastion.Cache:New() @@ -144,7 +148,7 @@ end -- Is the unit a hostile unit function Unit:IsHostile() - return UnitIsEnemy("player", self.unit) + return UnitCanAttack(self.unit, 'player') end -- Is the unit a boss @@ -217,15 +221,7 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000 -- Check if two units are in melee function Unit:InMelee(unit) - local combatReach = ObjectCombatReach(self.unit) - local themCombatReach = ObjectCombatReach(unit.unit) - - if not combatReach or not themCombatReach then - return false - end - - return self:GetDistance(unit) - < math.max(combatReach + 1.3333 + themCombatReach, 5) + return UnitInMelee(self.unit, unit.unit) end local losFlag = bit.bor(0x1, 0x10, 0x100000) @@ -317,27 +313,31 @@ function Unit:GetEnemies(range) end local count = 0 - local objs = Objects() - local numobjs = #objs - - for i = 1, numobjs do - local object = objs[i] - -- unit types 5,6,7 - if ObjectType(object) == 5 or ObjectType(object) == 6 then - local unit = Unit:New(object) - if Bastion.UnitManager['player']:CanAttack(unit) and unit:IsAffectingCombat() and unit:IsAlive() and - unit:CanSee(self) - and - self:GetDistance(unit) <= range then - count = count + 1 - end + + Bastion.UnitManager:EnumNameplates(function(unit) + if not self:IsUnit(unit) and unit:GetDistance(self) <= range and unit:IsAlive() and self:CanSee(unit) then + count = count + 1 end - end + end) self.cache:Set("enemies_" .. range, count, .5) return count end +-- Get the number of melee attackers +function Unit:GetMeleeAttackers() + local count = 0 + + Bastion.UnitManager:EnumNameplates(function(unit) + if not self:IsUnit(unit) and unit:IsAlive() and self:CanSee(unit) and + self:InMelee(unit) and unit:IsAffectingCombat() and not unit:IsFriendly(self) then + count = count + 1 + end + end) + + return count +end + function Unit:GetPartyHPAround(distance, percent) local count = 0 diff --git a/src/UnitManager/UnitManager.lua b/src/UnitManager/UnitManager.lua index 9c89b16..5102f13 100644 --- a/src/UnitManager/UnitManager.lua +++ b/src/UnitManager/UnitManager.lua @@ -69,25 +69,25 @@ function UnitManager:__index(k) self.cache:Set(k, self.customUnits[k].unit, 0.5) end - return self.customUnits[k].unit end - if self.objects[k] then - return self.objects[k] + local kguid = ObjectGUID(k) + + if kguid and self.objects[kguid] then + return self.objects[kguid] end -- if not Validate(k) then -- error("UnitManager:Get - Invalid token: " .. k) -- end - if self.units[k] == nil then - self.units[k] = Unit:New(k) + if self.objects[kguid] == nil then + local unit = Unit:New(Object(k)) + self:SetObject(unit) end - - - return self.units[k] + return self.objects[kguid] end -- Constructor @@ -109,11 +109,13 @@ function UnitManager:Get(token) -- error("UnitManager:Get - Invalid token: " .. token) -- end - if self.units[token] == nil then - self.units[token] = Unit:New(token) + local tguid = ObjectGUID(token) + + if self.objects[tguid] == nil then + self.objects[tguid] = Unit:New(Object(tguid)) end - return self.units[token] + return self.objects[tguid] end function UnitManager:GetObject(guid) diff --git a/src/_bastion.lua b/src/_bastion.lua index e2c98e2..5bc5c58 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -15,6 +15,7 @@ function Bastion.require(class) end Bastion.ClassMagic = Bastion.require("ClassMagic") +Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList") Bastion.Vector3 = Bastion.require("Vector3") Bastion.Commmand = Bastion.require("Command") Bastion.Cache = Bastion.require("Cache") @@ -34,10 +35,17 @@ Bastion.Class = Bastion.require("Class") Bastion.Timer = Bastion.require("Timer") Bastion.CombatTimer = Bastion.Timer:New('combat') Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New() +Bastion.Notifications = Bastion.NotificationsList:New() Bastion.modules = {} Bastion.Enabled = false +Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) + local u = Bastion.UnitManager[unit] + + u:GetAuras():OnUpdate(auras) +end) + Bastion.Ticker = C_Timer.NewTicker(0.1, function() if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then Bastion.CombatTimer:Start()