New general artificial water API

Now nodes other than sponges (i.e. downstream
mods) can create artificial temporary water sources
similar to sponge squeezing.

The API allows specifying a source node and position,
so the water will dissipate if the source node is
removed.  A min/max TTL can also be specified, so
like the sponge, it can require external triggering to
maintain the water flow as well as the presence of
the node.
This commit is contained in:
Aaron Suen 2021-04-10 08:25:21 -04:00
parent 693ff3e420
commit f91bc9d2a1
2 changed files with 90 additions and 42 deletions

View File

@ -16,19 +16,6 @@ local watersrc = "nc_terrain:water_gray_source"
local waterflow = "nc_terrain:water_gray_flowing"
local spongewet = modname .. ":sponge_wet"
local spongecache = {}
local function mkwater(pos, srcpos, new)
if new then nodecore.set_loud(pos, {name = watersrc}) end
local meta = minetest.get_meta(pos)
local data = {
srcpos = srcpos,
expire = nodecore.gametime + 10
}
meta:set_string(modname, minetest.serialize(data))
spongecache[minetest.hash_node_position(pos)] = data
end
nodecore.register_craft({
label = "squeeze sponge",
action = "pummel",
@ -44,36 +31,17 @@ nodecore.register_craft({
for _, d in pairs(spongedirs) do
local p = vector.add(pos, d)
local nn = minetest.get_node(p).name
if nn == "air" or nn == watersrc
or nn == waterflow then
mkwater(p, pos, nn ~= watersrc)
local def = minetest.registered_nodes[nn] or {}
if nn == watersrc or nn == waterflow or def.air_equivalent then
nodecore.artificial_water(p, {
matchpos = pos,
match = spongewet,
minttl = 1,
maxttl = 10
})
found = true
end
end
if found then nodecore.node_sound(pos, "dig") end
end
})
local function rmwater(pos)
nodecore.node_sound(pos, "dig")
return minetest.set_node(pos, {name = waterflow, param2 = 7})
end
nodecore.register_limited_abm({
label = "sponge water check",
interval = 1,
chance = 1,
nodenames = {watersrc},
action = function(pos)
local data = spongecache[minetest.hash_node_position(pos)]
if not data then
data = minetest.get_meta(pos):get_string(modname)
data = data and data ~= "" and minetest.deserialize(data)
end
if not data then return rmwater(pos) end
local snode = minetest.get_node(data.srcpos)
if snode.name == "ignore" then return end
if snode.name ~= spongewet then return rmwater(pos) end
if nodecore.gametime > data.expire then return rmwater(pos) end
end
})

View File

@ -1,12 +1,15 @@
-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore
= math, minetest, nodecore
local math_floor, math_pow
= math.floor, math.pow
local math_floor, math_pow, math_random
= math.floor, math.pow, math.random
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
------------------------------------------------------------------------
-- Hard Stone Strata
nodecore.hard_stone_strata = 7
function nodecore.hard_stone_tile(n)
@ -23,6 +26,9 @@ function nodecore.hard_stone_tile(n)
.. o .. ")"
end
------------------------------------------------------------------------
-- Dirt Leaching
function nodecore.register_dirt_leaching(fromnode, tonode, rate)
local function waterat(pos, dx, dy, dz)
pos = {x = pos.x + dx, y = pos.y + dy, z = pos.z + dz}
@ -54,3 +60,77 @@ function nodecore.register_dirt_leaching(fromnode, tonode, rate)
end
})
end
------------------------------------------------------------------------
-- Artificial Water
local graywatersrc = "nc_terrain:water_gray_source"
local graywaterflow = "nc_terrain:water_gray_flowing"
local graywatercache = {}
local function rmwater(pos)
nodecore.node_sound(pos, "dig")
return minetest.set_node(pos, {name = graywaterflow, param2 = 7})
end
function nodecore.artificial_water_check(pos)
local data = graywatercache[minetest.hash_node_position(pos)]
if not data then
data = minetest.get_meta(pos):get_string(modname)
data = data and data ~= "" and minetest.deserialize(data)
end
if not data then return rmwater(pos) end
if data.recheck and nodecore.gametime < data.recheck then
return nodecore.dnt_set(pos, graywatersrc, data.recheck - nodecore.gametime)
end
if data.expire and nodecore.gametime >= data.expire then
return rmwater(pos)
end
if data.matchpos and data.match then
local mnode = minetest.get_node(data.matchpos)
if mnode.name ~= "ignore" and not nodecore.match(mnode, data.match) then
return rmwater(pos)
end
end
return nodecore.dnt_set(pos, graywatersrc, 1 + math_random())
end
nodecore.register_dnt({
name = graywatersrc,
nodenames = {graywatersrc},
action = function(pos) return nodecore.artificial_water_check(pos) end
})
nodecore.register_limited_abm({
label = "artificial water check",
interval = 1,
chance = 1,
nodenames = {graywatersrc},
action = function(pos) return nodecore.artificial_water_check(pos) end
})
--[[
artificial water def:
- matchpos = position of node that's producing the water
- match = match criteria to check that water-producing node is still present
- minttl = minimum amount of time water must be there before rechecking for valid source
- maxttl = maximum amount of time water will remain without being updated
--]]
function nodecore.artificial_water(pos, def)
local nn = minetest.get_node(pos).name
if nn ~= graywatersrc and nn ~= graywaterflow then
nodecore.set_loud(pos, {name = graywatersrc})
end
local meta = minetest.get_meta(pos)
local data = {
match = def.match,
matchpos = def.matchpos,
recheck = def.minttl and nodecore.gametime + def.minttl,
expire = def.maxttl and nodecore.gametime + def.maxttl
}
meta:set_string(modname, minetest.serialize(data))
graywatercache[minetest.hash_node_position(pos)] = data
return nodecore.dnt_set(pos, graywatersrc, def.minttl or 1)
end