AuctioneerSuite/Auc-Stat-Simple/StatSimple.lua
2026-04-13 17:48:13 -04:00

675 lines
26 KiB
Lua

--[[
Auctioneer - StatSimple
Version: 5.7.4568 (KillerKoala)
Revision: $Id: StatSimple.lua 4840 2010-08-04 21:44:00Z Nechckn $
URL: http://auctioneeraddon.com/
This is an addon for World of Warcraft that adds statistical history to the auction data that is collected
when the auction is scanned, so that you can easily determine what price
you will be able to sell an item for at auction or at a vendor whenever you
mouse-over an item in the game
License:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program(see GPL.txt); if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Note:
This AddOn's source code is specifically designed to work with
World of Warcraft's interpreted AddOn system.
You have an implicit license to use this AddOn with these facilities
since that is its designated purpose as per:
http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
--]]
if not AucAdvanced then return end
local libType, libName = "Stat", "Simple"
local lib,parent,private = AucAdvanced.NewModule(libType, libName)
if not lib then return end
local aucPrint,decode,_,_,replicate,_,get,set,default,debugPrint,fill, _TRANS = AucAdvanced.GetModuleLocals()
local GetFaction = AucAdvanced.GetFaction
-- Eliminate some global lookups
local select = select
local sqrt = sqrt
local ipairs = ipairs
local unpack = unpack
local tinsert = table.insert
local assert = assert
local tonumber = tonumber
local pairs = pairs
local type,time,wipe,ceil = type,time,wipe,ceil
local concat=table.concat
local strsplit,strfind=strsplit,strfind
-- GLOBALS: AucAdvancedStatSimpleData
-- local reference to our saved stats table
local SSRealmData
function lib.CommandHandler(command, ...)
local serverKey = GetFaction()
local _,_,keyText = AucAdvanced.SplitServerKey(serverKey)
if (command == "help") then
aucPrint(_TRANS('SIMP_Help_SlashHelp1') ) --Help for Auctioneer Advanced - Simple
local line = AucAdvanced.Config.GetCommandLead(libType, libName)
aucPrint(line, "help}} - ".._TRANS('SIMP_Help_SlashHelp2') ) --this Simple help
aucPrint(line, "clear}} - ".._TRANS('SIMP_Help_SlashHelp3'):format(keyText) ) --clear current %s Simple price database
aucPrint(line, "push}} - ".._TRANS('SIMP_Help_SlashHelp4'):format(keyText) ) --force the %s Simple daily stats to archive (start a new day)
elseif (command == "clear") then
lib.ClearData(serverKey)
elseif (command == "push") then
aucPrint(_TRANS('SIMP_Help_SlashHelp6'):format(keyText) ) --Archiving {{%s}} daily stats and starting a new day
private.PushStats(serverKey)
end
end
function lib.Processor(callbackType, ...)
if (callbackType == "tooltip") then
private.ProcessTooltip(...)
elseif (callbackType == "config") then
--Called when you should build your Configator tab.
private.SetupConfigGui(...)
end
end
lib.Processors = {}
lib.Processors.tooltip = lib.Processor
lib.Processors.config = lib.Processor
lib.ScanProcessors = {}
function lib.ScanProcessors.create(operation, itemData, oldData)
if not get("stat.simple.enable") then return end
-- This function is responsible for processing and storing the stats after each scan
-- Note: itemData gets reused over and over again, so do not make changes to it, or use
-- it in places where you rely on it. Make a deep copy of it if you need it after this
-- function returns.
-- We're only interested in items with buyouts.
local buyout = itemData.buyoutPrice
if not buyout or buyout == 0 then return end
local buyoutper = ceil(buyout/itemData.stackSize)
-- In this case, we're only interested in the initial create, other
-- Get the signature of this item and find it's stats.
local itemType, itemId, property, factor = AucAdvanced.DecodeLink(itemData.link)
if (factor ~= 0) then property = property.."x"..factor end
local data = private.GetPriceData(GetFaction())
if not data.daily[itemId] then data.daily[itemId] = "" end
local stats = private.UnpackStats(data.daily[itemId])
if not stats[property] then stats[property] = { 0, 0 , buyoutper } end
if not stats[property][3] then stats[property][3] = buyoutper end
stats[property][1] = stats[property][1] + buyout
stats[property][2] = stats[property][2] + itemData.stackSize
if stats[property][3] > buyoutper then stats[property][3] = buyoutper end
data.daily[itemId] = private.PackStats(stats)
end
local dataset = {}
function lib.GetPrice(hyperlink, serverKey)
if not get("stat.simple.enable") then return end
local linkType,itemId,property,factor = AucAdvanced.DecodeLink(hyperlink)
if (linkType ~= "item") then return end
if (factor ~= 0) then property = property.."x"..factor end
serverKey = serverKey or GetFaction()
local data = private.GetPriceData(serverKey)
local dayTotal, dayCount, dayAverage, minBuyout = 0,0,0,0
local seenDays, seenCount, avg3, avg7, avg14, avgmins = 0,0,0,0,0,0
-- Stddev calculations for market price
local count=0 -- index into dataset[] (living static outside the function)
local daysUsed = 0 -- used to keep running track of which daily averages we have
if data.daily[itemId] then
local stats = private.UnpackStats(data.daily[itemId])
if stats[property] then
dayTotal, dayCount, minBuyout = unpack(stats[property])
dayAverage = dayTotal/dayCount
if not minBuyout then minBuyout = 0 end
-- Stddev calculations for market price
count=count+1
dataset[count] = dayAverage
daysUsed = 1
end
end
if data.means[itemId] then
local stats = private.UnpackStats(data.means[itemId])
if stats[property] then
seenDays, seenCount, avg3, avg7, avg14, avgmins = unpack(stats[property])
if not avgmins then avgmins = 0 end
-- Stddev calculations for market price
if seenDays >= 3 then
for n = 1, 3-daysUsed do
count=count+1
dataset[count] = avg3
end
daysUsed = 3
end
if seenDays >= 7 then
for n = 1, 7-daysUsed do
count=count+1
dataset[count] = avg7
end
daysUsed = 7
end
if seenDays >= 14 then
for n = 1, 14-daysUsed do
count=count+1
dataset[count] = avg14
end
daysUsed = 14
end
end
end
local mean = 0
if count > 0 then
for n=1,count do
mean=mean+dataset[n]
end
mean = mean/count
end
local variance = 0
if count == 1 then
variance = 0
else
for n=1,count do
variance = variance + (mean - dataset[n])^2;
end
variance = sqrt(variance/(count-1))
end
return dayAverage, avg3, avg7, avg14, minBuyout, avgmins, false, dayTotal, dayCount, seenDays, seenCount, mean, variance
end
function lib.GetPriceColumns()
return "Daily Avg", "3 Day Avg", "7 Day Avg", "14 Day Avg", "Min BO", "Avg MBO", false, "Daily Total", "Daily Count", "Seen Days", "Seen Count", "Mean", "StdDev"
end
local array = {}
function lib.GetPriceArray(hyperlink, serverKey)
if not get("stat.simple.enable") then return end
-- Clean out the old array
wipe(array)
-- Get our statistics
local dayAverage, avg3, avg7, avg14, minBuyout, avgmins, _, dayTotal, dayCount, seenDays, seenCount, mean, stddev = lib.GetPrice(hyperlink, serverKey)
--if nothing is returned, return nil
if not dayCount then return end
-- If reportsafe is on use the mean of all 14 day samples. Else use the "traditional" Simple values.
if not get("stat.simple.reportsafe") then
if (avg3 and seenDays > 3) or dayCount == 0 then
array.price = avg3
elseif dayCount > 0 then
array.price = dayAverage
end
else
array.price = mean
end
array.stddev = stddev
array.seen = seenCount
array.avgday = dayAverage
array.avg3 = avg3
array.avg7 = avg7
array.avg14 = avg14
array.mbo = minBuyout
array.avgmins = avgmins
array.daytotal = dayTotal
array.daycount = dayCount
array.seendays = seenDays
-- Return a temporary array. Data in this array is
-- only valid until this function is called again.
return array
end
local bellCurve = AucAdvanced.API.GenerateBellCurve();
-- Gets the PDF curve for a given item. This curve indicates
-- the probability of an item's mean price. Uses an estimation
-- of the normally distributed bell curve by performing
-- calculations on the daily, 3-day, 7-day, and 14-day averages
-- stored by SIMP
-- @param hyperlink The item to generate the PDF curve for
-- @param serverKey The realm-faction key from which to look up the data
-- @return The PDF for the requested item, or nil if no data is available
-- @return The lower limit of meaningful data for the PDF (determined
-- as the mean minus 5 standard deviations)
-- @return The upper limit of meaningful data for the PDF (determined
-- as the mean plus 5 standard deviations)
function lib.GetItemPDF(hyperlink, serverKey)
-- TODO: This is an estimate. Can we touch this up later? Especially the stddev==0 case
if not get("stat.simple.enable") then return end
-- Calculate the SE estimated standard deviation & mean
local dayAverage, avg3, avg7, avg14, minBuyout, avgmins, _, dayTotal, dayCount, seenDays, seenCount, mean, stddev = lib.GetPrice(hyperlink, serverKey)
if seenCount == 0 or stddev ~= stddev or mean ~= mean or not mean or mean == 0 then
return ; -- No available data or cannot estimate
end
-- If the standard deviation is zero, we'll have some issues, so we'll estimate it by saying
-- the std dev is 100% of the mean divided by square root of number of views
if stddev == 0 then stddev = mean / sqrt(seenCount); end
-- Calculate the lower and upper bounds as +/- 3 standard deviations
local lower, upper = mean - 3*stddev, mean + 3*stddev;
bellCurve:SetParameters(mean, stddev);
return bellCurve, lower, upper;
end
function lib.OnLoad(addon)
if SSRealmData then return end
-- Set defaults
default("stat.simple.tooltip", false)
default("stat.simple.avg3", false)
default("stat.simple.avg7", false)
default("stat.simple.avg14", false)
default("stat.simple.minbuyout", true)
default("stat.simple.avgmins", true)
default("stat.simple.quantmul", true)
default("stat.simple.enable", true)
default("stat.simple.reportsafe", false)
-- Load and check data
private.InitData()
end
function lib.ClearItem(hyperlink, serverKey)
local linkType, itemID, property, factor = AucAdvanced.DecodeLink(hyperlink)
if linkType ~= "item" then
return
end
if (factor ~= 0) then property = property.."x"..factor end
serverKey = serverKey or GetFaction ()
local data = private.GetPriceData (serverKey)
local cleareditem = false
if data.daily[itemID] then
local stats = private.UnpackStats (data.daily[itemID])
if stats[property] then
stats[property] = nil
cleareditem = true
data.daily[itemID] = private.PackStats (stats)
end
end
if data.means[itemID] then
local stats = private.UnpackStats (data.means[itemID])
if stats[property] then
stats[property] = nil
cleareditem = true
data.means[itemID] = private.PackStats (stats)
end
end
if cleareditem then
local _, _, keyText = AucAdvanced.SplitServerKey(serverKey)
aucPrint(_TRANS('SIMP_Help_SlashHelpClearingData'):format(libType, hyperlink, keyText)) --%s - Simple: clearing data for %s for {{%s}}
end
end
function private.SetupConfigGui(gui)
local id = gui:AddTab(lib.libName, lib.libType.." Modules" )
gui:AddHelp(id, "what simple stats",
_TRANS('SIMP_Help_SimpleStats') ,--What are simple stats?
_TRANS('SIMP_Help_SimpleStatsAnswer')
)--Simple stats are the numbers that are generated by the Simple module, the Simple module averages all of the prices for items that it sees and provides moving 3, 7, and 14 day averages. It also provides daily minimum buyout along with a running average minimum buyout within 10% variance.
--all options in here will be duplicated in the tooltip frame
function private.addTooltipControls(id)
gui:AddHelp(id, "what moving day average",
_TRANS('SIMP_Help_MovingAverage') , --What does \'moving day average\' mean?
_TRANS('SIMP_Help_MovingAverageAnswer') --Moving average means that it places more value on yesterday\'s moving averagethan today\'s average. The determined amount is then used for tomorrow\'s moving average calculation.
)
gui:AddHelp(id, "how day average calculated",
_TRANS('SIMP_Help_HowAveragesCalculated') , --How is the moving day averages calculated exactly?
_TRANS('SIMP_Help_HowAveragesCalculatedAnswer') --Todays Moving Average is ((X-1)*YesterdaysMovingAverage + TodaysAverage) / X, where X is the number of days (3,7, or 14).
)
gui:AddHelp(id, "no day saved",
_TRANS('SIMP_Help_NoDaySaved') ,--So you aren't saving a day-to-day average?
_TRANS('SIMP_Help_NoDaySavedAnswer') )--No, that would not only take up space, but heavy calculations on each auction house scan, and this is only a simple model.
gui:AddHelp(id, "minimum buyout",
_TRANS('SIMP_Help_MinimumBuyout') ,--Why do I need to know minimum buyout?
_TRANS('SIMP_Help_MinimumBuyoutAnswer')--While some items will sell very well at average within 2 days, others may sell only if it is the lowest price listed. This was an easy calculation to do, so it was put in this module.
)
gui:AddHelp(id, "average minimum buyout",
_TRANS('SIMP_Help_AverageMinimumBuyout') ,--What's the point in an average minimum buyout?
_TRANS('SIMP_Help_AverageMinimumBuyoutAnswer')--This way you know how good a market is dealing. If the MBO (minimum buyout) is bigger than the average MBO, then it\'s usually a good time to sell, and if the average MBO is greater than the MBO, then it\'s a good time to buy.
)
gui:AddHelp(id, "average minimum buyout variance",
_TRANS('SIMP_Help_MinimumBuyoutVariance') ,--What\'s the \'10% variance\' mentioned earlier for?
_TRANS('SIMP_Help_MinimumBuyoutVarianceAnswer')--If the current MBO is inside a 10% range of the running average, the current MBO is averaged in to the running average at 50% (normal). If the current MBO is outside the 10% range, the current MBO will only be averaged in at a 12.5% rate.
)
gui:AddHelp(id, "why have variance",
_TRANS('SIMP_Help_WhyVariance') ,--What\'s the point of a variance on minimum buyout?
_TRANS('SIMP_Help_WhyVarianceAnswer') --Because some people put their items on the market for rediculous price (too low or too high), so this helps keep the average from getting out of hand.
)
gui:AddHelp(id, "why multiply stack size simple",
_TRANS('SIMP_Help_WhyMultiplyStack') ,--Why have the option to multiply stack size?
_TRANS('SIMP_Help_WhyMultiplyStackAnswer') --The original Stat-Simple multiplied by the stack size of the item, but some like dealing on a per-item basis.
)
gui:AddControl(id, "Header", 0, _TRANS('SIMP_Interface_SimpleOptions') )--Simple options'
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
gui:AddControl(id, "Checkbox", 0, 1, "stat.simple.enable", _TRANS('SIMP_Interface_EnableSimpleStats') )--Enable Simple Stats
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_EnableSimpleStats') )--Allow Simple Stats to gather and return price data
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
gui:AddControl(id, "Checkbox", 0, 4, "stat.simple.tooltip", _TRANS('SIMP_Interface_Show') )--Show simple stats in the tooltips?
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_Show') )--Toggle display of stats from the Simple module on or off
gui:AddControl(id, "Checkbox", 0, 6, "stat.simple.avg3", _TRANS('SIMP_Interface_Toggle3Day') )--Display Moving 3 Day Average
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_Toggle3Day') )--Toggle display of 3-Day average from the Simple module on or off
gui:AddControl(id, "Checkbox", 0, 6, "stat.simple.avg7", _TRANS('SIMP_Interface_Toggle7Day') )--Display Moving 7 Day Average
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_Toggle7Day') )--Toggle display of 7-Day average from the Simple module on or off
gui:AddControl(id, "Checkbox", 0, 6, "stat.simple.avg14", _TRANS('SIMP_Interface_Toggle14Day') )--Display Moving 14 Day Average
gui:AddTip(id,_TRANS( 'SIMP_HelpTooltip_Toggle14Day') )--Toggle display of 14-Day average from the Simple module on or off
gui:AddControl(id, "Checkbox", 0, 6, "stat.simple.minbuyout", _TRANS('SIMP_Interface_MinBuyout') )--Display Daily Minimum Buyout
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_MinBuyout') )--Toggle display of Minimum Buyout from the Simple module on or offMultiplies by current stack size if on
gui:AddControl(id, "Checkbox", 0, 6, "stat.simple.avgmins", _TRANS('SIMP_Interface_MinBuyoutAverage') )--Display Average of Daily Minimum Buyouts
gui:AddTip(id,_TRANS( 'SIMP_HelpTooltip_MinBuyoutAverage') )--Toggle display of Minimum Buyout average from the Simple module on or off
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
gui:AddControl(id, "Checkbox", 0, 4, "stat.simple.quantmul", _TRANS('SIMP_Interface_MultiplyStack') )--Multiply by stack size
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_MultiplyStack') )--Multiplies by current stack size if on
gui:AddControl(id, "Checkbox", 0, 4, "stat.simple.reportsafe", _TRANS('SIMP_Interface_LongerAverage') )--Report safer prices for low volume items
gui:AddTip(id, _TRANS('SIMP_HelpTooltip_LongerAverage') )--Returns longer averages (7-day, or even 14-day) for low-volume items
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
end
--This is the Tooltip tab provided by aucadvnced so all tooltip configuration is in one place
local tooltipID = AucAdvanced.Settings.Gui.tooltipID
--now we create a duplicate of these in the tooltip frame
private.addTooltipControls(id)
if tooltipID then private.addTooltipControls(tooltipID) end
end
--[[ Local functions ]]--
function private.ProcessTooltip(tooltip, name, hyperlink, quality, quantity, cost)
-- In this function, you are afforded the opportunity to add data to the tooltip should you so
-- desire. You are passed a hyperlink, and it's up to you to determine whether or what you should
-- display in the tooltip.
if not get("stat.simple.tooltip") then return end
if not quantity or quantity < 1 then quantity = 1 end
if not get("stat.simple.quantmul") then quantity = 1 end
local serverKey, realm, faction = GetFaction () -- realm/faction requested for anticipated changes to add cross-faction tooltips
local dayAverage, avg3, avg7, avg14, minBuyout, avgmins, _, dayTotal, dayCount, seenDays, seenCount = lib.GetPrice(hyperlink, serverKey)
local dispAvg3 = get("stat.simple.avg3")
local dispAvg7 = get("stat.simple.avg7")
local dispAvg14 = get("stat.simple.avg14")
local dispMinB = get("stat.simple.minbuyout")
local dispAvgMBO = get("stat.simple.avgmins")
if (not dayAverage) then return end
if (seenDays + dayCount > 0) then
tooltip:AddLine(_TRANS('SIMP_Tooltip_SimplePrices') )--Simple prices:
if (seenDays > 0) then
if (dayCount>0) then seenDays = seenDays + 1 end
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_SeenNumberDays'):format(seenCount+dayCount, seenDays) ) --Seen {{%s}} over {{%s}} days:
end
if (seenDays > 6) and dispAvg14 then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_14DayAverage') , avg14*quantity)-- 14 day average
end
if (seenDays > 2) and dispAvg7 then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_7DayAverage') , avg7*quantity) -- 7 day average
end
if (seenDays > 0) and dispAvg3 then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_3DayAverage') , avg3*quantity)-- 3 day average
end
if (seenDays > 0) and (avgmins > 0) and dispAvgMBO then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_AverageMBO') , avgmins*quantity)-- Average MBO
end
if (dayCount > 0) then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_SeenToday'):format(dayCount) , dayAverage*quantity) --Seen {{%s}} today:
end
if (dayCount > 0) and (minBuyout > 0) and dispMinB then
tooltip:AddLine(" ".._TRANS('SIMP_Tooltip_TodaysMBO') , minBuyout*quantity)-- Today's Min BO
end
end
end
-- This is a function which migrates the data from a daily average to the
-- Exponential Moving Averages over the 3, 7 and 14 day ranges.
function private.PushStats(serverKey)
local dailyAvg
local data = private.GetPriceData(serverKey)
local pdata, fdata, temp
for itemId, stats in pairs(data.daily) do
if (itemId ~= "created") then
pdata = private.UnpackStats(stats)
fdata = private.UnpackStats(data.means[itemId] or "")
for property, info in pairs(pdata) do
dailyAvg = info[1] / info[2]
if not info[3] then info[3] = 0 end
if not fdata[property] then
fdata[property] = {
1,
info[2],
("%0.01f"):format(dailyAvg),
("%0.01f"):format(dailyAvg),
("%0.01f"):format(dailyAvg),
("%0.01f"):format(info[3])
}
else
fdata[property][1] = fdata[property][1] + 1
fdata[property][2] = fdata[property][2] + info[2]
fdata[property][3] = ("%0.01f"):format(((fdata[property][3] * 2) + dailyAvg)/3)
fdata[property][4] = ("%0.01f"):format(((fdata[property][4] * 6) + dailyAvg)/7)
fdata[property][5] = ("%0.01f"):format(((fdata[property][5] * 13) + dailyAvg)/14)
if not fdata[property][6] then fdata[property][6] = 0 end
temp = fdata[property][6]
if temp < 1 then
fdata[property][6] = info[3]
else
if info[3] ~= 0 then
if temp < info[3] then
if (temp*10/info[3]) < 9 then
fdata[property][6] = ("%0.01f"):format((temp+info[3])/2)
else
fdata[property][6] = ("%0.01f"):format((temp*7+info[3])/8)
end
else
if (info[3]*10/temp) < 9 then
fdata[property][6] = ("%0.01f"):format((temp+info[3])/2)
else
fdata[property][6] = ("%0.01f"):format((temp*7+info[3])/8)
end
end
end
end
end
end
data.means[itemId] = private.PackStats(fdata)
end
end
data.daily = {created = time()}
end
function private.UnpackStatIter(data, ...)
local c = select("#", ...)
local v
for i = 1, c do
v = select(i, ...)
local property, info = strsplit(":", v)
property = tonumber(property) or property
if (property and info) then
data[property] = {strsplit(";", info)}
local item
for i=1, #data[property] do
item = data[property][i]
data[property][i] = tonumber(item) or item
end
end
end
end
function private.UnpackStats(dataItem)
local data = {}
private.UnpackStatIter(data, strsplit(",", dataItem))
return data
end
local tmp={}
function private.PackStats(data)
local n=0
for property, info in pairs(data) do
n=n+1
tmp[n]=property..":"..concat(info, ";")
end
return concat(tmp,",",1,n)
end
-- The following Functions are the routines used to access the permanent store data
function private.UpgradeDb()
private.UpgradeDb = nil
if type(AucAdvancedStatSimpleData) == "table" and AucAdvancedStatSimpleData.Version == "2.0" then return end
local newSave = {Version = "2.0", RealmData = {}}
-- Will only be run once per user account; however must run smoothly every time
-- Can afford to perform extra type-checking for safety
if type(AucAdvancedStatSimpleData) == "table" and AucAdvancedStatSimpleData.Version == "1.0" then
-- perform upgrade from "1.0" to "2.0"
for realm, realmData in pairs (AucAdvancedStatSimpleData.RealmData) do
if type (realm) == "string" and type (realmData) == "table" then
-- valid stats will only be stored in serverKeys which match realm
local realmPattern = realm.."%-%u%l"
for serverKey, data in pairs (realmData) do
if type (serverKey) == "string" and type (data) == "table" and strfind (serverKey, realmPattern) then
-- found a valid serverKey
-- ensure all required subtables are present
if type (data.means) ~= "table" then
data.means = {}
end
if type (data.daily) ~= "table" then
data.daily = {created = time()}
elseif type (data.daily.created) ~= "number" then
data.daily.created = time()
end
newSave.RealmData[serverKey] = data
end
end
end
end
end
AucAdvancedStatSimpleData = newSave
end
function lib.ClearData(serverKey)
serverKey = serverKey or GetFaction()
if AucAdvanced.API.IsKeyword(serverKey, "ALL") then
wipe(SSRealmData)
aucPrint(_TRANS('SIMP_Interface_ClearingSimple').." {{".._TRANS("ADV_Interface_AllRealms").."}}") --Clearing Simple stats for // All realms
elseif SSRealmData[serverKey] then
local _,_,keyText = AucAdvanced.SplitServerKey(serverKey)
keyText = keyText or tostring(serverKey) -- avoid display error if database entry is not a valid serverKey (due to minor database corruption)
SSRealmData[serverKey] = nil
aucPrint(_TRANS('SIMP_Interface_ClearingSimple').." {{"..keyText.."}}") --Clearing Simple stats for
end
end
function private.GetPriceData(serverKey)
local data = SSRealmData[serverKey]
if not data then
if not AucAdvanced.SplitServerKey(serverKey) then
error("Invalid serverKey passed to Stat-Simple")
end
data = {means = {}, daily = {created = time ()}}
SSRealmData[serverKey] = data
end
return data
end
function private.InitData()
private.InitData = nil
-- Load data
private.UpgradeDb()
SSRealmData = AucAdvancedStatSimpleData.RealmData
if not SSRealmData then
SSRealmData = {} -- dummy value to avoid more errors - will not get saved
error("Error loading or creating StatSimple database")
end
-- Note: database errors can occur if user tries to run an older version of StatSimple after the database is upgraded.
for serverKey, data in pairs (SSRealmData) do
if type(serverKey) ~= "string" or not strfind (serverKey, ".%-%u%l") then
-- not a valid serverKey - remove it
SSRealmData[serverKey] = nil
else
-- aggressive checks to strip out any data that is the wrong type
for key, _ in pairs (data) do
if key ~= "means" and key ~= "daily" then
data[key] = nil
end
end
if type(data.means) == "table" then
for id, packed in pairs (data.means) do
if type(id) ~= "number" or type(packed) ~= "string" then
data.means[id] = nil
end
end
else
data.means = {}
end
if type(data.daily) == "table" then
for id, packed in pairs (data.daily) do
if id ~= "created" and (type(id) ~= "number" or type(packed) ~= "string") then
data.daily[id] = nil
end
end
if type(data.daily.created) ~= "number" then
data.daily.created = time ()
end
else
data.daily = {created = time()}
end
-- database maintenance
if time() - data.daily.created > 3600*16 then
-- This data is more than 16 hours old, we classify this as "yesterday's data"
private.PushStats(serverKey)
end
end
end
end
AucAdvanced.RegisterRevision("$URL: http://svn.norganna.org/auctioneer/branches/5.9/Auc-Stat-Simple/StatSimple.lua $", "$Rev: 4840 $")