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'; 'tree'; 'potions'; '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'; 'privs', 'admin'; } do sorcery.load(u) end sorcery.stage('finalize') sorcery.registry.defercheck()