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()