diff --git a/components/cache.lua b/components/cache.lua index 05422c5..efdf743 100644 --- a/components/cache.lua +++ b/components/cache.lua @@ -150,65 +150,59 @@ function private.merchant_sell_scan() for slot in Aux.util.inventory() do local item_info = Aux.info.container_item(unpack(slot)) if item_info then - aux_merchant_sell[item_info.item_id] = item_info.tooltip.money / item_info.aux_quantity + aux_merchant_sell[item_info.item_id] = item_info.tooltip_money / item_info.aux_quantity end end end -function private.scan_wdb() +function private.scan_wdb(item_id) + item_id = item_id or MIN_ITEM_ID - local function helper(item_id) - local processed = 0 - while processed <= 100 and item_id <= MAX_ITEM_ID do - local itemstring = 'item:'..item_id - local name, _, quality, level, class, subclass, max_stack, slot, texture = GetItemInfo(itemstring) - if name and not aux_item_ids[strlower(name)] then - aux_item_ids[strlower(name)] = item_id - aux_items[item_id] = Aux.persistence.write(items_schema, { - name = name, - quality = quality, - level = level, - class = class, - subclass = subclass, - slot = slot, - max_stack = max_stack, - texture = texture, - }) - local tooltip = Aux.info.tooltip(function(tt) tt:SetHyperlink(itemstring) end) - if Aux.info.auctionable(tooltip, quality) then - tinsert(aux_auctionable_items, strlower(name)) - end - processed = processed + 1 + local processed = 0 + while processed <= 100 and item_id <= MAX_ITEM_ID do + local itemstring = 'item:'..item_id + local name, _, quality, level, class, subclass, max_stack, slot, texture = GetItemInfo(itemstring) + if name and not aux_item_ids[strlower(name)] then + aux_item_ids[strlower(name)] = item_id + aux_items[item_id] = Aux.persistence.write(items_schema, { + name = name, + quality = quality, + level = level, + class = class, + subclass = subclass, + slot = slot, + max_stack = max_stack, + texture = texture, + }) + local tooltip = Aux.info.tooltip(function(tt) tt:SetHyperlink(itemstring) end) + if Aux.info.auctionable(tooltip, quality) then + tinsert(aux_auctionable_items, strlower(name)) end - item_id = item_id + 1 - end - - if item_id <= MAX_ITEM_ID then - local t0 = GetTime() - Aux.control.as_soon_as(function() return GetTime() - t0 > 0.1 end, Aux.f(helper, item_id)) - else - sort(aux_auctionable_items, function(a, b) return strlen(a) < strlen(b) or (strlen(a) == strlen(b) and a < b) end) + processed = processed + 1 end + item_id = item_id + 1 end - helper(MIN_ITEM_ID) + if item_id <= MAX_ITEM_ID then + local t0 = GetTime() + Aux.control.as_soon_as(function() return GetTime() - t0 > 0.1 end, m.scan_wdb, item_id) + else + sort(aux_auctionable_items, function(a, b) return strlen(a) < strlen(b) or (strlen(a) == strlen(b) and a < b) end) + end end -function public.populate_wdb() +function public.populate_wdb(item_id) + item_id = item_id or MIN_ITEM_ID - local function helper(item_id) - if item_id > MAX_ITEM_ID then - Aux.log('Cache populated.') - return - end - - if not GetItemInfo('item:'..item_id) then - Aux.log('Fetching item '..item_id..'.') - AuxTooltip:SetHyperlink('item:'..item_id) - end - - Aux.control.on_next_update(Aux.f(helper, item_id + 1)) + if item_id > MAX_ITEM_ID then + Aux.log('Cache populated.') + return end - helper(MIN_ITEM_ID) + if not GetItemInfo('item:'..item_id) then + Aux.log('Fetching item '..item_id..'.') + AuxTooltip:SetHyperlink('item:'..item_id) + end + + Aux.control.thread(m.populate_wdb, item_id + 1) end \ No newline at end of file diff --git a/components/disenchant.lua b/components/disenchant.lua index ba47097..dcca492 100644 --- a/components/disenchant.lua +++ b/components/disenchant.lua @@ -1,69 +1,74 @@ local m, public, private = Aux.module'disenchant' -function public.source(item_id) +private.UNCOMMON = 2 +private.RARE = 3 +private.EPIC = 4 - local info = { - [10940] = {'DUST', '1-20'}, - [11083] = {'DUST', '21-30'}, - [11137] = {'DUST', '31-40'}, - [11176] = {'DUST', '41-50'}, - [16204] = {'DUST', '51-60'}, +do + local data = { + [10940] = {'DUST', '1-20'}, + [11083] = {'DUST', '21-30'}, + [11137] = {'DUST', '31-40'}, + [11176] = {'DUST', '41-50'}, + [16204] = {'DUST', '51-60'}, - [10938] = {'ESSENCE', '1-10'}, - [10939] = {'ESSENCE', '11-15'}, - [10998] = {'ESSENCE', '16-20'}, - [11082] = {'ESSENCE', '21-25'}, - [11134] = {'ESSENCE', '26-30'}, - [11135] = {'ESSENCE', '31-35'}, - [11174] = {'ESSENCE', '36-40'}, - [11175] = {'ESSENCE', '41-45'}, - [16202] = {'ESSENCE', '46-50'}, - [16203] = {'ESSENCE', '51-60'}, + [10938] = {'ESSENCE', '1-10'}, + [10939] = {'ESSENCE', '11-15'}, + [10998] = {'ESSENCE', '16-20'}, + [11082] = {'ESSENCE', '21-25'}, + [11134] = {'ESSENCE', '26-30'}, + [11135] = {'ESSENCE', '31-35'}, + [11174] = {'ESSENCE', '36-40'}, + [11175] = {'ESSENCE', '41-45'}, + [16202] = {'ESSENCE', '46-50'}, + [16203] = {'ESSENCE', '51-60'}, - [10978] = {'SHARD', '1-20'}, - [11084] = {'SHARD', '21-25'}, - [11138] = {'SHARD', '26-30'}, - [11139] = {'SHARD', '31-35'}, - [11177] = {'SHARD', '36-40'}, - [11178] = {'SHARD', '41-45'}, - [14343] = {'SHARD', '46-50'}, - [14344] = {'SHARD', '51-60'}, + [10978] = {'SHARD', '1-20'}, + [11084] = {'SHARD', '21-25'}, + [11138] = {'SHARD', '26-30'}, + [11139] = {'SHARD', '31-35'}, + [11177] = {'SHARD', '36-40'}, + [11178] = {'SHARD', '41-45'}, + [14343] = {'SHARD', '46-50'}, + [14344] = {'SHARD', '51-60'}, - [20725] = {'CRYSTAL', '51+'}, - } + [20725] = {'CRYSTAL', '51+'}, + } - return unpack(info[item_id] or {}) + function public.source(item_id) + return data[item_id] and unpack(data[item_id]) + end end -local armor = { - INVTYPE_HEAD = true, - INVTYPE_NECK = true, - INVTYPE_SHOULDER = true, - INVTYPE_BODY = true, - INVTYPE_CHEST = true, - INVTYPE_ROBE = true, - INVTYPE_WAIST = true, - INVTYPE_LEGS = true, - INVTYPE_FEET = true, - INVTYPE_WRIST = true, - INVTYPE_HAND = true, - INVTYPE_FINGER = true, - INVTYPE_TRINKET = true, - INVTYPE_CLOAK = true, - INVTYPE_HOLDABLE = true, -} +function public.LOAD() + private.armor = Aux.util.set( + 'INVTYPE_HEAD', + 'INVTYPE_NECK', + 'INVTYPE_SHOULDER', + 'INVTYPE_BODY', + 'INVTYPE_CHEST', + 'INVTYPE_ROBE', + 'INVTYPE_WAIST', + 'INVTYPE_LEGS', + 'INVTYPE_FEET', + 'INVTYPE_WRIST', + 'INVTYPE_HAND', + 'INVTYPE_FINGER', + 'INVTYPE_TRINKET', + 'INVTYPE_CLOAK', + 'INVTYPE_HOLDABLE' + ) -local weapon = { - INVTYPE_2HWEAPON = true, - INVTYPE_WEAPONMAINHAND = true, - INVTYPE_WEAPON = true, - INVTYPE_WEAPONOFFHAND = true, - INVTYPE_SHIELD = true, - INVTYPE_RANGED = true, - INVTYPE_RANGEDRIGHT = true, -} - -local UNCOMMON, RARE, EPIC = 2, 3, 4 + private.weapon = Aux.util.set( + 'INVTYPE_2HWEAPON' , + 'INVTYPE_WEAPONMAINHAND', + 'INVTYPE_WEAPON', + 'INVTYPE_WEAPONOFFHAND', + 'INVTYPE_SHIELD', + 'INVTYPE_RANGED', + 'INVTYPE_RANGEDRIGHT' + ) +end function public.value(slot, quality, level) local expectation @@ -79,19 +84,19 @@ function public.value(slot, quality, level) end function public.distribution(slot, quality, level) - if not (armor[slot] or weapon[slot]) or level == 0 then + if not (m.armor[slot] or m.weapon[slot]) or level == 0 then return {} end local function p(probability_armor, probability_weapon) - if armor[slot] then + if m.armor[slot] then return probability_armor - elseif weapon[slot] then + elseif m.weapon[slot] then return probability_weapon end end - if quality == UNCOMMON then + if quality == m.UNCOMMON then if level <= 10 then return { {item_id=10940, min_quantity=1, max_quantity=2, probability=p(0.8, 0.2)}, @@ -158,7 +163,7 @@ function public.distribution(slot, quality, level) {item_id=14344, min_quantity=1, max_quantity=1, probability=p(0.05, 0.03)}, } end - elseif quality == RARE then + elseif quality == m.RARE then if level <= 20 then return {{item_id=10978, min_quantity=1, max_quantity=1, probability=1}} elseif level <= 25 then @@ -178,7 +183,7 @@ function public.distribution(slot, quality, level) elseif level <= 60 then return {{item_id=14344, min_quantity=1, max_quantity=1, probability=0.995}, {item_id=20725, min_quantity=1, max_quantity=1, probability=0.005}} end - elseif quality == EPIC then + elseif quality == m.EPIC then if level <= 40 then return {{item_id=11177, min_quantity=2, max_quantity=4, probability=1}} elseif level <= 45 then diff --git a/components/post.lua b/components/post.lua index fa078f8..395151f 100644 --- a/components/post.lua +++ b/components/post.lua @@ -43,7 +43,7 @@ function private.post_auction(slot, k) Aux.control.event_listener('CHAT_MSG_SYSTEM', function() if arg1 == ERR_AUCTION_STARTED then c() - return Aux.control.kill + Aux.control.kill() end end) else @@ -69,7 +69,7 @@ end function public.start(item_key, stack_size, duration, unit_start_price, unit_buyout_price, count, callback) m.stop() - local thread_id = Aux.control.new_thread(m.process) + local thread_id = Aux.control.thread(m.process) m.state = { thread_id = thread_id, diff --git a/components/scan.lua b/components/scan.lua index 04e1dd0..fa99a61 100644 --- a/components/scan.lua +++ b/components/scan.lua @@ -5,28 +5,52 @@ local PAGE_SIZE = 50 private.threads = {} private.last_query_time = {} -private.th = Aux.dynamic_table(function() +private.state = Aux.dynamic_table(function() return Aux.util.filter(m.threads, function(thread) return thread.id == Aux.control.thread_id end)[1] end) private.q = Aux.dynamic_table(function() - return m.th.params.queries[m.th.query_index] + return m.state.params.queries[m.state.query_index] end) +function private.wait_for_callback(...) + local ok = true + local ret + + local f = tremove(arg, 1) + local k = tremove(arg) + + if f then + tinsert(arg, { + suspend = function() ok = false end, + resume = function(...) ok = true ret = arg end, + }) + f(unpack(arg)) + end + + if ok then + return k() + else + return Aux.control.when(function() return ok end, function() return k(unpack(ret)) end) + end +end + function private.total_pages(total_auctions) return math.ceil(total_auctions / PAGE_SIZE) end function private.last_page(total_auctions) local last_page = max(m.total_pages(total_auctions) - 1, 0) - local last_page_limit = Aux.index(m.q.blizzard_query).last_page/last_page + local last_page_limit = m.q.blizzard_query and m.q.blizzard_query.last_page or last_page return min(last_page_limit, last_page) end function public.start(params) - m.abort(Aux.index(m.threads[params.type]).id/0) + if m.threads[params.type] then + m.abort(m.threads[params.type].id) + end - local thread_id = Aux.control.new_thread(Aux.f(m.wait_for_callback, params.on_scan_start, m.scan)) + local thread_id = Aux.control.thread(Aux.f(m.wait_for_callback, params.on_scan_start, m.scan)) m.threads[params.type] = { id = thread_id, @@ -45,42 +69,146 @@ function public.abort(scan_id) end end - for _, thread in ipairs(aborted_threads) do - Aux.call(thread.params.on_abort) + for _, thread in aborted_threads do + Aux.safe_call(thread.params.on_abort) end end +function private.complete() + local on_complete = m.state.params.on_complete + m.threads[m.state.params.type] = nil + if on_complete then + return on_complete() + end +end + +function private.scan() + Aux.log(Aux.control.thread_id) + m.state.query_index = m.state.query_index and m.state.query_index + 1 or 1 + if m.q() then + if m.q.blizzard_query then + m.state.page = m.q.blizzard_query.first_page or 0 + else + m.state.page = nil + end + return m.wait_for_callback(m.state.params.on_start_query, m.state.query_index, m.process_query) + else + m.complete() + end +end + +function private.process_query() + if m.q.blizzard_query then + return m.submit_query() + else + return m.scan_page() + end +end + +function private.submit_query() + Aux.control.when(function() return m.state.params.type ~= 'list' or CanSendAuctionQuery() end, function() + Aux.safe_call(m.state.params.on_submit_query) + m.last_query_time[m.state.params.type] = GetTime() + if m.state.params.type == 'bidder' then + GetBidderAuctionItems(m.state.page) + elseif m.state.params.type == 'owner' then + GetOwnerAuctionItems(m.state.page) + else + local blizzard_query = m.q.blizzard_query or {} + QueryAuctionItems( + blizzard_query.name, + blizzard_query.min_level, + blizzard_query.max_level, + blizzard_query.slot, + blizzard_query.class, + blizzard_query.subclass, + m.state.page, + blizzard_query.usable, + blizzard_query.quality + ) + end + return m.wait_for_results() + end) +end + +function private.scan_page(i) + i = i or 1 + local recurse = function(retry) + if i >= PAGE_SIZE then + m.wait_for_callback(m.state.params.on_page_scanned, function() + if m.q.blizzard_query and m.state.page < m.last_page(m.state.total_auctions) then + m.state.page = m.state.page + 1 + return m.process_query() + else + return m.scan() + end + end) + else + return m.scan_page(retry and i or i + 1) + end + end + + local auction_info = Aux.info.auction(i, m.state.params.type) + if auction_info and (auction_info.owner or m.state.params.ignore_owner or aux_ignore_owner) then + auction_info.index = i + auction_info.page = m.state.page + auction_info.blizzard_query = m.q.blizzard_query + auction_info.query_type = m.state.params.type + + Aux.history.process_auction(auction_info) + + if Aux.safe_call(m.state.params.auto_buy_validator, auction_info) then + local c = Aux.control.await(recurse) + Aux.place_bid(auction_info.query_type, auction_info.index, auction_info.buyout_price, Aux.f(c, true)) + return Aux.control.thread(Aux.control.sleep, 10, Aux.f(c, false)) + elseif not m.q.validator or m.q.validator(auction_info) then + return m.wait_for_callback(m.state.params.on_auction, auction_info, function(removed) + if removed then + return recurse(true) + else + return recurse() + end + end) + end + end + + return recurse() +end + function private.timeout(type) return GetTime() - m.last_query_time[type] > 11 end function private.wait_for_results() local c = Aux.control.await(function() - if m.timeout(m.th.params.type) then + if m.timeout(m.state.params.type) then return m.submit_query() else - _, m.th.total_auctions = GetNumAuctionItems(m.th.params.type) + _, m.state.total_auctions = GetNumAuctionItems(m.state.params.type) return m.wait_for_callback( - m.th.params.on_page_loaded, - m.th.page - (m.q.blizzard_query.first_page or 0) + 1, - m.last_page(m.th.total_auctions) - (m.q.blizzard_query.first_page or 0) + 1, - m.total_pages(m.th.total_auctions) - 1, + m.state.params.on_page_loaded, + m.state.page - (m.q.blizzard_query.first_page or 0) + 1, + m.last_page(m.state.total_auctions) - (m.q.blizzard_query.first_page or 0) + 1, + m.total_pages(m.state.total_auctions) - 1, m.scan_page ) end end) - Aux.control.as_soon_as(Aux.f(m.timeout, m.th.params.type), c) - if m.th.params.type == 'bidder' then + + local type = m.state.params.type + Aux.control.as_soon_as(function() return -c or m.timeout(type) end, c) + + if m.state.params.type == 'bidder' then return Aux.control.as_soon_as(function() return Aux.bids_loaded end, c) - elseif m.th.params.type == 'owner' then + elseif m.state.params.type == 'owner' then return m.wait_for_owner_results(c) - elseif m.th.params.type == 'list' then + elseif m.state.params.type == 'list' then return m.wait_for_list_results(c) end end function private.wait_for_owner_results(c) - if m.th.page == Aux.current_owner_page then + if m.state.page == Aux.current_owner_page then return c() else return Aux.control.on_next_event('AUCTION_OWNED_LIST_UPDATE', c) @@ -90,17 +218,14 @@ end function private.wait_for_list_results(c) local updated, last_update Aux.control.event_listener('AUCTION_ITEM_LIST_UPDATE', function() - if -c then - return Aux.control.kill - end + Aux.control.kill(-c) last_update = GetTime() updated = true end) - local type = m.th.params.type - local ignore_owner = m.th.params.ignore_owner or aux_ignore_owner + local ignore_owner = m.state.params.ignore_owner or aux_ignore_owner return Aux.control.as_soon_as(function() -- short circuiting order important, owner_data_complete must be called iif an update has happened. - local ok = updated and (ignore_owner or m.owner_data_complete(type)) or last_update and GetTime() - last_update > 5 + local ok = updated and (ignore_owner or m.owner_data_complete('list')) or last_update and GetTime() - last_update > 5 updated = false return ok end, c) @@ -115,124 +240,3 @@ function private.owner_data_complete(type) end return true end - -function private.wait_for_callback(...) - local ok = true - local ret - - local f = tremove(arg, 1) - local k = tremove(arg) - - if f then - tinsert(arg, { - suspend = function() ok = false end, - resume = function(...) ok = true ret = arg end, - }) - f(unpack(arg)) - end - - if ok then - return k() - else - return Aux.control.when(function() return ok end, function() return k(unpack(ret)) end) - end -end - -function private.scan() - m.th.query_index = m.th.query_index and m.th.query_index + 1 or 1 - if m.q() then - if m.q.blizzard_query then - m.th.page = m.q.blizzard_query.first_page or 0 - else - m.th.page = nil - end - return m.wait_for_callback(m.th.params.on_start_query, m.th.query_index, m.process_query) - else - local on_complete = m.th.params.on_complete - m.threads[m.th.params.type] = nil - if on_complete then - return on_complete() - end - end -end - -function private.process_query() - if m.q.blizzard_query then - return m.submit_query() - else - return m.scan_page() - end -end - -function private.scan_page() - return m.scan_page_helper(1) -end - -function private.scan_page_helper(i) - local recurse = function(retry) - if i >= PAGE_SIZE then - m.wait_for_callback(m.th.params.on_page_scanned, function() - if m.q.blizzard_query and m.th.page < m.last_page(m.th.total_auctions) then - m.th.page = m.th.page + 1 - return m.process_query() - else - return m.scan() - end - end) - else - return m.scan_page_helper(retry and i or i + 1) - end - end - - local auction_info = Aux.info.auction(i, m.th.params.type) - if auction_info and (auction_info.owner or m.th.params.ignore_owner or aux_ignore_owner) then - auction_info.index = i - auction_info.page = m.th.page - auction_info.blizzard_query = m.q.blizzard_query - auction_info.query_type = m.th.params.type - - Aux.history.process_auction(auction_info) - - if Aux.call(m.th.params.auto_buy_validator, auction_info)/false then - local c = Aux.control.await(recurse) - Aux.place_bid(auction_info.query_type, auction_info.index, auction_info.buyout_price, Aux.f(c, true)) - return Aux.control.new_thread(Aux.control.sleep, 10, Aux.f(c, false)) - elseif Aux.call(m.q.validator, auction_info)/true then - return m.wait_for_callback(m.th.params.on_auction, auction_info, function(removed) - if removed then - return recurse(true) - else - return recurse() - end - end) - end - end - - return recurse() -end - -function private.submit_query() - Aux.control.when(function() return m.th.params.type ~= 'list' or CanSendAuctionQuery() end, function() - Aux.call(m.th.params.on_submit_query) - m.last_query_time[m.th.params.type] = GetTime() - if m.th.params.type == 'bidder' then - GetBidderAuctionItems(m.th.page) - elseif m.th.params.type == 'owner' then - GetOwnerAuctionItems(m.th.page) - else - local blizzard_query = Aux.option(m.q.blizzard_query)/{} - QueryAuctionItems( - blizzard_query.name, - blizzard_query.min_level, - blizzard_query.max_level, - blizzard_query.slot, - blizzard_query.class, - blizzard_query.subclass, - m.th.page, - blizzard_query.usable, - blizzard_query.quality - ) - end - return m.wait_for_results() - end) -end diff --git a/components/slash.lua b/components/slash.lua index eb416e7..c2cf634 100644 --- a/components/slash.lua +++ b/components/slash.lua @@ -73,13 +73,13 @@ function SlashCmdList.AUX(command) elseif arguments[1] == 'chars' then local realm = GetCVar('realmName') local chars = {} - for name, _ in pairs(aux_characters[realm] or {}) do + for name, _ in aux_characters[realm] or {} do tinsert(chars, name) end if getn(chars) > 0 then Aux.log('Your characters: "'..Aux.util.join(chars, ', ')..'".') else - Aux.log('You don\'t have any additional characters. Type "/aux addchar NAME" to add one.') + Aux.log('You don\'t have any additional characters. To add your characters type "/aux chars add NAME1 NAME2 NAME3...".') end else Aux.log('Unknown command: "'..command..'"') diff --git a/components/stack.lua b/components/stack.lua index 9412919..4d78bbc 100644 --- a/components/stack.lua +++ b/components/stack.lua @@ -126,7 +126,7 @@ end function public.start(item_key, size, callback) m.stop() - local thread_id = Aux.control.new_thread(m.process) + local thread_id = Aux.control.thread(m.process) m.state = { thread_id = thread_id, diff --git a/components/tooltip.lua b/components/tooltip.lua index 6c60be8..7a0171a 100644 --- a/components/tooltip.lua +++ b/components/tooltip.lua @@ -48,7 +48,7 @@ function private.extend_tooltip(tooltip, hyperlink, quantity) quantity = IsShiftKeyDown() and quantity or 1 if aux_tooltip_disenchant_source then - local color = {r=0.7, g=0.7, b=0.7 } + local color = {r=0.7, g=0.7, b=0.7} local type, range = Aux.disenchant.source(item_id) @@ -105,7 +105,7 @@ function private.extend_tooltip(tooltip, hyperlink, quantity) end end - local color = {r=1, g=1, b=0.6 } + local color = {r=1, g=1, b=0.6} local auctionable = not item_info or Aux.info.auctionable(Aux.info.tooltip(function(tt) tt:SetHyperlink(item_info.itemstring) end), item_info.quality) local item_key = (item_id or 0)..':'..(suffix_id or 0) diff --git a/control.lua b/control.lua index 9d5575b..f4852f3 100644 --- a/control.lua +++ b/control.lua @@ -4,36 +4,42 @@ private.event_frame = CreateFrame('Frame') private.event_listeners = {} private.threads = {} public.thread_id = nil -public.kill = {} function public.LOAD() m.event_frame:SetScript('OnUpdate', m.on_update) m.event_frame:SetScript('OnEvent', m.on_event) end -function private.on_event() - for _, listener in m.event_listeners do - if event == listener.event and not listener.deleted then - listener.deleted = (listener.action() == m.kill) +do + local active_listener + + function public.kill(...) + Aux.log(arg.n) --TODO + active_listener.killed = arg.n == 0 or arg[1] + end + + function private.on_event() + for thread_id, listener in m.event_listeners do + if event == listener.event and not listener.killed then + m.thread_id = thread_id + active_listener = listener + listener.cb() + active_listener = nil + m.thread_id = nil + end end end end function private.on_update() for _, listener in m.event_listeners do - if not Aux.util.any(m.event_listeners, function(l) return not l.deleted and l.event == listener.event end) then + if not Aux.util.any(m.event_listeners, function(l) return not l.killed and l.event == listener.event end) then m.event_frame:UnregisterEvent(listener.event) end end - m.event_listeners = Aux.util.filter(m.event_listeners, function(l) return not l.deleted end) - local threads = {} - for thread_id, thread in m.threads do - if not thread.killed then - threads[thread_id] = thread - end - end - m.threads = threads + m.event_listeners = Aux.util.filter(m.event_listeners, function(l) return not l.killed end) + m.threads = Aux.util.filter(m.threads, function(th) return not th.killed end) for thread_id, thread in m.threads do if not thread.killed then @@ -49,33 +55,32 @@ function private.on_update() end end -function public.event_listener(event, action) - tinsert(m.event_listeners, { event=event, action=action }) +function public.event_listener(event, cb) + local thread_id = Aux.unique() + m.event_listeners[thread_id] = { event=event, cb=cb } m.event_frame:RegisterEvent(event) + return thread_id end function public.on_next_event(event, callback) m.event_listener(event, function() callback() - return m.kill + m.kill() end) end -function public.on_next_update(callback) - return m.new_thread(callback) +function public.as_soon_as(p, ...) + return m.thread(m.when, p, unpack(arg)) end -function public.as_soon_as(p, callback) - return m.new_thread(m.when, p, callback) -end - -function public.new_thread(k, ...) +function public.thread(k, ...) local thread_id = Aux.unique() m.threads[thread_id] = { k = Aux.f(k, unpack(arg)) } return thread_id end function public.kill_thread(thread_id) + Aux.log('kek') if m.threads[thread_id] then m.threads[thread_id].killed = true end @@ -85,7 +90,7 @@ function public.await(k) local ret m.when(function() return ret end, function() return k(unpack(ret)) end) return setmetatable({}, { - __call = function(self, ...) + __call = function(_, ...) ret = arg end, __unm = function() @@ -94,14 +99,14 @@ function public.await(k) }) end -function public.sleep(dt, ...) +function public.sleep(seconds, ...) local t0 = GetTime() - return m.when(function() return GetTime() - t0 >= dt end, unpack(arg)) + return m.when(function() return GetTime() - t0 >= seconds end, unpack(arg)) end function public.wait(k, ...) if type(k) == 'number' then - m.when(function() k = k - 1 return k <= 0 end, unpack(arg)) + m.when(function() k = k - 1 return k <= 1 end, unpack(arg)) else m.threads[m.thread_id].k = Aux.f(k, unpack(arg)) end diff --git a/core.lua b/core.lua index 588a350..f868a1a 100644 --- a/core.lua +++ b/core.lua @@ -38,31 +38,28 @@ do end end -function public.get(table, key) - return table[key] -end +--unpack(arg) TODO -function public.set(table, key, value) - table[key] = value -end +--m.enum TODO +--.INVTYPE_HEAD +--.INVTYPE_NECK +--.INVTYPE_SHOULDER +--() -function public.f(f, ...) - local params = arg - return function(...) - for i=1,arg.n do - tinsert(params, arg[i]) - end - return f(unpack(params)) - end +do + local x = 0 + function public.unique() + x = x + 1 + return x + end end do - local dynamic_table_mt = { + local mt = { __newindex = function(self, key, value) rawget(self, '_f')()[key] = value end, __index = function(self, key) - if rawget(self, '_f')() == nil then error('', 2) end return rawget(self, '_f')()[key] end, __call = function(self) @@ -70,68 +67,33 @@ do end, } function public.dynamic_table(f) - return setmetatable({ _f=f }, dynamic_table_mt) + return setmetatable({ _f=f }, mt) end end -function public.call(f, ...) - return m.option(f)..function() - return m.option(f(unpack(arg))) +function public.f(f, ...) + local params = arg + return function(...) + for i=1,arg.n do + tinsert(params, arg[i]) + end + return f(unpack(params)) + end +end + +function public.safe_call(f, ...) + if f then + return f(unpack(arg)) end end -do - local index_mt = { - __index = function(self, key) - return m.option(rawget(self, '_value'))..function() - return m.option(rawget(self, '_value')[key]) - end - end, - } - function public.index(value) - return setmetatable({ _value=value }, index_mt) - end -end - -do - local option_mt = { - __call = function(self, f) - if rawget(self, '_value') ~= nil then - return m.option(f(rawget(self, '_value'))) - else - return self - end - end, - __div = function(self, alt) - if rawget(self, '_value') ~= nil then - return rawget(self, '_value') - else - return alt - end - end, - __unm = function(self, alt) - return rawget(self, '_value') ~= nil - end, - __concat = function(self, f) - if rawget(self, '_value') ~= nil then - return f(rawget(self, '_value')) - else - return self - end - end, - } - function public.option(value) - return setmetatable({ _value=value }, option_mt) - end -end - -do - local x = 0 - - function public.unique() - x = x + 1 - return x - end +function public.safe_index(t, ...) + for i=1,arg.n do + if t then + t = t[arg[i]] + end + end + return t end function public.on_load() @@ -146,11 +108,6 @@ function public.on_load() Aux.gui.set_window_style(AuxFrame) tinsert(UISpecialFrames, 'AuxFrame') - CreateFrame('GameTooltip', 'AuxTooltip', nil, 'GameTooltipTemplate') - AuxTooltip:SetScript('OnTooltipAddMoney', function() - this.money = arg1 - end) - Aux.control.event_listener('CURSOR_UPDATE', m.CURSOR_UPDATE) do @@ -199,7 +156,7 @@ function public.on_event() if event == 'VARIABLES_LOADED' then m.on_load() elseif event == 'ADDON_LOADED' then - m.call(m.on_addon_load[arg1]) + m.safe_call(m.on_addon_load[arg1]) elseif event == 'AUCTION_HOUSE_SHOW' then m.on_auction_house_show() elseif event == 'AUCTION_HOUSE_CLOSED' then @@ -325,9 +282,9 @@ do m.control.event_listener('CHAT_MSG_SYSTEM', function() if arg1 == ERR_AUCTION_BID_PLACED then - Aux.call(on_success) + Aux.safe_call(on_success) locked = false - return Aux.control.kill + Aux.control.kill() end end) end @@ -352,9 +309,9 @@ do CancelAuction(index) m.control.event_listener('CHAT_MSG_SYSTEM', function() if arg1 == ERR_AUCTION_REMOVED then - Aux.call(on_success) + Aux.safe_call(on_success) locked = false - return Aux.control.kill + Aux.control.kill() end end) end @@ -425,8 +382,8 @@ do -- TODO make it work for other ways to pick up things end function private.PickupContainerItem(...) local bag, slot = unpack(arg) - Aux.control.on_next_update(function() - last_picked_up = { bag, slot } + Aux.control.thread(function() + last_picked_up = {bag, slot} end) return m.orig.PickupContainerItem(unpack(arg)) end @@ -479,7 +436,7 @@ end function public.is_player(name, current) local realm = GetCVar('realmName') - return (not current and m.index(aux_characters[realm])[name]/false) or UnitName('player') == name + return not current and Aux.safe_index(aux_characters, realm, name) or UnitName('player') == name end function public.unmodified() diff --git a/tables/auction_listing.lua b/tables/auction_listing.lua index 79a51d3..cca161f 100644 --- a/tables/auction_listing.lua +++ b/tables/auction_listing.lua @@ -1010,7 +1010,7 @@ function public.CreateAuctionResultsTable(parent, config) rt.records = {} rt.rowInfo = { numDisplayRows=0 } - for name, func in pairs(methods) do + for name, func in methods do rt[name] = func end diff --git a/tables/listing.lua b/tables/listing.lua index 2e64506..7190279 100644 --- a/tables/listing.lua +++ b/tables/listing.lua @@ -10,7 +10,7 @@ local DEFAULT_COL_INFO = {{width=1}} local function GetTableIndex(tbl, value) - for i, v in pairs(tbl) do + for i, v in tbl do if value == v then return i end @@ -344,7 +344,7 @@ local methods = { col:SetFontString(text) col:SetHeight(ST_ROW_HEIGHT) col:RegisterForClicks('LeftButtonUp', 'RightButtonUp') - for name, func in pairs(defaultColScripts) do + for name, func in defaultColScripts do col:SetScript(name, func) end col.st = st @@ -443,7 +443,7 @@ function public.CreateScrollingTable(parent) st.headLine = Aux.gui.horizontal_line(st, 0) -- add all the methods - for name, func in pairs(methods) do + for name, func in methods do st[name] = func end diff --git a/tabs/post/core.lua b/tabs/post/core.lua index 3481357..df9f8a5 100644 --- a/tabs/post/core.lua +++ b/tabs/post/core.lua @@ -462,7 +462,7 @@ function private.update_inventory_records() end m.inventory_records = {} - for _, auction_candidate in pairs(auction_candidate_map) do + for _, auction_candidate in auction_candidate_map do tinsert(m.inventory_records, auction_candidate) end sort(m.inventory_records, function(a, b) return a.name < b.name end) diff --git a/tabs/search/core.lua b/tabs/search/core.lua index c75bfb8..1004aa8 100644 --- a/tabs/search/core.lua +++ b/tabs/search/core.lua @@ -234,7 +234,7 @@ function private.start_real_time_scan(query, search, continuation) if search.auto_buy then ctrl.suspend() Aux.place_bid('list', auction_record.index, auction_record.buyout_price, Aux.f(ctrl.resume, true)) - Aux.control.new_thread(Aux.control.sleep, 10, Aux.f(ctrl.resume, false)) + Aux.control.thread(Aux.control.sleep, 10, Aux.f(ctrl.resume, false)) else tinsert(new_records, auction_record) end @@ -330,7 +330,7 @@ function private.start_search(queries, continuation) if search.auto_buy then ctrl.suspend() Aux.place_bid('list', auction_record.index, auction_record.buyout_price, Aux.f(ctrl.resume, true)) - Aux.control.new_thread(Aux.control.sleep, 10, Aux.f(ctrl.resume, false)) + Aux.control.thread(Aux.control.sleep, 10, Aux.f(ctrl.resume, false)) elseif getn(search.records) < 1000 then tinsert(search.records, auction_record) if getn(search.records) == 1000 then @@ -475,7 +475,7 @@ do search.table:RemoveAuctionRecord(record) end, function(index) - if Aux.index(search.table:GetSelection()).record/nil ~= record then + if search.table:GetSelection() and search.table:GetSelection().record ~= record then return end @@ -643,7 +643,7 @@ function private.initialize_class_dropdown() func = on_click, } - for i, class in pairs({ GetAuctionItemClasses() }) do + for i, class in { GetAuctionItemClasses() } do UIDropDownMenu_AddButton{ text = class, value = i, @@ -670,7 +670,7 @@ function private.initialize_subclass_dropdown() func = on_click, } - for i, subclass in pairs({ GetAuctionItemSubClasses(class_index) }) do + for i, subclass in { GetAuctionItemSubClasses(class_index) } do UIDropDownMenu_AddButton{ text = subclass, value = i, @@ -696,7 +696,7 @@ function private.initialize_slot_dropdown() func = on_click, } - for i, slot in pairs({ GetAuctionInvTypes(class_index, subclass_index) }) do + for i, slot in { GetAuctionInvTypes(class_index, subclass_index) } do local slot_name = getglobal(slot) UIDropDownMenu_AddButton{ text = slot_name, @@ -731,11 +731,11 @@ function private.initialize_filter_dropdown() local function on_click() UIDropDownMenu_SetSelectedValue(m.filter_dropdown, this.value) m.filter_button:SetText(this.value) - if Aux.index(Aux.filter.filters[this.value]).input_type/'' == '' and this.value ~= 'and' and this.value ~= 'or' then + if (not Aux.filter.filters[this.value] or Aux.filter.filters[this.value].input_type == '') and this.value ~= 'and' and this.value ~= 'or' then m.filter_input:Hide() else local _, _, suggestions = Aux.filter.parse_query_string(UIDropDownMenu_GetSelectedValue(m.filter_dropdown)..'/') - m.filter_input:SetNumeric(Aux.index(Aux.filter.filters[this.value]).input_type/'number' == 'number') + m.filter_input:SetNumeric(not Aux.filter.filters[this.value] or Aux.filter.filters[this.value].input_type == 'number') m.filter_input.complete = Aux.completion.complete(function() return suggestions or {} end) m.filter_input:Show() m.filter_input:SetFocus() diff --git a/util/core.lua b/util/core.lua index d8109fb..053dc7f 100644 --- a/util/core.lua +++ b/util/core.lua @@ -3,22 +3,6 @@ local m, public, private = Aux.module'util' function public.pass() end -function public.sum(...) - local x = 0 - for i=1,arg.n do - x = x + arg[i] - end - return x -end - -function public.product(...) - local x = 0 - for i=1,arg.n do - x = x * arg[i] - end - return x -end - function public.id(x) return x end @@ -104,7 +88,7 @@ function public.inventory() end if bag <= 4 then - return { bag, slot }, m.bag_type(bag) + return {bag, slot}, m.bag_type(bag) end end end @@ -136,18 +120,9 @@ function public.without_sound(f) SetCVar('MasterSoundEffects', orig) end -function public.iter(array) - local i = 0 - return function() - local ret = {iter(array, i)} - i = ret[1] - return ret[2] - end -end - function public.any(xs, p) local holds = false - for _, x in ipairs(xs) do + for _, x in xs do holds = holds or p(x) end return holds @@ -155,7 +130,7 @@ end function public.all(xs, p) local holds = true - for _, x in ipairs(xs) do + for _, x in xs do holds = holds and p(x) end return holds @@ -173,9 +148,9 @@ end function public.filter(xs, p) local ys = {} - for _, x in xs do + for k, x in xs do if p(x) then - tinsert(ys, x) + ys[k] = x end end return ys @@ -183,18 +158,16 @@ end function public.map(xs, f) local ys = {} - for _, x in xs do - tinsert(ys, f(x)) + for k, x in xs do + ys[k] = f(x) end return ys end function public.take(n, xs) local ys = {} - for i=1,n do - if xs[i] then - tinsert(ys, xs[i]) - end + for i=1,min(n, getn(xs)) do + tinsert(ys, xs[i]) end return ys end @@ -224,40 +197,46 @@ function public.group_by(tables, equal) return groups end -function public.set(...) - local set = {} - for i=1,arg.n do - set[arg[i]] = true +do + local mt = { + __call = function(self) + return + end, + } + + local methods = {} + + function methods:add(key) + self[key] = true end - return set -end -function public.set_add(set, key) - set[key] = true -end - -function public.set_remove(set, key) - set[key] = nil -end - -function public.set_contains(set, key) - return set[key] ~= nil -end - -function public.set_size(set) - local size = 0 - for _,_ in set do - size = size + 1 + function methods:remove(key) + self[key] = nil end - return size -end -function public.set_to_array(set) - local array = {} - for element, _ in set do - tinsert(array, element) + function methods:size() + local size = 0 + for _,_ in self do + size = size + 1 + end + return size + end + + function methods:elements() + local elements = {} + for element, _ in self do + tinsert(elements, element) + end + return elements + end + + function public.set(...) + local self = {} + for i=1,arg.n do + set[arg[i]] = true + end + return setmetatable(self, mt) end - return array end function public.join(array, separator) @@ -271,14 +250,6 @@ function public.join(array, separator) return str end -function public.tokenize(str) - local tokens = {} - for token in string.gfind(str, '%S+') do - tinsert(tokens, token) - end - return tokens -end - function public.split(str, separator) local array = {} @@ -297,6 +268,14 @@ function public.split(str, separator) end end +function public.tokenize(str) + local tokens = {} + for token in string.gfind(str, '%S+') do + tinsert(tokens, token) + end + return tokens +end + function public.format_money(money, exact, color) color = color or '|r' @@ -319,15 +298,15 @@ function public.format_money(money, exact, color) local fmt = GSC_START if g > 0 then - gsc = gsc..string.format(fmt, GSC_GOLD, g) + gsc = gsc..format(fmt, GSC_GOLD, g) fmt = GSC_PART end if s > 0 or c > 0 then - gsc = gsc..string.format(fmt, GSC_SILVER, s) + gsc = gsc..format(fmt, GSC_SILVER, s) fmt = GSC_PART end if c > 0 then - gsc = gsc..string.format(fmt, GSC_COPPER, c) + gsc = gsc..format(fmt, GSC_COPPER, c) end if gsc == '' then gsc = GSC_NONE diff --git a/util/filter.lua b/util/filter.lua index 8777f0b..8a7bb23 100644 --- a/util/filter.lua +++ b/util/filter.lua @@ -457,7 +457,7 @@ function private.suggestions(components) tinsert(suggestions, 'not') tinsert(suggestions, 'tt') - for filter, _ in pairs(m.filters) do + for filter, _ in m.filters do tinsert(suggestions, strlower(filter)) end diff --git a/util/info.lua b/util/info.lua index eaa8108..1a3dd33 100644 --- a/util/info.lua +++ b/util/info.lua @@ -2,35 +2,41 @@ local m, public, private = Aux.module'info' local TOOLTIP_LENGTH = 30 -function public.inventory_index(slot) - local inventory_index_map = { - INVTYPE_AMMO = {0}, - INVTYPE_HEAD = {1}, - INVTYPE_NECK = {2}, - INVTYPE_SHOULDER = {3}, - INVTYPE_BODY = {4}, - INVTYPE_CHEST = {5}, - INVTYPE_ROBE = {5}, - INVTYPE_WAIST = {6}, - INVTYPE_LEGS = {7}, - INVTYPE_FEET = {8}, - INVTYPE_WRIST = {9}, - INVTYPE_HAND = {10}, - INVTYPE_FINGER = {11, 12}, - INVTYPE_TRINKET = {13, 14}, - INVTYPE_CLOAK = {15}, - INVTYPE_2HWEAPON = {16, 17}, - INVTYPE_WEAPONMAINHAND = {16, 17}, - INVTYPE_WEAPON = {16, 17}, - INVTYPE_WEAPONOFFHAND = {16, 17}, - INVTYPE_HOLDABLE = {16, 17}, - INVTYPE_SHIELD = {16, 17}, - INVTYPE_RANGED = {18}, - INVTYPE_RANGEDRIGHT = {18}, - INVTYPE_TABARD = {19}, - } +CreateFrame('GameTooltip', 'AuxTooltip', nil, 'GameTooltipTemplate') +AuxTooltip:SetScript('OnTooltipAddMoney', function() + this.money = arg1 +end) - return unpack(inventory_index_map[slot] or {}) +do + local inventory_index_map = { + INVTYPE_AMMO = {0}, + INVTYPE_HEAD = {1}, + INVTYPE_NECK = {2}, + INVTYPE_SHOULDER = {3}, + INVTYPE_BODY = {4}, + INVTYPE_CHEST = {5}, + INVTYPE_ROBE = {5}, + INVTYPE_WAIST = {6}, + INVTYPE_LEGS = {7}, + INVTYPE_FEET = {8}, + INVTYPE_WRIST = {9}, + INVTYPE_HAND = {10}, + INVTYPE_FINGER = {11, 12}, + INVTYPE_TRINKET = {13, 14}, + INVTYPE_CLOAK = {15}, + INVTYPE_2HWEAPON = {16, 17}, + INVTYPE_WEAPONMAINHAND = {16, 17}, + INVTYPE_WEAPON = {16, 17}, + INVTYPE_WEAPONOFFHAND = {16, 17}, + INVTYPE_HOLDABLE = {16, 17}, + INVTYPE_SHIELD = {16, 17}, + INVTYPE_RANGED = {18}, + INVTYPE_RANGEDRIGHT = {18}, + INVTYPE_TABARD = {19}, + } + function public.inventory_index(slot) + return unpack(inventory_index_map[slot] or {}) + end end function public.container_item(bag, slot) @@ -44,7 +50,7 @@ function public.container_item(bag, slot) local item_info = m.item(item_id, suffix_id, unique_id, enchant_id) local texture, count, locked, quality, readable, lootable = GetContainerItemInfo(bag, slot) -- quality not working? - local tooltip = m.tooltip(function(tt) tt:SetBagItem(bag, slot) end) + local tooltip, tooltip_money = m.tooltip(function(tt) tt:SetBagItem(bag, slot) end) local max_charges = m.max_item_charges(item_id) local charges = max_charges and m.item_charges(tooltip) local aux_quantity = charges or count @@ -74,6 +80,7 @@ function public.container_item(bag, slot) lootable = lootable, tooltip = tooltip, + tooltip_money = tooltip_money, max_charges = max_charges, charges = charges, aux_quantity = aux_quantity, @@ -110,7 +117,7 @@ function public.auction(index, query_type) local name, texture, count, quality, usable, level, start_price, min_increment, buyout_price, high_bid, high_bidder, owner, sale_status = GetAuctionItemInfo(query_type, index) local duration = GetAuctionItemTimeLeft(query_type, index) - local tooltip = m.tooltip(function(tt) tt:SetAuctionItem(query_type, index) end) + local tooltip, tooltip_money = m.tooltip(function(tt) tt:SetAuctionItem(query_type, index) end) local max_charges = m.max_item_charges(item_id) local charges = max_charges and m.item_charges(tooltip) local aux_quantity = charges or count @@ -155,6 +162,7 @@ function public.auction(index, query_type) usable = usable, tooltip = tooltip, + tooltip_money = tooltip_money, max_charges = max_charges, charges = charges, aux_quantity = aux_quantity, @@ -223,7 +231,7 @@ end function public.tooltip_find(pattern, tooltip) local count = 0 - for _, line in ipairs(tooltip) do + for _, line in tooltip do if line.left_text and strfind(line.left_text, pattern) then count = count + 1 end @@ -236,7 +244,7 @@ function public.tooltip_find(pattern, tooltip) end function public.load_tooltip(frame, tooltip) - for _, line in ipairs(tooltip) do + for _, line in tooltip do if line.right_text then frame:AddDoubleLine(line.left_text, line.right_text, line.left_color[1], line.left_color[2], line.left_color[3], line.right_color[1], line.right_color[2], line.right_color[3]) else @@ -249,14 +257,14 @@ function public.load_tooltip(frame, tooltip) end end -function public.display_name(item_id, plain, uncolored) +function public.display_name(item_id, no_brackets, no_color) local item_info = Aux.info.item(item_id) if item_info then local name = item_info.name - if not plain then + if not no_brackets then name = '['..name..']' end - if not uncolored then + if not no_color then name = ({GetItemQualityColor(item_info.quality)})[4]..name..FONT_COLOR_CODE_CLOSE end return name @@ -280,7 +288,7 @@ function public.tooltip(setter) setter(AuxTooltip) AuxTooltip:Show() - local tooltip = { money=AuxTooltip.money } + local tooltip = {} for i = 1,TOOLTIP_LENGTH do local left_text = getglobal('AuxTooltipTextLeft'..i):GetText() local left_color = { getglobal('AuxTooltipTextLeft'..i):GetTextColor() } @@ -298,7 +306,7 @@ function public.tooltip(setter) end end - return tooltip + return tooltip, AuxTooltip.money end function private.item_charges(tooltip)