This commit is contained in:
Andrew6810
2022-11-05 21:19:42 -07:00
parent b79f4bd588
commit f3e579cb57
386 changed files with 93729 additions and 2 deletions
+185
View File
@@ -0,0 +1,185 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_AuctionDB --
-- http://www.curse.com/addons/wow/tradeskillmaster_auctiondb --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select(2, ...)
local GUI = TSM:NewModule("GUI")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_AuctionDB") -- loads the localization table
local private = {}
function GUI:Show(frame)
private.statusBar = private.statusBar or private:CreateStatusBar(frame.content)
private.statusBar:Show()
GUI:UpdateStatus("", 0, 0)
private.startScanContent = private.startScanContent or private:CreateStartScanContent(frame)
private.startScanContent:Show()
end
function GUI:Hide()
private.statusBar:Hide()
private.startScanContent:Hide()
TSM.Scan:DoneScanning()
TSMAPI.AuctionScan:StopScan()
end
function GUI:UpdateStatus(text, major, minor)
if text then
private.statusBar:SetStatusText(text)
end
if major or minor then
private.statusBar:UpdateStatus(major, minor)
end
end
function private:CreateStatusBar(parent)
local frame = TSMAPI.GUI:CreateStatusBar(parent, "TSMAuctionDBStatusBar")
TSMAPI.GUI:CreateHorizontalLine(frame, -30, parent)
return frame
end
function private:CreateStartScanContent(parent)
local frame = CreateFrame("Frame", nil, parent)
frame:SetAllPoints(parent)
frame:Hide()
local function UpdateGetAllButton()
if TSM.Scan.isScanning then
frame:Disable()
elseif not select(2, CanSendAuctionQuery()) then
local previous = TSM.db.profile.lastGetAll or time()
if previous > (time() - 15*60) then
local diff = previous + 15*60 - time()
local diffMin = math.floor(diff/60)
local diffSec = diff - diffMin*60
frame.getAllStatusText:SetText("|cff990000"..format(L["Ready in %s min and %s sec"], diffMin, diffSec))
else
frame.getAllStatusText:SetText("|cff990000"..L["Not Ready"])
end
frame:Enable()
frame.startGetAllButton:Disable()
else
frame:Enable()
frame.getAllStatusText:SetText("|cff009900"..L["Ready"])
frame.startGetAllButton:Enable()
end
end
frame:SetScript("OnShow", function(self)
TSMAPI:CreateTimeDelay("auctionDBGetAllStatus", 0, UpdateGetAllButton, 0.2)
end)
frame:SetScript("OnHide", function(self)
TSMAPI:CancelFrame("auctionDBGetAllStatus")
end)
frame.Enable = function(self)
self.startGetAllButton:Enable()
self.startFullScanButton:Enable()
self.startGroupScanButton:Enable()
end
frame.Disable = function(self)
self.startGetAllButton:Disable()
self.startFullScanButton:Disable()
self.startGroupScanButton:Disable()
end
-- top row (auto updater)
local text = TSMAPI.GUI:CreateLabel(frame)
text:SetFont(TSMAPI.Design:GetContentFont(), 24)
text:SetPoint("TOP", 0, -24)
text:SetHeight(24)
text:SetJustifyH("CENTER")
text:SetJustifyV("CENTER")
text:SetText(TSMAPI.Design:GetInlineColor("link").."TSM_AuctionDB")
local ag = text:CreateAnimationGroup()
local a1 = ag:CreateAnimation("Alpha")
a1:SetChange(-.5)
a1:SetDuration(.5)
ag:SetLooping("BOUNCE")
ag:Play()
local content = CreateFrame("Frame", nil, frame)
content:SetAllPoints(parent.content)
TSMAPI.Design:SetFrameBackdropColor(content)
-- group tree
local container = CreateFrame("Frame", nil, content)
container:SetPoint("TOPLEFT", 5, -35)
container:SetPoint("BOTTOMRIGHT", -205, 5)
TSMAPI.Design:SetFrameColor(container)
frame.groupTree = TSMAPI:CreateGroupTree(container, nil, "AuctionDB")
local bar = TSMAPI.GUI:CreateVerticalLine(content, 0)
bar:ClearAllPoints()
bar:SetPoint("TOPRIGHT", -200, -30)
bar:SetPoint("BOTTOMRIGHT", -200, 0)
local buttonFrame = CreateFrame("Frame", nil, content)
buttonFrame:SetPoint("TOPLEFT", content, "TOPRIGHT", -200, 0)
buttonFrame:SetPoint("BOTTOMRIGHT")
-- first row (getall scan)
local btn = TSMAPI.GUI:CreateButton(buttonFrame, 18)
btn:SetPoint("TOPLEFT", 6, -50)
btn:SetPoint("TOPRIGHT", -6, -50)
btn:SetHeight(22)
btn:SetScript("OnClick", TSM.Scan.StartGetAllScan)
btn:SetText(L["Run GetAll Scan"])
btn.tooltip = L["A GetAll scan is the fastest in-game method for scanning every item on the auction house. However, there are many possible bugs on Blizzard's end with it including the chance for it to disconnect you from the game. Also, it has a 15 minute cooldown."]
frame.startGetAllButton = btn
local text = TSMAPI.GUI:CreateLabel(buttonFrame)
text:SetPoint("TOPLEFT", btn, "BOTTOMLEFT", 0, -3)
text:SetPoint("TOPRIGHT", btn, "BOTTOMRIGHT", 0, -3)
text:SetHeight(16)
text:SetJustifyH("CENTER")
text:SetJustifyV("CENTER")
frame.getAllStatusText = text
TSMAPI.GUI:CreateHorizontalLine(buttonFrame, -110)
-- second row (full scan)
local btn = TSMAPI.GUI:CreateButton(buttonFrame, 18)
btn:SetPoint("TOPLEFT", 6, -150)
btn:SetPoint("TOPRIGHT", -6, -150)
btn:SetHeight(22)
btn:SetScript("OnClick", TSM.Scan.StartFullScan)
btn:SetText(L["Run Full Scan"])
btn.tooltip = L["A full auction house scan will scan every item on the auction house but is far slower than a GetAll scan. Expect this scan to take several minutes or longer."]
frame.startFullScanButton = btn
TSMAPI.GUI:CreateHorizontalLine(buttonFrame, -200)
-- third row (group scan)
local btn = TSMAPI.GUI:CreateButton(buttonFrame, 18)
btn:SetPoint("TOPLEFT", 6, -225)
btn:SetPoint("TOPRIGHT", -6, -225)
btn:SetHeight(22)
btn:SetScript("OnClick", GUI.StartGroupScan)
btn:SetText(L["Scan Selected Groups"])
btn.tooltip = L["This will do a slow auction house scan of every item in the selected groups and update their AuctionDB prices. This may take several minutes."]
frame.startGroupScanButton = btn
return frame
end
function GUI:StartGroupScan()
local items = {}
for groupName, data in pairs(private.startScanContent.groupTree:GetSelectedGroupInfo()) do
groupName = TSMAPI:FormatGroupPath(groupName, true)
for itemString in pairs(data.items) do
tinsert(items, itemString)
end
end
TSM.Scan:StartGroupScan(items)
end
@@ -0,0 +1,229 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_AuctionDB --
-- http://www.curse.com/addons/wow/tradeskillmaster_auctiondb --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select(2, ...)
local Scan = TSM:NewModule("Scan", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_AuctionDB") -- loads the localization table
Scan.groupScanData = {}
Scan.filterList = {}
Scan.numFilters = 0
local function ScanCallback(event, ...)
if event == "SCAN_PAGE_UPDATE" then
local page, total = ...
TSM.GUI:UpdateStatus(format(L["Scanning page %s/%s"], page, total), page*100/total)
elseif event == "SCAN_COMPLETE" then
local data = ...
Scan:ProcessScanData(data)
Scan:DoneScanning()
elseif event == "INTERRUPTED" then
Scan:DoneScanning()
end
end
function Scan.ProcessGetAllScan(self)
local temp = 0
while true do
temp = min(temp + 1, 100)
self:Sleep(0.2)
if not Scan.isScanning then return end
if Scan.getAllLoaded then
break
end
TSM.GUI:UpdateStatus(L["Running query..."], nil, temp)
end
local data = {}
for i=1, Scan.getAllLoaded do
TSM.GUI:UpdateStatus(format(L["Scanning page %s/%s"], 1, 1), i*100/Scan.getAllLoaded)
if i % 100 == 0 then
self:Yield()
if GetNumAuctionItems("list") ~= Scan.getAllLoaded then
--TSM:Print(L["GetAll scan did not run successfully due to issues on Blizzard's end. Using the TSM application for your scans is recommended."])
TSM:Print("GetAll scan did not run successfully.")
Scan:DoneScanning()
return
end
end
local itemID = TSMAPI:GetItemID(GetAuctionItemLink("list", i))
--local _, _, count, _, _, _, _, _, _, buyout = GetAuctionItemInfo("list", i)
local _, _, count, _, _, _, _, _, buyout = GetAuctionItemInfo("list", i)
if itemID and buyout and buyout > 0 then
data[itemID] = data[itemID] or {records={}, minBuyout=math.huge, quantity=0}
data[itemID].minBuyout = min(data[itemID].minBuyout, floor(buyout/count))
data[itemID].quantity = data[itemID].quantity + count
for j=1, count do
tinsert(data[itemID].records, floor(buyout/count))
end
end
end
TSM.db.factionrealm.lastCompleteScan = time()
TSM.Data:ProcessData(data)
TSM.GUI:UpdateStatus(L["Processing data..."])
while TSM.processingData do
self:Sleep(0.2)
end
TSM:Print(L["It is strongly recommended that you reload your ui (type '/reload') after running a GetAll scan. Otherwise, any other scans (Post/Cancel/Search/etc) will be much slower than normal."])
end
function Scan:AUCTION_ITEM_LIST_UPDATE()
Scan:UnregisterEvent("AUCTION_ITEM_LIST_UPDATE")
local num, total = GetNumAuctionItems("list")
--if num ~= total or num == 0 then
if num == 0 then
--TSM:Print(L["GetAll scan did not run successfully due to issues on Blizzard's end. Using the TSM application for your scans is recommended."])
TSM:Print("GetAll scan did not run successfully.")
Scan:DoneScanning()
return
end
Scan.getAllLoaded = num
end
function Scan:GetAllScanQuery()
local canScan, canGetAll = CanSendAuctionQuery()
if not canGetAll then return TSM:Print(L["Can't run a GetAll scan right now."]) end
if not canScan then return TSMAPI:CreateTimeDelay(0.5, Scan.GetAllScanQuery) end
QueryAuctionItems("", nil, nil, nil, nil, nil, nil, nil, nil, true)
Scan:RegisterEvent("AUCTION_ITEM_LIST_UPDATE")
TSMAPI.Threading:Start(Scan.ProcessGetAllScan, 1, function() Scan:DoneScanning() end)
end
local function GroupScanCallback(event, ...)
if event == "QUERY_COMPLETE" then
local filterList = ...
local numItems = 0
for _, v in ipairs(filterList) do
numItems = numItems + #v.items
end
Scan.filterList = filterList
Scan.numFilters = #filterList
Scan:ScanNextGroupFilter()
elseif event == "QUERY_UPDATE" then
local current, total = ...
TSM.GUI:UpdateStatus(format(L["Preparing Filter %d / %d"], current, total))
elseif event == "SCAN_INTERRUPTED" then
Scan:DoneScanning()
elseif event == "SCAN_TIMEOUT" then
tremove(Scan.filterList, 1)
Scan:ScanNextGroupFilter()
elseif event == "SCAN_PAGE_UPDATE" then
local page, total = ...
TSM.GUI:UpdateStatus(format(L["Scanning %d / %d (Page %d / %d)"], Scan.numFilters-#Scan.filterList, Scan.numFilters, page+1, total), nil, page*100/total)
elseif event == "SCAN_COMPLETE" then
local data = ...
for _, itemString in ipairs(Scan.filterList[1].items) do
if not Scan.groupScanData[itemString] then
Scan.groupScanData[itemString] = data[itemString]
end
end
tremove(Scan.filterList, 1)
Scan:ScanNextGroupFilter()
end
end
function Scan:ScanNextGroupFilter(data)
if #Scan.filterList == 0 then
Scan:ProcessScanData(Scan.groupScanData)
Scan:DoneScanning()
return
end
TSM.GUI:UpdateStatus(format(L["Scanning %d / %d (Page %d / %d)"], Scan.numFilters-#Scan.filterList, Scan.numFilters, 1, 1), (Scan.numFilters-#Scan.filterList)*100/Scan.numFilters)
TSMAPI.AuctionScan:RunQuery(Scan.filterList[1], GroupScanCallback)
end
function Scan:StartGroupScan(items)
Scan.isScanning = "Group"
Scan.isBuggedGetAll = nil
Scan.groupItems = items
wipe(Scan.filterList)
wipe(Scan.groupScanData)
Scan.numFilters = 0
TSMAPI.AuctionScan:StopScan()
TSMAPI:GenerateQueries(items, GroupScanCallback)
TSM.GUI:UpdateStatus(L["Preparing Filters..."])
end
function Scan:StartFullScan()
Scan.isScanning = "Full"
TSM.GUI:UpdateStatus(L["Running query..."])
Scan.isBuggedGetAll = nil
Scan.groupItems = nil
TSMAPI.AuctionScan:StopScan()
TSMAPI.AuctionScan:RunQuery({name=""}, ScanCallback)
end
function Scan:StartGetAllScan()
TSM.db.profile.lastGetAll = time()
Scan.isScanning = "GetAll"
Scan.isBuggedGetAll = nil
Scan.groupItems = nil
TSMAPI.AuctionScan:StopScan()
Scan:GetAllScanQuery()
end
function Scan:DoneScanning()
TSM.GUI:UpdateStatus(L["Done Scanning"], 100)
Scan.isScanning = nil
Scan.getAllLoaded = nil
end
function Scan:ProcessScanData(scanData)
local data = {}
for itemString, obj in pairs(scanData) do
if TSMAPI:GetBaseItemString(itemString) == itemString then
local itemID = obj:GetItemID()
local quantity, minBuyout = 0, 0
local records = {}
for _, record in ipairs(obj.records) do
local itemBuyout = record:GetItemBuyout()
if itemBuyout and (itemBuyout < minBuyout or minBuyout == 0) then
minBuyout = itemBuyout
end
quantity = quantity + record.count
for i=1, record.count do
tinsert(records, itemBuyout)
end
end
data[itemID] = {records=records, minBuyout=minBuyout, quantity=quantity}
end
end
if Scan.isScanning ~= "group" then
TSM.db.factionrealm.lastCompleteScan = time()
end
TSM.Data:ProcessData(data, Scan.groupItems)
end
function Scan:ProcessImportedData(auctionData)
local data = {}
for itemID, auctions in pairs(auctionData) do
local quantity, minBuyout, records = 0, 0, {}
for _, auction in ipairs(auctions) do
local itemBuyout, count = unpack(auction)
if itemBuyout and (itemBuyout < minBuyout or minBuyout == 0) then
minBuyout = itemBuyout
end
quantity = quantity + count
for i=1, count do
tinsert(records, itemBuyout)
end
end
data[itemID] = {records=records, minBuyout=minBuyout, quantity=quantity}
end
TSM.db.factionrealm.lastCompleteScan = time()
TSM.Data:ProcessData(data)
end
@@ -0,0 +1,489 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_AuctionDB --
-- http://www.curse.com/addons/wow/tradeskillmaster_auctiondb --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select(2, ...)
local Config = TSM:NewModule("Config", "AceHook-3.0")
local AceGUI = LibStub("AceGUI-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_AuctionDB") -- loads the localization table
local searchPage = 0
local filter = { text = nil, class = nil, subClass = nil }
local items = {}
-- options page
function Config:Load(parent)
filter = {}
local tg = AceGUI:Create("TSMTabGroup")
tg:SetLayout("Fill")
tg:SetFullHeight(true)
tg:SetFullWidth(true)
tg:SetTabs({ { value = 1, text = SEARCH }, { value = 2, text = L["Options"] } })
tg:SetCallback("OnGroupSelected", function(self, _, value)
tg:ReleaseChildren()
parent:DoLayout()
if value == 1 then
Config:LoadSearch(tg)
elseif value == 2 then
Config:LoadOptions(tg)
end
tg.children[1]:DoLayout()
end)
parent:AddChild(tg)
tg:SelectTab(1)
end
function Config:UpdateItems()
wipe(items)
local cache = {}
local sortMethod = TSM.db.profile.resultsSortMethod
local fClass = filter.class and select(filter.class, GetAuctionItemClasses())
local fSubClass = filter.subClass and select(filter.subClass, GetAuctionItemSubClasses(filter.class))
if filter.text or fClass then
for itemID, data in pairs(TSM.data) do
TSM:DecodeItemData(itemID)
local name, _, rarity, ilvl, minlvl, class, subClass = GetItemInfo(itemID)
if (name and filter.text and strfind(strlower(name), strlower(filter.text))) and (not fClass or (class == fClass and (not fSubClass or subClass == fSubClass))) and (not TSM.db.profile.hidePoorQualityItems or rarity > 0) then
tinsert(items, itemID)
if sortMethod == "name" then
cache[itemID] = name
elseif sortMethod == "ilvl" then
cache[itemID] = ilvl
elseif sortMethod == "minlvl" then
cache[itemID] = minlvl
elseif sortMethod == "marketvalue" then
cache[itemID] = data.marketValue
elseif sortMethod == "minbuyout" then
cache[itemID] = data.minBuyout
end
end
end
end
if TSM.db.profile.resultsSortOrder == "ascending" then
sort(items, function(a, b) return (cache[a] or math.huge) < (cache[b] or math.huge) end)
else
sort(items, function(a, b) return (cache[a] or 0) > (cache[b] or 0) end)
end
end
function Config:LoadSearch(container)
local searchDataTmp = Config:GetSearchData()
local results = {}
local totalResults = #items
local minIndex = searchPage * TSM.db.profile.resultsPerPage + 1
local maxIndex = min(TSM.db.profile.resultsPerPage * (searchPage + 1), totalResults)
if totalResults == 0 then
if filter.text then
results = {
{
type = "Spacer",
quantity = 2,
},
{
type = "Label",
relativeWidth = 0.4
},
{
type = "Label",
relativeWidth = 0.6,
text = L["No items found"],
fontObject = GameFontNormalLarge,
},
}
else
results = {
{
type = "Spacer",
quantity = 2,
},
{
type = "Label",
relativeWidth = 0.05
},
{
type = "Label",
relativeWidth = 0.949,
text = "|cffffffff" .. L["Use the search box and category filters above to search the AuctionDB data."] .. "|r",
fontObject = GameFontNormalLarge,
},
}
end
end
local classes, subClasses = {}, {}
for i, className in ipairs({ GetAuctionItemClasses() }) do
classes[i] = className
subClasses[i] = {}
for j, subClassName in ipairs({ GetAuctionItemSubClasses(i) }) do
subClasses[i][j] = subClassName
end
tinsert(subClasses[i], "")
end
tinsert(classes, "")
local lastScanInfo
if TSM.db.factionrealm.lastCompleteScan > 0 then
if TSM.db.factionrealm.lastCompleteScan == TSM.db.factionrealm.appDataUpdate then
lastScanInfo = format(L["Last updated from the TSM Application %s ago."], SecondsToTime(time() - TSM.db.factionrealm.appDataUpdate))
else
lastScanInfo = format(L["Last updated from in-game scan %s ago."], SecondsToTime(time() - TSM.db.factionrealm.lastCompleteScan))
end
else
lastScanInfo = L["No scans found."]
end
local page = {
{
type = "SimpleGroup",
layout = "Flow",
fullHeight = true,
children = {
{
type = "Label",
text = L["You can use this page to lookup an item or group of items in the AuctionDB database. Note that this does not perform a live search of the AH."],
relativeWidth = 1,
},
{
type = "Label",
text = lastScanInfo,
relativeWidth = 1,
},
{
type = "HeadingLine",
},
{
type = "EditBox",
label = SEARCH,
settingInfo = {filter, "text"},
relativeWidth = 0.49,
callback = function(_, _, value)
searchPage = 0
container:ReloadTab()
end,
tooltip = L["Any items in the AuctionDB database that contain the search phrase in their names will be displayed."],
},
{
type = "Dropdown",
label = L["Item Type Filter"],
list = classes,
value = filter.class or #classes,
relativeWidth = 0.25,
callback = function(self, _, value)
filter.text = TSMAPI:StrEscape(filter.text or "")
if value ~= filter.class then
filter.subClass = nil
end
if value == #classes then
filter.class = nil
else
filter.class = value
end
searchPage = 0
container:ReloadTab()
end,
tooltip = L["You can filter the results by item type by using this dropdown. For example, if you want to search for all herbs, you would select \"Trade Goods\" in this dropdown and \"Herbs\" as the subtype filter."],
},
{
type = "Dropdown",
label = L["Item SubType Filter"],
disabled = filter.class == nil or (subClasses[filter.class] and #subClasses[filter.class] == 0),
list = subClasses[filter.class or 0],
value = filter.subClass or #(subClasses[filter.class or 0] or {}),
relativeWidth = 0.25,
callback = function(_, _, value)
if value == #subClasses[filter.class] then
filter.subClass = nil
else
filter.subClass = value
end
searchPage = 0
container:ReloadTab()
end,
tooltip = L["You can filter the results by item subtype by using this dropdown. For example, if you want to search for all herbs, you would select \"Trade Goods\" in the item type dropdown and \"Herbs\" in this dropdown."],
},
{
type = "Label",
relativeWidth = 0.15
},
{
type = "Button",
text = REFRESH,
relativeWidth = 0.2,
callback = function()
searchPage = 0
Config:UpdateItems()
container:ReloadTab()
container:DoLayout()
end,
tooltip = L["Refreshes the current search results."],
},
{
type = "Label",
relativeWidth = 0.15
},
{
type = "Icon",
image = "Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Up",
width = 24,
imageWidth = 24,
imageHeight = 24,
disabled = minIndex == 1,
callback = function(self)
searchPage = searchPage - 1
container:ReloadTab()
end,
tooltip = L["Previous Page"],
},
{
type = "Label",
relativeWidth = 0.03
},
{
type = "Label",
text = format(L["Items %s - %s (%s total)"], minIndex, maxIndex, totalResults),
relativeWidth = 0.35,
},
{
type = "Icon",
image = "Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up",
width = 24,
imageWidth = 24,
imageHeight = 24,
disabled = maxIndex == totalResults,
callback = function(self)
searchPage = searchPage + 1
container:ReloadTab()
end,
tooltip = L["Next Page"],
},
{
type = "HeadingLine"
},
{
type = "SimpleGroup",
fullHeight = true,
layout = "Flow",
children = results,
},
},
},
}
TSMAPI:BuildPage(container, page)
local stParent = container.children[1].children[#container.children[1].children].frame
if not Config.st then
local stCols = {
{
name = L["Item Link"],
width = 0.40,
},
{
name = L["Minimum Buyout"],
width = 0.19,
},
{
name = L["Market Value"],
width = 0.19,
},
{
name = L["Last Scanned"],
width = 0.22,
},
}
local handlers = {
OnClick = function(_, data, _, button)
if data and IsShiftKeyDown() and button == "RightButton" then
TSM.data[data.itemID] = nil
TSM:Printf(L["Removed %s from AuctionDB."], select(2, GetItemInfo(data.itemID)) or data.itemID)
end
end,
OnEnter = function(_, data, self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetHyperlink("item:" .. data.itemID)
GameTooltip:AddLine("\n")
GameTooltip:AddLine(TSMAPI.Design:GetInlineColor("link2") .. L["Shift-Right-Click to clear all data for this item from AuctionDB."] .. "|r")
GameTooltip:Show()
end,
OnLeave = function()
GameTooltip:ClearLines()
GameTooltip:Hide()
end
}
Config.st = TSMAPI:CreateScrollingTable(stParent, stCols, handlers)
Config.st:EnableSorting(true)
end
Config:UnhookAll()
Config:HookScript(stParent, "OnHide", function() Config:UnhookAll() Config.st:Hide() end)
Config.st:Show()
Config.st:SetParent(stParent)
Config.st:SetAllPoints()
Config.st:SetData(searchDataTmp)
end
function Config:GetSearchData()
Config:UpdateItems()
local stData = {}
local totalResults = #items
local minIndex = searchPage * TSM.db.profile.resultsPerPage + 1
local maxIndex = min(TSM.db.profile.resultsPerPage * (searchPage + 1), totalResults)
if totalResults > 0 then
for i = minIndex, maxIndex do
local itemID = items[i]
TSM:DecodeItemData(itemID)
local data = TSM.data[itemID]
local timeDiff = data.lastScan and SecondsToTime(time() - data.lastScan)
local name, link = GetItemInfo(itemID)
tinsert(stData, {
cols = {
{
value = link or "???",
sortArg = name or "",
},
{
value = TSMAPI:FormatTextMoney(data.minBuyout, "|cffffffff") or "---",
sortArg = data.minBuyout or 0,
},
{
value = TSMAPI:FormatTextMoney(data.marketValue, "|cffffffff") or "---",
sortArg = data.marketValue or 0,
},
{
value = (timeDiff and TSMAPI.Design:GetInlineColor("link2") .. format(L["%s ago"], timeDiff) .. "|r" or TSMAPI.Design:GetInlineColor("link2") .. "---|r"),
sortArg = data.lastScan and (time() - data.lastScan) or 0,
},
},
itemID = itemID,
})
end
end
return stData
end
function Config:LoadOptions(container)
local page = {
{
type = "ScrollFrame",
layout = "Flow",
children = {
{
type = "InlineGroup",
title = "General Options",
layout = "Flow",
children = {
{
type = "CheckBox",
label = L["Show AuctionDB AH Tab (Requires Reload)"],
settingInfo = { TSM.db.profile, "showAHTab" },
relativeWidth = 0.5,
tooltip = L["If checked, AuctionDB will add a tab to the AH to allow for in-game scans. If you are using the TSM app exclusively for your scans, you may want to hide it by unchecking this option. This option requires a reload to take effect."],
},
},
},
{
type = "InlineGroup",
title = L["Search Options"],
layout = "Flow",
children = {
{
type = "EditBox",
label = L["Items per page"],
value = TSM.db.profile.resultsPerPage,
relativeWidth = 0.2,
callback = function(_, _, value)
value = tonumber(value)
if value and value <= 500 and value >= 5 then
TSM.db.profile.resultsPerPage = value
else
TSM:Print(L["Invalid value entered. You must enter a number between 5 and 500 inclusive."])
end
end,
tooltip = L["This determines how many items are shown per page in results area of the \"Search\" tab of the AuctionDB page in the main TSM window. You may enter a number between 5 and 500 inclusive. If the page lags, you may want to decrease this number."],
},
{
type = "Label",
relativeWidth = 0.1
},
{
type = "Dropdown",
label = L["Sort items by"],
list = { ["name"] = NAME, ["rarity"] = RARITY, ["ilvl"] = STAT_AVERAGE_ITEM_LEVEL, ["minlvl"] = L["Item MinLevel"], ["marketvalue"] = L["Market Value"], ["minbuyout"] = L["Minimum Buyout"] },
settingInfo = {TSM.db.profile, "resultsSortMethod"},
relativeWidth = 0.34,
tooltip = L["Select how you would like the search results to be sorted. After changing this option, you may need to refresh your search results by hitting the \"Refresh\" button."],
},
{
type = "Label",
relativeWidth = 0.02
},
{
type = "Dropdown",
label = L["Result Order:"],
settingInfo = {TSM.db.profile, "resultsSortOrder"},
list = { ascending = L["Ascending"], descending = L["Descending"] },
relativeWidth = 0.3,
tooltip = L["Select whether to sort search results in ascending or descending order."],
},
{
type = "CheckBox",
label = L["Hide poor quality items"],
settingInfo = { TSM.db.profile, "hidePoorQualityItems" },
tooltip = L["If checked, poor quality items won't be shown in the search results."],
},
},
},
},
},
}
TSMAPI:BuildPage(container, page)
end
function Config:LoadTooltipOptions(container)
local page = {
{
type = "SimpleGroup",
layout = "Flow",
fullHeight = true,
children = {
{
type = "CheckBox",
label = L["Enable display of AuctionDB data in tooltip."],
relativeWidth = 1,
settingInfo = { TSM.db.profile, "tooltip" },
callback = function(_, _, value)
container:ReloadTab()
end,
},
{
type = "CheckBox",
label = L["Display market value in tooltip."],
disabled = not TSM.db.profile.tooltip,
settingInfo = { TSM.db.profile, "marketValueTooltip" },
tooltip = L["If checked, the market value of the item will be displayed"],
},
{
type = "CheckBox",
label = L["Display lowest buyout value seen in the last scan in tooltip."],
disabled = not TSM.db.profile.tooltip,
settingInfo = { TSM.db.profile, "minBuyoutTooltip" },
tooltip = L["If checked, the lowest buyout value seen in the last scan of the item will be displayed."],
},
},
},
}
TSMAPI:BuildPage(container, page)
end
+225
View File
@@ -0,0 +1,225 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_AuctionDB --
-- http://www.curse.com/addons/wow/tradeskillmaster_auctiondb --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select(2, ...)
local Data = TSM:NewModule("Data")
-- weight for the market value from X days ago (where X is the index of the table)
local WEIGHTS = {[0] = 132, [1] = 125, [2] = 100, [3] = 75, [4] = 45, [5] = 34, [6] = 33,
[7] = 38, [8] = 28, [9] = 21, [10] = 15, [11] = 10, [12] = 7, [13] = 5, [14] = 4}
local MIN_PERCENTILE = 0.15 -- consider at least the lowest 15% of auctions
local MAX_PERCENTILE = 0.30 -- consider at most the lowest 30% of auctions
local MAX_JUMP = 1.2 -- between the min and max percentiles, any increase in price over 120% will trigger a discard of remaining auctions
function Data:ConvertScansToAvg(scans)
if not scans then return end
-- do a sanity check
if type(scans) == "number" then
scans = {scans}
end
if not scans.avg then
local total, num = 0, 0
for _, value in ipairs(scans) do
total = total + value
num = num + 1
end
scans.avg = floor(total/num+0.5)
scans.count = num
end
return scans
end
function Data:GetDay(t)
t = t or time()
return floor(t / (60*60*24))
end
-- Updates all the market values
function Data:UpdateMarketValue(itemData)
local day = Data:GetDay()
local scans = CopyTable(itemData.scans)
itemData.scans = {}
for i=0, 14 do
if i <= TSM.MAX_AVG_DAY then
if type(scans[day-i]) == "number" then
scans[day-i] = {avg=scans[day-i], count=1}
end
itemData.scans[day-i] = scans[day-i] and CopyTable(scans[day-i])
else
local dayScans = scans[day-i]
if type(dayScans) == "table" then
if dayScans.avg then
itemData.scans[day-i] = dayScans.avg
else
-- old method
itemData.scans[day-i] = Data:GetAverage(dayScans)
end
elseif dayScans then
itemData.scans[day-i] = dayScans
end
end
end
itemData.marketValue = Data:GetMarketValue(itemData.scans)
end
-- gets the average of a list of numbers
-- DEPRECATED
function Data:GetAverage(data)
local total, num = 0, 0
for _, marketValue in ipairs(data) do
total = total + marketValue
num = num + 1
end
return num > 0 and floor((total / num) + 0.5)
end
-- gets the market value given a set of scans
function Data:GetMarketValue(scans)
local day = Data:GetDay()
local totalAmount, totalWeight = 0, 0
for i=0, 14 do
local dayScans = scans[day-i]
if dayScans then
local dayMarketValue
if type(dayScans) == "table" then
if dayScans.avg then
dayMarketValue = dayScans.avg
else
-- old method
dayMarketValue = Data:GetAverage(scans)
end
else
dayMarketValue = dayScans
end
if dayMarketValue then
totalAmount = totalAmount + (WEIGHTS[i] * dayMarketValue)
totalWeight = totalWeight + WEIGHTS[i]
end
end
end
for i in ipairs(scans) do
if i < day - 14 then
scans[i] = nil
end
end
return totalWeight > 0 and floor(totalAmount / totalWeight + 0.5) or 0
end
function Data:ProcessData(scanData, groupItems)
if TSM.processingData then return TSMAPI:CreateTimeDelay(0.2, function() Data:ProcessData(scanData, groupItems) end) end
-- wipe all the minBuyout data
if groupItems then
for itemString in pairs(groupItems) do
local itemID = TSMAPI:GetItemID(itemString)
if TSM.data[itemID] then
TSM:DecodeItemData(itemID)
TSM.data[itemID].minBuyout = nil
TSM:EncodeItemData(itemID)
end
end
else
for itemID, data in pairs(TSM.data) do
TSM:DecodeItemData(itemID)
data.minBuyout = nil
TSM:EncodeItemData(itemID)
end
end
local scanDataList = {}
for itemID, data in pairs(scanData) do
tinsert(scanDataList, {itemID, data})
end
-- go through each item and figure out the market value / update the data table
local index = 1
local day = Data:GetDay()
local function DoDataProcessing()
for i = 1, 500 do
if index > #scanDataList then
TSMAPI:CancelFrame("adbProcessDelay")
TSM.processingData = nil
break
end
local itemID, data = unpack(scanDataList[index])
TSM:DecodeItemData(itemID)
TSM.data[itemID] = TSM.data[itemID] or {scans={}, lastScan = 0}
local marketValue = Data:CalculateMarketValue(data.records)
local scanData = TSM.data[itemID].scans
scanData[day] = scanData[day] or {avg=0, count=0}
if type(scanData[day]) == "number" then
-- this should never happen...
scanData[day] = {scanData[day]}
end
scanData[day].avg = scanData[day].avg or 0
scanData[day].count = scanData[day].count or 0
if #scanData[day] > 0 then
scanData[day] = Data:ConvertScansToAvg(scanData[day])
end
scanData[day].avg = floor((scanData[day].avg * scanData[day].count + marketValue) / (scanData[day].count + 1) + 0.5)
scanData[day].count = scanData[day].count + 1
TSM.data[itemID].lastScan = TSM.db.factionrealm.lastCompleteScan
TSM.data[itemID].minBuyout = data.minBuyout > 0 and data.minBuyout or nil
TSM.data[itemID].quantity = data.quantity
Data:UpdateMarketValue(TSM.data[itemID])
TSM:EncodeItemData(itemID)
index = index + 1
end
end
TSM.processingData = true
TSMAPI:CreateTimeDelay("adbProcessDelay", 0, DoDataProcessing, 0.1)
end
function Data:CalculateMarketValue(records)
local totalNum, totalBuyout = 0, 0
local numRecords = #records
for i=1, numRecords do
totalNum = i - 1
if i ~= 1 and i > numRecords*MIN_PERCENTILE and (i > numRecords*MAX_PERCENTILE or records[i] >= MAX_JUMP*records[i-1]) then
break
end
totalBuyout = totalBuyout + records[i]
if i == numRecords then
totalNum = i
end
end
local uncorrectedMean = totalBuyout / totalNum
local varience = 0
for i=1, totalNum do
varience = varience + (records[i]-uncorrectedMean)^2
end
local stdDev = sqrt(varience/totalNum)
local correctedTotalNum, correctedTotalBuyout = 1, uncorrectedMean
for i=1, totalNum do
if abs(uncorrectedMean - records[i]) < 1.5*stdDev then
correctedTotalNum = correctedTotalNum + 1
correctedTotalBuyout = correctedTotalBuyout + records[i]
end
end
local correctedMean = floor(correctedTotalBuyout / correctedTotalNum + 0.5)
return correctedMean
end