2019-03-04 23:49:16 -05:00
|
|
|
-- LUALOCALS < ---------------------------------------------------------
|
2020-07-03 08:31:03 -04:00
|
|
|
local math, minetest, nodecore, pairs, tonumber, type, vector
|
|
|
|
= math, minetest, nodecore, pairs, tonumber, type, vector
|
2019-12-03 08:01:33 -05:00
|
|
|
local math_random
|
|
|
|
= math.random
|
2019-03-04 23:49:16 -05:00
|
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
|
2020-06-24 08:11:44 -04:00
|
|
|
local modname = minetest.get_current_modname()
|
|
|
|
|
2020-07-03 08:31:03 -04:00
|
|
|
local function config(n)
|
|
|
|
return minetest.settings:get(nodecore.product:lower()
|
|
|
|
.. "_optic_" .. n)
|
|
|
|
end
|
|
|
|
local optic_distance = tonumber(config("distance")) or 16
|
|
|
|
local optic_speed = tonumber(config("speed")) or 12
|
|
|
|
local optic_tick_limit = tonumber(config("tick_limit")) or 10
|
|
|
|
local optic_interval = tonumber(config("interval")) or 5
|
|
|
|
local optic_passive_max = tonumber(config("passive_max")) or 25
|
|
|
|
local optic_passive_min = tonumber(config("passive_max")) or 5
|
|
|
|
|
2020-07-03 09:26:26 -04:00
|
|
|
local hashpos = minetest.hash_node_position
|
2020-07-03 09:23:19 -04:00
|
|
|
local unhash = minetest.get_position_from_hash
|
|
|
|
|
2020-07-01 21:35:23 -04:00
|
|
|
local node_optic_checks = {}
|
|
|
|
local node_optic_sources = {}
|
2020-07-01 21:40:32 -04:00
|
|
|
local node_opaque = {}
|
|
|
|
local node_visinv = {}
|
2020-07-01 21:35:23 -04:00
|
|
|
minetest.after(0, function()
|
|
|
|
for k, v in pairs(minetest.registered_nodes) do
|
|
|
|
node_optic_checks[k] = v.optic_check or nil
|
|
|
|
node_optic_sources[k] = v.optic_source or nil
|
2020-07-01 21:40:32 -04:00
|
|
|
node_opaque[k] = (not v.sunlight_propagates) or nil
|
|
|
|
node_visinv[k] = v.groups and v.groups.visinv or nil
|
2020-07-01 21:35:23 -04:00
|
|
|
end
|
|
|
|
end)
|
2019-03-04 23:49:16 -05:00
|
|
|
|
2020-07-01 21:35:23 -04:00
|
|
|
local optic_queue = {}
|
2020-07-03 09:23:19 -04:00
|
|
|
local passive_queue = {}
|
|
|
|
local dependency_index = {}
|
|
|
|
local dependency_reverse = {}
|
2019-03-07 00:35:27 -05:00
|
|
|
|
2020-07-03 08:37:09 -04:00
|
|
|
local function scan(pos, dir, max, getnode)
|
2019-03-05 23:05:56 -05:00
|
|
|
local p = {x = pos.x, y = pos.y, z = pos.z}
|
2020-07-03 08:31:03 -04:00
|
|
|
if (not max) or (max > optic_distance) then max = optic_distance end
|
2019-12-03 07:57:22 -05:00
|
|
|
for _ = 1, max do
|
2019-03-05 23:05:56 -05:00
|
|
|
p = vector.add(p, dir)
|
2020-07-03 08:37:09 -04:00
|
|
|
local node = getnode(p)
|
|
|
|
if (not node) or node.name == "ignore" then return end
|
2020-07-01 21:40:32 -04:00
|
|
|
if node_opaque[node.name] then return p, node end
|
|
|
|
if node_visinv[node.name] then
|
2019-11-23 08:57:03 -05:00
|
|
|
local stack = nodecore.stack_get(p)
|
2020-07-01 21:40:32 -04:00
|
|
|
if node_opaque[stack:get_name()] then
|
2019-11-23 08:57:03 -05:00
|
|
|
return p, node
|
|
|
|
end
|
|
|
|
end
|
2019-03-05 23:05:56 -05:00
|
|
|
end
|
2019-03-04 23:49:16 -05:00
|
|
|
end
|
|
|
|
|
2020-07-03 08:37:09 -04:00
|
|
|
local function scan_recv(pos, dir, max, getnode)
|
|
|
|
local hit, node = scan(pos, dir, max, getnode)
|
|
|
|
if not node then return end
|
2020-07-01 21:35:23 -04:00
|
|
|
local src = node_optic_sources[node.name]
|
|
|
|
src = src and src(hit, node)
|
|
|
|
if not src then return end
|
|
|
|
local rev = vector.multiply(dir, -1)
|
|
|
|
for _, v in pairs(src) do
|
|
|
|
if vector.equals(v, rev) then
|
|
|
|
return hit, node
|
|
|
|
end
|
|
|
|
end
|
2019-03-05 23:05:56 -05:00
|
|
|
end
|
2019-03-04 23:49:16 -05:00
|
|
|
|
2019-03-07 00:35:27 -05:00
|
|
|
local function optic_check(pos)
|
2020-07-03 09:23:19 -04:00
|
|
|
optic_queue[hashpos(pos)] = pos
|
2019-03-04 23:49:16 -05:00
|
|
|
end
|
2019-03-07 00:35:27 -05:00
|
|
|
nodecore.optic_check = optic_check
|
2019-03-04 23:49:16 -05:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
local get_node_virtual, set_node_virtual, node_virtual_commit
|
|
|
|
do
|
|
|
|
local commit = {}
|
|
|
|
local cache = {}
|
|
|
|
get_node_virtual = function(pos)
|
|
|
|
local hash = hashpos(pos)
|
|
|
|
local found = commit[hash] or cache[hash]
|
|
|
|
if found then return found end
|
|
|
|
found = minetest.get_node(pos)
|
|
|
|
cache[hash] = found
|
|
|
|
return found
|
|
|
|
end
|
|
|
|
set_node_virtual = function(pos, node)
|
|
|
|
commit[hashpos(pos)] = node
|
|
|
|
end
|
|
|
|
node_virtual_commit = function()
|
|
|
|
for k, v in pairs(commit) do
|
|
|
|
minetest.set_node(unhash(k), v)
|
|
|
|
end
|
|
|
|
commit = {}
|
|
|
|
cache = {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-12-03 07:57:22 -05:00
|
|
|
local function optic_trigger(start, dir, max)
|
2020-07-03 09:23:19 -04:00
|
|
|
local pos, node = scan(start, dir, max, get_node_virtual)
|
2020-07-03 08:37:09 -04:00
|
|
|
if node and node_optic_checks[node.name] then
|
|
|
|
return optic_check(pos)
|
|
|
|
end
|
2019-03-04 23:49:16 -05:00
|
|
|
end
|
|
|
|
|
2019-03-12 20:22:42 -04:00
|
|
|
local function optic_process(trans, pos)
|
2020-07-03 09:23:19 -04:00
|
|
|
local node = get_node_virtual(pos)
|
2019-03-24 19:52:14 -04:00
|
|
|
if node.name == "ignore" then return end
|
2019-03-07 00:58:37 -05:00
|
|
|
|
2020-07-01 21:35:23 -04:00
|
|
|
local check = node_optic_checks[node.name]
|
|
|
|
if check then
|
2020-07-03 08:31:03 -04:00
|
|
|
local ignored
|
2020-06-19 10:01:25 -04:00
|
|
|
local deps = {}
|
2020-07-03 08:24:09 -04:00
|
|
|
local getnode = function(p)
|
2020-07-03 09:23:19 -04:00
|
|
|
local gn = get_node_virtual(p)
|
|
|
|
deps[hashpos(p)] = true
|
2020-07-03 08:24:09 -04:00
|
|
|
ignored = ignored or gn.name == "ignore"
|
|
|
|
return gn
|
|
|
|
end
|
2020-07-03 08:37:09 -04:00
|
|
|
local recv = function(dir, max)
|
|
|
|
return scan_recv(pos, dir, max, getnode)
|
2020-07-03 08:31:03 -04:00
|
|
|
end
|
2020-07-03 08:24:09 -04:00
|
|
|
local nn = check(pos, node, recv, getnode)
|
2019-03-24 23:15:25 -04:00
|
|
|
if (not ignored) and nn then
|
2020-07-03 09:23:19 -04:00
|
|
|
trans[hashpos(pos)] = {
|
2019-03-12 20:30:59 -04:00
|
|
|
pos = pos,
|
|
|
|
nn = nn,
|
2020-06-19 10:01:25 -04:00
|
|
|
deps = deps
|
2019-03-12 20:30:59 -04:00
|
|
|
}
|
2019-03-07 00:35:27 -05:00
|
|
|
end
|
|
|
|
end
|
2019-03-04 23:49:16 -05:00
|
|
|
end
|
|
|
|
|
2019-03-12 20:30:59 -04:00
|
|
|
local function optic_commit(v)
|
2020-07-03 09:23:19 -04:00
|
|
|
local node = get_node_virtual(v.pos)
|
2019-03-12 20:30:59 -04:00
|
|
|
|
2020-07-01 21:35:23 -04:00
|
|
|
local oldidx = {}
|
|
|
|
local oldsrc = node_optic_sources[node.name]
|
|
|
|
oldsrc = oldsrc and oldsrc(v.pos, node)
|
|
|
|
if oldsrc then
|
|
|
|
for _, dir in pairs(oldsrc) do
|
2020-07-03 09:23:19 -04:00
|
|
|
oldidx[hashpos(dir)] = dir
|
2020-07-01 21:35:23 -04:00
|
|
|
end
|
2019-03-12 20:30:59 -04:00
|
|
|
end
|
|
|
|
|
2020-07-01 21:35:23 -04:00
|
|
|
local nn = v.nn
|
|
|
|
if type(nn) == "string" then nn = {name = nn} end
|
|
|
|
nn.param = nn.param or node.param
|
|
|
|
nn.param2 = nn.param2 or node.param2
|
|
|
|
if node.name ~= nn.name or node.param ~= nn.param or nn.param2 ~= nn.param2 then
|
2020-07-03 09:23:19 -04:00
|
|
|
set_node_virtual(v.pos, nn)
|
2020-07-01 21:35:23 -04:00
|
|
|
local src = node_optic_sources[nn.name]
|
|
|
|
src = src and src(v.pos, nn)
|
|
|
|
local newidx = {}
|
|
|
|
if src then
|
|
|
|
for _, dir in pairs(src) do
|
2020-07-03 09:23:19 -04:00
|
|
|
local hash = hashpos(dir)
|
2020-07-01 21:35:23 -04:00
|
|
|
if not oldidx[hash] then optic_trigger(v.pos, dir) end
|
|
|
|
newidx[hash] = dir
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for hash, dir in pairs(oldidx) do
|
|
|
|
if not newidx[hash] then optic_trigger(v.pos, dir) end
|
2019-08-27 19:14:51 -04:00
|
|
|
end
|
2019-12-03 07:57:22 -05:00
|
|
|
end
|
2020-06-19 10:01:25 -04:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
local hash = hashpos(v.pos)
|
|
|
|
local olddep = dependency_reverse[hash]
|
2020-06-19 10:01:25 -04:00
|
|
|
if olddep then
|
|
|
|
for k in pairs(olddep) do
|
2020-07-03 09:23:19 -04:00
|
|
|
local t = dependency_index[k]
|
2020-06-19 10:01:25 -04:00
|
|
|
if t then t[hash] = nil end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for k in pairs(v.deps) do
|
2020-07-03 09:23:19 -04:00
|
|
|
local t = dependency_index[k]
|
2020-06-19 10:01:25 -04:00
|
|
|
if not t then
|
|
|
|
t = {}
|
2020-07-03 09:23:19 -04:00
|
|
|
dependency_index[k] = t
|
2020-06-19 10:01:25 -04:00
|
|
|
end
|
|
|
|
t[hash] = true
|
|
|
|
end
|
2019-03-12 20:30:59 -04:00
|
|
|
end
|
|
|
|
|
2020-06-21 10:25:07 -04:00
|
|
|
nodecore.register_limited_abm({
|
2020-06-17 07:09:20 -04:00
|
|
|
label = "optic check",
|
2020-07-03 08:31:03 -04:00
|
|
|
interval = optic_interval,
|
2019-12-03 08:01:33 -05:00
|
|
|
chance = 1,
|
|
|
|
nodenames = {"group:optic_check"},
|
|
|
|
action = function(pos)
|
|
|
|
passive_queue[#passive_queue + 1] = pos
|
|
|
|
end
|
|
|
|
})
|
2020-06-24 08:11:44 -04:00
|
|
|
nodecore.register_lbm({
|
|
|
|
name = modname .. ":check",
|
|
|
|
run_at_every_load = true,
|
|
|
|
nodenames = {"group:optic_check"},
|
|
|
|
action = optic_check
|
|
|
|
})
|
2019-12-03 08:01:33 -05:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
local optic_check_pump
|
|
|
|
do
|
|
|
|
local passive_batch = {}
|
|
|
|
optic_check_pump = function()
|
|
|
|
local batch = optic_queue
|
|
|
|
optic_queue = {}
|
2019-03-07 00:35:27 -05:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
if nodecore.stasis then
|
|
|
|
passive_queue = {}
|
|
|
|
return
|
|
|
|
end
|
2020-06-21 10:46:35 -04:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
if #passive_queue > 0 then
|
|
|
|
passive_batch = passive_queue
|
|
|
|
passive_queue = {}
|
|
|
|
for i = 1, #passive_batch do
|
|
|
|
local j = math_random(1, #passive_batch)
|
|
|
|
local t = passive_batch[i]
|
|
|
|
passive_batch[i] = passive_batch[j]
|
|
|
|
passive_batch[j] = t
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local max = optic_passive_max - #batch
|
|
|
|
if max < optic_passive_min then max = optic_passive_min end
|
|
|
|
if max > #passive_batch then max = #passive_batch end
|
|
|
|
for _ = 1, max do
|
|
|
|
local pos = passive_batch[#passive_batch]
|
|
|
|
passive_batch[#passive_batch] = nil
|
|
|
|
batch[hashpos(pos)] = pos
|
2019-12-03 08:01:33 -05:00
|
|
|
end
|
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
local trans = {}
|
|
|
|
for _, pos in pairs(batch) do
|
|
|
|
optic_process(trans, pos)
|
|
|
|
end
|
2019-03-12 20:22:42 -04:00
|
|
|
|
2020-07-03 09:23:19 -04:00
|
|
|
for _, v in pairs(trans) do
|
|
|
|
optic_commit(v)
|
|
|
|
end
|
2020-06-24 07:45:20 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
do
|
2020-07-03 08:31:03 -04:00
|
|
|
local tick = 1 / optic_speed
|
2020-06-24 07:45:20 -04:00
|
|
|
local total = 0
|
2020-07-03 09:23:19 -04:00
|
|
|
nodecore.register_globalstep("optic tick", function(dtime)
|
2020-06-24 08:03:42 -04:00
|
|
|
total = total + dtime / tick
|
2020-07-03 08:31:03 -04:00
|
|
|
if total > optic_tick_limit then total = optic_tick_limit end
|
2020-06-24 08:03:42 -04:00
|
|
|
while total > 1 do
|
2020-06-24 07:45:20 -04:00
|
|
|
optic_check_pump()
|
2020-06-24 08:03:42 -04:00
|
|
|
total = total - 1
|
2020-06-24 07:45:20 -04:00
|
|
|
end
|
2020-07-03 09:23:19 -04:00
|
|
|
node_virtual_commit()
|
2020-06-24 07:45:20 -04:00
|
|
|
end)
|
|
|
|
end
|
2020-06-19 10:01:25 -04:00
|
|
|
|
|
|
|
for fn in pairs({
|
|
|
|
set_node = true,
|
|
|
|
add_node = true,
|
|
|
|
remove_node = true,
|
|
|
|
swap_node = true,
|
|
|
|
dig_node = true,
|
|
|
|
place_node = true,
|
|
|
|
add_node_level = true
|
|
|
|
}) do
|
|
|
|
local func = minetest[fn]
|
|
|
|
minetest[fn] = function(pos, ...)
|
2020-07-03 09:23:19 -04:00
|
|
|
local t = dependency_index[hashpos(pos)]
|
2020-06-19 10:01:25 -04:00
|
|
|
if t then
|
|
|
|
for k in pairs(t) do
|
2020-07-03 09:23:19 -04:00
|
|
|
optic_check(unhash(k))
|
2020-06-19 10:01:25 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return func(pos, ...)
|
|
|
|
end
|
|
|
|
end
|