Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Illuna-Minetest/mesecons
1 result
Show changes
Showing
with 94 additions and 41 deletions
Effector, glows blue when powered.
It works in an inactive block.
Effector, glows dark grey when powered.
It works in an inactive block.
Effector, glows green when powered.
It works in an inactive block.
Effector, glows light grey when powered.
It works in an inactive block.
Effector, glows red when powered.
It works in an inactive block.
Effector, glows yellow when powered.
It works in an inactive block.
The Luacontroller is an advanced programmable component.
You can simply code it in the language Mesecons uses itself: Lua!
All the code runs in a sandbox, so it's completely safe (but I won't guarantee that for absolute certainty!).
It works fine in an unloaded block, loading the block when the program needs to run.
Events are properly delivered after a server restart.
<a href="http://mesecons.net/luacontroller/">Documentation is available here!</a>
......@@ -266,32 +266,45 @@ local function remove_functions(x)
return x
end
-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
local function get_interrupt(pos, itbl, send_warning)
-- iid = interrupt id
local function interrupt(time, iid)
-- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
-- Hence the values get moved out. Should take less time than original, so totally compatible
if type(time) ~= "number" then return end
table.insert(itbl, function ()
-- Outside string metatable sandbox, can safely run this now
local luac_id = minetest.get_meta(pos):get_int("luac_id")
-- Check if IID is dodgy, so you can't use interrupts to store an infinite amount of data.
-- Note that this is safe from alter-after-free because this code gets run after the sandbox has ended.
-- This runs outside of the timer and *shouldn't* harm perf. unless dodgy data is being sent in the first place
iid = remove_functions(iid)
local msg_ser = minetest.serialize(iid)
if #msg_ser <= mesecon.setting("luacontroller_interruptid_maxlen", 256) then
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1)
else
send_warning("An interrupt ID was too large!")
end
-- The setting affects API so is not intended to be changeable at runtime
local get_interrupt
if mesecon.setting("luacontroller_lightweight_interrupts", false) then
-- use node timer
get_interrupt = function(pos, itbl, send_warning)
return (function(time, iid)
if type(time) ~= "number" then error("Delay must be a number") end
if iid ~= nil then send_warning("Interrupt IDs are disabled on this server") end
table.insert(itbl, function() minetest.get_node_timer(pos):start(time) end)
end)
end
return interrupt
else
-- use global action queue
-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
get_interrupt = function(pos, itbl, send_warning)
-- iid = interrupt id
local function interrupt(time, iid)
-- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
-- Hence the values get moved out. Should take less time than original, so totally compatible
if type(time) ~= "number" then error("Delay must be a number") end
table.insert(itbl, function ()
-- Outside string metatable sandbox, can safely run this now
local luac_id = minetest.get_meta(pos):get_int("luac_id")
-- Check if IID is dodgy, so you can't use interrupts to store an infinite amount of data.
-- Note that this is safe from alter-after-free because this code gets run after the sandbox has ended.
-- This runs outside of the timer and *shouldn't* harm perf. unless dodgy data is being sent in the first place
iid = remove_functions(iid)
local msg_ser = minetest.serialize(iid)
if #msg_ser <= mesecon.setting("luacontroller_interruptid_maxlen", 256) then
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1)
else
send_warning("An interrupt ID was too large!")
end
end)
end
return interrupt
end
end
-- Given a message object passed to digiline_send, clean it up into a form
-- which is safe to transmit over the network and compute its "cost" (a very
-- rough estimate of its memory usage).
......@@ -414,7 +427,6 @@ local function get_digiline_send(pos, itbl, send_warning)
end
end
local safe_globals = {
-- Don't add pcall/xpcall unless willing to deal with the consequences (unless very careful, incredibly likely to allow killing server indirectly)
"assert", "error", "ipairs", "next", "pairs", "select",
......@@ -619,12 +631,13 @@ local function reset_formspec(meta, code, errmsg)
meta:mark_as_private("code")
code = minetest.formspec_escape(code or "")
errmsg = minetest.formspec_escape(tostring(errmsg or ""))
meta:set_string("formspec", "size[12,10]"..
"background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]"..
"textarea[0.2,0.2;12.2,9.5;code;;"..code.."]"..
"image_button[4.75,8.75;2.5,1;jeija_luac_runbutton.png;program;]"..
"image_button_exit[11.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"..
"label[0.1,9;"..errmsg.."]")
meta:set_string("formspec", "size[12,10]"
.."background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]"
.."label[0.1,8.3;"..errmsg.."]"
.."textarea[0.2,0.2;12.2,9.5;code;;"..code.."]"
.."image_button[4.75,8.75;2.5,1;jeija_luac_runbutton.png;program;]"
.."image_button_exit[11.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"
)
end
local function reset_meta(pos, code, errmsg)
......@@ -650,6 +663,14 @@ local function reset(pos)
set_port_states(pos, {a=false, b=false, c=false, d=false})
end
local function node_timer(pos)
if minetest.registered_nodes[minetest.get_node(pos).name].is_burnt then
return false
end
run(pos, {type="interrupt"})
return false
end
-----------------------
-- A.Queue callbacks --
-----------------------
......@@ -822,6 +843,7 @@ for d = 0, 1 do
mesecon.receptor_off(pos, output_rules)
end,
is_luacontroller = true,
on_timer = node_timer,
on_blast = mesecon.on_blastnode,
})
end
......
......@@ -571,6 +571,7 @@ yc.command_parsecondition = function(cond, L, eeprom)
if cond:sub(i+1, i+1) == nil then break end
if s == "&" then
if a==nil then return nil end
if b==nil then return nil end
local buf = ((a==1) and (b==1))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
......@@ -580,6 +581,7 @@ yc.command_parsecondition = function(cond, L, eeprom)
end
if s == "|" then
if a==nil then return nil end
if b==nil then return nil end
local buf = ((a == 1) or (b == 1))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
......@@ -589,6 +591,7 @@ yc.command_parsecondition = function(cond, L, eeprom)
end
if s == "~" then
if a==nil then return nil end
if b==nil then return nil end
local buf = (((a == 1) or (b == 1)) and not((a==1) and (b==1)))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
......
Movestones are effectors that push the blocks in front of them. They move along on the right side of a mesecon wire track.
A movestone trying to move into, or push other nodes into, an unloaded block doesn't move.
Movestones are effectors that push the blocks in front of them. They move along on the right side of a mesecon wire track. Sticky ones also pull blocks.
A sticky movestone trying to move into, or push other nodes into, an unloaded block doesn't move.
A sticky movestone trying to pull nodes from an unloaded block moves but leaves them behind.
......@@ -55,8 +55,6 @@ end
-- tests if the node can be pushed into, e.g. air, water, grass
local function node_replaceable(name)
if name == "ignore" then return true end
if minetest.registered_nodes[name] then
return minetest.registered_nodes[name].buildable_to or false
end
......@@ -260,6 +258,10 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor)
end
end
-- Never push into unloaded blocks. Don’t try to pull from them, either.
-- TODO: load blocks instead, as with wires.
mesecon.register_mvps_stopper("ignore")
mesecon.register_mvps_stopper("doors:door_steel_b_1")
mesecon.register_mvps_stopper("doors:door_steel_t_1")
mesecon.register_mvps_stopper("doors:door_steel_b_2")
......
Pistons are effectors, they push up to 20 blocks in front of them. The push direction can be set by placing them from different angles.
A piston pointing into an unloaded block won't extend.
A piston retracting from an unloaded block works, but gravity-sensitive nodes above the empty space may not fall.
Sticky pistons are effectors, they push up to 20 blocks in front of them. The push direction can be set by placing them from different angles. Sticky ones also pull 1 block.
A sticky piston pointing into an unloaded block won't extend.
A sticky piston retracting from within an unloaded block works and pulls a node, but if it doesn't pull anything, then gravity-sensitive nodes above the empty space may not fall.
An extended sticky piston that touches the surface of an unloaded block and loses signal retracts but doesn't pull anything.
......@@ -55,7 +55,7 @@ local function piston_get_rules(node)
return rules
end
local function piston_remove_pusher(pos, node)
local function piston_remove_pusher(pos, node, check_falling)
local pistonspec = get_pistonspec(node.name, "onname")
local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local pusherpos = vector.add(pos, dir)
......@@ -72,7 +72,14 @@ local function piston_remove_pusher(pos, node)
max_hear_distance = 20,
gain = 0.3,
})
minetest.check_for_falling(pusherpos)
if check_falling then
minetest.check_for_falling(pusherpos)
end
end
local function piston_after_dig(pos, node)
piston_remove_pusher(pos, node, true)
end
local piston_on = function(pos, node)
......@@ -97,7 +104,7 @@ end
local function piston_off(pos, node)
local pistonspec = get_pistonspec(node.name, "onname")
minetest.set_node(pos, {param2 = node.param2, name = pistonspec.offname})
piston_remove_pusher(pos, node)
piston_remove_pusher(pos, node, not pistonspec.sticky)
if not pistonspec.sticky then
return
......@@ -293,7 +300,7 @@ minetest.register_node("mesecons_pistons:piston_normal_on", {
paramtype2 = "facedir",
is_ground_content = false,
drop = "mesecons_pistons:piston_normal_off",
after_dig_node = piston_remove_pusher,
after_dig_node = piston_after_dig,
node_box = piston_on_box,
selection_box = piston_on_box,
sounds = default.node_sound_wood_defaults(),
......@@ -371,7 +378,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_on", {
paramtype2 = "facedir",
is_ground_content = false,
drop = "mesecons_pistons:piston_sticky_off",
after_dig_node = piston_remove_pusher,
after_dig_node = piston_after_dig,
node_box = piston_on_box,
selection_box = piston_on_box,
sounds = default.node_sound_wood_defaults(),
......
A power plant is a receptor that is always turned on: It provides energy.
A power plant is a receptor that is always turned on: it provides energy.
It continues to work in an unloaded block.
This receptor turns on if there's an object above it. And object can be a player, an item, a mob...
This receptor turns on if there's an object above it. An object can be a player, an item, a mob...
This receptor turns on if there's an object above it. And object can be a player, an item, a mob...
This receptor turns on if there's an object above it. An object can be a player, an item, a mob...
Ghoststones disappear when powered, just like Removestones. But in contrast to Removestones, they Reappear again when not powered anymore and they are also conductive.
Ghoststones disappear when powered, just like Removestones. But in contrast to Removestones, they reappear again when not powered anymore and they are also conductive.
They work in inactive blocks.
Removestones are propably the simplest effectors possible. They simply disappear when powered.
Removestones are probably the simplest effectors possible. They simply disappear when powered.
They work in inactive blocks.