minetest_rx/minetest_rx/registration.lua

164 lines
5.3 KiB
Lua

minetest = minetest or require("mock_minetest")
local Rx = minetest.lib.Rx or require("rx")
local _ = minetest.lib._ or require("moses_min")
local function wrap_existing(name, existing)
return
type(existing) == "function" and existing()
or type(existing) == "string" and minetest[existing]
or minetest["registered_"..name.."s"]
end
local mt_native = {}
-- Keyless Events
local function keyless_event_setup(name, native, existing)
local existing = wrap_existing(name, existing)
local future = Rx.Subject.create()
local observable = Rx.Observable.create(function(observer)
for i, value in ipairs(existing) do
observer:onNext(value)
end
end):merge(future)
local wrapper = function(...)
local result = {native(...)}
future:onNext(...)
return unpack(result)
end
return native, wrapper, observable
end
for i, key in pairs({
"craft",
"decoration",
"ore"
}) do
mt_native["register_"..key], minetest["register_"..key], minetest["on_register_"..key] =
keyless_event_setup(key, minetest["register_"..key])
end
-- Keyed Events
local any = ""
local function key_event_setup(name, native, existing)
local existing = wrap_existing(name, existing)
local store = {
[any] = Rx.Subject.create()
}
local observables = function(key)
if (type(key) ~= "string") then
return store[any]
end
if (store[key] == nil) then
if string.match(key, "^group:") then
local g_name = string.gsub(key, "^group:", "")
-- This is a group.
store[key] = Rx.Observable.create(function(obs)
for k,params in pairs(existing) do
local g_val = type(params.groups) == "table" and params.groups[g_name] or 0
obs:onNext({
key = key,
value = g_val,
params = params
})
end
end):merge(store[any]:map(function(kvp)
local params = kvp.value[1]
local g_val = type(params.groups) == "table" and params.groups[g_name] or 0
return {
key = kvp.key,
value = g_val,
params = params
}
end))
else
-- This is just a node name.
store[key] = Rx.ReplaySubject.create(1)
if (existing[key]) then
store[key]:onNext(existing[key])
end
end
end
return store[key]
end
local wrapper = function(key, ...)
assert(type(key) == "string", "Key for registration function must be a string. Got "..type(key).." instead.")
local san_key = string.gsub(key, "^:+", "")
assert(san_key ~= any, "Attempted to use special 'any' value for registration.")
local result = {native(":"..san_key, ...)}
observables(any):onNext({
key = san_key,
value = {...}
})
observables(key):onNext(...)
return unpack(result)
end
return native, wrapper, observables
end
for i, key in pairs({
"craftitem",
"node",
"tool",
"privilege"
}) do
mt_native["register_"..key], minetest["register_"..key], minetest["on_register_"..key] =
key_event_setup(key, minetest["register_"..key])
end
-- Special case for weird plurals.
mt_native.register_entity, minetest.register_entity, minetest.on_register_entity =
key_event_setup("entity", minetest.register_entity, "registered_entities")
local function lazy_extend(base, length)
if (length == 0) then
return base
end
return function(n)
local step = _.extend(n, base)
return lazy_extend(step, length-1)
end
end
-- Extend/Copy functions
for i, key in pairs({
"craftitem",
"node",
"tool",
"entity"
}) do
minetest["extend_"..key] = function(old_name, new_name, params)
assert(type(old_name) == "string", "Extension target key must be a string. Got "..type(old_name).." instead.")
assert(old_name ~= any, "Attempted to use special 'any' value for extension.")
assert(not string.match(old_name, "^group:"), old_name.." is a group and shouldn't be used as an extension target.")
if type(new_name) ~= "string" and params == nil then
params = new_name
new_name = old_name
end
local san_name = string.gsub(new_name, "^:+", "")
local extend = type(params) == "function" and params
or function(old,new)
local result = {}
for k,v in pairs(old) do
result[k] = v
end
for k,v in pairs(new) do
result[k] = v
end
return result
end
minetest["on_register_"..key](old_name):subscribe(function(old_params)
if (old_params) then
local new_params = extend(old_params, params or {})
print("Extending "..old_name.." to "..new_name..".")
-- At least try to prevent infinite loops
if (old_name == new_name) then
mt_native["register_"..key](":"..san_name, new_params)
else
minetest["register_"..key](":"..san_name, new_params)
end
end
end)
end
end