From fef75da2a6dd5ae924804b0c0f133355ebbbd263 Mon Sep 17 00:00:00 2001 From: Ofrex <30585460+Ofrex@users.noreply.github.com> Date: Tue, 31 Jan 2023 15:21:37 +0000 Subject: [PATCH] Updated Updated to 4n0n latest - object manager and unit manager updates --- src/Aura/Aura.lua | 25 +++- src/AuraTable/AuraTable.lua | 134 ++++++++++++++++++++-- src/Item/Item.lua | 19 ++- src/List/List.lua | 21 +++- src/ObjectManager/ObjectManager.lua | 65 ++++++++++- src/Refreshable/Refreshable.lua | 10 +- src/Spell/Spell.lua | 16 ++- src/Unit/Unit.lua | 172 ++++++++++++++++------------ src/UnitManager/UnitManager.lua | 24 ++-- src/_bastion.lua | 21 +++- 10 files changed, 404 insertions(+), 103 deletions(-) diff --git a/src/Aura/Aura.lua b/src/Aura/Aura.lua index a1ca4e9..c8a3de5 100644 --- a/src/Aura/Aura.lua +++ b/src/Aura/Aura.lua @@ -1,6 +1,7 @@ local Tinkr, Bastion = ... -- Create a new Aura class +---@class Aura local Aura = {} function Aura:__index(k) @@ -17,6 +18,19 @@ function Aura:__index(k) return response end +-- Equals +function Aura:__eq(other) + if getmetatable(other) == Aura then + return self:GetSpell():GetID() == other:GetSpell():GetID() + end + + if getmetatable(other) == Bastion.Spell then + return self:GetSpell():GetID() == other:GetID() + end + + return false +end + function Aura:__tostring() return "Bastion.__Aura(" .. self:GetSpell():GetID() .. ")" .. " - " .. (self:GetName() or "''") end @@ -46,12 +60,15 @@ function Aura:New(unit, index, type) type = nil, } - Bastion.SpellBook:GetSpell(self.aura.spellId) + + if self.aura.spellId then + Bastion.SpellBook:GetSpell(self.aura.spellId) + end return self end local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, - spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit.unit, index, type) + spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type) local self = setmetatable({}, Aura) self.aura = { @@ -75,7 +92,9 @@ function Aura:New(unit, index, type) index = index, type = type, } - Bastion.SpellBook:GetSpell(self.aura.spellId) + if self.aura.spellId then + Bastion.SpellBook:GetSpell(self.aura.spellId) + end return self end diff --git a/src/AuraTable/AuraTable.lua b/src/AuraTable/AuraTable.lua index 893e106..fddcca6 100644 --- a/src/AuraTable/AuraTable.lua +++ b/src/AuraTable/AuraTable.lua @@ -1,6 +1,7 @@ local Tinkr, Bastion = ... -- Create a new AuraTable class +---@class AuraTable local AuraTable = {} AuraTable.__index = AuraTable @@ -17,9 +18,10 @@ function AuraTable:New(unit) local self = setmetatable({}, AuraTable) self.unit = unit - self.auras = {} + self.auras = {} self.playerAuras = {} + self.guid = unit:GetGUID() self.instanceIDLookup = {} @@ -27,6 +29,10 @@ function AuraTable:New(unit) end function AuraTable:OnUpdate(auras) + if not auras then + self:Update() + return + end local isFullUpdate = auras.isFullUpdate if isFullUpdate then @@ -51,7 +57,7 @@ function AuraTable:OnUpdate(auras) if updatedAuras and #updatedAuras > 0 then for i = 1, #updatedAuras do local id = updatedAuras[i] - local newAura = C_UnitAuras_GetAuraDataByAuraInstanceID(self.unit.unit, id); + local newAura = C_UnitAuras_GetAuraDataByAuraInstanceID(self.unit:GetOMToken(), id); if newAura then local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura) self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) @@ -109,7 +115,34 @@ end -- Get a units buffs function AuraTable:GetUnitBuffs() - AuraUtil_ForEachAura(self.unit.unit, 'HELPFUL', nil, function(a) + if Tinkr.classic then + for i = 1, 40 do + local aura = Bastion.Aura:New(self.unit, i, 'HELPFUL') + + if not aura:IsValid() then + break + end + + local spellId = aura:GetSpell():GetID() + + if Bastion.UnitManager['player']:IsUnit(aura:GetSource()) then + if not self.playerAuras[spellId] then + self.playerAuras[spellId] = {} + end + + table.insert(self.playerAuras[spellId], aura) + else + if not self.auras[spellId] then + self.auras[spellId] = {} + end + + table.insert(self.auras[spellId], aura) + end + end + return + end + + AuraUtil_ForEachAura(self.unit:GetOMToken(), 'HELPFUL', nil, function(a) local aura = Bastion.Aura:CreateFromUnitAuraInfo(a) if aura:IsValid() then @@ -120,7 +153,34 @@ end -- Get a units debuffs function AuraTable:GetUnitDebuffs() - AuraUtil_ForEachAura(self.unit.unit, 'HARMFUL', nil, function(a) + if Tinkr.classic then + for i = 1, 40 do + local aura = Bastion.Aura:New(self.unit, i, 'HARMFUL') + + if not aura:IsValid() then + break + end + + local spellId = aura:GetSpell():GetID() + + if Bastion.UnitManager['player']:IsUnit(aura:GetSource()) then + if not self.playerAuras[spellId] then + self.playerAuras[spellId] = {} + end + + table.insert(self.playerAuras[spellId], aura) + else + if not self.auras[spellId] then + self.auras[spellId] = {} + end + + table.insert(self.auras[spellId], aura) + end + end + return + end + + AuraUtil_ForEachAura(self.unit:GetOMToken(), 'HARMFUL', nil, function(a) local aura = Bastion.Aura:CreateFromUnitAuraInfo(a) if aura:IsValid() then @@ -196,6 +256,7 @@ function AuraTable:Clear() end -- Check if the unit has a specific aura +---@return Aura function AuraTable:Find(spell) local auras = self:GetUnitAuras() local aurasub = auras[spell:GetID()] @@ -205,11 +266,14 @@ function AuraTable:Find(spell) end for k, a in pairs(aurasub) do + print(a) if a ~= nil then if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA return a else - self:RemoveInstanceID(a:GetAuraInstanceID()) + if not Tinkr.classic then + self:RemoveInstanceID(a:GetAuraInstanceID()) + end end end end @@ -217,8 +281,10 @@ function AuraTable:Find(spell) return Bastion.Aura:New() end +---@return Aura function AuraTable:FindMy(spell) - local aurasub = self.playerAuras[spell:GetID()] + local auras = self:GetMyUnitAuras() + local aurasub = auras[spell:GetID()] if not aurasub then return Bastion.Aura:New() @@ -229,7 +295,60 @@ function AuraTable:FindMy(spell) if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA return a else - self:RemoveInstanceID(a:GetAuraInstanceID()) + if not Tinkr.classic then + self:RemoveInstanceID(a:GetAuraInstanceID()) + end + end + end + end + + return Bastion.Aura:New() +end + +function AuraTable:FindFrom(spell, source) + local auras = self:GetUnitAuras() + local aurasub = auras[spell:GetID()] + + if not aurasub then + return Bastion.Aura:New() + end + + for k, a in pairs(aurasub) do + if a ~= nil then + if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA + if a:GetSource() == source then + return a + end + else + if not Tinkr.classic then + self:RemoveInstanceID(a:GetAuraInstanceID()) + end + end + end + end + + return Bastion.Aura:New() +end + +-- Find the aura from the current unit +function AuraTable:FindTheirs(spell) + local auras = self:GetUnitAuras() + local aurasub = auras[spell:GetID()] + + if not aurasub then + return Bastion.Aura:New() + end + + for k, a in pairs(aurasub) do + if a ~= nil then + if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA + if self.unit:IsUnit(a:GetSource()) then + return a + end + else + if not Tinkr.classic then + self:RemoveInstanceID(a:GetAuraInstanceID()) + end end end end @@ -238,6 +357,7 @@ function AuraTable:FindMy(spell) end -- Find any +---@return Aura function AuraTable:FindAny(spell) local a = self:Find(spell) if a:IsValid() then diff --git a/src/Item/Item.lua b/src/Item/Item.lua index 205c638..1ae6282 100644 --- a/src/Item/Item.lua +++ b/src/Item/Item.lua @@ -1,6 +1,7 @@ local Tinkr, Bastion = ... -- Create a new Item class +---@class Item local Item = { UsableIfFunc = false, PreUseFunc = false, @@ -29,6 +30,11 @@ function Item:__index(k) return response end +-- Equals +function Item:__eq(other) + return self:GetID() == other:GetID() +end + -- tostring function Item:__tostring() return "Bastion.__Item(" .. self:GetID() .. ")" .. " - " .. self:GetName() @@ -110,7 +116,7 @@ function Item:Use(unit, condition) self.wasLooking = IsMouselooking() -- Use the Item - UseItemByName(self:GetName(), unit.unit) + UseItemByName(self:GetName(), unit:GetOMToken()) Bastion:Debug("Using", self) @@ -170,18 +176,21 @@ function Item:Usable() end -- Set a script to check if the Item is Usable +---@param func fun(self:Item):boolean function Item:UsableIf(func) self.UsableIfFunc = func return self end -- Set a script to run before the Item has been Use +---@param func fun(self:Item) function Item:PreUse(func) self.PreUseFunc = func return self end -- Set a script to run after the Item has been Use +---@param func fun(self:Item) function Item:OnUse(func) self.OnUseFunc = func return self @@ -221,9 +230,9 @@ end function Item:IsInRange(unit) local name, rank, icon, UseTime, Itemmin, Itemmax, ItemID = GetItemInfo(self:GetID()) - local them = Object(unit.unit) + local them = Object(unit:GetOMToken()) - local tx, ty, tz = ObjectPosition(unit.unit) + local tx, ty, tz = ObjectPosition(unit:GetOMToken()) local px, py, pz = ObjectPosition('player') if not them then @@ -235,7 +244,7 @@ function Item:IsInRange(unit) end local combatReach = ObjectCombatReach("player") - local themCombatReach = ObjectCombatReach(unit.unit) + local themCombatReach = ObjectCombatReach(unit:GetOMToken()) if Bastion.UnitManager['player']:InMelee(unit) and Itemmin == 0 then return true @@ -278,6 +287,8 @@ function Item:GetChargesRemaining() end -- Create a condition for the Item +---@param name string +---@param func fun(self:Item) function Item:Condition(name, func) self.conditions[name] = { func = func diff --git a/src/List/List.lua b/src/List/List.lua index bc03ebe..f26a86b 100644 --- a/src/List/List.lua +++ b/src/List/List.lua @@ -1,6 +1,25 @@ local Tinkr, Bastion = ... -local List = {} +---@class List +local List = { + -- Add overload + ---@param self List + ---@param value any + ---@return List + __add = function(self, value) + self:push(value) + return self + end, + + -- Subtract overload + ---@param self List + ---@param value any + ---@return List + __sub = function(self, value) + self:remove(value) + return self + end, +} List.__index = List function List:New(from) diff --git a/src/ObjectManager/ObjectManager.lua b/src/ObjectManager/ObjectManager.lua index d90b561..cd0bbc4 100644 --- a/src/ObjectManager/ObjectManager.lua +++ b/src/ObjectManager/ObjectManager.lua @@ -1,12 +1,13 @@ local Tinkr, Bastion = ... +---@class ObjectManager local ObjectManager = {} ObjectManager.__index = ObjectManager function ObjectManager:New() local self = setmetatable({}, ObjectManager) - self._objects = {} + self._lists = {} self.enemies = Bastion.List:New() self.friends = Bastion.List:New() @@ -16,15 +17,54 @@ function ObjectManager:New() return self end +-- Register a custom list with a callback +function ObjectManager:RegisterList(name, cb) + if self._lists[name] then + return false + end + + self._lists[name] = { + list = Bastion.List:New(), + cb = cb + } + + return self._lists[name].list +end + +-- reset custom lists +function ObjectManager:ResetLists() + for _, list in pairs(self._lists) do + list.list:clear() + end +end + +-- Refresh custom lists +function ObjectManager:EnumLists(object) + for _, list in pairs(self._lists) do + local r = list.cb(object) + if r then + list.list:push(r) + end + end +end + +-- Get a list +function ObjectManager:GetList(name) + return self._lists[name].list +end + function ObjectManager:Refresh() self.enemies:clear() self.friends:clear() self.activeEnemies:clear() self.explosives:clear() + self:ResetLists() local objects = Objects() for _, object in pairs(objects) do + self:EnumLists(object) + if ObjectType(object) == 5 or ObjectType(object) == 6 then local unit = Bastion.UnitManager:GetObject(ObjectGUID(object)) if not unit then @@ -39,7 +79,7 @@ function ObjectManager:Refresh() elseif unit:IsEnemy() then self.enemies:push(unit) - if unit:IsAffectingCombat() then + if unit:InCombatOdds() > 80 then self.activeEnemies:push(unit) end end @@ -48,3 +88,24 @@ function ObjectManager:Refresh() end return ObjectManager + + +-- -- Register a list of objects that are training dummies +-- local dummies = Bastion.ObjectManager:RegisterList('dummies', function(object) +-- if ObjectType(object) == 5 or ObjectType(object) == 6 then +-- local unit = Bastion.UnitManager:GetObject(ObjectGUID(object)) + +-- if not unit then +-- unit = Bastion.Unit:New(object) +-- Bastion.UnitManager:SetObject(unit) +-- end + +-- if unit:GetID() == 198594 then +-- return unit +-- end +-- end +-- end) + +-- dummies:each(function(dummy) +-- print(dummy:GetName()) +-- end) diff --git a/src/Refreshable/Refreshable.lua b/src/Refreshable/Refreshable.lua index 1018c1c..5f8a365 100644 --- a/src/Refreshable/Refreshable.lua +++ b/src/Refreshable/Refreshable.lua @@ -1,10 +1,14 @@ local Tinkr, Bastion = ... -- Define a Refreshable class +---@class Refreshable local Refreshable = { cache = nil, callback = nil, - value = nil + value = nil, + __eq = function(self, other) + return self.value.__eq(rawget(self, 'value'), other) + end } -- On index check the cache to be valid and return the value or reconstruct the value and return it @@ -19,7 +23,7 @@ end -- When the object is accessed return the value function Refreshable:__tostring() - return "Bastion.__Refreshable(" .. tostring(self.value) .. ")" + return "Bastion.__Refreshable(" .. tostring(rawget(self, 'value')) .. ")" end -- Create @@ -30,7 +34,7 @@ function Refreshable:New(value, cb) self.value = value self.callback = cb - self.cache:Set('self', self.value, 0.5) + self.cache:Set('self', rawget(self, 'value'), 0.5) return self end diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index a474928..851964c 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -1,6 +1,7 @@ local Tinkr, Bastion = ... -- Create a new Spell class +---@class Spell local Spell = { CastableIfFunc = false, PreCastFunc = false, @@ -30,6 +31,11 @@ function Spell:__index(k) return response end +-- Equals +function Spell:__eq(other) + return self:GetID() == other:GetID() +end + -- tostring function Spell:__tostring() return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName() @@ -50,6 +56,7 @@ function Spell:GetID() end -- Add post cast func +---@param func fun(self:Spell) function Spell:PostCast(func) self.PostCastFunc = func return self @@ -114,8 +121,8 @@ function Spell:Cast(unit, condition) -- Check if the mouse was looking self.wasLooking = IsMouselooking() - -- if unit.unit contains 'nameplate' then we need to use Object wrapper to cast - local u = unit.unit + -- if unit:GetOMToken() contains 'nameplate' then we need to use Object wrapper to cast + local u = unit:GetOMToken() if type(u) == "string" and string.find(u, 'nameplate') then u = Object(u) end @@ -173,18 +180,21 @@ function Spell:Castable() end -- Set a script to check if the spell is castable +---@param func fun(spell:Spell):boolean function Spell:CastableIf(func) self.CastableIfFunc = func return self end -- Set a script to run before the spell has been cast +---@param func fun(spell:Spell) function Spell:PreCast(func) self.PreCastFunc = func return self end -- Set a script to run after the spell has been cast +---@param func fun(spell:Spell) function Spell:OnCast(func) self.OnCastFunc = func return self @@ -227,7 +237,7 @@ end -- Check if the spell is in range of the unit function Spell:IsInRange(unit) local hasRange = self:HasRange() - local inRange = IsSpellInRange(self:GetName(), unit.unit) + local inRange = IsSpellInRange(self:GetName(), unit:GetOMToken()) if hasRange == false then return true diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index d60328f..4fa5e83 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -1,19 +1,27 @@ local Tinkr, Bastion = ... -- Create a new Unit class +---@class Unit local Unit = { cache = nil, + ---@type AuraTable aura_table = nil, + ---@type Unit unit = nil, last_shadow_techniques = 0, swings_since_sht = 0, last_off_attack = 0, last_main_attack = 0, + last_combat_time = 0, } function Unit:__index(k) local response = Bastion.ClassMagic:Resolve(Unit, k) + if k == 'unit' then + return rawget(self, k) + end + if response == nil then response = rawget(self, k) end @@ -25,9 +33,14 @@ function Unit:__index(k) return response end +-- Equals +function Unit:__eq(other) + return UnitIsUnit(self:GetOMToken(), other.unit) +end + -- tostring function Unit:__tostring() - return "Bastion.__Unit(" .. tostring(self.unit) .. ")" .. " - " .. (self:GetName() or '') + return "Bastion.__Unit(" .. tostring(self:GetOMToken()) .. ")" .. " - " .. (self:GetName() or '') end -- Constructor @@ -42,37 +55,37 @@ end -- Check if the unit is valid function Unit:IsValid() - return self.unit ~= nil and self:Exists() + return self:GetOMToken() ~= nil and self:Exists() end -- Check if the unit exists function Unit:Exists() - return Object(self.unit) + return Object(self:GetOMToken()) end -- Get the units token function Unit:Token() - return self.unit + return self:GetOMToken() end -- Get the units name function Unit:GetName() - return UnitName(self.unit) + return UnitName(self:GetOMToken()) end -- Get the units GUID function Unit:GetGUID() - return ObjectGUID(self.unit) + return ObjectGUID(self:GetOMToken()) end -- Get the units health function Unit:GetHealth() - return UnitHealth(self.unit) + return UnitHealth(self:GetOMToken()) end -- Get the units max health function Unit:GetMaxHealth() - return UnitHealthMax(self.unit) + return UnitHealthMax(self:GetOMToken()) end -- Get the units health percentage @@ -86,19 +99,19 @@ end -- Get the units power type function Unit:GetPowerType() - return UnitPowerType(self.unit) + return UnitPowerType(self:GetOMToken()) end -- Get the units power function Unit:GetPower(powerType) local powerType = powerType or self:GetPowerType() - return UnitPower(self.unit, powerType) + return UnitPower(self:GetOMToken(), powerType) end -- Get the units max power function Unit:GetMaxPower(powerType) local powerType = powerType or self:GetPowerType() - return UnitPowerMax(self.unit, powerType) + return UnitPowerMax(self:GetOMToken(), powerType) end -- Get the units power percentage @@ -115,7 +128,7 @@ end -- Get the units position function Unit:GetPosition() - local x, y, z = ObjectPosition(self.unit) + local x, y, z = ObjectPosition(self:GetOMToken()) return Bastion.Vector3:New(x, y, z) end @@ -129,37 +142,37 @@ end -- Is the unit dead function Unit:IsDead() - return UnitIsDeadOrGhost(self.unit) + return UnitIsDeadOrGhost(self:GetOMToken()) end -- Is the unit alive function Unit:IsAlive() - return not UnitIsDeadOrGhost(self.unit) + return not UnitIsDeadOrGhost(self:GetOMToken()) end -- Is the unit a pet function Unit:IsPet() - return UnitIsUnit(self.unit, "pet") + return UnitIsUnit(self:GetOMToken(), "pet") end -- Is the unit a friendly unit function Unit:IsFriendly() - return UnitIsFriend("player", self.unit) + return UnitIsFriend("player", self:GetOMToken()) end -- IsEnemy function Unit:IsEnemy() - return UnitCanAttack("player", self.unit) + return UnitCanAttack("player", self:GetOMToken()) end -- Is the unit a hostile unit function Unit:IsHostile() - return UnitCanAttack(self.unit, 'player') + return UnitCanAttack(self:GetOMToken(), 'player') end -- Is the unit a boss function Unit:IsBoss() - if UnitClassification(self.unit) == "worldboss" then + if UnitClassification(self:GetOMToken()) == "worldboss" then return true end @@ -174,77 +187,80 @@ function Unit:IsBoss() return false end +function Unit:GetOMToken() + if not self.unit then + return "none" + end + return self.unit:unit() +end + -- Is the unit a target function Unit:IsTarget() - return UnitIsUnit(self.unit, "target") + return UnitIsUnit(self:GetOMToken(), "target") end -- Is the unit a focus function Unit:IsFocus() - return UnitIsUnit(self.unit, "focus") + return UnitIsUnit(self:GetOMToken(), "focus") end -- Is the unit a mouseover function Unit:IsMouseover() - return UnitIsUnit(self.unit, "mouseover") + return UnitIsUnit(self:GetOMToken(), "mouseover") end -- Is the unit a tank function Unit:IsTank() - return UnitGroupRolesAssigned(self.unit) == "TANK" + return UnitGroupRolesAssigned(self:GetOMToken()) == "TANK" end -- Is the unit a healer function Unit:IsHealer() - return UnitGroupRolesAssigned(self.unit) == "HEALER" + return UnitGroupRolesAssigned(self:GetOMToken()) == "HEALER" end -- Is the unit a damage dealer function Unit:IsDamage() - return UnitGroupRolesAssigned(self.unit) == "DAMAGER" + return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER" end -- Is the unit a player function Unit:IsPlayer() - return UnitIsPlayer(self.unit) + return UnitIsPlayer(self:GetOMToken()) end -- Is the unit a player controlled unit function Unit:IsPCU() - return UnitPlayerControlled(self.unit) + return UnitPlayerControlled(self:GetOMToken()) end -- Get if the unit is affecting combat function Unit:IsAffectingCombat() - return UnitAffectingCombat('player', self.unit) -end - --- Is the unit indoors -function Unit:IsIndoors() - return IsIndoors() + return UnitAffectingCombat(self:GetOMToken()) end -- Get the units class id function Unit:GetClass() - local locale, class, classID = UnitClass(self.unit) + local locale, class, classID = UnitClass(self:GetOMToken()) return Bastion.Class:New(locale, class, classID) end -- Get the units auras +---@return AuraTable function Unit:GetAuras() return self.aura_table end -- Get the raw unit function Unit:GetRawUnit() - return self.unit + return self:GetOMToken() end local isClassicWow = select(4, GetBuildInfo()) < 40000 -- Check if two units are in melee -- function Unit:InMelee(unit) --- return UnitInMelee(self.unit, unit.unit) +-- return UnitInMelee(self:GetOMToken(), unit.unit) -- end local losFlag = bit.bor(0x1, 0x10, 0x100000) @@ -266,8 +282,8 @@ function Unit:CanSee(unit) -- return false -- end -- end - local ax, ay, az = ObjectPosition(self.unit) - local ah = ObjectHeight(self.unit) + local ax, ay, az = ObjectPosition(self:GetOMToken()) + local ah = ObjectHeight(self:GetOMToken()) local attx, atty, attz = GetUnitAttachmentPosition(unit.unit, 34) if (ax == 0 and ay == 0 and az == 0) or (attx == 0 and atty == 0 and attz == 0) then @@ -288,7 +304,7 @@ end -- Check if the unit is casting a spell function Unit:IsCasting() - return UnitCastingInfo(self.unit) ~= nil + return UnitCastingInfo(self:GetOMToken()) ~= nil end -- Get Casting or channeling spell @@ -297,7 +313,8 @@ function Unit:GetCastingOrChannelingSpell() .unit) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit + :unit()) end if name then @@ -309,7 +326,7 @@ end -- Check if the unit is channeling a spell function Unit:IsChanneling() - return UnitChannelInfo(self.unit) ~= nil + return UnitChannelInfo(self:GetOMToken()) ~= nil end -- Check if the unit is casting or channeling a spell @@ -319,7 +336,7 @@ end -- Check if the unit can attack the target function Unit:CanAttack(unit) - return UnitCanAttack(self.unit, unit.unit) + return UnitCanAttack(self:GetOMToken(), unit.unit) end function Unit:GetChannelOrCastPercentComplete() @@ -327,7 +344,8 @@ function Unit:GetChannelOrCastPercentComplete() .unit) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit + :unit()) end if name and startTimeMS and endTimeMS then @@ -345,7 +363,8 @@ function Unit:IsInterruptible() .unit) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit + :unit()) end if name then @@ -382,7 +401,7 @@ function Unit:GetEnemies(range) Bastion.UnitManager:EnumEnemies(function(unit) if not self:IsUnit(unit) and unit:GetDistance(self) <= range and unit:IsAlive() and self:CanSee(unit) and - unit:IsEnemy() and unit:IsAffectingCombat() then + unit:IsEnemy() then count = count + 1 end end) @@ -402,7 +421,7 @@ function Unit:GetMeleeAttackers() Bastion.UnitManager:EnumEnemies(function(unit) if not self:IsUnit(unit) and unit:IsAlive() and self:CanSee(unit) and - self:InMelee(unit) and unit:IsEnemy() and unit:IsAffectingCombat() then + self:InMelee(unit) and unit:IsEnemy() and unit:InCombatOdds() > 80 then count = count + 1 end end) @@ -426,19 +445,19 @@ end -- Is moving function Unit:IsMoving() - return GetUnitSpeed(self.unit) > 0 + return GetUnitSpeed(self:GetOMToken()) > 0 end function Unit:IsMovingAtAll() - return ObjectMovementFlag(self.unit) ~= 0 + return ObjectMovementFlag(self:GetOMToken()) ~= 0 end function Unit:GetComboPoints() - return UnitPower(self.unit, 4) + return UnitPower(self:GetOMToken(), 4) end function Unit:GetComboPointsMax() - return UnitPowerMax(self.unit, 4) + return UnitPowerMax(self:GetOMToken(), 4) end -- Get combopoints deficit @@ -448,19 +467,20 @@ end -- IsUnit function Unit:IsUnit(unit) - return UnitIsUnit(self.unit, unit.unit) + return UnitIsUnit(self:GetOMToken(), unit and unit:GetOMToken() or 'none') end -- IsTanking function Unit:IsTanking(unit) - local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self.unit, unit.unit) + local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(), + unit.unit) return isTanking end -- IsFacing function Unit:IsFacing(unit) - local rot = ObjectRotation(self.unit) - local x, y, z = ObjectPosition(self.unit) + local rot = ObjectRotation(self:GetOMToken()) + local x, y, z = ObjectPosition(self:GetOMToken()) local x2, y2, z2 = ObjectPosition(unit.unit) if not x or not x2 then @@ -481,7 +501,7 @@ end function Unit:IsBehind(unit) local rot = ObjectRotation(unit.unit) local x, y, z = ObjectPosition(unit.unit) - local x2, y2, z2 = ObjectPosition(self.unit) + local x2, y2, z2 = ObjectPosition(self:GetOMToken()) if not x or not x2 then return false @@ -513,7 +533,7 @@ end -- InMelee function Unit:InMelee(unit) - local x, y, z = ObjectPosition(self.unit) + local x, y, z = ObjectPosition(self:GetOMToken()) local x2, y2, z2 = ObjectPosition(unit.unit) if not x or not x2 then @@ -521,7 +541,7 @@ function Unit:InMelee(unit) end local dist = math.sqrt((x - x2) ^ 2 + (y - y2) ^ 2 + (z - z2) ^ 2) - local maxDist = math.max((ObjectCombatReach(self.unit) + 1.3333) + ObjectCombatReach(unit.unit), 5.0) + local maxDist = math.max((ObjectCombatReach(self:GetOMToken()) + 1.3333) + ObjectCombatReach(unit.unit), 5.0) maxDist = maxDist + 1.0 + self:GetMeleeBoost() return dist <= maxDist @@ -529,12 +549,12 @@ end -- Get object id function Unit:GetID() - return ObjectID(self.unit) + return ObjectID(self:GetOMToken()) end -- In party function Unit:IsInParty() - return UnitInParty(self.unit) + return UnitInParty(self:GetOMToken()) end -- Linear regression between time and percent to something @@ -623,17 +643,20 @@ end -- Set combat time if affecting combat and return the difference between now and the last time function Unit:GetCombatTime() - if self:IsAffectingCombat() then - self.last_combat_time = GetTime() - elseif not self:IsAffectingCombat() and self.last_combat_time then - self.last_combat_time = nil - end + return GetTime() - self.last_combat_time +end - if not self.last_combat_time then - return 0 - end +function Unit:SetLastCombatTime(time) + self.last_combat_time = time +end - return GetTime() - self.last_combat_time +-- Get combat odds (if the last combat time is less than 1 minute ago return 1 / time, else return 0) +-- the closer to 0 the more likely the unit is to be in combat (0 = 100%) 60 = 0% +function Unit:InCombatOdds() + local time = self:GetCombatTime() + local percent = 1 - (time / 60) + + return percent * 100 end -- Get units gcd time @@ -656,7 +679,7 @@ More than 50% Haste will drop a spell below 1 second ]] function Unit:GetMaxGCD() - local haste = UnitSpellHaste(self.unit) + local haste = UnitSpellHaste(self:GetOMToken()) if haste > 50 then haste = 50 end @@ -674,12 +697,12 @@ function Unit:IsStealthed() local Sepsis = Bastion.SpellBook:GetSpell(328305) - return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance) + return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance) end -- Get unit swing timers function Unit:GetSwingTimers() - local main_speed, off_speed = UnitAttackSpeed(self.unit) + local main_speed, off_speed = UnitAttackSpeed(self:GetOMToken()) local main_speed = main_speed or 2 local off_speed = off_speed or 2 @@ -833,4 +856,9 @@ function Unit:GetTimeToShurikenTornado(n) end end -return Unit +-- Is the unit indoors +function Unit:IsIndoors() + return IsIndoors() +end + +return Unit \ No newline at end of file diff --git a/src/UnitManager/UnitManager.lua b/src/UnitManager/UnitManager.lua index 53a6b54..6031459 100644 --- a/src/UnitManager/UnitManager.lua +++ b/src/UnitManager/UnitManager.lua @@ -48,6 +48,7 @@ local function Validate(token) end -- Create a new UnitManager class +---@class UnitManager local UnitManager = { units = {}, customUnits = {}, @@ -87,11 +88,14 @@ function UnitManager:__index(k) -- end if self.objects[kguid] == nil then - local unit = Unit:New(Object(k)) - self:SetObject(unit) + local o = Object(k) + if o then + local unit = Unit:New(Object(k)) + self:SetObject(unit) + end end - return self.objects[kguid] + return self.objects['none'] end -- Constructor @@ -108,6 +112,7 @@ function UnitManager:Validate(token) end -- Get or create a unit +---@return Unit function UnitManager:Get(token) -- if not Validate(token) then -- error("UnitManager:Get - Invalid token: " .. token) @@ -115,19 +120,20 @@ function UnitManager:Get(token) local tguid = ObjectGUID(token) - if self.objects[tguid] == nil then + if tguid and self.objects[tguid] == nil then if token == 'none' then - self.objects[tguid] = Unit:New(token) + self.objects['none'] = Unit:New() else self.objects[tguid] = Unit:New(Object(tguid)) end end return Bastion.Refreshable:New(self.objects[tguid], function() - local tguid = ObjectGUID(token) + local tguid = ObjectGUID(token) or "none" + if self.objects[tguid] == nil then if token == 'none' then - self.objects[tguid] = Unit:New(token) + self.objects['none'] = Unit:New() else self.objects[tguid] = Unit:New(Object(tguid)) end @@ -145,6 +151,9 @@ function UnitManager:SetObject(unit) end -- Create a custom unit and cache it for .5 seconds +---@param token string +---@param cb fun():Unit +---@return Unit function UnitManager:CreateCustomUnit(token, cb) local unit = cb() local cachedUnit = Bastion.Cacheable:New(unit, cb) @@ -175,6 +184,7 @@ function UnitManager:EnumFriends(cb) end -- Enum Enemies (object manager) +---@param cb fun(unit: Unit):boolean function UnitManager:EnumEnemies(cb) Bastion.ObjectManager.activeEnemies:each(function(unit) if cb(unit) then diff --git a/src/_bastion.lua b/src/_bastion.lua index b9a5e71..ef4c6e9 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -42,7 +42,9 @@ Bastion.Enabled = false Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) local u = Bastion.UnitManager[unit] - u:GetAuras():OnUpdate(auras) + if u then + u:GetAuras():OnUpdate(auras) + end end) Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) @@ -59,6 +61,23 @@ Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) end end) +Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() + local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike = CombatLogGetCurrentEventInfo() + + local u = Bastion.UnitManager[sourceGUID] + local u2 = Bastion.UnitManager[destGUID] + + local t = GetTime() + + if u then + u:SetLastCombatTime(t) + end + + if u2 then + u2:SetLastCombatTime(t) + end +end) + Bastion.Ticker = C_Timer.NewTicker(0.1, function() if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then Bastion.CombatTimer:Start()