Advertisement
Guest User

TradeSkillMaster.lua

a guest
Sep 23rd, 2019
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.20 KB | None | 0 0
  1. -- ------------------------------------------------------------------------------ --
  2. -- TradeSkillMaster --
  3. -- http://www.curse.com/addons/wow/tradeskill-master --
  4. -- --
  5. -- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
  6. -- All Rights Reserved* - Detailed license information included with addon. --
  7. -- ------------------------------------------------------------------------------ --
  8.  
  9. -- This is the main TSM file that holds the majority of the APIs that modules will use.
  10.  
  11. local TSM = TSMAPI_FOUR.Addon.New(...)
  12. local LibRealmInfo = LibStub("LibRealmInfo")
  13. local LibDBIcon = LibStub("LibDBIcon-1.0")
  14. local L = TSM.L
  15. local private = { appInfo = nil }
  16. TSMAPI = {Operations={}, Settings={}}
  17. local APP_INFO_REQUIRED_KEYS = { "version", "lastSync", "message", "news" }
  18. local LOGOUT_TIME_WARNING_THRESHOLD_MS = 20
  19. do
  20. -- show a message if we were updated
  21. if GetAddOnMetadata("TradeSkillMaster", "Version") ~= "v4.8.9" then
  22. message("TSM was just updated and may not work properly until you restart WoW.")
  23. end
  24. end
  25.  
  26. -- Changelog:
  27. -- [6] added 'global.locale' key
  28. -- [7] changed default value of 'tsmItemTweetEnabled' to false
  29. -- [8] added 'global.itemCacheVersion' key
  30. -- [9] removed 'global.itemCacheVersion' key, added 'global.clientVersion' key
  31. -- [10] first TSM4 version - combined all module settings into a single DB
  32. -- [11] added profile.internalData.createdDefaultOperations
  33. -- [12] added global.shoppingOptions.pctSource
  34. -- [13] added profile.internalData.{managementGroupTreeContext,auctioningGroupTreeContext,shoppingGroupTreeContext}
  35. -- [14] added global.userData.savedAuctioningSearches
  36. -- [15] added global.coreOptions.bankUITab, profile.coreOptions.{bankUIBankFramePosition,bankUIGBankFramePosition}
  37. -- [16] moved profile.coreOptions.{bankUIBankFramePosition,bankUIGBankFramePosition} to profile.internalData.{bankUIBankFramePosition,bankUIGBankFramePosition}
  38. -- [17] added global.internalData.{mainUIFrameContext,auctionUIFrameContext,craftingUIFrameContext}
  39. -- [18] removed global.internalData.itemStringLookup
  40. -- [19] added sync scope (initially with internalData.{classKey,bagQuantity,bankQuantity,reagentBankQuantity,auctionQuantity,mailQuantity}), removed factionrealm.internalData.{syncMetadata,accountKey,inventory,characters} and factionrealm.coreOptions.syncAccounts, added global.debug.chatLoggingEnabled
  41. -- [20] added global.tooltipOptions.enabled
  42. -- [21] added global.craftingOptions.{profitPercent,questSmartCrafting,queueSort}
  43. -- [22] added global.coreOptions.cleanGuildBank
  44. -- [23] changed global.shoppingOptions.maxDeSearchPercent default to 100
  45. -- [24] added global.auctioningOptions.{showAuctionDBTab,openAllBags,ahRowDisplay}
  46. -- [25] split realm.internalData.goldLog into sync.internalData.goldLog and factionrealm.internalData.guildGoldLog
  47. -- [26] added profile.internalData.{shoppingTabGroupContext,auctioningTabGroupContext}
  48. -- [27] added char.internalData.craftingCooldowns
  49. -- [28] added global.internalData.mailingUIFrameContext
  50. -- [29] added global.internalData.vendoringUIFrameContext
  51. -- [30] added global.internalData.bankingUIFrameContext
  52. -- [31] changed global.internalData.bankingUIFrameContext default (isOpen = true), added profile.internalData.{bankingWarehousingGroupTreeContext,bankingAuctioningGroupTreeContext,bankingMailingGroupTreeContext}
  53. -- [32] removed factionrealm.internalData.gathering, added factionrealm.internalData.gatheringContext.{crafter,professions}, added profile.gatheringOptions.sources
  54. -- [33] added global.internalData.taskListUIFrameContext
  55. -- [34] removed realm.internalData.{lastAuctionDBCompleteScan,lastAuctionDBSaveTime,auctionDBScanData}
  56. -- [35] added factionrealm.userData.craftingCooldownIgnore
  57. -- [36] removed factionrealm.internalData.playerProfessions and added sync.internalData.playerProfessions
  58. -- [37] removed global.auctioningOptions.showAuctionDBTab
  59. -- [38] removed global.mailingOptions.{defaultMailTab,autoCheck,displayMoneyCollected,deleteEmptyNPCMail,showReloadBtn,sendDelay,defaultPage}, added global.mailingOptions.recentlyMailedList
  60. -- [39] added profile.internalData.{craftingGroupTreeContext,mailingGroupTreeContext,vendoringGroupTreeContext,importGroupTreeContext}
  61. -- [40] removed global.accountingOptions.{timeFormat,mvSource}
  62. -- [41] removed global.coreOptions.groupPriceSource
  63. -- [42] removed global.vendoringOptions.defaultMerchantTab
  64. -- [43] removed global.coreOptions.{moveDelay,bankUITab}, removed global.auctioningOptions.{openAllBags,ahRowDisplay}, removed global.craftingOptions.{profitPercent,questSmartCrafting,queueSort}, removed global.destroyingOptions.{logDays,timeFormat}, removed global.vendoringOptions.{autoSellTrash,qsHideGrouped,qsHideSoulbound,qsBatchSize,defaultPage,qsMaxMarketValue,qsDestroyValue}, removed profile.coreOptions.{cleanBags,cleanBank,cleanReagentBank,cleanGuildBank}
  65. -- [44] changed global.internalData.{mainUIFrameContext,auctionUIFrameContext,craftingUIFrameContext,destroyingUIFrameContext,mailingUIFrameContext,vendoringUIFrameContext,bankingUIFrameContext} default (added "scale = 1")
  66. -- [45] added char.internalData.auctionSaleHints
  67. -- [46] added global.shoppingOptions.{buyoutConfirm,buyoutAlertSource}
  68. -- [47] added factionrealm.internalData.expiringMail and factionrealm.internalData.expiringAuction
  69. -- [48] added profile.internalData.exportGroupTreeContext
  70. -- [49] added factionrealm.internalData.{mailDisenchantablesChar,mailExcessGoldChar,mailExcessGoldLimit}
  71. -- [50] added factionrealm.internalData.{csvAuctionDBScan,auctionDBScanTime,auctionDBScanHash}
  72. -- [51] resetting factionrealm.internalData.crafts
  73.  
  74. local SETTINGS_INFO = {
  75. version = 51,
  76. global = {
  77. debug = {
  78. chatLoggingEnabled = { type = "boolean", default = false, lastModifiedVersion = 19 },
  79. },
  80. internalData = {
  81. vendorItems = { type = "table", default = {}, lastModifiedVersion = 10 },
  82. appMessageId = { type = "number", default = 0, lastModifiedVersion = 10 },
  83. destroyingHistory = { type = "table", default = {}, lastModifiedVersion = 10 },
  84. mainUIFrameContext = { type = "table", default = { width = 948, height = 757, centerX = 0, centerY = 0, page = 1, scale = 1 }, lastModifiedVersion = 44 },
  85. auctionUIFrameContext = { type = "table", default = { width = 830, height = 587, centerX = -300, centerY = 100, page = 1, scale = 1 }, lastModifiedVersion = 44 },
  86. craftingUIFrameContext = { type = "table", default = { width = 820, height = 587, centerX = -200, centerY = 0, page = 1, scale = 1 }, lastModifiedVersion = 44 },
  87. destroyingUIFrameContext = { type = "table", default = { width = 296, height = 442, centerX = 0, centerY = 0, scale = 1 }, lastModifiedVersion = 44 },
  88. mailingUIFrameContext = { type = "table", default = { width = 560, height = 500, centerX = -200, centerY = 0, page = 1, scale = 1 }, lastModifiedVersion = 44 },
  89. vendoringUIFrameContext = { type = "table", default = { width = 560, height = 500, centerX = -200, centerY = 0, page = 1, scale = 1 }, lastModifiedVersion = 44 },
  90. bankingUIFrameContext = { type = "table", default = { width = 325, height = 600, centerX = 500, centerY = 0, tab = "Warehousing", isOpen = true, scale = 1 }, lastModifiedVersion = 44 },
  91. taskListUIFrameContext = { type = "table", default = { topRightX = -220, topRightY = -10, minimized = false, isOpen = true }, lastModifiedVersion = 33 },
  92. },
  93. coreOptions = {
  94. globalOperations = { type = "boolean", default = false, lastModifiedVersion = 10 },
  95. chatFrame = { type = "string", default = "", lastModifiedVersion = 10 },
  96. auctionSaleEnabled = { type = "boolean", default = true, lastModifiedVersion = 10 },
  97. auctionSaleSound = { type = "string", default = TSM.CONST.NO_SOUND_KEY, lastModifiedVersion = 10 },
  98. auctionBuyEnabled = { type = "boolean", default = true, lastModifiedVersion = 10 },
  99. tsmItemTweetEnabled = { type = "boolean", default = false, lastModifiedVersion = 10 },
  100. minimapIcon = { type = "table", default = { hide = false, minimapPos = 220, radius = 80 }, lastModifiedVersion = 10 },
  101. destroyValueSource = { type = "string", default = "dbmarket", lastModifiedVersion = 10 },
  102. groupPriceSource = { type = "string", default = "dbmarket", lastModifiedVersion = 41 },
  103. },
  104. accountingOptions = {
  105. trackTrades = { type = "boolean", default = true, lastModifiedVersion = 10 },
  106. autoTrackTrades = { type = "boolean", default = false, lastModifiedVersion = 10 },
  107. smartBuyPrice = { type = "boolean", default = false, lastModifiedVersion = 10 },
  108. },
  109. auctioningOptions = {
  110. cancelWithBid = { type = "boolean", default = false, lastModifiedVersion = 10 },
  111. disableInvalidMsg = { type = "boolean", default = false, lastModifiedVersion = 10 },
  112. roundNormalPrice = { type = "boolean", default = false, lastModifiedVersion = 10 },
  113. matchWhitelist = { type = "boolean", default = true, lastModifiedVersion = 10 },
  114. scanCompleteSound = { type = "string", default = TSM.CONST.NO_SOUND_KEY, lastModifiedVersion = 10 },
  115. confirmCompleteSound = { type = "string", default = TSM.CONST.NO_SOUND_KEY, lastModifiedVersion = 10 },
  116. },
  117. craftingOptions = {
  118. ignoreCDCraftCost = { type = "boolean", default = true, lastModifiedVersion = 10 },
  119. defaultMatCostMethod = { type = "string", default = "min(dbmarket, crafting, vendorbuy, convert(dbmarket))", lastModifiedVersion = 10 },
  120. defaultCraftPriceMethod = { type = "string", default = "first(dbminbuyout, dbmarket)", lastModifiedVersion = 10 },
  121. ignoreCharacters = { type = "table", default = {}, lastModifiedVersion = 10 },
  122. ignoreGuilds = { type = "table", default = {}, lastModifiedVersion = 10 },
  123. },
  124. destroyingOptions = {
  125. autoStack = { type = "boolean", default = true, lastModifiedVersion = 10 },
  126. includeSoulbound = { type = "boolean", default = false, lastModifiedVersion = 10 },
  127. autoShow = { type = "boolean", default = true, lastModifiedVersion = 10 },
  128. deMaxQuality = { type = "number", default = 3, lastModifiedVersion = 10 },
  129. deAbovePrice = { type = "string", default = "0c", lastModifiedVersion = 10 },
  130. },
  131. mailingOptions = {
  132. sendItemsIndividually = { type = "boolean", default = false, lastModifiedVersion = 10 },
  133. inboxMessages = { type = "boolean", default = true, lastModifiedVersion = 10 },
  134. sendMessages = { type = "boolean", default = true, lastModifiedVersion = 10 },
  135. resendDelay = { type = "number", default = 1, lastModifiedVersion = 10 },
  136. keepMailSpace = { type = "number", default = 0, lastModifiedVersion = 10 },
  137. deMaxQuality = { type = "number", default = 2, lastModifiedVersion = 10 },
  138. openMailSound = { type = "string", default = TSM.CONST.NO_SOUND_KEY, lastModifiedVersion = 10 },
  139. recentlyMailedList = { type = "table", default = {}, lastModifiedVersion = 38 },
  140. },
  141. shoppingOptions = {
  142. minDeSearchLvl = { type = "number", default = 1, lastModifiedVersion = 10 },
  143. maxDeSearchLvl = { type = "number", default = 735, lastModifiedVersion = 10 },
  144. maxDeSearchPercent = { type = "number", default = 100, lastModifiedVersion = 23 },
  145. pctSource = { type = "string", default = "dbmarket", lastModifiedVersion = 12 },
  146. buyoutConfirm = { type = "boolean", default = false, lastModifiedVersion = 46 },
  147. buyoutAlertSource = { type = "string", default = "min(100000g, 200% dbmarket)", lastModifiedVersion = 46 },
  148. },
  149. sniperOptions = {
  150. sniperSound = { type = "string", default = TSM.CONST.NO_SOUND_KEY, lastModifiedVersion = 10 },
  151. },
  152. vendoringOptions = {
  153. displayMoneyCollected = { type = "boolean", default = false, lastModifiedVersion = 10 },
  154. qsMarketValue = { type = "string", default = "dbmarket", lastModifiedVersion = 10 },
  155. },
  156. tooltipOptions = {
  157. enabled = { type = "boolean", default = true, lastModifiedVersion = 20 },
  158. embeddedTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  159. customPriceTooltips = { type = "table", default = {}, lastModifiedVersion = 10 },
  160. moduleTooltips = { type = "table", default = {}, lastModifiedVersion = 10 },
  161. vendorBuyTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  162. vendorSellTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  163. groupNameTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  164. detailedDestroyTooltip = { type = "boolean", default = false, lastModifiedVersion = 10 },
  165. millTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  166. prospectTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  167. deTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  168. transformTooltip = { type = "boolean", default = true, lastModifiedVersion = 10 },
  169. operationTooltips = { type = "table", default = {}, lastModifiedVersion = 10 },
  170. tooltipShowModifier = { type = "string", default = "none", lastModifiedVersion = 10 },
  171. inventoryTooltipFormat = { type = "string", default = "full", lastModifiedVersion = 10 },
  172. tooltipPriceFormat = { type = "string", default = "text", lastModifiedVersion = 10 },
  173. },
  174. userData = {
  175. operations = { type = "table", default = {}, lastModifiedVersion = 10 },
  176. customPriceSources = { type = "table", default = {}, lastModifiedVersion = 10 },
  177. destroyingIgnore = { type = "table", default = {}, lastModifiedVersion = 10 },
  178. savedShoppingSearches = { type = "table", default = {}, lastModifiedVersion = 10 },
  179. vendoringIgnore = { type = "table", default = {}, lastModifiedVersion = 10 },
  180. savedAuctioningSearches = { type = "table", default = {}, lastModifiedVersion = 14 },
  181. },
  182. },
  183. profile = {
  184. internalData = {
  185. createdDefaultOperations = { type = "boolean", default = false, lastModifiedVersion = 11 },
  186. managementGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 13 },
  187. auctioningGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 13 },
  188. shoppingGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 13 },
  189. shoppingTabGroupContext = { type = "table", default = {}, lastModifiedVersion = 26 },
  190. auctioningTabGroupContext = { type = "table", default = {}, lastModifiedVersion = 26 },
  191. bankUIBankFramePosition = { type = "table", default = { 100, 300 }, lastModifiedVersion = 16 },
  192. bankUIGBankFramePosition = { type = "table", default = { 100, 300 }, lastModifiedVersion = 16 },
  193. bankingWarehousingGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 31 },
  194. bankingAuctioningGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 31 },
  195. bankingMailingGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 31 },
  196. craftingGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 39 },
  197. mailingGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 39 },
  198. vendoringGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 39 },
  199. importGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 39 },
  200. exportGroupTreeContext = { type = "table", default = {}, lastModifiedVersion = 48 },
  201. },
  202. userData = {
  203. groups = { type = "table", default = {}, lastModifiedVersion = 10 },
  204. items = { type = "table", default = {}, lastModifiedVersion = 10 },
  205. operations = { type = "table", default = {}, lastModifiedVersion = 10 },
  206. },
  207. gatheringOptions = {
  208. sources = { type = "table", default = { "vendor", "guildBank", "alt", "altGuildBank", "craftProfit", "auction", "craftNoProfit" }, lastModifiedVersion = 32 },
  209. },
  210. },
  211. factionrealm = {
  212. internalData = {
  213. characterGuilds = { type = "table", default = {}, lastModifiedVersion = 10 },
  214. guildVaults = { type = "table", default = {}, lastModifiedVersion = 10 },
  215. pendingMail = { type = "table", default = {}, lastModifiedVersion = 10 },
  216. expiringMail = { type = "table", default = {}, lastModifiedVersion = 47 },
  217. expiringAuction = { type = "table", default = {}, lastModifiedVersion = 47 },
  218. mailDisenchantablesChar = { type = "string", default = "", lastModifiedVersion = 49 },
  219. mailExcessGoldChar = { type = "string", default = "", lastModifiedVersion = 49 },
  220. mailExcessGoldLimit = { type = "number", default = 10000000000, lastModifiedVersion = 49 },
  221. crafts = { type = "table", default = {}, lastModifiedVersion = 51 },
  222. mats = { type = "table", default = {}, lastModifiedVersion = 10 },
  223. guildGoldLog = { type = "table", default = {}, lastModifiedVersion = 25 },
  224. csvAuctionDBScan = { type = "string", default = "", lastModifiedVersion = 50 },
  225. auctionDBScanTime = { type = "number", default = 0, lastModifiedVersion = 50 },
  226. auctionDBScanHash = { type = "number", default = 0, lastModifiedVersion = 50 },
  227. },
  228. coreOptions = {
  229. ignoreGuilds = { type = "table", default = {}, lastModifiedVersion = 10 },
  230. },
  231. auctioningOptions = {
  232. whitelist = { type = "table", default = {}, lastModifiedVersion = 10 },
  233. },
  234. gatheringContext = {
  235. crafter = { type = "string", default = "", lastModifiedVersion = 32 },
  236. professions = { type = "table", default = {}, lastModifiedVersion = 32 },
  237. },
  238. userData = {
  239. craftingCooldownIgnore = { type = "table", default = {}, lastModifiedVersion = 35 },
  240. },
  241. },
  242. realm = {
  243. internalData = {
  244. csvSales = { type = "string", default = "", lastModifiedVersion = 10 },
  245. csvBuys = { type = "string", default = "", lastModifiedVersion = 10 },
  246. csvIncome = { type = "string", default = "", lastModifiedVersion = 10 },
  247. csvExpense = { type = "string", default = "", lastModifiedVersion = 10 },
  248. csvExpired = { type = "string", default = "", lastModifiedVersion = 10 },
  249. csvCancelled = { type = "string", default = "", lastModifiedVersion = 10 },
  250. saveTimeSales = { type = "string", default = "", lastModifiedVersion = 10 },
  251. saveTimeBuys = { type = "string", default = "", lastModifiedVersion = 10 },
  252. saveTimeExpires = { type = "string", default = "", lastModifiedVersion = 10 },
  253. saveTimeCancels = { type = "string", default = "", lastModifiedVersion = 10 },
  254. accountingTrimmed = { type = "table", default = {}, lastModifiedVersion = 10 },
  255. },
  256. },
  257. char = {
  258. internalData = {
  259. auctionPrices = { type = "table", default = {}, lastModifiedVersion = 10 },
  260. auctionMessages = { type = "table", default = {}, lastModifiedVersion = 10 },
  261. craftingCooldowns = { type = "table", default = {}, lastModifiedVersion = 27 },
  262. auctionSaleHints = { type = "table", default = {}, lastModifiedVersion = 45 },
  263. },
  264. },
  265. sync = {
  266. -- NOTE: whenever these are changed, the sync version needs to be increased in Core/Lib/Sync/Core.lua
  267. internalData = {
  268. classKey = { type = "string", default = "", lastModifiedVersion = 19 },
  269. bagQuantity = { type = "table", default = {}, lastModifiedVersion = 19 },
  270. bankQuantity = { type = "table", default = {}, lastModifiedVersion = 19 },
  271. reagentBankQuantity = { type = "table", default = {}, lastModifiedVersion = 19 },
  272. auctionQuantity = { type = "table", default = {}, lastModifiedVersion = 19 },
  273. mailQuantity = { type = "table", default = {}, lastModifiedVersion = 19 },
  274. goldLog = { type = "string", default = "", lastModifiedVersion = 25 },
  275. playerProfessions = { type = "table", default = {}, lastModifiedVersion = 36 },
  276. },
  277. },
  278. }
  279.  
  280.  
  281.  
  282. -- ============================================================================
  283. -- Module Functions
  284. -- ============================================================================
  285.  
  286. function TSM.OnInitialize()
  287. -- create setting migration table
  288. TradeSkillMasterModulesDB = TradeSkillMasterModulesDB or {}
  289. for _, moduleName in ipairs(TSM.CONST.OLD_TSM_MODULES) do
  290. moduleName = gsub(moduleName, "TradeSkillMaster_", "")
  291. TradeSkillMasterModulesDB[moduleName] = TradeSkillMasterModulesDB[moduleName] or {}
  292. end
  293.  
  294. -- load settings
  295. local db, upgradeObj = TSM.Settings.New("TradeSkillMasterDB", SETTINGS_INFO)
  296. TSM.db = db
  297. if upgradeObj then
  298. local prevVersion = upgradeObj:GetPrevVersion()
  299. if prevVersion < 10 then
  300. -- migrate all the old settings to their new namespaces
  301. for key, value in upgradeObj:RemovedSettingIterator() do
  302. local scopeType, scopeKey, _, settingKey = upgradeObj:GetKeyInfo(key)
  303. for namespace, namespaceInfo in pairs(SETTINGS_INFO[scopeType]) do
  304. if namespaceInfo[settingKey] then
  305. TSM.db:Set(scopeType, scopeKey, namespace, settingKey, value)
  306. end
  307. end
  308. end
  309. -- migrade all old module settings into the core settings
  310. local MIGRATION_INFO = {
  311. Accounting = {
  312. ["global.trackTrades"] = "global.accountingOptions.trackTrades",
  313. ["global.autoTrackTrades"] = "global.accountingOptions.autoTrackTrades",
  314. ["realm.csvSales"] = "realm.internalData.csvSales",
  315. ["realm.csvBuys"] = "realm.internalData.csvBuys",
  316. ["realm.csvIncome"] = "realm.internalData.csvIncome",
  317. ["realm.csvExpense"] = "realm.internalData.csvExpense",
  318. ["realm.csvExpired"] = "realm.internalData.csvExpired",
  319. ["realm.csvCancelled"] = "realm.internalData.csvCancelled",
  320. ["realm.saveTimeSales"] = "realm.internalData.saveTimeSales",
  321. ["realm.saveTimeBuys"] = "realm.internalData.saveTimeBuys",
  322. ["realm.saveTimeExpires"] = "realm.internalData.saveTimeExpires",
  323. ["realm.saveTimeCancels"] = "realm.internalData.saveTimeCancels",
  324. ["realm.accountingTrimmed"] = "realm.internalData.accountingTrimmed",
  325. },
  326. Auctioning = {
  327. ["global.cancelWithBid"] = "global.auctioningOptions.cancelWithBid",
  328. ["global.disableInvalidMsg"] = "global.auctioningOptions.disableInvalidMsg",
  329. ["global.roundNormalPrice"] = "global.auctioningOptions.roundNormalPrice",
  330. ["global.matchWhitelist"] = "global.auctioningOptions.matchWhitelist",
  331. ["global.scanCompleteSound"] = "global.auctioningOptions.scanCompleteSound",
  332. ["global.confirmCompleteSound"] = "global.auctioningOptions.confirmCompleteSound",
  333. ["factionrealm.whitelist"] = "factionrealm.auctioningOptions.whitelist",
  334. },
  335. Crafting = {
  336. ["global.ignoreCDCraftCost"] = "global.craftingOptions.ignoreCDCraftCost",
  337. ["global.defaultMatCostMethod"] = "global.craftingOptions.defaultMatCostMethod",
  338. ["global.defaultCraftPriceMethod"] = "global.craftingOptions.defaultCraftPriceMethod",
  339. ["global.ignoreCharacters"] = "global.craftingOptions.ignoreCharacters",
  340. ["global.ignoreGuilds"] = "global.craftingOptions.ignoreGuilds",
  341. ["factionrealm.crafts"] = "factionrealm.internalData.crafts",
  342. ["factionrealm.mats"] = "factionrealm.internalData.mats",
  343. },
  344. Destroying = {
  345. ["global.history"] = "global.internalData.destroyingHistory",
  346. ["global.autoStack"] = "global.destroyingOptions.autoStack",
  347. ["global.includeSoulbound"] = "global.destroyingOptions.includeSoulbound",
  348. ["global.autoShow"] = "global.destroyingOptions.autoShow",
  349. ["global.deMaxQuality"] = "global.destroyingOptions.deMaxQuality",
  350. ["global.deAbovePrice"] = "global.destroyingOptions.deAbovePrice",
  351. ["global.ignore"] = "global.userData.destroyingIgnore",
  352. },
  353. Mailing = {
  354. ["global.sendItemsIndividually"] = "global.mailingOptions.sendItemsIndividually",
  355. ["global.inboxMessages"] = "global.mailingOptions.inboxMessages",
  356. ["global.sendMessages"] = "global.mailingOptions.sendMessages",
  357. ["global.resendDelay"] = "global.mailingOptions.resendDelay",
  358. ["global.keepMailSpace"] = "global.mailingOptions.keepMailSpace",
  359. ["global.deMaxQuality"] = "global.mailingOptions.deMaxQuality",
  360. ["global.openMailSound"] = "global.mailingOptions.openMailSound",
  361. },
  362. Shopping = {
  363. ["global.minDeSearchLvl"] = "global.shoppingOptions.minDeSearchLvl",
  364. ["global.maxDeSearchLvl"] = "global.shoppingOptions.maxDeSearchLvl",
  365. ["global.maxDeSearchPercent"] = "global.shoppingOptions.maxDeSearchPercent",
  366. ["global.sniperSound"] = "global.sniperOptions.sniperSound",
  367. ["global.savedSearches"] = "global.userData.savedShoppingSearches",
  368. },
  369. Vendoring = {
  370. ["global.displayMoneyCollected"] = "global.vendoringOptions.displayMoneyCollected",
  371. ["global.qsMarketValue"] = "global.vendoringOptions.qsMarketValue",
  372. ["global.ignore"] = "global.userData.vendoringIgnore",
  373. },
  374. }
  375. for module, migrations in pairs(MIGRATION_INFO) do
  376. for key, value in pairs(TradeSkillMasterModulesDB[module]) do
  377. if strsub(key, 1, 1) ~= "_" then
  378. local scopeType, scopeKey, _, settingKey = upgradeObj:GetKeyInfo(key)
  379. local oldPath = strjoin(".", scopeType, settingKey)
  380. local newPath = migrations[oldPath]
  381. if newPath then
  382. local newScopeType, newNamespace, newSettingKey = strsplit(".", newPath)
  383. assert(newScopeType == scopeType)
  384. TSM.db:Set(newScopeType, scopeKey, newNamespace, newSettingKey, value)
  385. end
  386. end
  387. end
  388. end
  389. end
  390. if prevVersion < 19 then
  391. -- migrate inventory data to the sync scope
  392. local oldInventoryData = TSMAPI_FOUR.Util.AcquireTempTable()
  393. local oldSyncMetadata = TSMAPI_FOUR.Util.AcquireTempTable()
  394. local oldAccountKey = TSMAPI_FOUR.Util.AcquireTempTable()
  395. local oldCharacters = TSMAPI_FOUR.Util.AcquireTempTable()
  396. for key, value in upgradeObj:RemovedSettingIterator() do
  397. local scopeType, scopeKey, _, settingKey = upgradeObj:GetKeyInfo(key)
  398. if scopeType == "factionrealm" then
  399. if settingKey == "inventory" then
  400. oldInventoryData[scopeKey] = value
  401. elseif settingKey == "syncMetadata" then
  402. oldSyncMetadata[scopeKey] = value
  403. elseif settingKey == "accountKey" then
  404. oldAccountKey[scopeKey] = value
  405. elseif settingKey == "characters" then
  406. oldCharacters[scopeKey] = value
  407. end
  408. end
  409. end
  410. for factionrealm, characters in pairs(oldInventoryData) do
  411. local syncMetadata = oldSyncMetadata[factionrealm] and oldSyncMetadata[factionrealm].TSM_CHARACTERS
  412. for character, inventoryData in pairs(characters) do
  413. if not syncMetadata or not syncMetadata[character] or syncMetadata[character].owner == oldAccountKey[factionrealm] then
  414. TSM.db:NewSyncCharacter(character, TSM.db:GetSyncAccountKey(factionrealm), factionrealm)
  415. local syncScopeKey = TSM.db:GetSyncScopeKeyByCharacter(character, factionrealm)
  416. local class = oldCharacters[factionrealm] and oldCharacters[factionrealm][character]
  417. if type(class) == "string" then
  418. TSM.db:Set("sync", syncScopeKey, "internalData", "classKey", class)
  419. end
  420. TSM.db:Set("sync", syncScopeKey, "internalData", "bagQuantity", inventoryData.bag)
  421. TSM.db:Set("sync", syncScopeKey, "internalData", "bankQuantity", inventoryData.bank)
  422. TSM.db:Set("sync", syncScopeKey, "internalData", "reagentBankQuantity", inventoryData.reagentBank)
  423. TSM.db:Set("sync", syncScopeKey, "internalData", "auctionQuantity", inventoryData.auction)
  424. TSM.db:Set("sync", syncScopeKey, "internalData", "mailQuantity", inventoryData.mail)
  425. end
  426. end
  427. end
  428. TSMAPI_FOUR.Util.ReleaseTempTable(oldInventoryData)
  429. TSMAPI_FOUR.Util.ReleaseTempTable(oldSyncMetadata)
  430. TSMAPI_FOUR.Util.ReleaseTempTable(oldAccountKey)
  431. TSMAPI_FOUR.Util.ReleaseTempTable(oldCharacters)
  432. end
  433. if prevVersion < 25 then
  434. -- migrate gold log info
  435. local NEW_CSV_COLS = { "minute", "copper" }
  436. local function ConvertGoldLogFormat(data)
  437. local decodedData = select(2, TSMAPI_FOUR.CSV.Decode(data))
  438. if not decodedData then
  439. return
  440. end
  441. for _, entry in ipairs(decodedData) do
  442. local minute = entry.startMinute
  443. local copper = entry.copper
  444. wipe(entry)
  445. entry.minute = minute
  446. entry.copper = copper
  447. end
  448. return TSMAPI_FOUR.CSV.Encode(NEW_CSV_COLS, decodedData)
  449. end
  450. local function ProcessGoldLogData(character, data, scopeKey)
  451. if type(data) ~= "string" then
  452. return
  453. end
  454. -- check if we know about this character and under what faction
  455. local syncScopeKey = nil
  456. for factionrealm in TSM.db:FactionrealmByRealmIterator(scopeKey) do
  457. local testSyncScopeKey = TSM.db:GetSyncScopeKeyByCharacter(character, factionrealm)
  458. if TSM.db:Get("sync", testSyncScopeKey, "internalData", "classKey") then
  459. syncScopeKey = testSyncScopeKey
  460. end
  461. end
  462. if syncScopeKey then
  463. TSM.db:Set("sync", syncScopeKey, "internalData", "goldLog", ConvertGoldLogFormat(data))
  464. else
  465. -- check if this is a known guild
  466. local found = false
  467. for factionrealm in TSM.db:FactionrealmByRealmIterator(scopeKey) do
  468. local characterGuilds = TSM.db:Get("factionrealm", factionrealm, "internalData", "characterGuilds")
  469. if not found and characterGuilds and TSMAPI_FOUR.Util.TableKeyByValue(characterGuilds, character) then
  470. local guildGoldLog = TSM.db:Get("factionrealm", factionrealm, "internalData", "guildGoldLog") or {}
  471. guildGoldLog[character] = ConvertGoldLogFormat(data)
  472. TSM.db:Set("factionrealm", factionrealm, "internalData", "guildGoldLog", guildGoldLog)
  473. found = true
  474. end
  475. end
  476. end
  477. end
  478. if prevVersion < 10 then
  479. for key, value in pairs(TradeSkillMasterModulesDB.Accounting) do
  480. if strmatch(key,"^r@.+@goldLog$") then
  481. local _, scopeKey = upgradeObj:GetKeyInfo(key)
  482. for character, data in pairs(value) do
  483. ProcessGoldLogData(character, data, scopeKey)
  484. end
  485. end
  486. end
  487. else
  488. for key, value in upgradeObj:RemovedSettingIterator() do
  489. local scopeType, scopeKey, _, settingKey = upgradeObj:GetKeyInfo(key)
  490. if scopeType == "realm" and settingKey == "goldLog" then
  491. for character, data in pairs(value) do
  492. ProcessGoldLogData(character, data, scopeKey)
  493. end
  494. end
  495. end
  496. end
  497. end
  498. if prevVersion < 36 then
  499. for key, value in upgradeObj:RemovedSettingIterator() do
  500. local scopeType, factionrealm, _, settingKey = upgradeObj:GetKeyInfo(key)
  501. if scopeType == "factionrealm" and settingKey == "playerProfessions" then
  502. for character, data in pairs(value) do
  503. -- check if we know about this character
  504. local syncScopeKey = TSM.db:GetSyncScopeKeyByCharacter(character, factionrealm)
  505. if TSM.db:Get("sync", syncScopeKey, "internalData", "classKey") then
  506. TSM.db:Set("sync", syncScopeKey, "internalData", "playerProfessions", data)
  507. end
  508. end
  509. end
  510. end
  511. end
  512. if prevVersion < 51 and WOW_PROJECT_ID ~= WOW_PROJECT_CLASSIC then
  513. for key, value in upgradeObj:RemovedSettingIterator() do
  514. local scopeType, factionrealm, namespace, settingKey = upgradeObj:GetKeyInfo(key)
  515. if scopeType == "factionrealm" and namespace == "internalData" and settingKey == "crafts" then
  516. TSM.db:Set("factionrealm", factionrealm, "internalData", "crafts", value)
  517. end
  518. end
  519. end
  520. end
  521.  
  522. -- store the class of this character
  523. TSM.db.sync.internalData.classKey = select(2, UnitClass("player"))
  524.  
  525. -- core price sources
  526. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "VendorBuy", L["Buy from Vendor"], TSMAPI_FOUR.Item.GetVendorBuy)
  527. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "VendorSell", L["Sell to Vendor"], TSMAPI_FOUR.Item.GetVendorSell)
  528. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "Destroy", L["Destroy Value"], function(itemString) return TSMAPI_FOUR.Conversions.GetValue(itemString, TSM.db.global.coreOptions.destroyValueSource) end)
  529. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "ItemQuality", L["Item Quality"], TSMAPI_FOUR.Item.GetQuality)
  530. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "ItemLevel", L["Item Level"], TSMAPI_FOUR.Item.GetItemLevel)
  531. TSM.CustomPrice.RegisterSource("TradeSkillMaster", "RequiredLevel", L["Required Level"], TSMAPI_FOUR.Item.GetMinLevel)
  532.  
  533. -- Auctioneer price sources
  534. if TSMAPI_FOUR.Util.IsAddonEnabled("Auc-Advanced") and AucAdvanced then
  535. if AucAdvanced.Modules.Util.Appraiser and AucAdvanced.Modules.Util.Appraiser.GetPrice then
  536. TSM.CustomPrice.RegisterSource("External", "AucAppraiser", L["Auctioneer - Appraiser"], AucAdvanced.Modules.Util.Appraiser.GetPrice, true)
  537. end
  538. if AucAdvanced.Modules.Util.SimpleAuction and AucAdvanced.Modules.Util.SimpleAuction.Private.GetItems then
  539. local function GetAucMinBuyout(itemLink)
  540. return select(6, AucAdvanced.Modules.Util.SimpleAuction.Private.GetItems(itemLink)) or nil
  541. end
  542. TSM.CustomPrice.RegisterSource("External", "AucMinBuyout", L["Auctioneer - Minimum Buyout"], GetAucMinBuyout, true)
  543. end
  544. if AucAdvanced.API.GetMarketValue then
  545. TSM.CustomPrice.RegisterSource("External", "AucMarket", L["Auctioneer - Market Value"], AucAdvanced.API.GetMarketValue, true)
  546. end
  547. end
  548.  
  549. -- Auctionator price sources
  550. if TSMAPI_FOUR.Util.IsAddonEnabled("Auctionator") and Atr_GetAuctionBuyout then
  551. TSM.CustomPrice.RegisterSource("External", "AtrValue", L["Auctionator - Auction Value"], Atr_GetAuctionBuyout, true)
  552. end
  553.  
  554. -- TheUndermineJournal price sources
  555. if TSMAPI_FOUR.Util.IsAddonEnabled("BootyBayGazette") and TUJMarketInfo then
  556. local function GetTUJPrice(itemLink, arg)
  557. local data = TUJMarketInfo(itemLink)
  558. return data and data[arg] or nil
  559. end
  560. TSM.CustomPrice.RegisterSource("External", "BBGRecent", L["BBG 2-Day Price"], GetTUJPrice, true, "recent")
  561. TSM.CustomPrice.RegisterSource("External", "BBGMarket", L["BBG 7-Day Price"], GetTUJPrice, true, "market")
  562. TSM.CustomPrice.RegisterSource("External", "BBGGlobalMean", L["BBG Global Mean"], GetTUJPrice, true, "globalMean")
  563. TSM.CustomPrice.RegisterSource("External", "BBGGlobalMedian", L["BBG Global Median"], GetTUJPrice, true, "globalMedian")
  564. end
  565.  
  566. -- AHDB price sources
  567. if TSMAPI_FOUR.Util.IsAddonEnabled("AuctionDB") and AuctionDB and AuctionDB.AHGetAuctionInfoByLink then
  568. local function GetAHDBPrice(itemLink, arg)
  569. local info = AuctionDB:AHGetAuctionInfoByLink(itemLink)
  570. return info and info[arg] or nil
  571. end
  572. TSM.CustomPrice.RegisterSource("External", "AHDBMinBuyout", L["AHDB Minimum Buyout"], GetAHDBPrice, true, "minBuyout")
  573. TSM.CustomPrice.RegisterSource("External", "AHDBMinBid", L["AHDB Minimum Bid"], GetAHDBPrice, true, "minBid")
  574. end
  575.  
  576. -- module price sources
  577. TSM.CustomPrice.RegisterSource("Accounting", "avgSell", L["Avg Sell Price"], TSM.Accounting.Transactions.GetAverageSalePrice)
  578. TSM.CustomPrice.RegisterSource("Accounting", "avgSell", L["Avg Sell Price"], TSM.Accounting.Transactions.GetAverageSalePrice)
  579. TSM.CustomPrice.RegisterSource("Accounting", "maxSell", L["Max Sell Price"], TSM.Accounting.Transactions.GetMaxSalePrice)
  580. TSM.CustomPrice.RegisterSource("Accounting", "minSell", L["Min Sell Price"], TSM.Accounting.Transactions.GetMinSalePrice)
  581. TSM.CustomPrice.RegisterSource("Accounting", "avgBuy", L["Avg Buy Price"], TSM.Accounting.Transactions.GetAverageBuyPrice)
  582. TSM.CustomPrice.RegisterSource("Accounting", "maxBuy", L["Max Buy Price"], TSM.Accounting.Transactions.GetMaxBuyPrice)
  583. TSM.CustomPrice.RegisterSource("Accounting", "minBuy", L["Min Buy Price"], TSM.Accounting.Transactions.GetMinBuyPrice)
  584. TSM.CustomPrice.RegisterSource("Accounting", "NumExpires", L["Expires Since Last Sale"], TSM.Accounting.Auctions.GetNumExpiresSinceSale)
  585. TSM.CustomPrice.RegisterSource("AuctionDB", "DBMarket", L["AuctionDB - Market Value"], TSM.AuctionDB.GetRealmItemData, false, "marketValue")
  586. TSM.CustomPrice.RegisterSource("AuctionDB", "DBMinBuyout", L["AuctionDB - Minimum Buyout"], TSM.AuctionDB.GetRealmItemData, false, "minBuyout")
  587. TSM.CustomPrice.RegisterSource("AuctionDB", "DBHistorical", L["AuctionDB - Historical Price (via TSM App)"], TSM.AuctionDB.GetRealmItemData, false, "historical")
  588. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionMinBuyoutAvg", L["AuctionDB - Region Minimum Buyout Average (via TSM App)"], TSM.AuctionDB.GetRegionItemData, false, "regionMinBuyout")
  589. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionMarketAvg", L["AuctionDB - Region Market Value Average (via TSM App)"], TSM.AuctionDB.GetRegionItemData, false, "regionMarketValue")
  590. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionHistorical", L["AuctionDB - Region Historical Price (via TSM App)"], TSM.AuctionDB.GetRegionItemData, false, "regionHistorical")
  591. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionSaleAvg", L["AuctionDB - Region Sale Average (via TSM App)"], TSM.AuctionDB.GetRegionItemData, false, "regionSale")
  592. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionSaleRate", L["AuctionDB - Region Sale Rate (via TSM App)"], TSM.AuctionDB.GetRegionSaleInfo, false, "regionSalePercent")
  593. TSM.CustomPrice.RegisterSource("AuctionDB", "DBRegionSoldPerDay", L["AuctionDB - Region Sold Per Day (via TSM App)"], TSM.AuctionDB.GetRegionSaleInfo, false, "regionSoldPerDay")
  594. TSM.CustomPrice.RegisterSource("Crafting", "Crafting", L["Crafting Cost"], TSM.Crafting.Cost.GetLowestCostByItem)
  595. TSM.CustomPrice.RegisterSource("Crafting", "matPrice", L["Crafting Material Cost"], TSM.Crafting.Cost.GetMatCost)
  596.  
  597. -- slash commands
  598. TSM.SlashCommands.Register("version", private.PrintVersions, L["Prints out the version numbers of all installed modules"])
  599. TSM.SlashCommands.Register("sources", TSM.CustomPrice.PrintSources, L["Prints out the available price sources for use in custom prices"])
  600. TSM.SlashCommands.Register("price", private.TestPriceSource, L["Allows for testing of custom prices"])
  601. TSM.SlashCommands.Register("profile", private.ChangeProfile, L["Changes to the specified profile (i.e. '/tsm profile Default' changes to the 'Default' profile)"])
  602. TSM.SlashCommands.Register("debug", private.DebugSlashCommandHandler)
  603. TSM.SlashCommands.Register("destroy", TSM.UI.DestroyingUI.Toggle, L["Opens the Destroying frame if there's stuff in your bags to be destroyed."])
  604. TSM.SlashCommands.Register("crafting", TSM.UI.CraftingUI.Toggle, L["Toggles the TSM Crafting UI."])
  605. TSM.SlashCommands.Register("tasklist", TSM.UI.TaskListUI.Toggle, L["Toggles the TSM Task List UI"])
  606. TSM.SlashCommands.Register("bankui", TSM.UI.BankingUI.Toggle, L["Toggles the TSM Banking UI if either the bank or guild bank is currently open."])
  607. TSM.SlashCommands.Register("get", TSM.Banking.GetByFilter, L["Gets items from the bank or guild bank matching the item or partial text entered."])
  608. TSM.SlashCommands.Register("put", TSM.Banking.PutByFilter, L["Puts items matching the item or partial text entered into the bank or guild bank."])
  609. TSM.SlashCommands.Register("restock_help", TSM.Crafting.RestockHelp, L["Tells you why a specific item is not being restocked and added to the queue."])
  610. if WOW_PROJECT_ID == WOW_PROJECT_CLASSIC then
  611. TSM.SlashCommands.Register("scan", TSM.AuctionDB.RunScan, L["Performs a full, manual scan of the AH to populate some AuctionDB data if none is otherwise available."])
  612. end
  613.  
  614. -- create / register the minimap button
  615. local dataObj = LibStub("LibDataBroker-1.1"):NewDataObject("TradeSkillMaster", {
  616. type = "launcher",
  617. icon = "Interface\\Addons\\TradeSkillMaster\\Media\\TSM_Icon2",
  618. OnClick = function(_, button)
  619. if button ~= "LeftButton" then return end
  620. TSM.MainUI.Toggle()
  621. end,
  622. OnTooltipShow = function(tooltip)
  623. local cs = "|cffffffcc"
  624. local ce = "|r"
  625. tooltip:AddLine("TradeSkillMaster " .. TSM:GetVersion())
  626. tooltip:AddLine(format(L["%sLeft-Click%s to open the main window"], cs, ce))
  627. tooltip:AddLine(format(L["%sDrag%s to move this button"], cs, ce))
  628. end,
  629. })
  630. LibDBIcon:Register("TradeSkillMaster", dataObj, TSM.db.global.coreOptions.minimapIcon)
  631.  
  632. -- cache battle pet names
  633. if WOW_PROJECT_ID ~= WOW_PROJECT_CLASSIC then
  634. for i = 1, C_PetJournal.GetNumPets() do
  635. C_PetJournal.GetPetInfoByIndex(i)
  636. end
  637. end
  638.  
  639. -- force a garbage collection
  640. collectgarbage()
  641. end
  642.  
  643. function TSM.OnEnable()
  644. -- disable old TSM modules
  645. local didDisable = false
  646. for _, name in ipairs(TSM.CONST.OLD_TSM_MODULES) do
  647. if TSMAPI_FOUR.Util.IsAddonEnabled(name) then
  648. didDisable = true
  649. DisableAddOn(name, true)
  650. end
  651. end
  652. if didDisable then
  653. StaticPopupDialogs["TSM_OLD_MODULE_DISABLE"] = {
  654. text = L["Welcome to TSM4! All of the old TSM3 modules (i.e. Crafting, Shopping, etc) are now built-in to the main TSM addon, so you only need TSM and TSM_AppHelper installed. TSM has disabled the old modules and requires a reload."],
  655. button1 = L["Reload"],
  656. timeout = 0,
  657. whileDead = true,
  658. OnAccept = ReloadUI,
  659. }
  660. TSMAPI_FOUR.Util.ShowStaticPopupDialog("TSM_OLD_MODULE_DISABLE")
  661. else
  662. TradeSkillMasterModulesDB = nil
  663. end
  664.  
  665. TSM.LoadAppData()
  666. end
  667.  
  668. function TSM.OnDisable()
  669. local originalProfile = TSM.db:GetCurrentProfile()
  670. -- erroring here would cause the profile to be reset, so use pcall
  671. local startTime = debugprofilestop()
  672. local success, errMsg = pcall(private.SaveAppData)
  673. local timeTaken = debugprofilestop() - startTime
  674. if timeTaken > LOGOUT_TIME_WARNING_THRESHOLD_MS then
  675. TSM:LOG_WARN("private.SaveAppData took %0.2fms", timeTaken)
  676. end
  677. if not success then
  678. TSM:LOG_ERR("private.SaveAppData hit an error: %s", tostring(errMsg))
  679. end
  680. -- ensure we're back on the correct profile
  681. TSM.db:SetProfile(originalProfile)
  682. end
  683.  
  684. function TSM.LoadAppData()
  685. if not TSMAPI_FOUR.Util.IsAddonInstalled("TradeSkillMaster_AppHelper") then
  686. return
  687. end
  688.  
  689. if not TSMAPI_FOUR.Util.IsAddonEnabled("TradeSkillMaster_AppHelper") then
  690. -- TSM_AppHelper is disabled
  691. StaticPopupDialogs["TSM_APP_DATA_ERROR"] = {
  692. text = L["The TradeSkillMaster_AppHelper addon is installed, but not enabled. TSM has enabled it and requires a reload."],
  693. button1 = L["Reload"],
  694. timeout = 0,
  695. whileDead = true,
  696. OnAccept = function()
  697. EnableAddOn("TradeSkillMaster_AppHelper")
  698. ReloadUI()
  699. end,
  700. }
  701. TSMAPI_FOUR.Util.ShowStaticPopupDialog("TSM_APP_DATA_ERROR")
  702. return
  703. end
  704.  
  705. assert(TSMAPI.AppHelper)
  706. local appInfo = TSMAPI.AppHelper:FetchData("APP_INFO")
  707. if not appInfo then
  708. -- The app hasn't run yet or isn't pointing at the right WoW directory
  709. StaticPopupDialogs["TSM_APP_DATA_ERROR"] = {
  710. text = L["TSM is missing important information from the TSM Desktop Application. Please ensure the TSM Desktop Application is running and is properly configured."],
  711. button1 = OKAY,
  712. timeout = 0,
  713. whileDead = true,
  714. }
  715. TSMAPI_FOUR.Util.ShowStaticPopupDialog("TSM_APP_DATA_ERROR")
  716. return
  717. end
  718.  
  719. -- load the app info
  720. assert(#appInfo == 1 and #appInfo[1] == 2 and appInfo[1][1] == "Global")
  721. private.appInfo = assert(loadstring(appInfo[1][2]))()
  722. for _, key in ipairs(APP_INFO_REQUIRED_KEYS) do
  723. assert(private.appInfo[key])
  724. end
  725.  
  726. if private.appInfo.message and private.appInfo.message.id > TSM.db.global.internalData.appMessageId then
  727. -- show the message from the app
  728. TSM.db.global.internalData.appMessageId = private.appInfo.message.id
  729. StaticPopupDialogs["TSM_APP_MESSAGE"] = {
  730. text = private.appInfo.message.msg,
  731. button1 = OKAY,
  732. timeout = 0,
  733. }
  734. TSMAPI_FOUR.Util.ShowStaticPopupDialog("TSM_APP_MESSAGE")
  735. end
  736.  
  737. if time() - private.appInfo.lastSync > 60 * 60 then
  738. -- the app hasn't been running for over an hour
  739. StaticPopupDialogs["TSM_APP_DATA_ERROR"] = {
  740. text = L["TSM is missing important information from the TSM Desktop Application. Please ensure the TSM Desktop Application is running and is properly configured."],
  741. button1 = OKAY,
  742. timeout = 0,
  743. whileDead = true,
  744. }
  745. TSMAPI_FOUR.Util.ShowStaticPopupDialog("TSM_APP_DATA_ERROR")
  746. end
  747. end
  748.  
  749.  
  750.  
  751. -- ============================================================================
  752. -- General Slash-Command Handlers
  753. -- ============================================================================
  754.  
  755. function private.TestPriceSource(price)
  756. local _, endIndex, link = strfind(price, "(\124c[0-9a-f]+\124H[^\124]+\124h%[[^%]]+%]\124h\124r)")
  757. price = link and strtrim(strsub(price, endIndex + 1))
  758. if not price or price == "" then
  759. TSM:Print(L["Usage: /tsm price <ItemLink> <Price String>"])
  760. return
  761. end
  762.  
  763. local isValid, err = TSMAPI_FOUR.CustomPrice.Validate(price)
  764. if not isValid then
  765. TSM:Printf(L["%s is not a valid custom price and gave the following error: %s"], "|cff99ffff"..price.."|r", err)
  766. return
  767. end
  768.  
  769. local itemString = TSMAPI_FOUR.Item.ToItemString(link)
  770. if not itemString then
  771. TSM:Printf(L["%s is a valid custom price but %s is an invalid item."], "|cff99ffff"..price.."|r", link)
  772. return
  773. end
  774.  
  775. local value = TSMAPI_FOUR.CustomPrice.GetValue(price, itemString)
  776. if not value then
  777. TSM:Printf(L["%s is a valid custom price but did not give a value for %s."], "|cff99ffff"..price.."|r", link)
  778. return
  779. end
  780.  
  781. TSM:Printf(L["A custom price of %s for %s evaluates to %s."], "|cff99ffff"..price.."|r", link, TSM.Money.ToString(value))
  782. end
  783.  
  784. function private.ChangeProfile(targetProfile)
  785. targetProfile = strtrim(targetProfile)
  786. local profiles = TSM.db:GetProfiles()
  787. if targetProfile == "" then
  788. TSM:Printf(L["No profile specified. Possible profiles: '%s'"], table.concat(profiles, "', '"))
  789. else
  790. for _, profile in ipairs(profiles) do
  791. if profile == targetProfile then
  792. if profile ~= TSM.db:GetCurrentProfile() then
  793. TSM.db:SetProfile(profile)
  794. end
  795. TSM:Printf(L["Profile changed to '%s'."], profile)
  796. return
  797. end
  798. end
  799. TSM:Printf(L["Could not find profile '%s'. Possible profiles: '%s'"], targetProfile, table.concat(profiles, "', '"))
  800. end
  801. end
  802.  
  803. function private.DebugSlashCommandHandler(arg)
  804. if arg == "fstack" then
  805. TSM.UI.ToggleFrameStack()
  806. elseif arg == "error" then
  807. TSM.ShowManualError()
  808. elseif arg == "logging" then
  809. TSM.db.global.debug.chatLoggingEnabled = not TSM.db.global.debug.chatLoggingEnabled
  810. if TSM.db.global.debug.chatLoggingEnabled then
  811. TSM:Printf("Logging to chat enabled")
  812. else
  813. TSM:Printf("Logging to chat disabled")
  814. end
  815. elseif arg == "db" then
  816. TSM.UI.DBViewer.Toggle()
  817. elseif arg == "logout" then
  818. TSM.AddonTestLogout()
  819. elseif arg == "clearitemdb" then
  820. TSMItemInfoDB = nil
  821. ReloadUI()
  822. end
  823. end
  824.  
  825. function private.PrintVersions()
  826. TSM:Print(L["TSM Version Info:"])
  827. TSM:PrintfRaw("TradeSkillMaster |cff99ffff%s|r", TSM:GetVersion())
  828. local appHelperVersion = GetAddOnMetadata("TradeSkillMaster_AppHelper", "Version")
  829. if appHelperVersion then
  830. -- use strmatch so that our sed command doesn't replace this string
  831. if strmatch(appHelperVersion, "^@tsm%-project%-version@$") then
  832. appHelperVersion = "Dev"
  833. end
  834. TSM:PrintfRaw("TradeSkillMaster_AppHelper |cff99ffff%s|r", appHelperVersion)
  835. end
  836. end
  837.  
  838. function private.SaveAppData()
  839. if not TSMAPI.AppHelper then
  840. return
  841. end
  842.  
  843. TradeSkillMaster_AppHelperDB = TradeSkillMaster_AppHelperDB or {}
  844. local appDB = TradeSkillMaster_AppHelperDB
  845.  
  846. -- store region
  847. local region = TSM.GetRegion()
  848. appDB.region = region
  849.  
  850. -- save errors
  851. TSM.SaveErrorReports(appDB)
  852.  
  853. local function GetShoppingMaxPrice(itemString)
  854. local operation = TSM.Operations.GetFirstOperationByItem("Shopping", itemString)
  855. if not operation or type(operation.maxPrice) ~= "string" then
  856. return
  857. end
  858. local value = TSMAPI_FOUR.CustomPrice.GetValue(operation.maxPrice, itemString)
  859. if not value or value <= 0 then
  860. return
  861. end
  862. return value
  863. end
  864.  
  865. -- save TSM_Shopping max prices in the app DB
  866. appDB.shoppingMaxPrices = {}
  867. for profile in TSM.GetTSMProfileIterator() do
  868. local profileGroupData = {}
  869. for _, itemString, groupPath in TSM.Groups.ItemIterator() do
  870. local itemId = tonumber(strmatch(itemString, "^i:([0-9]+)$"))
  871. if itemId then
  872. local maxPrice = GetShoppingMaxPrice(itemString)
  873. if maxPrice then
  874. if not profileGroupData[groupPath] then
  875. profileGroupData[groupPath] = {}
  876. end
  877. tinsert(profileGroupData[groupPath], "["..table.concat({itemId, maxPrice}, ",").."]")
  878. end
  879. end
  880. end
  881. if next(profileGroupData) then
  882. appDB.shoppingMaxPrices[profile] = {}
  883. for groupPath, data in pairs(profileGroupData) do
  884. appDB.shoppingMaxPrices[profile][groupPath] = "["..table.concat(data, ",").."]"
  885. end
  886. appDB.shoppingMaxPrices[profile].updateTime = time()
  887. end
  888. end
  889.  
  890. -- save black market data
  891. local realmName = GetRealmName()
  892. appDB.blackMarket = appDB.blackMarket or {}
  893. if TSM.Features.blackMarket then
  894. local hash = TSMAPI_FOUR.Util.CalculateHash(TSM.Features.blackMarket..":"..TSM.Features.blackMarketTime)
  895. appDB.blackMarket[realmName] = {data=TSM.Features.blackMarket, key=hash, updateTime=TSM.Features.blackMarketTime}
  896. end
  897.  
  898. -- save analytics
  899. TSM.Analytics.Save(appDB)
  900. end
  901.  
  902.  
  903.  
  904. -- ============================================================================
  905. -- General Module Functions
  906. -- ============================================================================
  907.  
  908. function TSM:GetAppNews()
  909. return private.appInfo and private.appInfo.news
  910. end
  911.  
  912. function TSM:GetChatFrame()
  913. local chatFrame = DEFAULT_CHAT_FRAME
  914. for i = 1, NUM_CHAT_WINDOWS do
  915. local name = strlower(GetChatWindowInfo(i) or "")
  916. if name ~= "" and (not TSM.db or name == strlower(TSM.db.global.coreOptions.chatFrame)) then
  917. chatFrame = _G["ChatFrame" .. i]
  918. break
  919. end
  920. end
  921. return chatFrame
  922. end
  923.  
  924. function TSM:GetVersion()
  925. return TSMAPI_FOUR.Util.IsDevVersion("TradeSkillMaster") and "Dev" or GetAddOnMetadata("TradeSkillMaster", "Version")
  926. end
  927.  
  928.  
  929.  
  930. -- ============================================================================
  931. -- General TSMAPI Functions
  932. -- ============================================================================
  933.  
  934. function TSM.GetRegion()
  935. local cVar = GetCVar("Portal")
  936. local region = WOW_PROJECT_ID ~= WOW_PROJECT_CLASSIC and LibRealmInfo:GetCurrentRegion() or (cVar ~= "public-test" and cVar) or "PTR"
  937. if WOW_PROJECT_ID == WOW_PROJECT_CLASSIC then
  938. region = region.."-Classic"
  939. end
  940. return region
  941. end
  942.  
  943. function TSM.GetTSMProfileIterator()
  944. local originalProfile = TSM.db:GetCurrentProfile()
  945. local profiles = TSM.db:GetProfiles()
  946.  
  947. return function()
  948. local profile = tremove(profiles)
  949. if profile then
  950. TSM.db:SetProfile(profile)
  951. return profile
  952. end
  953. TSM.db:SetProfile(originalProfile)
  954. end
  955. end
  956.  
  957.  
  958.  
  959. -- ============================================================================
  960. -- FIXME: this is all just temporary code which should eventually be removed
  961. -- ============================================================================
  962.  
  963. do
  964. TSMAPI.Settings.Init = function(_, name)
  965. local moduleName = gsub(name, "DB$", "")
  966. local AceAddon = LibStub("AceAddon-3.0")
  967. local obj = AceAddon and AceAddon:GetAddon(gsub(moduleName, "TradeSkillMaster", "TSM"))
  968. if obj and tContains(TSM.CONST.OLD_TSM_MODULES, moduleName) then
  969. obj.OnInitialize = nil
  970. obj.OnEnable = nil
  971. obj.OnDisable = nil
  972. for _, module in ipairs(obj.modules) do
  973. module.OnInitialize = nil
  974. module.OnEnable = nil
  975. module.OnDisable = nil
  976. end
  977. wipe(obj.modules)
  978. wipe(obj.orderedModules)
  979. end
  980. error(moduleName, 2)
  981. end
  982. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement