initial commit
This commit is contained in:
204
Core/Lib/Addon.lua
Normal file
204
Core/Lib/Addon.lua
Normal file
@@ -0,0 +1,204 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local TSM_NAME, TSM = ...
|
||||
local Analytics = TSM.Include("Util.Analytics")
|
||||
local Event = TSM.Include("Util.Event")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local LibTSMClass = TSM.Include("LibTSMClass")
|
||||
local private = {
|
||||
eventFrames = {},
|
||||
initializeQueue = {},
|
||||
enableQueue = {},
|
||||
disableQueue = {},
|
||||
totalInitializeTime = 0,
|
||||
totalEnableTime = 0,
|
||||
}
|
||||
local TIME_WARNING_THRESHOLD_MS = 20
|
||||
local MAX_TIME_PER_EVENT_MS = 12000
|
||||
local NUM_EVENT_FRAMES = 10
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Event Handling
|
||||
-- ============================================================================
|
||||
|
||||
function private.DoInitialize()
|
||||
local eventStartTime = debugprofilestop()
|
||||
while #private.initializeQueue > 0 and debugprofilestop() < (eventStartTime + MAX_TIME_PER_EVENT_MS) do
|
||||
local addon = tremove(private.initializeQueue, 1)
|
||||
if addon.OnInitialize then
|
||||
local addonStartTime = debugprofilestop()
|
||||
addon.OnInitialize()
|
||||
local addonTimeTaken = debugprofilestop() - addonStartTime
|
||||
if addonTimeTaken > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("OnInitialize (%s) took %0.2fms", addon, addonTimeTaken)
|
||||
end
|
||||
end
|
||||
tinsert(private.enableQueue, addon)
|
||||
end
|
||||
if private.totalInitializeTime == 0 then
|
||||
for _, path, moduleLoadTime, settingsLoadTime in TSM.ModuleInfoIterator() do
|
||||
if moduleLoadTime > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("Loading module %s took %0.2fms", path, moduleLoadTime)
|
||||
end
|
||||
if settingsLoadTime > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("Loading settings for %s took %0.2fms", path, settingsLoadTime)
|
||||
end
|
||||
end
|
||||
end
|
||||
private.totalInitializeTime = private.totalInitializeTime + debugprofilestop() - eventStartTime
|
||||
return #private.initializeQueue == 0
|
||||
end
|
||||
|
||||
function private.DoEnable()
|
||||
local eventStartTime = debugprofilestop()
|
||||
while #private.enableQueue > 0 and debugprofilestop() < (eventStartTime + MAX_TIME_PER_EVENT_MS) do
|
||||
local addon = tremove(private.enableQueue, 1)
|
||||
if addon.OnEnable then
|
||||
local addonStartTime = debugprofilestop()
|
||||
addon.OnEnable()
|
||||
local addonTimeTaken = debugprofilestop() - addonStartTime
|
||||
if addonTimeTaken > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("OnEnable (%s) took %0.2fms", addon, addonTimeTaken)
|
||||
end
|
||||
end
|
||||
tinsert(private.disableQueue, addon)
|
||||
end
|
||||
if private.totalEnableTime == 0 then
|
||||
for _, path, _, _, gameDataLoadTime in TSM.ModuleInfoIterator() do
|
||||
if (gameDataLoadTime or 0) > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("Loading game data for %s took %0.2fms", path, gameDataLoadTime)
|
||||
end
|
||||
end
|
||||
end
|
||||
private.totalEnableTime = private.totalEnableTime + debugprofilestop() - eventStartTime
|
||||
return #private.enableQueue == 0
|
||||
end
|
||||
|
||||
function private.PlayerLogoutHandler()
|
||||
private.OnDisableHelper()
|
||||
wipe(private.disableQueue)
|
||||
end
|
||||
|
||||
function private.OnDisableHelper()
|
||||
local disableStartTime = debugprofilestop()
|
||||
for _, addon in ipairs(private.disableQueue) do
|
||||
-- defer the main TSM.OnDisable() call to the very end
|
||||
if addon.OnDisable and addon ~= TSM then
|
||||
local startTime = debugprofilestop()
|
||||
addon.OnDisable()
|
||||
local timeTaken = debugprofilestop() - startTime
|
||||
if timeTaken > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("OnDisable (%s) took %0.2fms", addon, timeTaken)
|
||||
end
|
||||
end
|
||||
end
|
||||
local totalDisableTime = debugprofilestop() - disableStartTime
|
||||
Analytics.Action("ADDON_DISABLE", floor(totalDisableTime))
|
||||
if TSM.OnDisable then
|
||||
TSM.OnDisable()
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
-- Blizzard did something silly in 8.1 where scripts time throw an error after 19 seconds, but nothing prevents us
|
||||
-- from just splitting the processing across multiple script handlers, so we do that here.
|
||||
local function EventHandler(self, event, arg)
|
||||
if event == "ADDON_LOADED" and arg == "TradeSkillMaster" then
|
||||
if private.DoInitialize() then
|
||||
-- we're done
|
||||
for _, frame in ipairs(private.eventFrames) do
|
||||
frame:UnregisterEvent(event)
|
||||
end
|
||||
Analytics.Action("ADDON_INITIALIZE", floor(private.totalInitializeTime))
|
||||
elseif self == private.eventFrames[#private.eventFrames] then
|
||||
error("Ran out of event frames to initialize TSM")
|
||||
end
|
||||
elseif event == "PLAYER_LOGIN" then
|
||||
if private.DoEnable() then
|
||||
-- we're done
|
||||
for _, frame in ipairs(private.eventFrames) do
|
||||
frame:UnregisterEvent(event)
|
||||
end
|
||||
Analytics.Action("ADDON_ENABLE", floor(private.totalEnableTime))
|
||||
elseif self == private.eventFrames[#private.eventFrames] then
|
||||
error("Ran out of event frames to enable TSM")
|
||||
end
|
||||
end
|
||||
end
|
||||
for _ = 1, NUM_EVENT_FRAMES do
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:SetScript("OnEvent", EventHandler)
|
||||
frame:RegisterEvent("ADDON_LOADED")
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
tinsert(private.eventFrames, frame)
|
||||
end
|
||||
Event.Register("PLAYER_LOGOUT", private.PlayerLogoutHandler)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- AddonPackage Class
|
||||
-- ============================================================================
|
||||
|
||||
local AddonPackage = LibTSMClass.DefineClass("AddonPackage")
|
||||
|
||||
function AddonPackage.__init(self, name)
|
||||
self.name = name
|
||||
tinsert(private.initializeQueue, self)
|
||||
end
|
||||
|
||||
function AddonPackage.__tostring(self)
|
||||
return self.name
|
||||
end
|
||||
|
||||
function AddonPackage.NewPackage(self, name)
|
||||
local package = AddonPackage(name)
|
||||
assert(not self[name])
|
||||
self[name] = package
|
||||
return package
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Addon Class
|
||||
-- ============================================================================
|
||||
|
||||
local Addon = LibTSMClass.DefineClass("Addon", AddonPackage)
|
||||
|
||||
function Addon.__init(self, name)
|
||||
self.__super:__init(name)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Initialization Code
|
||||
-- ============================================================================
|
||||
|
||||
do
|
||||
LibTSMClass.ConstructWithTable(TSM, Addon, TSM_NAME)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions (Debug Only)
|
||||
-- ============================================================================
|
||||
|
||||
function TSM.AddonTestLogout()
|
||||
private.OnDisableHelper()
|
||||
TSM.DebugLogout()
|
||||
for _, path, _, _, _, moduleUnloadTime in TSM.ModuleInfoIterator() do
|
||||
if moduleUnloadTime > TIME_WARNING_THRESHOLD_MS then
|
||||
Log.Warn("Unloading %s took %0.2fms", path, moduleUnloadTime)
|
||||
end
|
||||
end
|
||||
end
|
||||
188
Core/Lib/Exporter.lua
Normal file
188
Core/Lib/Exporter.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local ExporterModule = TSM:NewPackage("Exporter")
|
||||
local TempTable = TSM.Include("Util.TempTable")
|
||||
local LibAceSerializer = LibStub("AceSerializer-3.0")
|
||||
local Exporter = TSM.Include("LibTSMClass").DefineClass("Exporter")
|
||||
local private = {}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function ExporterModule.New()
|
||||
return Exporter()
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Class definition
|
||||
-- ============================================================================
|
||||
|
||||
function Exporter.__init(self)
|
||||
self.options = {
|
||||
["includeAttachedOperations"] = true
|
||||
}
|
||||
self.groups = {}
|
||||
self.operations = {}
|
||||
self.groupOperations = {}
|
||||
self.operationsBlacklist = {}
|
||||
self.groupTargets = {}
|
||||
for _, module in TSM.Operations.ModuleIterator() do
|
||||
self.groupOperations[module] = {}
|
||||
self.operationsBlacklist[module] = {}
|
||||
self.operations[module] = {}
|
||||
end
|
||||
end
|
||||
|
||||
--- Blacklist the given operation from being included with the export
|
||||
-- @tparam self the exporter
|
||||
-- @tparam module the operation belongs to
|
||||
-- @tparam name of the operation
|
||||
function Exporter.BlacklistOperation(self, module, name)
|
||||
self.operationsBlacklist[module][name] = true
|
||||
end
|
||||
|
||||
--- Reset the selected groups and drop the cached copies of the operations
|
||||
-- @tparam self the exporter
|
||||
function Exporter.ResetSelection(self)
|
||||
wipe(self.groups)
|
||||
wipe(self.groupOperations)
|
||||
for _, module in TSM.Operations.ModuleIterator() do
|
||||
wipe(self.operations[module])
|
||||
end
|
||||
end
|
||||
|
||||
--- Add the path to the current selected groups
|
||||
-- @tparam self the exporter
|
||||
-- @tparam string path the group to add
|
||||
function Exporter.SelectGroup(self, path)
|
||||
if path ~= TSM.CONST.ROOT_GROUP_PATH then
|
||||
tinsert(self.groups, path)
|
||||
for _, module in TSM.Operations.ModuleIterator() do
|
||||
for _, operationName, operationSettings in TSM.Operations.GroupOperationIterator(module, path) do
|
||||
if not self.operationsBlacklist[module][operationName] then
|
||||
self.operations[module][operationName] = operationSettings
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Finishes bookkeeping when the group selection changes
|
||||
-- @tparam self the exporter
|
||||
function Exporter.FinalizeGroupSelections(self)
|
||||
TSM.Groups.SortGroupList(self.groups)
|
||||
self:_SetupGroupTargets()
|
||||
for _, path in ipairs(self.groups) do
|
||||
self:_SaveGroupOperations(path)
|
||||
end
|
||||
end
|
||||
|
||||
--- gets a string that is the exported groups with the selected options
|
||||
-- @tparam self the exporter
|
||||
function Exporter.GetExportString(self)
|
||||
local items = {}
|
||||
local selectedGroups = {}
|
||||
|
||||
for _, group in ipairs(self.groups) do
|
||||
selectedGroups[group] = true
|
||||
self:_SaveGroupOperations(group)
|
||||
end
|
||||
|
||||
self:_SaveItems(selectedGroups, items)
|
||||
|
||||
local groupExport = table.concat(items, ",")
|
||||
if not self.options.includeAttachedOperations then
|
||||
return groupExport
|
||||
end
|
||||
return LibAceSerializer:Serialize({groupExport=groupExport, groupOperations=self.groupOperations, operations=self.operations})
|
||||
end
|
||||
|
||||
function Exporter._SaveGroupOperations(self, group)
|
||||
if not self.options.includeAttachedOperations then
|
||||
return
|
||||
end
|
||||
local relPath = self.groupTargets[group]
|
||||
self.groupOperations[relPath] = TSM.db.profile.userData.groups[group]
|
||||
for _, moduleName in TSM.Operations.ModuleIterator() do
|
||||
local operationInfo = self.groupOperations[relPath][moduleName]
|
||||
for _, operationName in ipairs(operationInfo) do
|
||||
local data = CopyTable(TSM.Operations.GetSettings(moduleName, operationName))
|
||||
data.ignorePlayer = nil
|
||||
data.ignoreFactionrealm = nil
|
||||
data.relationships = nil
|
||||
self.operations[moduleName] = self.operations[moduleName] or {}
|
||||
self.operations[moduleName][operationName] = data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Exporter._SaveItems(self, selectedGroups, saveItems)
|
||||
local temp = TempTable.Acquire()
|
||||
|
||||
for _, itemString, groupPath in TSM.Groups.ItemIterator() do
|
||||
if selectedGroups[groupPath] then
|
||||
tinsert(temp, itemString)
|
||||
end
|
||||
end
|
||||
|
||||
sort(temp, private.GroupsThenItemsSortFunc)
|
||||
|
||||
local currentPath = ""
|
||||
for _, itemString in pairs(temp) do
|
||||
local rawPath = TSM.Groups.GetPathByItem(itemString)
|
||||
local relPath = self.groupTargets[rawPath]
|
||||
if relPath ~= currentPath then
|
||||
tinsert(saveItems, "group:"..relPath)
|
||||
currentPath = relPath
|
||||
end
|
||||
tinsert(saveItems, itemString)
|
||||
end
|
||||
TempTable.Release(temp)
|
||||
end
|
||||
|
||||
function Exporter._SetupGroupTargets(self)
|
||||
wipe(self.groupTargets)
|
||||
if #self.groups < 1 then
|
||||
return
|
||||
end
|
||||
local knownRoots = {}
|
||||
for _, groupPath in ipairs(self.groups) do
|
||||
local root, leaf = TSM.Groups.Path.Split(groupPath)
|
||||
leaf = gsub(leaf, ",", TSM.CONST.GROUP_SEP..TSM.CONST.GROUP_SEP)
|
||||
if knownRoots[root] then
|
||||
self.groupTargets[groupPath] = leaf
|
||||
else
|
||||
if self.groupTargets[root] then
|
||||
self.groupTargets[groupPath] = TSM.Groups.Path.Join(self.groupTargets[root], leaf)
|
||||
else
|
||||
knownRoots[root] = true
|
||||
self.groupTargets[groupPath] = leaf
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.GroupsThenItemsSortFunc(a, b)
|
||||
local groupA = strlower(gsub(TSM.Groups.GetPathByItem(a), TSM.CONST.GROUP_SEP, "\001"))
|
||||
local groupB = strlower(gsub(TSM.Groups.GetPathByItem(b), TSM.CONST.GROUP_SEP, "\001"))
|
||||
if groupA == groupB then
|
||||
return a < b
|
||||
end
|
||||
return groupA < groupB
|
||||
end
|
||||
Reference in New Issue
Block a user