From 2792ff9358ed941f462d443285e0f5806292e96f Mon Sep 17 00:00:00 2001 From: Manuel Simon Hirsig Date: Fri, 15 Jul 2016 01:48:52 +0200 Subject: [PATCH] working on sniping mode --- core.lua | 15 +++-- modules/scan.lua | 137 +++++++++++++++++++++-------------------- panels/search/core.lua | 110 ++++++++++++++++++++++++++------- util/info.lua | 1 + util/scan_util.lua | 7 ++- 5 files changed, 173 insertions(+), 97 deletions(-) diff --git a/core.lua b/core.lua index 73dfe6a..a30669a 100644 --- a/core.lua +++ b/core.lua @@ -2,12 +2,18 @@ function Aux_module(self, name) local module, data, is_public, private, public = {}, {}, {}, {}, {} setmetatable(private, { __newindex = function(_, key, value) + if data[key] ~= nil then + error('Multiple declarations of "'..key..'" in module"'..name..'"!') + end rawset(data, key, value) is_public[key] = nil end, }) setmetatable(public, { __newindex = function(_, key, value) + if data[key] ~= nil then + error('Multiple declarations of "'..key..'" in module"'..name..'"!') + end rawset(data, key, value) is_public[key] = true end, @@ -15,7 +21,7 @@ function Aux_module(self, name) setmetatable(data, { __newindex = function(_, key) if data[key] == nil then - error('Assignment of undeclared module attribute "'..key..'"!') + error('Assignment of undeclared module attribute "'..key..'" in module"'..name..'"!') end end, }) @@ -32,7 +38,6 @@ end function Aux_addon() local addon = { - metadata = metadata, modules = {}, module = Aux_module, } @@ -472,9 +477,9 @@ function Aux.show_elements(elements) end end -function Aux.is_player(name) +function Aux.is_player(name, current) local realm = GetCVar('realmName') - return Aux.util.safe_index(aux_characters, realm, name) or UnitName('player') == name + return (not current and Aux.util.safe_index(aux_characters, realm, name)) or UnitName('player') == name end function Aux.unmodified() @@ -493,7 +498,7 @@ function Aux.hook(name, handler, object) end if orig[name] then - error('"'..name..'"'..'is already hooked!') + error('"'..name..'" is already hooked!') end orig[name] = object[name] diff --git a/modules/scan.lua b/modules/scan.lua index 1e01c33..1469217 100644 --- a/modules/scan.lua +++ b/modules/scan.lua @@ -1,20 +1,22 @@ -local private , public = {}, {} -Aux.scan = public +local m, private , public = Aux:module('scan') local PAGE_SIZE = 50 local state local threads = {} +function private.total_pages(total_count) + return math.ceil(total_count / PAGE_SIZE) +end + function private.last_page(total_count) - local total_pages = math.ceil(total_count / PAGE_SIZE) - local last_page = max(total_pages - 1, 0) - local last_page_limit = Aux.util.safe_index(private.current_query().blizzard_query, 'last_page') + local last_page = max(m.total_pages(total_count) - 1, 0) + local last_page_limit = Aux.util.safe_index(m.current_query().blizzard_query, 'last_page') return last_page_limit and min(last_page_limit, last_page) or last_page end function private.current_query() - return private.current_thread().params.queries[private.current_thread().query_index] + return m.current_thread().params.queries[m.current_thread().query_index] end function private.current_thread() @@ -27,11 +29,11 @@ end function public.start(params) if threads[params.type] then - public.abort(threads[params.type].id) + m.abort(threads[params.type].id) end local thread_id = Aux.control.new_thread(function() - return private.wait_for_callback(private.current_thread().params.on_scan_start, private.scan) + return m.wait_for_callback(m.current_thread().params.on_scan_start, m.scan) end) threads[params.type] = { id = thread_id, @@ -58,18 +60,18 @@ function public.abort(scan_id) end function private.wait_for_results(k) - if private.current_thread().params.type == 'bidder' then + if m.current_thread().params.type == 'bidder' then return Aux.control.wait_until(function() return Aux.bids_loaded end, k) - elseif private.current_thread().params.type == 'owner' then - return private.wait_for_owner_results(k) - elseif private.current_thread().params.type == 'list' then - return private.wait_for_list_results(k) + elseif m.current_thread().params.type == 'owner' then + return m.wait_for_owner_results(k) + elseif m.current_thread().params.type == 'list' then + return m.wait_for_list_results(k) end end function private.wait_for_owner_results(k) local updated - if private.current_thread().page == Aux.current_owner_page then + if m.current_thread().page == Aux.current_owner_page then updated = true else Aux.control.on_next_event('AUCTION_OWNED_LIST_UPDATE', function() @@ -89,7 +91,7 @@ function private.wait_for_list_results(k) listener:start() Aux.control.wait_until(function() -- order important, owner_data_complete must be called after an update to request missing data - local ok = updated and private.owner_data_complete() or last_update and GetTime() - last_update > 5 + local ok = updated and m.owner_data_complete() or last_update and GetTime() - last_update > 5 updated = false return ok end, function() @@ -99,12 +101,12 @@ function private.wait_for_list_results(k) end function private.owner_data_complete() - if private.current_thread().params.ignore_owner or aux_ignore_owner then + if m.current_thread().params.ignore_owner or aux_ignore_owner then return true end - local count = GetNumAuctionItems(private.current_thread().params.type) + local count = GetNumAuctionItems(m.current_thread().params.type) for i=1,count do - local auction_info = Aux.info.auction(i, private.current_thread().params.type) + local auction_info = Aux.info.auction(i, m.current_thread().params.type) if auction_info and not auction_info.owner then return false end @@ -134,17 +136,17 @@ function private.wait_for_callback(...) end function private.scan() - private.current_thread().query_index = private.current_thread().query_index and private.current_thread().query_index + 1 or 1 - if private.current_query() then - if private.current_query().blizzard_query then - private.current_thread().page = private.current_query().blizzard_query.first_page or 0 + m.current_thread().query_index = m.current_thread().query_index and m.current_thread().query_index + 1 or 1 + if m.current_query() then + if m.current_query().blizzard_query then + m.current_thread().page = m.current_query().blizzard_query.first_page or 0 else - private.current_thread().page = nil + m.current_thread().page = nil end - private.wait_for_callback(private.current_thread().params.on_start_query, private.current_thread().query_index, private.process_query) + m.wait_for_callback(m.current_thread().params.on_start_query, m.current_thread().query_index, m.process_query) else - local on_complete = private.current_thread().params.on_complete - threads[private.current_thread().params.type] = nil + local on_complete = m.current_thread().params.on_complete + threads[m.current_thread().params.type] = nil if on_complete then return on_complete() end @@ -152,23 +154,23 @@ function private.scan() end function private.process_query() - if private.current_query().blizzard_query then - return private.submit_query(private.scan_page) + if m.current_query().blizzard_query then + return m.submit_query(m.scan_page) else - return private.scan_page() + return m.scan_page() end end function private.scan_page() - private.scan_auctions(function() + m.scan_auctions(function() - private.wait_for_callback(private.current_thread().params.on_page_scanned, function() + m.wait_for_callback(m.current_thread().params.on_page_scanned, function() - if private.current_query().blizzard_query and private.current_thread().page < private.last_page(private.current_thread().total_auctions) then - private.current_thread().page = private.current_thread().page + 1 - return private.process_query() + if m.current_query().blizzard_query and m.current_thread().page < m.last_page(m.current_thread().total_auctions) then + m.current_thread().page = m.current_thread().page + 1 + return m.process_query() else - return private.scan() + return m.scan() end end) @@ -176,29 +178,29 @@ function private.scan_page() end function private.scan_auctions(k) - return private.scan_auctions_helper(1, k) + return m.scan_auctions_helper(1, k) end function private.scan_auctions_helper(i, k) local recurse = function() - if i >= (private.current_thread().page_auctions or GetNumAuctionItems(private.current_thread().params.type)) then + if i >= (m.current_thread().page_auctions or GetNumAuctionItems(m.current_thread().params.type)) then return k() else - return private.scan_auctions_helper(i + 1, k) + return m.scan_auctions_helper(i + 1, k) end end - local auction_info = Aux.info.auction(i, private.current_thread().params.type) - if auction_info and (auction_info.owner or private.current_thread().params.ignore_owner or aux_ignore_owner) then + local auction_info = Aux.info.auction(i, m.current_thread().params.type) + if auction_info and (auction_info.owner or m.current_thread().params.ignore_owner or aux_ignore_owner) then auction_info.index = i - auction_info.page = private.current_thread().page - auction_info.blizzard_query = private.current_query().blizzard_query - auction_info.query_type = private.current_thread().params.type + auction_info.page = m.current_thread().page + auction_info.blizzard_query = m.current_query().blizzard_query + auction_info.query_type = m.current_thread().params.type Aux.history.process_auction(auction_info) - if not private.current_query().validator or private.current_query().validator(auction_info) then - return private.wait_for_callback(private.current_thread().params.on_auction, auction_info, recurse) + if not m.current_query().validator or m.current_query().validator(auction_info) then + return m.wait_for_callback(m.current_thread().params.on_auction, auction_info, recurse) end end @@ -206,34 +208,35 @@ function private.scan_auctions_helper(i, k) end function private.submit_query(k) - Aux.control.wait_until(function() return private.current_thread().params.type ~= 'list' or CanSendAuctionQuery() end, function() + Aux.control.wait_until(function() return m.current_thread().params.type ~= 'list' or CanSendAuctionQuery() end, function() - if private.current_thread().params.on_submit_query then - private.current_thread().params.on_submit_query() + if m.current_thread().params.on_submit_query then + m.current_thread().params.on_submit_query() end - if private.current_thread().params.type == 'bidder' then - GetBidderAuctionItems(private.current_thread().page) - elseif private.current_thread().params.type == 'owner' then - GetOwnerAuctionItems(private.current_thread().page) + if m.current_thread().params.type == 'bidder' then + GetBidderAuctionItems(m.current_thread().page) + elseif m.current_thread().params.type == 'owner' then + GetOwnerAuctionItems(m.current_thread().page) else QueryAuctionItems( - Aux.util.safe_index(private.current_query().blizzard_query, 'name'), - Aux.util.safe_index(private.current_query().blizzard_query, 'min_level'), - Aux.util.safe_index(private.current_query().blizzard_query, 'max_level'), - Aux.util.safe_index(private.current_query().blizzard_query, 'slot'), - Aux.util.safe_index(private.current_query().blizzard_query, 'class'), - Aux.util.safe_index(private.current_query().blizzard_query, 'subclass'), - private.current_thread().page, - Aux.util.safe_index(private.current_query().blizzard_query, 'usable'), - Aux.util.safe_index(private.current_query().blizzard_query, 'quality') + Aux.util.safe_index(m.current_query().blizzard_query, 'name'), + Aux.util.safe_index(m.current_query().blizzard_query, 'min_level'), + Aux.util.safe_index(m.current_query().blizzard_query, 'max_level'), + Aux.util.safe_index(m.current_query().blizzard_query, 'slot'), + Aux.util.safe_index(m.current_query().blizzard_query, 'class'), + Aux.util.safe_index(m.current_query().blizzard_query, 'subclass'), + m.current_thread().page, + Aux.util.safe_index(m.current_query().blizzard_query, 'usable'), + Aux.util.safe_index(m.current_query().blizzard_query, 'quality') ) end - private.wait_for_results(function() - private.current_thread().page_auctions, private.current_thread().total_auctions = GetNumAuctionItems(private.current_thread().params.type) - private.wait_for_callback( - private.current_thread().params.on_page_loaded, - private.current_thread().page - (private.current_query().blizzard_query.first_page or 0) + 1, - private.last_page(private.current_thread().total_auctions) - (private.current_query().blizzard_query.first_page or 0) + 1, + m.wait_for_results(function() + m.current_thread().page_auctions, m.current_thread().total_auctions = GetNumAuctionItems(m.current_thread().params.type) + m.wait_for_callback( + m.current_thread().params.on_page_loaded, + m.current_thread().page - (m.current_query().blizzard_query.first_page or 0) + 1, + m.last_page(m.current_thread().total_auctions) - (m.current_query().blizzard_query.first_page or 0) + 1, + m.total_pages(m.current_thread().total_auctions), k ) end) diff --git a/panels/search/core.lua b/panels/search/core.lua index a91c14f..0519f60 100644 --- a/panels/search/core.lua +++ b/panels/search/core.lua @@ -209,15 +209,86 @@ end function public.execute(mode, filter_string) - if filter_string then - private.search_box:SetText(filter_string) + filter_string = filter_string or private.search_box:GetText() + private.search_box:SetText(filter_string) + + local queries = Aux.scan_util.parse_filter_string(filter_string) + if not queries then + return + elseif getn(queries) > 1 then + Aux.log('Invalid filter: The sniping mode does not support multiple queries') end + if queries[1].blizzard_query.first_page or queries[1].blizzard_query.last_page then + Aux.log('Invalid filter: The sniping mode does not support page range filters') + end + + private.new_search(filter_string, Aux.util.join(Aux.util.map(queries, function(filter) return filter.prettified end), ';')) + + private.sniping_helper(private.current_search(), queries[1]) +end + +function private.sniping_helper(search, query) + + local ignore_page = not query.blizzard_query.first_page + query.blizzard_query.first_page = query.blizzard_query.first_page or 0 + query.blizzard_query.last_page = query.blizzard_query.last_page or 0 + + local sniping_map = {} + for _, record in search.records do + sniping_map[record.sniping_signature] = record + end + + private.update_tab(private.RESULTS) + + search_scan_id = Aux.scan.start{ + type = 'list', + queries = {query}, + on_scan_start = function() + private.status_bar:update_status(99.99, 99.99) + private.status_bar:set_text('Sniping ...') + end, + on_page_loaded = function(_, _, last_page) + query.blizzard_query.first_page = last_page - 1 + query.blizzard_query.last_page = last_page - 1 + if last_page == 1 then + ignore_page = false + end + end, + on_auction = function(auction_record) + if not ignore_page then + sniping_map[auction_record.sniping_signature] = auction_record + end + end, + on_complete = function() + if Aux.util.set_size(sniping_map) > 1000 then + StaticPopup_Show('AUX_SEARCH_TABLE_FULL') + else + search.records = {} + for _, record in sniping_map do + tinsert(search.records, record) + end + private.results_listing:SetDatabase(search.records) + end + + private.sniping_helper(search, query) + end, + on_abort = function() + private.status_bar:update_status(100, 100) + private.status_bar:set_text('Done Sniping') + end, + } +end + +function public.snipe(mode, filter_string) + + filter_string = filter_string or private.search_box:GetText() + private.search_box:SetText(filter_string) if mode == 'search' and private.search_box:GetText() == private.current_search().filter_string then mode = 'refresh' end - local queries, filters, current_query, current_page, total_queries, start_page, start_query + local queries, current_query, current_page, total_queries, start_page, start_query if mode == 'refresh' or mode == 'resume' then private.search_box:ClearFocus() @@ -228,16 +299,10 @@ function public.execute(mode, filter_string) private.results_listing:SetDatabase(private.current_search().records) end - filters = Aux.scan_util.parse_filter_string(private.search_box:GetText()) - if not filters then + queries = Aux.scan_util.parse_filter_string(filter_string) + if not queries then return end - queries = Aux.util.map(filters, function(filter) - return { - blizzard_query = filter.blizzard_query, - validator = filter.validator, - } - end) total_queries = getn(queries) if mode == 'resume' then @@ -252,15 +317,7 @@ function public.execute(mode, filter_string) end if mode == 'search' then - tinsert(aux_recent_searches, 1, { - filter_string = private.search_box:GetText(), - prettified = Aux.util.join(Aux.util.map(filters, function(filter) return filter.prettified end), ';'), - }) - while getn(aux_recent_searches) > 50 do - tremove(aux_recent_searches) - end - private.update_search_listings() - private.new_search() + private.new_search(filter_string, Aux.util.join(Aux.util.map(queries, function(filter) return filter.prettified end), ';')) end if mode == 'resume' or mode == 'refresh' then @@ -475,9 +532,18 @@ do end end - function private.new_search() + function private.new_search(filter_string, prettified) + tinsert(aux_recent_searches, 1, { + filter_string = filter_string, + prettified = prettified, + }) + while getn(aux_recent_searches) > 50 do + tremove(aux_recent_searches) + end + private.update_search_listings() + tinsert(searches, search_index + 1, { - filter_string = private.search_box:GetText(), + filter_string = filter_string, records = {}, }) while getn(searches) > search_index + 1 do diff --git a/util/info.lua b/util/info.lua index 188cd9d..e8c4a9e 100644 --- a/util/info.lua +++ b/util/info.lua @@ -138,6 +138,7 @@ function public.auction(index, query_type) itemstring = item_info.itemstring, item_key = item_id..':'..suffix_id, search_signature = Aux.util.join({item_id, suffix_id, enchant_id, start_price, buyout_price, bid_price, aux_quantity, duration, query_type == 'owner' and high_bidder or (high_bidder and 1 or 0), aux_ignore_owner and (Aux.is_player(owner) and 0 or 1) or (owner or '?')}, ':'), + sniping_signature = Aux.util.join({item_id, suffix_id, enchant_id, start_price, buyout_price, aux_quantity, aux_ignore_owner and (Aux.is_player(owner, true) and 0 or 1) or (owner or '?')}, ':'), name = name, texture = texture, diff --git a/util/scan_util.lua b/util/scan_util.lua index a36416a..04c46cf 100644 --- a/util/scan_util.lua +++ b/util/scan_util.lua @@ -281,7 +281,7 @@ m.filters = { return vendor_price and vendor_price * auction_record.aux_quantity - auction_record.bid_price >= amount end else - return false, {}, 'Erroneous bid vendor profit Modifier' + return false, {}, 'Erroneous bid vendor profit modifier' end end }, @@ -296,7 +296,7 @@ m.filters = { return auction_record.buyout_price > 0 and vendor_price and vendor_price * auction_record.aux_quantity - auction_record.buyout_price >= amount end else - return false, {}, 'Erroneous buyout vendor profit Modifier' + return false, {}, 'Erroneous buyout vendor profit modifier' end end }, @@ -424,7 +424,8 @@ function m.parse_filter_string(filter_string) Aux.log('Invalid filter: '..error) return elseif filter.name and strlen(filter.name) > 63 then - + Aux.log('Invalid filter: The name may not longer than 63 characters') + return else tinsert(filters, filter) end