This site works best with JavaScript enabled. Please enable JavaScript to get the best experience from this site.
I have made a change to your released (4.3.2) version of LibRangeCheck to solve two issues:
1. Merge the 'misc' checks with both harmful and friendly checks. Otherwise you can/will end up with situations where harm/help will be missing ranges that DO exist under misc. eg. 8 yards, 28 yards.
2. Added GetXRanges() functions, so I can get a list of all the transition points (so I can put them in a dropdown menu).
3. Allow concurrent GetItemInfo requests (by default, unless CacheAll is enabled, one per range for harm and help). This will speed up the time to getting useful range spells (which makes a difference, otherwise it can take far too long to get an accurate list of range spells).
I am using this for range-based conditions in Rotation Master, thanks for writing it so I can pull out my bodge job of attempting to do the same. I don't know how to attach a file with this issue system, so here is the diff.
--- LibRangeCheck-2.0.lua.orig 2019-11-04 04:13:25.754001100 -0500 +++ LibRangeCheck-2.0.lua 2019-11-04 05:17:33.797220600 -0500 @@ -110,6 +110,7 @@ FriendSpells["HUNTER"] = {} HarmSpells["HUNTER"] = { 75, -- ["Auto Shot"], -- 40 + 1495, -- ["Mongoose Bite"], -- Melee } FriendSpells["MAGE"] = { @@ -383,6 +384,7 @@ local setmetatable = setmetatable local tonumber = tonumber local pairs = pairs +local ipairs = ipairs local tostring = tostring local print = print local next = next @@ -416,8 +418,7 @@ -- temporary stuff -local pendingItemRequest -local itemRequestTimeoutAt +local itemRequestTimeoutAt = {} local foundNewItems local cacheAllItems local friendItemRequests @@ -621,6 +622,27 @@ end end +local function ranges(array) + local vals = {} + for k,v in pairs(array) do + if v.range == 0 then + vals[MeleeRange] = 1 + else + vals[v.range] = 1 + end + if v.minRange then + vals[v.minRange] = 1 + end + end + local rv = {} + for k,v in pairs(vals) do + table.insert(rv, k) + end + -- Sort the keys + table.sort(rv, function (lhs, rhs) return lhs > rhs end) + return rv +end + local function getMinChecker(checkerList, range) local checker, checkerRange for i = 1, #checkerList do @@ -719,6 +741,42 @@ return minRange .. " - " .. maxRange end +local function mergeCheckers(target, source) + local i,j = 1, 1 + + while i <= #target and j <= #source do + if source[j].range == target[i].range then + if target[i].minRange == source[j].minRange then + -- Both range and minRanges match, skip + j = j + 1 + elseif target[i].minRange and (not source[j].minRange or + sourece[j].minRange > target[i].minRange) then + -- Same range, but lower minRange, insert / advance + table.insert(target, i, source[j]) + i = i + 1 + j = j + 1 + else + -- Same range, but higher minRange, advance i (target) to insert after this one + i = i + 1 + end + elseif source[j].range > target[i].range then + -- Lower range, insert here. + table.insert(target, i, source[j]) + i = i + 1 + j = j + 1 + else + -- Higher range, advance i (target) to insert after this one + i = i + 1 + end + + end + + while j <= #source do + table.insert(target, source[j]) + j = j + 1 + end +end + -- initialize RangeCheck if not yet initialized or if "forced" function lib:init(forced) if self.initialized and (not forced) then @@ -778,13 +836,15 @@ local interactList = InteractLists[playerRace] or DefaultInteractList self.handSlotItem = GetInventoryItemLink("player", HandSlotId) local changed = false - if updateCheckers(self.friendRC, createCheckerList(FriendSpells[playerClass], FriendItems, interactList)) then + if updateCheckers(self.miscRC, createCheckerList(nil, nil, interactList)) then changed = true end - if updateCheckers(self.harmRC, createCheckerList(HarmSpells[playerClass], HarmItems, interactList)) then + if updateCheckers(self.friendRC, createCheckerList(FriendSpells[playerClass], FriendItems, interactList)) then + mergeCheckers(self.friendRC, self.miscRC) changed = true end - if updateCheckers(self.miscRC, createCheckerList(nil, nil, interactList)) then + if updateCheckers(self.harmRC, createCheckerList(HarmSpells[playerClass], HarmItems, interactList)) then + mergeCheckers(self.harmRC, self.miscRC) changed = true end if changed and self.callbacks then @@ -807,6 +867,21 @@ return rcIterator(self.miscRC) end +--- Return an array of range boundaries available for friendly units. +function lib:GetFriendRanges() + return ranges(self.friendRC) +end + +--- Return an array of range boundaries available for enemy units. +function lib:GetHarmRanges() + return ranges(self.harmRC) +end + +--- Return an array of range boundaries available for miscellaneous units. These units are neither enemy nor friendly, such as people in sanctuaries or corpses. +function lib:GetMiscRanges() + return ranges(self.miscRC) +end + --- Return a checker suitable for out-of-range checking on friendly units, that is, a checker whose range is equal or larger than the requested range. -- @param range the range to check for. -- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for. @@ -970,8 +1045,7 @@ function lib:GET_ITEM_INFO_RECEIVED(event, item, success) -- print("### GET_ITEM_INFO_RECEIVED: " .. tostring(item) .. ", " .. tostring(success)) - if item == pendingItemRequest then - pendingItemRequest = nil + if itemRequestTimeoutAt[item] then if not success then self.failedItemRequests[item] = true end @@ -980,76 +1054,90 @@ end function lib:processItemRequests(itemRequests) - while true do - local range, items = next(itemRequests) + local waiting + for range, items in pairs(itemRequests) do if not range then return end - while true do - local i, item = next(items) - if not i then - itemRequests[range] = nil - break - elseif self.failedItemRequests[item] then - -- print("### processItemRequests: failed: " .. tostring(item)) - tremove(items, i) - elseif item == pendingItemRequest and GetTime() < itemRequestTimeoutAt then - return true; -- still waiting for server response - elseif GetItemInfo(item) then - -- print("### processItemRequests: found: " .. tostring(item)) - if itemRequestTimeoutAt then - -- print("### processItemRequests: new: " .. tostring(item)) - foundNewItems = true - itemRequestTimeoutAt = nil - pendingItemRequest = nil - end - if not cacheAllItems then - itemRequests[range] = nil + if not items then + itemRequests[range] = nil + else + local count = 0 + for i, item in ipairs(items) do + if count > 0 and not cacheAllItems then break end - tremove(items, i) - elseif not itemRequestTimeoutAt then - -- print("### processItemRequests: waiting: " .. tostring(item)) - itemRequestTimeoutAt = GetTime() + ItemRequestTimeout - pendingItemRequest = item - if not self.frame:IsEventRegistered("GET_ITEM_INFO_RECEIVED") then - self.frame:RegisterEvent("GET_ITEM_INFO_RECEIVED") + local localWaiting + if self.failedItemRequests[item] then + -- print("### processItemRequests: failed: " .. tostring(item)) + tremove(items, i) + elseif itemRequestTimeoutAt[item] and GetTime() < itemRequestTimeoutAt[item] then + localWaiting = true + elseif GetItemInfo(item) then + -- print("### processItemRequests: found: " .. tostring(item)) + if itemRequestTimeoutAt[item] then + -- print("### processItemRequests: new: " .. tostring(item)) + foundNewItems = true + itemRequestTimeoutAt[item] = nil + end + if not cacheAllItems then + itemRequests[range] = nil + break + end + tremove(items, i) + elseif not itemRequestTimeoutAt[item] then + -- print("### processItemRequests: waiting: " .. tostring(item)) + itemRequestTimeoutAt[item] = GetTime() + ItemRequestTimeout + localWaiting = true + if not self.frame:IsEventRegistered("GET_ITEM_INFO_RECEIVED") then + self.frame:RegisterEvent("GET_ITEM_INFO_RECEIVED") + end + elseif GetTime() >= itemRequestTimeoutAt[item] then + -- print("### processItemRequests: timeout: " .. tostring(item)) + if cacheAllItems then + print(MAJOR_VERSION .. ": timeout for item: " .. tostring(item)) + end + self.failedItemRequests[item] = true + itemRequestTimeoutAt[item] = nil + tremove(items, i) + else + localWaiting = true end - return true - elseif GetTime() >= itemRequestTimeoutAt then - -- print("### processItemRequests: timeout: " .. tostring(item)) - if cacheAllItems then - print(MAJOR_VERSION .. ": timeout for item: " .. tostring(item)) + if localWaiting then + waiting = true + count = count + 1 end - self.failedItemRequests[item] = true - itemRequestTimeoutAt = nil - pendingItemRequest = nil - tremove(items, i) - else - return true -- still waiting for server response + end + if count == 0 then + itemRequests[range] = nil end end end + return waiting end function lib:initialOnUpdate() self:init() if friendItemRequests then - if self:processItemRequests(friendItemRequests) then return end - friendItemRequests = nil + if not self:processItemRequests(friendItemRequests) then + friendItemRequests = nil + end end if harmItemRequests then - if self:processItemRequests(harmItemRequests) then return end - harmItemRequests = nil + if not self:processItemRequests(harmItemRequests) then + harmItemRequests = nil + end end if foundNewItems then self:init(true) foundNewItems = nil end - if cacheAllItems then - print(MAJOR_VERSION .. ": finished cache") - cacheAllItems = nil + if not friendItemRequests and not harmItemRequests then + if cacheAllItems then + print(MAJOR_VERSION .. ": finished cache") + cacheAllItems = nil + end + self.frame:Hide() + self.frame:UnregisterEvent("GET_ITEM_INFO_RECEIVED") end - self.frame:Hide() - self.frame:UnregisterEvent("GET_ITEM_INFO_RECEIVED") end function lib:scheduleInit()
Hello!
Thanks for the patch, I'll take a look at it if I'll have some spare time.
Regarding the misc ranges: they started out being mixed with the normal ranges, but their calculation is a bit different and can cause issues if mixed, that'd why they got separated. (something to do with hitbox size)
the concurrent item query is also an interesting question, as someone is already reporting event storm caused by item queries. I'll look into it...
The way I have it currently coded, only one spell of each distance will be 'outstanding' at once (well, one for friendly, one for harmful). Finding all ranges at once, but not all spells in all ranges at once. So if it can't find the first one of a given distance, it will still try and find the next one (so if you have 3 '30 yard' items it will still do them one at a time). It just allows concurrency across different distances.
Hey is there any update on implementing this? I'm pretty certain this problem is related to my issues implementing this into WeakAuras for Classic.
To post a comment, please login or register a new account.