initial commit
This commit is contained in:
252
LibTSM/Core.lua
Normal file
252
LibTSM/Core.lua
Normal file
@@ -0,0 +1,252 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- This is loaded before anything else and simply sets up the addon table
|
||||
|
||||
local ADDON_NAME, TSM = ...
|
||||
local VERSION_RAW = GetAddOnMetadata("TradeSkillMaster", "Version")
|
||||
local IS_DEV_VERSION = strmatch(VERSION_RAW, "^@tsm%-project%-version@$") and true or false
|
||||
local private = {
|
||||
context = {},
|
||||
initOrder = {},
|
||||
loadOrder = {},
|
||||
frame = nil,
|
||||
gotAddonLoaded = false,
|
||||
gotPlayerLogin = false,
|
||||
gotPlayerLogout = false,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Metatable
|
||||
-- ============================================================================
|
||||
|
||||
local MODULE_METHODS = {
|
||||
OnModuleLoad = function(self, func)
|
||||
local context = private.context[self]
|
||||
assert(context and not context.moduleLoadFunc and not context.moduleLoadTime and type(func) == "function")
|
||||
context.moduleLoadFunc = func
|
||||
end,
|
||||
OnSettingsLoad = function(self, func)
|
||||
local context = private.context[self]
|
||||
assert(context and not context.settingsLoadFunc and not context.settingsLoadTime and type(func) == "function")
|
||||
context.settingsLoadFunc = func
|
||||
end,
|
||||
OnGameDataLoad = function(self, func)
|
||||
local context = private.context[self]
|
||||
assert(context and not context.gameDataLoadFunc and not context.gameDataLoadTime and type(func) == "function")
|
||||
context.gameDataLoadFunc = func
|
||||
end,
|
||||
OnModuleUnload = function(self, func)
|
||||
local context = private.context[self]
|
||||
assert(context and not context.moduleUnloadFunc and not context.moduleUnloadTime and type(func) == "function")
|
||||
context.moduleUnloadFunc = func
|
||||
end,
|
||||
}
|
||||
|
||||
local MODULE_MT = {
|
||||
__index = MODULE_METHODS,
|
||||
__newindex = function(self, key, value)
|
||||
local context = private.context[self]
|
||||
assert(context and not MODULE_METHODS[key] and not context.moduleLoadTime)
|
||||
rawset(self, key, value)
|
||||
end,
|
||||
__metatable = false,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Addon Object Functions
|
||||
-- ============================================================================
|
||||
|
||||
function TSM.Init(path)
|
||||
assert(type(path) == "string")
|
||||
if private.context[path] then
|
||||
error("Module already exists for path: "..tostring(path))
|
||||
end
|
||||
local module = setmetatable({}, MODULE_MT)
|
||||
private.context[path] = {
|
||||
path = path,
|
||||
module = module,
|
||||
moduleLoadFunc = nil,
|
||||
moduleLoadTime = nil,
|
||||
settingsLoadFunc = nil,
|
||||
settingsLoadTime = nil,
|
||||
gameDataLoadFunc = nil,
|
||||
gameDataLoadTime = nil,
|
||||
moduleUnloadFunc = nil,
|
||||
moduleUnloadTime = nil,
|
||||
}
|
||||
-- store a reference to the context by both the module object and the path
|
||||
private.context[module] = private.context[path]
|
||||
tinsert(private.initOrder, path)
|
||||
return module
|
||||
end
|
||||
|
||||
function TSM.Include(path)
|
||||
local context = private.context[path]
|
||||
if not context then
|
||||
error("Module doesn't exist for path: "..tostring(path))
|
||||
end
|
||||
private.ProcessModuleLoad(path)
|
||||
return context.module
|
||||
end
|
||||
|
||||
function TSM.IsDevVersion()
|
||||
return IS_DEV_VERSION
|
||||
end
|
||||
|
||||
function TSM.GetVersion()
|
||||
return IS_DEV_VERSION and "Dev" or VERSION_RAW
|
||||
end
|
||||
|
||||
function TSM.ModuleInfoIterator()
|
||||
return private.ModuleInfoIterator, nil, 0
|
||||
end
|
||||
|
||||
function TSM.IsWowClassic()
|
||||
return WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
|
||||
end
|
||||
|
||||
function TSM.IsShadowlands()
|
||||
return select(4, GetBuildInfo()) >= 90000
|
||||
end
|
||||
|
||||
function TSM.DebugLogout()
|
||||
private.UnloadAll()
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.ModuleInfoIterator(_, index)
|
||||
index = index + 1
|
||||
local path = private.initOrder[index]
|
||||
if not path then
|
||||
return
|
||||
end
|
||||
local context = private.context[path]
|
||||
assert(context)
|
||||
return index, path, context.moduleLoadTime, context.settingsLoadTime, context.gameDataLoadTime, context.moduleUnloadTime
|
||||
end
|
||||
|
||||
function private.ProcessModuleLoad(path)
|
||||
local context = private.context[path]
|
||||
assert(context)
|
||||
if context.moduleLoadTime then
|
||||
-- already loaded
|
||||
return
|
||||
end
|
||||
tinsert(private.loadOrder, path)
|
||||
context.moduleLoadTime = 0
|
||||
if context.moduleLoadFunc then
|
||||
local st = debugprofilestop()
|
||||
context.moduleLoadFunc()
|
||||
context.moduleLoadTime = debugprofilestop() - st
|
||||
end
|
||||
end
|
||||
|
||||
function private.ProcessSettingsLoad(path)
|
||||
local context = private.context[path]
|
||||
assert(context)
|
||||
if context.settingsLoadTime then
|
||||
-- already loaded
|
||||
return
|
||||
end
|
||||
context.settingsLoadTime = 0
|
||||
if context.settingsLoadFunc then
|
||||
local st = debugprofilestop()
|
||||
context.settingsLoadFunc()
|
||||
context.settingsLoadTime = debugprofilestop() - st
|
||||
end
|
||||
end
|
||||
|
||||
function private.ProcessGameDataLoad(path)
|
||||
local context = private.context[path]
|
||||
assert(context)
|
||||
if context.gameDataLoadTime then
|
||||
-- already loaded
|
||||
return
|
||||
end
|
||||
context.gameDataLoadTime = 0
|
||||
if context.gameDataLoadFunc then
|
||||
local st = debugprofilestop()
|
||||
context.gameDataLoadFunc()
|
||||
context.gameDataLoadTime = debugprofilestop() - st
|
||||
end
|
||||
end
|
||||
|
||||
function private.ProcessModuleUnload(path)
|
||||
local context = private.context[path]
|
||||
assert(context)
|
||||
if context.moduleUnloadTime then
|
||||
-- already unloaded
|
||||
return
|
||||
end
|
||||
context.moduleUnloadTime = 0
|
||||
if context.moduleUnloadFunc then
|
||||
local st = debugprofilestop()
|
||||
context.moduleUnloadFunc()
|
||||
context.moduleUnloadTime = debugprofilestop() - st
|
||||
end
|
||||
end
|
||||
|
||||
function private.UnloadAll()
|
||||
-- unload in the opposite order we loaded
|
||||
for i = #private.loadOrder, 1, -1 do
|
||||
private.ProcessModuleUnload(private.loadOrder[i])
|
||||
end
|
||||
end
|
||||
|
||||
function private.OnEvent(_, event, arg)
|
||||
if event == "ADDON_LOADED" and arg == ADDON_NAME and not private.gotAddonLoaded then
|
||||
assert(not private.gotAddonLoaded and not private.gotPlayerLogin and not private.gotPlayerLogout)
|
||||
private.gotAddonLoaded = true
|
||||
-- load any module which haven't already
|
||||
for _, path in ipairs(private.initOrder) do
|
||||
private.ProcessModuleLoad(path)
|
||||
end
|
||||
-- settings are now available
|
||||
for _, path in ipairs(private.loadOrder) do
|
||||
private.ProcessSettingsLoad(path)
|
||||
end
|
||||
private.frame:UnregisterEvent("ADDON_LOADED")
|
||||
elseif event == "PLAYER_LOGIN" then
|
||||
assert(private.gotAddonLoaded and not private.gotPlayerLogin and not private.gotPlayerLogout)
|
||||
private.gotPlayerLogin = true
|
||||
-- game data is now available
|
||||
for _, path in ipairs(private.loadOrder) do
|
||||
private.ProcessGameDataLoad(path)
|
||||
end
|
||||
elseif event == "PLAYER_LOGOUT" then
|
||||
assert(private.gotAddonLoaded and not private.gotPlayerLogout)
|
||||
private.gotPlayerLogout = true
|
||||
if not private.gotPlayerLogin then
|
||||
-- this can happen if the player exists the game during the loading screen, in which case we just ignore it
|
||||
return
|
||||
end
|
||||
private.UnloadAll()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Initialization Code
|
||||
-- ============================================================================
|
||||
|
||||
do
|
||||
private.frame = CreateFrame("Frame")
|
||||
private.frame:RegisterEvent("ADDON_LOADED")
|
||||
private.frame:RegisterEvent("PLAYER_LOGIN")
|
||||
private.frame:RegisterEvent("PLAYER_LOGOUT")
|
||||
private.frame:SetScript("OnEvent", private.OnEvent)
|
||||
end
|
||||
Reference in New Issue
Block a user