view DependencyLoader/Core.lua @ 18:e7995d599184 tip

updated pkgmeta fix the inversion in addon:Enable added support for late-loading
author mckenziemc
date Tue, 21 Dec 2010 00:23:57 -0800
parents f825ccf94a89
children
line wrap: on
line source
--	Core
--	Provides core functionality of Core


--	TODO: disable bootstrap if we load successfully?
--	TODO: implement a feature to disable unneeded libraries when a parent 
--	is disabled?


local addonName, addonTable = ...


--	locals
local print = addonTable.print
local debug = addonTable.debug
local classes = addonTable.classes

local AceHook = LibStub("AceHook-3.0")
local LibScriptLink = LibStub("LibScriptLink-1.0")


local Core = addonTable:NewClass("Core")


AceHook:Embed(Core)

Core.queuedEnables = {}		--	addons queued to be enabled after PLAYER_LOGIN


--	Does not consider user settings or addon errata.
function Core:IsForceLoadAvailable()
	if IsLoggedIn() then
		return false
	else
		return true
	end
end


function Core:IsForceLoadAllowed()
	--	TODO: check user settings
	return true
end


function Core:CanForceLoad()
	return self:IsForceLoadAvailable() and self:IsForceLoadAllowed()
end


function Core:CanLoadLate()
	--	assume we've already logged in
	return true
	--	TODO: check user settings
end


--	Enables any dependencies needed by the addons 
--	that have already been enabled
function Core:PrepareAllAddons()
	for i=1, GetNumAddOns() do
		local addon = classes.Addon:Get(i)
		
		--	TODO: what if an addon was loaded but its deps were then disabled?
		if addon:IsEnabled() and not addon:IsLoaded() then
			self:EnableAddOn(i)
		end
	end
end


function Core:SetHooks()
	self:RawHook("EnableAddOn", true)
	self:RawHook("LoadAddOn", true)
end


--	FIXME: use pcall in EnableAddOn and LoadAddOn, so that if my part errors,  
--	it can still use the unhooked version

function Core:EnableAddOn(...)
	local id = ...
	
	debug("EnableAddOn", ...)
	
	--	even though we know EnableAddOn can cause force-loading before PLAYER_LOGIN, 
	--	DO NOT attempt to "fix" it: another addon that -does- know about 
	--	the different behavior might call our hook.
	
	if classes.Addon:Exists(id) then
		local addon = classes.Addon:Get(id)
		local tree = classes.Tree:Get(addon)
		
		local requestReload = false
		
		if self:CanForceLoad() then
			--	NOTE: if we can force-load, then will enabling LoD addons cause them to load too?
			--	A: no, they will still wait for LoadAddOn
			
			--	Can the addon be loaded on demand if force-loading is 
			--	allowed for its dependencies
			--	if so, enable all deps and force-load if nec.
			--		deps will get enabled if all parents are lod, force-loaded
			--		if any parent can't be loaded on demand
			--	else
			--	if the addon is not loadable on demand but the tree can be
			--	force-loaded, then force-load it all
			--		deps will all get loaded since req. for root to load
			--	else
			--	if it can be loaded with a reloadui then prepare after login
			--	else
			--	it can't be loaded, maybe tell the user
			
			debug("EnableAddOn hook, checking", addon:GetName())
			
			if tree:CanForceLoad() then
				if addon:CanLoD() then
					tree:PrepareForLoD()
				else
					tree:ForceLoad()
				end
			elseif tree:CanLoad() then
				tree:PrepareForLoad()
				requestReload = true
			else
				--	TODO: tell user
			end
			
			
			--[[
			if tree:CanLoDWithForce() then
				tree:PrepareForLoD()
			elseif tree:CanForceLoad() then
				tree:ForceLoad()
			elseif tree:CanLoad() then
				tree:PrepareForLoad()
				requestReload = true
			else
				--	TODO: tell user
			end
			]]
		else
			--	if it can be loaded on demand (deps are loaded or LoD) then
			--	prepare it (enable all deps)
			--	else
			--	if it can be loaded (and isn't already) then
			--		if force loading is available, we have to wait, then enable everything
			--		else
			--		prepare for reload (TODO: move this check and similar to PLAYER_LOGOUT)
			--	else
			--	can't be loaded, maybe tell the user
			
			if tree:CanLoD() then
				tree:PrepareForLoad()
				--	don't actually intend to reload, just enable everything
			elseif self:CanLoadLate() and tree:CanLoadLate() then
				tree:LoadLate()
			elseif tree:CanLoad() then
				tree:PrepareForLoad()
				requestReload = true
			else
				--	TODO: tell user
			end
		end
		
		if requestReload then
			self:RequestReload()
		end
	end
	
	--	propogate the call even if it doesn't exist or deps are unavailable
	return self:RawEnableAddOn(...)
end



---	Prepares the addon tree rooted at the specified addon
function Core:LoadAddOn(...)
	local id = ...
	
	debug("LoadAddOn", ...)
	
	if classes.Addon:Exists(id) then
		local addon = classes.Addon:Get(id)
		local tree = classes.Tree:Get(addon)
		
		if tree:CanLoD() then
			tree:PrepareForLoD()
		elseif tree:CanLoad() then
			tree:PrepareForLoad()
			--	TODO: request reload
		end
	end
		
	--	call even if it can't be loaded so regular returns appear
	return self:RawLoadAddOn(...)
end


function Core:RequestReload()
	--	TODO: this should be throtled so that it can 
	--	occur more than once but not within a short time
	
	debug("reload requested (NYI)")
end


--	name or index
function Core:QueueEnable(addon)
	self.queuedEnables[addon] = true
end


function Core:RawEnableAddOn(...)
	debug("RawEnableAddOn: enabling", ...)
	return self.hooks.EnableAddOn(...)
end


function Core:RawLoadAddOn(...)
	return self.hooks.LoadAddOn(...)
end


function Core:ProcessEnableQueue()
	for addon in pairs(self.queuedEnables) do
		self:RawEnableAddOn(addon)
		self.queuedEnables[addon] = nil
	end
end