Compare commits

...

22 Commits

Author SHA1 Message Date
cora 8810a24ce0 Merge pull request 'ITEMS/REDSTONE/mcl_comparators: Fix redstone comparator flooding crash' (#284) from fix-comparator-cauldron-water-crash into master
Reviewed-on: Mineclonia/Mineclonia#284
Reviewed-by: cora <cora@noreply.git.minetest.land>
2022-02-23 22:30:44 +00:00
Nils Dagsson Moskopp be915478af
Fix redstone comparator flooding crash
Redstone comparators have two modes, comparison mode & subtraction mode.
Before this patch, the functions to turn comparators on or off attempted
to swap nodes with comparators in the same mode, but failed to determine
the correct replacement node, if the existing node was not a comparator.

When a comparator in an on state (e.g. powered by a filled cauldron) was
flooded, the flooding dropped the comparator and replaced the comparator
node that was to be swapped out with air, which lead to a server crash.

This patch changes the functions that turn comparators on or off so they
only swap existing nodes with comparators in the same mode if the name
of the replacement node can be determined – i.e. if it is not nil.
2022-02-23 00:27:56 +01:00
Nils Dagsson Moskopp d9764fdac6
Add comparator test structure
This patch adds a new test structure to the “/spawnstruct” command which
can be spawned with this command: /spawnstruct test_structure_comparator

The structure was added to reduce manual work when examining or
verifying comparator behaviour after changes to comparator code.
2022-02-22 23:48:10 +01:00
cora de9f2479eb Merge pull request 'HUD/mcl_tmp_message: Add setting for temporary message display duration (default: 10s)' (#266) from tmp-message-timeout-increase into master
Reviewed-on: Mineclonia/Mineclonia#266
Reviewed-by: cora <cora@noreply.git.minetest.land>
2022-02-18 10:59:47 +00:00
Nils Dagsson Moskopp c128d43321
Increase temporary message display duration to 10s 2022-02-12 17:25:09 +01:00
Nils Dagsson Moskopp e7070c034c
Add setting for temporary message display duration 2022-02-12 17:25:03 +01:00
My favourite Minetest cheat clients are Dragonfire and Waspsaliva. 18e299d923 Merge pull request 'ITEMS/mcl_fire: Fix fire spread to not freeze the game' (#234) from fix-fire into master
Reviewed-on: Mineclonia/Mineclonia#234
Reviewed-by: erlehmann <nils+git.minetest.land@dieweltistgarnichtso.net>
2022-02-12 03:39:40 +00:00
cora f5ba6f5649
Fix memory leak & C stack overflow
Before this patch, when placing a fire above a node that would turn it
into eternal fire (e.g. Netherrack or Magma) the spawn_fire() function
would call itself infinitely via the on_construct() handler of eternal
fire – because the latter called spawn_fire() itself.

On an x86 machine, this caused a memory leak, hanging Minetest. On an
x86_64 machine though, Minetest crashed immediately, showing an error
message about a stack overflow.
2022-02-11 17:44:11 +01:00
cora 4647710945
Extinguish fire without nearby “fuel” faster
This patch adjusts how often the ABM runs that removes fire nodes with
no adjacent nodes that can burn up. This makes fire linger less in air.
2022-02-11 17:44:10 +01:00
cora 5d09ec311c
Extinguish fire using an ABM instead of timers
Even the mitigated timers seem to have lead to slow
memory leaks. Once Minetest has used up all the RAM,
it will free some, then quickly use memory up again,
then repeat it ad nauseum, requiring 100% CPU. On a
PC with 2GB of RAM this could be reliably triggered
by having a fire burn a forest for 20 to 30 minutes.

This patch removes fire node timers completely and
instead extinguishes fire using an ABM.
2022-02-11 17:44:09 +01:00
cora ef7370550f
Make fire spread direction truly random
This patch initializes the random number generator used in mcl_fire with
the current Unix timestamp. It also corrects two biases in fire spread
that were caused by nodes being iterated over in a predictable way.
2022-02-11 17:41:42 +01:00
cora 6c2fb98160
Fix nodes with “flammable = -1” not catching fire 2022-02-07 04:51:27 +01:00
cora 052c9fcbcf
Fix diagonal fire-spread
In Minecraft fire spread logic, “adjacent” does not mean “diagonal”.
2022-02-07 04:51:06 +01:00
cora db8fbdc5dd
Fix beds burning away and dropping 2022-02-07 03:39:52 +01:00
cora 1b89c15193
Fix double nodes not being properly removed 2022-02-07 03:39:51 +01:00
cora 02fa2c9e07
Fix nodes that should not burn up burning up
Nodes with the group “flammable = -1” (e.g. crafting tables) must be
able to catch fire, but must not burn up. This patch adds checks for
this group.
2022-02-07 03:39:51 +01:00
cora c12076e74d
Reimplement basic Minecraft-like fire spread 2022-02-07 03:39:45 +01:00
cora 4deca628dc
Make fire actually remove nodes 2022-02-07 03:22:15 +01:00
cora df4ea94dbc
Add node timer back in so fires burn out 2022-02-07 03:22:02 +01:00
cora 8e8ccddb68
Replace MineClone2 fire with Minetest Game ABMs
ABMs have better performance than the laggy timer-based implementation.
2022-02-07 03:18:54 +01:00
My favourite Minetest cheat clients are Dragonfire and Waspsaliva. 11469886e0 Merge pull request 'MAPGEN/mcl_structures: Add (theoretically) fireproof test structure' (#258) from add-fireproof-structure into master
Reviewed-on: Mineclonia/Mineclonia#258
Reviewed-by: Li0n_2 <li0n_2@noreply.git.minetest.land>
2022-02-07 01:24:58 +00:00
Nils Dagsson Moskopp 96822be63d
Add (theoretically) fireproof test structure
This patch adds a new test structure to the “/spawnstruct” command which
can be spawned with this command: /spawnstruct test_structure_fireproof

The structure can be used to verify that eternal fire can be spawned by
the structure placement code. It can also be used to debug fire spread,
as according to Minecraft fire spread rules, it should be fireproof.

See <https://minecraft.fandom.com/wiki/Fire#Spread> for those rules.
2022-02-06 01:19:23 +01:00
8 changed files with 201 additions and 243 deletions

View File

@ -1,4 +1,8 @@
mcl_tmp_message = {}
mcl_tmp_message = {
hud_hide_timeout = tonumber(
minetest.settings:get("mcl_tmp_message_hud_hide_timeout")
) or 10
}
local huds = {}
local hud_hide_timeouts = {}
@ -6,7 +10,7 @@ local hud_hide_timeouts = {}
function mcl_tmp_message.message(player, message)
local name = player:get_player_name()
player:hud_change(huds[name], "text", message)
hud_hide_timeouts[name] = 3
hud_hide_timeouts[name] = mcl_tmp_message.hud_hide_timeout
end
minetest.register_on_joinplayer(function(player)

View File

@ -43,14 +43,20 @@ end
local comparator_activate = function(pos, node)
local def = minetest.registered_nodes[node.name]
minetest.swap_node(pos, { name = def.comparator_onstate, param2 = node.param2 })
local onstate = def.comparator_onstate
if onstate then
minetest.swap_node(pos, { name = onstate, param2 = node.param2 })
end
minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
end
local comparator_deactivate = function(pos, node)
local def = minetest.registered_nodes[node.name]
minetest.swap_node(pos, { name = def.comparator_offstate, param2 = node.param2 })
local offstate = def.comparator_offstate
if offstate then
minetest.swap_node(pos, { name = offstate, param2 = node.param2 })
end
minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
end

View File

@ -81,7 +81,7 @@ function mcl_beds.register_bed(name, def)
paramtype2 = "facedir",
is_ground_content = false,
stack_max = 1,
groups = {handy=1, flammable = 3, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1},
groups = {handy=1, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or default_sounds,
@ -204,7 +204,7 @@ function mcl_beds.register_bed(name, def)
paramtype2 = "facedir",
is_ground_content = false,
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or default_sounds,

View File

@ -5,29 +5,6 @@ mcl_fire = {}
local S = minetest.get_translator("mcl_fire")
local N = function(s) return s end
-- inverse pyramid pattern above lava source, floor 1 of 2:
local lava_fire=
{
{ x =-1, y = 1, z =-1},
{ x =-1, y = 1, z = 0},
{ x =-1, y = 1, z = 1},
{ x = 0, y = 1, z =-1},
{ x = 0, y = 1, z = 0},
{ x = 0, y = 1, z = 1},
{ x = 1, y = 1, z =-1},
{ x = 1, y = 1, z = 0},
{ x = 1, y = 1, z = 1}
}
local alldirs=
{
{ x =-1, y = 0, z = 0},
{ x = 1, y = 0, z = 0},
{ x = 0, y =-1, z = 0},
{ x = 0, y = 1, z = 0},
{ x = 0, y = 0, z =-1},
{ x = 0, y = 0, z = 1}
}
local spawn_smoke = function(pos)
mcl_particles.add_node_particlespawner(pos, {
amount = 0.1,
@ -50,6 +27,34 @@ local spawn_smoke = function(pos)
}, "high")
end
local adjacents = {
{ x =-1, y = 0, z = 0 },
{ x = 1, y = 0, z = 0 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y =-1, z = 0 },
{ x = 0, y = 0, z =-1 },
{ x = 0, y = 0, z = 1 },
}
math.randomseed(os.time())
local function shuffle_table(t)
for i = #t, 1, -1 do
local r = math.random(i)
t[i], t[r] = t[r], t[i]
end
end
shuffle_table(adjacents)
local function has_flammable(pos)
for k,v in pairs(adjacents) do
local p=vector.add(pos,v)
local n=minetest.get_node_or_nil(p)
if n and minetest.get_item_group(n.name, "flammable") ~= 0 then
return p
end
end
end
--
-- Items
--
@ -85,10 +90,6 @@ local fire_death_messages = {
N("@1 died in a fire."),
}
local fire_timer = function(pos)
minetest.get_node_timer(pos):start(math.random(3, 7))
end
local spawn_fire = function(pos, age)
minetest.set_node(pos, {name="mcl_fire:fire", param2 = age})
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
@ -124,82 +125,6 @@ minetest.register_node("mcl_fire:fire", {
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
local node = minetest.get_node(pos)
-- Age is a number from 0 to 15 and is increased every timer step.
-- "old" fire is more likely to be extinguished
local age = node.param2
local flammables = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local below = minetest.get_node({x=pos.x, y=pos.z-1, z=pos.z})
local below_is_flammable = minetest.get_item_group(below.name, "flammable") > 0
-- Extinguish fire
if (not fire_enabled) and (math.random(1,3) == 1) then
minetest.remove_node(pos)
return
end
if age == 15 and not below_is_flammable then
minetest.remove_node(pos)
return
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then
minetest.remove_node(pos)
return
end
local age_add = 1
-- If fire spread is disabled, we have to skip the "destructive" code
if (not fire_enabled) then
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
return
end
-- Spawn fire to nearby flammable nodes
local is_next_to_flammable = minetest.find_node_near(pos, 2, {"group:flammable"}) ~= nil
if is_next_to_flammable and math.random(1,2) == 1 then
-- The fire we spawn copies the age of this fire.
-- This prevents fire from spreading infinitely far as the fire fire dies off
-- quicker the further it has spreaded.
local age_next = math.min(15, age + math.random(0, 1))
-- Select random type of fire spread
local burntype = math.random(1,2)
if burntype == 1 then
-- Spawn fire in air
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #nodes > 0 do
local r = math.random(1, #nodes)
if minetest.find_node_near(nodes[r], 1, {"group:flammable"}) then
spawn_fire(nodes[r], age_next)
break
else
table.remove(nodes, r)
end
end
else
-- Burn flammable block
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
if #nodes > 0 then
local r = math.random(1, #nodes)
local nn = minetest.get_node(nodes[r]).name
local ndef = minetest.registered_nodes[nn]
local fgroup = minetest.get_item_group(nn, "flammable")
if ndef and ndef._on_burn then
ndef._on_burn(nodes[r])
elseif fgroup ~= -1 then
spawn_fire(nodes[r], age_next)
end
end
end
end
-- Regular age increase
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
end,
drop = "",
sounds = {},
-- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer
@ -209,14 +134,12 @@ minetest.register_node("mcl_fire:fire", {
local dim = mcl_worlds.pos_to_dimension(bpos)
if under == "mcl_nether:magma" or under == "mcl_nether:netherrack" or (under == "mcl_core:bedrock" and dim == "end") then
minetest.swap_node(pos, {name = "mcl_fire:eternal_fire"})
minetest.set_node(pos, {name="mcl_fire:eternal_fire"})
end
if minetest.get_modpath("mcl_portals") then
mcl_portals.light_nether_portal(pos)
end
fire_timer(pos)
spawn_smoke(pos)
end,
on_destruct = function(pos)
@ -255,29 +178,7 @@ minetest.register_node("mcl_fire:eternal_fire", {
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
if fire_enabled then
local airs = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #airs > 0 do
local r = math.random(1, #airs)
if minetest.find_node_near(airs[r], 1, {"group:flammable"}) then
local node = minetest.get_node(airs[r])
local age = node.param2
local age_next = math.min(15, age + math.random(0, 1))
spawn_fire(airs[r], age_next)
break
else
table.remove(airs, r)
end
end
end
-- Restart timer
fire_timer(pos)
end,
-- Start burning timer and light Nether portal (if possible)
on_construct = function(pos)
fire_timer(pos)
if minetest.get_modpath("mcl_portals") then
mcl_portals.light_nether_portal(pos)
end
@ -402,114 +303,6 @@ if flame_sound then
end
--
-- ABMs
--
-- Extinguish all flames quickly with water and such
minetest.register_abm({
label = "Extinguish fire",
nodenames = {"mcl_fire:fire", "mcl_fire:eternal_fire"},
neighbors = {"group:puts_out_fire"},
interval = 3,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos)
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end,
})
-- Enable the following ABMs according to 'enable fire' setting
local function has_flammable(pos)
local npos, node
for n, v in ipairs(alldirs) do
npos = vector.add(pos, v)
node = minetest.get_node_or_nil(npos)
if node and node.name and minetest.get_item_group(node.name, "flammable") ~= 0 then
return npos
end
end
return false
end
if not fire_enabled then
-- Occasionally remove fire if fire disabled
-- NOTE: Fire is normally extinguished in timer function
minetest.register_abm({
label = "Remove disabled fire",
nodenames = {"mcl_fire:fire"},
interval = 10,
chance = 10,
catch_up = false,
action = minetest.remove_node,
})
else -- Fire enabled
-- Set fire to air nodes
minetest.register_abm({
label = "Ignite fire by lava",
nodenames = {"group:lava"},
neighbors = {"air"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local i, dir, target, node, i2, f
i = math.random(1,9)
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
if not node or node.name ~= "air" then
i = ((i + math.random(0,7)) % 9) + 1
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
if not node or node.name ~= "air" then
return
end
end
i2 = math.random(1,15)
if i2 < 10 then
local dir2, target2, node2
dir2 = lava_fire[i2]
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z}
node2 = minetest.get_node(target2)
if node2 and node2.name == "air" then
f = has_flammable(target2)
if f then
minetest.after(1, spawn_fire, {x=target2.x, y=target2.y, z=target2.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.7), z=f.z-pos.z},
expirationtime=1, size=1.5, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
return
end
end
end
f = has_flammable(target)
if f then
minetest.after(1, spawn_fire, {x=target.x, y=target.y, z=target.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
expirationtime=1, size=1, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
end
end,
})
end
-- Set pointed_thing on (normal) fire.
-- * pointed_thing: Pointed thing to ignite
-- * player: Player who sets fire or nil if nobody
@ -535,6 +328,144 @@ mcl_fire.set_fire = function(pointed_thing, player, allow_on_fire)
end
end
--
-- ABMs
--
-- Extinguish all flames quickly with water and such
minetest.register_abm({
label = "Extinguish fire",
nodenames = {"mcl_fire:fire", "mcl_fire:eternal_fire"},
neighbors = {"group:puts_out_fire"},
interval = 3,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos)
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end,
})
-- Enable the following ABMs according to 'enable fire' setting
-- [...]a fire that is not adjacent to any flammable block does not spread, even to another flammable block within the normal range.
-- https://minecraft.fandom.com/wiki/Fire#Spread
local function check_aircube(p1,p2)
local nds=minetest.find_nodes_in_area(p1,p2,{"air"})
shuffle_table(nds)
for k,v in pairs(nds) do
if has_flammable(v) then return v end
end
end
-- [...] a fire block can turn any air block that is adjacent to a flammable block into a fire block. This can happen at a distance of up to one block downward, one block sideways (including diagonals), and four blocks upward of the original fire block (not the block the fire is on/next to).
local function get_ignitable(pos)
return check_aircube(vector.add(pos,vector.new(-1,-1,-1)),vector.add(pos,vector.new(1,4,1)))
end
-- Fire spreads from a still lava block similarly: any air block one above and up to one block sideways (including diagonals) or two above and two blocks sideways (including diagonals) that is adjacent to a flammable block may be turned into a fire block.
local function get_ignitable_by_lava(pos)
return check_aircube(vector.add(pos,vector.new(-1,1,-1)),vector.add(pos,vector.new(1,1,1))) or check_aircube(vector.add(pos,vector.new(-2,2,-2)),vector.add(pos,vector.new(2,2,2))) or nil
end
if not fire_enabled then
-- Occasionally remove fire if fire disabled
-- NOTE: Fire is normally extinguished in timer function
minetest.register_abm({
label = "Remove disabled fire",
nodenames = {"mcl_fire:fire"},
interval = 10,
chance = 10,
catch_up = false,
action = minetest.remove_node,
})
else -- Fire enabled
-- Fire Spread
minetest.register_abm({
label = "Ignite flame",
nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"},
interval = 7,
chance = 12,
catch_up = false,
action = function(pos)
local p = get_ignitable(pos)
if p then
spawn_fire(p)
shuffle_table(adjacents)
end
end
})
--lava fire spread
minetest.register_abm({
label = "Ignite fire by lava",
nodenames = {"mcl_core:lava_source","mcl_nether:nether_lava_source"},
neighbors = {"air","group:flammable"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local p=get_ignitable_by_lava(pos)
if p then
spawn_fire(p)
end
end,
})
minetest.register_abm({
label = "Remove fires",
nodenames = {"mcl_fire:fire"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local p=has_flammable(pos)
if p then
local n=minetest.get_node_or_nil(p)
if n and minetest.get_item_group(n.name, "flammable") < 1 then
minetest.remove_node(pos)
end
else
minetest.remove_node(pos)
end
end,
})
-- Remove flammable nodes around basic flame
minetest.register_abm({
label = "Remove flammable nodes",
nodenames = {"mcl_fire:fire","mcl_fire:eternal_fire"},
neighbors = {"group:flammable"},
interval = 5,
chance = 18,
catch_up = false,
action = function(pos)
local p = has_flammable(pos)
if not p then
return
end
local nn = minetest.get_node(p).name
local def = minetest.registered_nodes[nn]
local fgroup = minetest.get_item_group(nn, "flammable")
if def and def._on_burn then
def._on_burn(p)
elseif fgroup ~= -1 then
spawn_fire(p)
minetest.check_for_falling(p)
end
end
})
end
minetest.register_lbm({
label = "Smoke particles from fire",
name = "mcl_fire:smoke",

View File

@ -532,9 +532,19 @@ local function dir_to_rotation(dir)
return "0"
end
mcl_structures.generate_test_structure_comparator = function(pos, rotation, pr)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_test_structure_comparator.mts"
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, nil, pr)
end
mcl_structures.generate_test_structure_fireproof = function(pos, rotation, pr)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_test_structure_fireproof.mts"
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, nil, pr)
end
-- Debug command
minetest.register_chatcommand("spawnstruct", {
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine",
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | test_structure_comparator | test_structure_fireproof",
description = S("Generate a pre-defined structure near your position."),
privs = {debug = true},
func = function(name, param)
@ -568,6 +578,10 @@ minetest.register_chatcommand("spawnstruct", {
mcl_structures.generate_end_exit_portal(pos, rot, pr)
elseif param == "end_portal_shrine" then
mcl_structures.generate_end_portal_shrine(pos, rot, pr)
elseif param == "test_structure_comparator" then
mcl_structures.generate_test_structure_comparator(pos, rot, pr)
elseif param == "test_structure_fireproof" then
mcl_structures.generate_test_structure_fireproof(pos, rot, pr)
elseif param == "" then
message = S("Error: No structure type given. Please use “/spawnstruct <type>”.")
errord = true

View File

@ -102,6 +102,9 @@ animated_chests (Animated chests) bool true
# Whether to preview the player in inventory in 3D (requires Minetest 5.4)
3d_player_preview (3D Player preview) bool true
# How long a temporary message will be shown in the HUD
mcl_tmp_message_hud_hide_timeout (Temporary message display duration) int 10 0 60
[Experimental]
# Whether ice is translucent. If disabled, ice is fully opaque.
#