sorcery  init.lua at tip

File init.lua from the latest check-in


do
	local path = minetest.get_modpath('sorcery');
	local get = function(unit)
		return dofile(path .. '/' .. unit .. '.lua')
	end
	local test = function(file) -- :/
		local hnd = io.open(file,'r')
		if hnd == nil then return false else
			hnd:close()
			return true
		end
	end
	local worldcfg = function(str)
		return minetest.get_worldpath() .. '/' .. str
	end
	local cfg = function(str) return worldcfg('sorcery/' .. str) end
	local selfname = minetest.get_current_modname()
	local function
	argjoin(arg, nxt, ...)
		if arg and not nxt then return tostring(arg) end
		if not arg then return "(nil)" end
		return tostring(arg) .. ' ' .. argjoin(nxt, ...)
	end

	local logger = function(module)
		local lg = {}
		local setup = function(fn, lvl)
			lvl = lvl or fn
			local function emit(...)
				local call = (fn == 'fatal') and error
					or function(str) minetest.log(lvl, str) end
				if module
					then call(string.format('[%s :: %s] %s',selfname,module,argjoin(...)))
					else call(string.format('[%s] %s',selfname,argjoin(...)))
				end
			end
			lg[fn       ] = function(...) emit(...)                end
			lg[fn .. 'f'] = function(...) emit(string.format(...)) end -- convenience fn
		end
		setup('info')
		setup('warn','warning')
		setup('err','error')
		setup('act','action')
		setup('fatal')
		return lg
	end;

	local stage = function(s,...)
		logger().info('entering stage',s)
		local f = sorcery.cfg(s .. '.lua')
		if test(f) then return loadfile(f)(...) or true end
		return false
	end

	sorcery = {
		self = selfname;
		path = path;
		load = function(name) get(name) end;
		worldcfg = worldcfg, cfg = cfg;
		stage = stage;
		
		log = function(module,text)
			if module then
				minetest.log('info',string.format('[%s :: %s] %s',selfname,module,text))
			else
				minetest.log('info',string.format('[%s] %s',selfname,text))
			end
		end;
		act = function(module,text)
			minetest.log('action',string.format('[%s :: %s] %s',selfname,module,text))
		end;
		logger = logger;
		unit = function(ns,sfx,override)
			if ns then logger('loader').info('opening unit',ns) end
			local log = logger(ns and ('loader/'..ns))
			local target
			if ns then
				sorcery[ns] = {}
				target = sorcery[ns]
			else target = sorcery end
			if override == true then override = ''
				elseif override then override = override .. '-' end
			local loaded = {}
			return function(lst)
				for i,name in pairs(lst) do
					if not loaded[name] then
						loaded[name] = true
						log.info('installing component', name)
						local fpath = ((ns and ns..'/') or '')..name
						local extra = cfg(string.format('%s%s-extra.lua', override,name))
						local replace = cfg(string.format('%s%s.lua', override,name))
						local default = get(fpath)
						if override and test(replace) then
							log.info('loading local replacement for', fpath,'from', replace)
							target[name] = loadfile(replace)(default)
						else
							target[name] = default
							if override and test(extra) then
								log.info('loading local extras for', fpath, 'from', extra)
								local extbl = loadfile(extra)(default)
								for k,v in pairs(extbl) do target[name][k] = v end
							end
						end
					end
				end
			end
		end;
	}

	-- LEGACY INTERFACE
	sorcery.log = function(mod,...) return sorcery.logger(mod).info(...) end
	sorcery.act = function(mod,...) return sorcery.logger(mod).act(...) end
end

-- unfortunately we can't just iterate over the files
-- and load them automatically, as interdependencies
-- exist (especially with /lib) and we need to be very
-- careful about the order they're loaded in

local log = sorcery.logger()

log.info('loading data')

local data = sorcery.unit('data',nil,'lore')
local root = sorcery.unit()
sorcery.stage('bootstrap',data,root)

data {'ui'}
sorcery.unit('lib') {
	-- convenience
	'str', 'math';
	-- serialization
	'marshal', 'json';
	-- data structures
	'tbl', 'class';
	-- wrappers
	'color', 'image', 'ui', 'obj';
	-- game
	'node', 'item';
}

sorcery.stage('worldbuilding',data,root)
root {'compat','matreg'}
if not sorcery.stage('loadlore', data, root) then
	data {
		'compat';
		'affinities'; 'gods';
		'calendar', 'signs';
		'resonance';
		'trees', 'gems', 'metals';
		'enchants', 'spells', 'runes';
		'potions', 'oils', 'greases',
			'draughts', 'elixirs',
			'philters', 'extracts';
	}
end

sorcery.load('registration') do
	local exclude = {'compat','ui'}
	for k,v in pairs(sorcery.data) do
		if not sorcery.lib.tbl.has(exclude,k) then
			sorcery.registry.mk(k,v)
		end
	end
	sorcery.registry.mk('residue',false)
end

sorcery.stage('startup',data)
for _,u in pairs {
	'global'; 'vfx'; 'context'; 'attunement'; 'itemclass'; 'craft'; 'spell';
	'liquid'; 'potions'; 'lathe'; 'tree'; 'metal', 'gems'; 'leylines';
	'infuser'; 'altar'; 'wands'; 'tools', 'crafttools';
	'enchanter'; 'harvester'; 'metallurgy-hot', 'metallurgy-cold';
	'entities'; 'recipes'; 'coins'; 'interop';
	'tnodes'; 'forcefield'; 'farcaster'; 'portal';
	'cookbook', 'writing'; 'disassembly'; 'displacer';
	'gravitator'; 'precipitator'; 'calendar', 'astrolabe';
	'keypunch'; 'runeforge'; 'keg'; 'tap'; 'mixing-stand'; 'distiller';

	'privs', 'admin';
} do sorcery.load(u) end
sorcery.stage('finalize')

sorcery.registry.defercheck()