diff options
| -rw-r--r-- | LICENSE | 191 | ||||
| -rw-r--r-- | default_settings.lua | 1 | ||||
| -rw-r--r-- | init.lua | 1 | ||||
| -rw-r--r-- | lua_tube.lua | 850 | ||||
| -rw-r--r-- | models.lua | 4 | ||||
| -rw-r--r-- | settingtypes.txt | 4 | ||||
| -rw-r--r-- | textures/pipeworks_lua_tube_port_burnt.png | bin | 0 -> 178 bytes | |||
| -rw-r--r-- | textures/pipeworks_lua_tube_port_off.png | bin | 0 -> 178 bytes | |||
| -rw-r--r-- | textures/pipeworks_lua_tube_port_on.png | bin | 0 -> 178 bytes | 
9 files changed, 1049 insertions, 2 deletions
| @@ -500,3 +500,194 @@ necessary.  Here is a sample; alter the names:    Ty Coon, President of Vice  That's all there is to it! + + +-------------------------------------------------------------------------------- + +Some code in lua_tube.lua is copied from The Mesecons Mod for Minetest: + +License of source code +---------------------- +Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors + +This program is free software; you can redistribute the Mesecons Mod and/or +modify it under the terms of the GNU Lesser General Public License version 3 +published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA  02110-1301, USA. + + +GNU LESSER GENERAL PUBLIC LICENSE +                       Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +  This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + +  0. Additional Definitions. + +  As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + +  "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + +  An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + +  A "Combined Work" is a work produced by combining or linking an +Application with the Library.  The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + +  The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + +  The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +  1. Exception to Section 3 of the GNU GPL. + +  You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +  2. Conveying Modified Versions. + +  If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + +   a) under this License, provided that you make a good faith effort to +   ensure that, in the event an Application does not supply the +   function or data, the facility still operates, and performs +   whatever part of its purpose remains meaningful, or + +   b) under the GNU GPL, with none of the additional permissions of +   this License applicable to that copy. + +  3. Object Code Incorporating Material from Library Header Files. + +  The object code form of an Application may incorporate material from +a header file that is part of the Library.  You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + +   a) Give prominent notice with each copy of the object code that the +   Library is used in it and that the Library and its use are +   covered by this License. + +   b) Accompany the object code with a copy of the GNU GPL and this license +   document. + +  4. Combined Works. + +  You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + +   a) Give prominent notice with each copy of the Combined Work that +   the Library is used in it and that the Library and its use are +   covered by this License. + +   b) Accompany the Combined Work with a copy of the GNU GPL and this license +   document. + +   c) For a Combined Work that displays copyright notices during +   execution, include the copyright notice for the Library among +   these notices, as well as a reference directing the user to the +   copies of the GNU GPL and this license document. + +   d) Do one of the following: + +       0) Convey the Minimal Corresponding Source under the terms of this +       License, and the Corresponding Application Code in a form +       suitable for, and under terms that permit, the user to +       recombine or relink the Application with a modified version of +       the Linked Version to produce a modified Combined Work, in the +       manner specified by section 6 of the GNU GPL for conveying +       Corresponding Source. + +       1) Use a suitable shared library mechanism for linking with the +       Library.  A suitable mechanism is one that (a) uses at run time +       a copy of the Library already present on the user's computer +       system, and (b) will operate properly with a modified version +       of the Library that is interface-compatible with the Linked +       Version. + +   e) Provide Installation Information, but only if you would otherwise +   be required to provide such information under section 6 of the +   GNU GPL, and only to the extent that such information is +   necessary to install and execute a modified version of the +   Combined Work produced by recombining or relinking the +   Application with a modified version of the Linked Version. (If +   you use option 4d0, the Installation Information must accompany +   the Minimal Corresponding Source and Corresponding Application +   Code. If you use option 4d1, you must provide the Installation +   Information in the manner specified by section 6 of the GNU GPL +   for conveying Corresponding Source.) + +  5. Combined Libraries. + +  You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + +   a) Accompany the combined library with a copy of the same work based +   on the Library, uncombined with any other library facilities, +   conveyed under the terms of this License. + +   b) Give prominent notice with the combined library that part of it +   is a work based on the Library, and explaining where to find the +   accompanying uncombined form of the same work. + +  6. Revised Versions of the GNU Lesser General Public License. + +  The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +  Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + +  If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/default_settings.lua b/default_settings.lua index f027461..91e511c 100644 --- a/default_settings.lua +++ b/default_settings.lua @@ -22,6 +22,7 @@ local settings = {  	enable_mese_sand_tube = true,  	enable_one_way_tube = true,  	enable_priority_tube = true, +	enable_lua_tube = true,  	enable_cyclic_mode = true,  	drop_on_routing_fail = false, @@ -119,6 +119,7 @@ if pipeworks.enable_redefines then  	dofile(pipeworks.modpath.."/compat-furnaces.lua")  end  if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.lua") end +if pipeworks.enable_lua_tube then dofile(pipeworks.modpath.."/lua_tube.lua") end  minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty") diff --git a/lua_tube.lua b/lua_tube.lua new file mode 100644 index 0000000..51665ae --- /dev/null +++ b/lua_tube.lua @@ -0,0 +1,850 @@ +--        ______ +--       | +--       | +--       |        __       ___  _   __         _  _ +-- |   | |       |  | |\ |  |  |_| |  | |  |  |_ |_| +-- |___| |______ |__| | \|  |  | \ |__| |_ |_ |_ |\  tube +-- | +-- | +-- + +-- Reference +-- ports = get_real_port_states(pos): gets if inputs are powered from outside +-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port +-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states +-- set_port_states(pos, ports): Applies new port states to a Luacontroller at pos +-- run(pos): runs the code in the controller at pos +-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error messages +-- resetn(pos): performs a hardware reset, turns off all ports +-- +-- The Sandbox +-- The whole code of the controller runs in a sandbox, +-- a very restricted environment. +-- Actually the only way to damage the server is to +-- use too much memory from the sandbox. +-- You can add more functions to the environment +-- (see where local env is defined) +-- Something nice to play is is appending minetest.env to it. + +local BASENAME = "pipeworks:lua_tube" + +local rules = { +	red    = {x = -1, y =  0, z =  0, name = "red"}, +	blue   = {x =  1, y =  0, z =  0, name = "blue"}, +	yellow = {x =  0, y = -1, z =  0, name = "yellow"}, +	green  = {x =  0, y =  1, z =  0, name = "green"}, +	black  = {x =  0, y =  0, z = -1, name = "black"}, +	white  = {x =  0, y =  0, z =  1, name = "white"}, +} + + +------------------ +-- Action stuff -- +------------------ +-- These helpers are required to set the port states of the lua_tube + +local function update_real_port_states(pos, rule_name, new_state) +	local meta = minetest.get_meta(pos) +	if rule_name == nil then +		meta:set_int("real_portstates", 1) +		return +	end +	local n = meta:get_int("real_portstates") - 1 +	local L = {} +	for i = 1, 6 do +		L[i] = n % 2 +		n = math.floor(n / 2) +	end +	--                  (0,0,-1) (0,-1,0) (-1,0,0)      (1,0,0) (0,1,0) (0,0,1) +	local pos_to_side = {  5,        3,       1,   nil,    2,      4,      6  } +	if rule_name.x == nil then +		for _, rname in ipairs(rule_name) do +			local port = pos_to_side[rname.x + (2 * rname.y) + (3 * rname.z) + 4] +			L[port] = (newstate == "on") and 1 or 0 +		end +	else +		local port = pos_to_side[rule_name.x + (2 * rule_name.y) + (3 * rule_name.z) + 4] +		L[port] = (new_state == "on") and 1 or 0 +	end +	meta:set_int("real_portstates", +		 1 + +		 1 * L[1] + +		 2 * L[2] + +		 4 * L[3] + +		 8 * L[4] + +		16 * L[5] + +		32 * L[6]) +end + + +local port_names = {"red", "blue", "yellow", "green", "black", "white"} + +local function get_real_port_states(pos) +	-- Determine if ports are powered (by itself or from outside) +	local meta = minetest.get_meta(pos) +	local L = {} +	local n = meta:get_int("real_portstates") - 1 +	for _, name in ipairs(port_names) do +		L[name] = ((n % 2) == 1) +		n = math.floor(n / 2) +	end +	return L +end + + +local function merge_port_states(ports, vports) +	return { +		red    = ports.red    or vports.red, +		blue   = ports.blue   or vports.blue, +		yellow = ports.yellow or vports.yellow, +		green  = ports.green  or vports.green, +		black  = ports.black  or vports.black, +		white  = ports.white  or vports.white, +	} +end + +local function generate_name(ports) +	local red    = ports.red    and 1 or 0 +	local blue   = ports.blue   and 1 or 0 +	local yellow = ports.yellow and 1 or 0 +	local green  = ports.green  and 1 or 0 +	local black  = ports.black  and 1 or 0 +	local white  = ports.white  and 1 or 0 +	return BASENAME..white..black..green..yellow..blue..red +end + + +local function set_port(pos, rule, state) +	if state then +		mesecon.receptor_on(pos, {rule}) +	else +		mesecon.receptor_off(pos, {rule}) +	end +end + + +local function clean_port_states(ports) +	ports.red    = ports.red    and true or false +	ports.blue   = ports.blue   and true or false +	ports.yellow = ports.yellow and true or false +	ports.green  = ports.green  and true or false +	ports.black  = ports.black  and true or false +	ports.white  = ports.white  and true or false +end + + +local function set_port_states(pos, ports) +	local node = minetest.get_node(pos) +	local name = node.name +	clean_port_states(ports) +	local vports = minetest.registered_nodes[name].virtual_portstates +	local new_name = generate_name(ports) + +	if name ~= new_name and vports then +		-- Problem: +		-- We need to place the new node first so that when turning +		-- off some port, it won't stay on because the rules indicate +		-- there is an onstate output port there. +		-- When turning the output off then, it will however cause feedback +		-- so that the lua_tube will receive an "off" event by turning +		-- its output off. +		-- Solution / Workaround: +		-- Remember which output was turned off and ignore next "off" event. +		local meta = minetest.get_meta(pos) +		local ign = minetest.deserialize(meta:get_string("ignore_offevents")) or {} +		if ports.red    and not vports.red    and not mesecon.is_powered(pos, rules.red)    then ign.red    = true end +		if ports.blue   and not vports.blue   and not mesecon.is_powered(pos, rules.blue)   then ign.blue   = true end +		if ports.yellow and not vports.yellow and not mesecon.is_powered(pos, rules.yellow) then ign.yellow = true end +		if ports.green  and not vports.green  and not mesecon.is_powered(pos, rules.green)  then ign.green  = true end +		if ports.black  and not vports.black  and not mesecon.is_powered(pos, rules.black)  then ign.black  = true end +		if ports.white  and not vports.white  and not mesecon.is_powered(pos, rules.white)  then ign.white  = true end +		meta:set_string("ignore_offevents", minetest.serialize(ign)) + +		minetest.swap_node(pos, {name = new_name, param2 = node.param2}) + +		if ports.red    ~= vports.red    then set_port(pos, rules.red,    ports.red)    end +		if ports.blue   ~= vports.blue   then set_port(pos, rules.blue,   ports.blue)   end +		if ports.yellow ~= vports.yellow then set_port(pos, rules.yellow, ports.yellow) end +		if ports.green  ~= vports.green  then set_port(pos, rules.green,  ports.green)  end +		if ports.black  ~= vports.black  then set_port(pos, rules.black,  ports.black)  end +		if ports.white  ~= vports.white  then set_port(pos, rules.white,  ports.white)  end +	end +end + + +----------------- +-- Overheating -- +----------------- +local function burn_controller(pos) +	local node = minetest.get_node(pos) +	node.name = BASENAME.."_burnt" +	minetest.swap_node(pos, node) +	minetest.get_meta(pos):set_string("lc_memory", ""); +	-- Wait for pending operations +	minetest.after(0.2, mesecon.receptor_off, pos, mesecon.rules.flat) +end + +local function overheat(pos, meta) +	if mesecon.do_overheat(pos) then -- If too hot +		burn_controller(pos) +		return true +	end +end + +------------------------ +-- Ignored off events -- +------------------------ + +local function ignore_event(event, meta) +	if event.type ~= "off" then return false end +	local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents")) or {} +	if ignore_offevents[event.pin.name] then +		ignore_offevents[event.pin.name] = nil +		meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents)) +		return true +	end +end + +------------------------- +-- Parsing and running -- +------------------------- + +local function safe_print(param) +	print(dump(param)) +end + +local function safe_date() +	return(os.date("*t",os.time())) +end + +-- string.rep(str, n) with a high value for n can be used to DoS +-- the server. Therefore, limit max. length of generated string. +local function safe_string_rep(str, n) +	if #str * n > mesecon.setting("luacontroller_string_rep_max", 64000) then +		debug.sethook() -- Clear hook +		error("string.rep: string length overflow", 2) +	end + +	return string.rep(str, n) +end + +-- string.find with a pattern can be used to DoS the server. +-- Therefore, limit string.find to patternless matching. +local function safe_string_find(...) +	if (select(4, ...)) ~= true then +		debug.sethook() -- Clear hook +		error("string.find: 'plain' (fourth parameter) must always be true in a lua controlled tube") +	end + +	return string.find(...) +end + +local function remove_functions(x) +	local tp = type(x) +	if tp == "function" then +		return nil +	end + +	-- Make sure to not serialize the same table multiple times, otherwise +	-- writing mem.test = mem in the lua controlled tube will lead to infinite recursion +	local seen = {} + +	local function rfuncs(x) +		if seen[x] then return end +		seen[x] = true +		if type(x) ~= "table" then return end + +		for key, value in pairs(x) do +			if type(key) == "function" or type(value) == "function" then +				x[key] = nil +			else +				if type(key) == "table" then +					rfuncs(key) +				end +				if type(value) == "table" then +					rfuncs(value) +				end +			end +		end +	end + +	rfuncs(x) + +	return x +end + +local function get_interrupt(pos) +	-- iid = interrupt id +	local function interrupt(time, iid) +		if type(time) ~= "number" then return end +		local luac_id = minetest.get_meta(pos):get_int("luac_id") +		mesecon.queue:add_action(pos, "pipeworks:lc_tube_interrupt", {luac_id, iid}, time, iid, 1) +	end +	return interrupt +end + + +local function get_digiline_send(pos) +	if not digiline then return end +	return function(channel, msg) +		-- Make sure channel is string, number or boolean +		if (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then +			return false +		end + +		-- It is technically possible to send functions over the wire since +		-- the high performance impact of stripping those from the data has +		-- been decided to not be worth the added realism. +		-- Make sure serialized version of the data is not insanely long to +		-- prevent DoS-like attacks +		local msg_ser = minetest.serialize(msg) +		if #msg_ser > mesecon.setting("luacontroller_digiline_maxlen", 50000) then +			return false +		end + +		minetest.after(0, function() +			digilines.receptor_send(pos, digiline.rules.default, channel, msg) +		end) +		return true +	end +end + + +local safe_globals = { +	"assert", "error", "ipairs", "next", "pairs", "select", +	"tonumber", "tostring", "type", "unpack", "_VERSION" +} + +local function create_environment(pos, mem, event) +	-- Gather variables for the environment +	local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates +	local vports_copy = {} +	for k, v in pairs(vports) do vports_copy[k] = v end +	local rports = get_real_port_states(pos) + +	-- Create new library tables on each call to prevent one Luacontroller +	-- from breaking a library and messing up other Luacontrollers. +	local env = { +		pin = merge_port_states(vports, rports), +		port = vports_copy, +		event = event, +		mem = mem, +		heat = mesecon.get_heat(pos), +		heat_max = mesecon.setting("overheat_max", 20), +		print = safe_print, +		interrupt = get_interrupt(pos), +		digiline_send = get_digiline_send(pos), +		string = { +			byte = string.byte, +			char = string.char, +			format = string.format, +			len = string.len, +			lower = string.lower, +			upper = string.upper, +			rep = safe_string_rep, +			reverse = string.reverse, +			sub = string.sub, +			find = safe_string_find, +		}, +		math = { +			abs = math.abs, +			acos = math.acos, +			asin = math.asin, +			atan = math.atan, +			atan2 = math.atan2, +			ceil = math.ceil, +			cos = math.cos, +			cosh = math.cosh, +			deg = math.deg, +			exp = math.exp, +			floor = math.floor, +			fmod = math.fmod, +			frexp = math.frexp, +			huge = math.huge, +			ldexp = math.ldexp, +			log = math.log, +			log10 = math.log10, +			max = math.max, +			min = math.min, +			modf = math.modf, +			pi = math.pi, +			pow = math.pow, +			rad = math.rad, +			random = math.random, +			sin = math.sin, +			sinh = math.sinh, +			sqrt = math.sqrt, +			tan = math.tan, +			tanh = math.tanh, +		}, +		table = { +			concat = table.concat, +			insert = table.insert, +			maxn = table.maxn, +			remove = table.remove, +			sort = table.sort, +		}, +		os = { +			clock = os.clock, +			difftime = os.difftime, +			time = os.time, +			datetable = safe_date, +		}, +	} +	env._G = env + +	for _, name in pairs(safe_globals) do +		env[name] = _G[name] +	end + +	return env +end + + +local function timeout() +	debug.sethook() -- Clear hook +	error("Code timed out!", 2) +end + + +local function create_sandbox(code, env) +	if code:byte(1) == 27 then +		return nil, "Binary code prohibited." +	end +	local f, msg = loadstring(code) +	if not f then return nil, msg end +	setfenv(f, env) + +	-- Turn off JIT optimization for user code so that count +	-- events are generated when adding debug hooks +	if rawget(_G, "jit") then +		jit.off(f, true) +	end + +	return function(...) +		-- Use instruction counter to stop execution +		-- after luacontroller_maxevents +		local maxevents = mesecon.setting("luacontroller_maxevents", 10000) +		debug.sethook(timeout, "", maxevents) +		local ok, ret = pcall(f, ...) +		debug.sethook()  -- Clear hook +		if not ok then error(ret, 0) end +		return ret +	end +end + + +local function load_memory(meta) +	return minetest.deserialize(meta:get_string("lc_memory")) or {} +end + + +local function save_memory(pos, meta, mem) +	local memstring = minetest.serialize(remove_functions(mem)) +	local memsize_max = mesecon.setting("luacontroller_memsize", 100000) + +	if (#memstring <= memsize_max) then +		meta:set_string("lc_memory", memstring) +	else +		print("Error: lua_tube memory overflow. "..memsize_max.." bytes available, " +				..#memstring.." required. Controller overheats.") +		burn_controller(pos) +	end +end + + +local function run(pos, event) +	local meta = minetest.get_meta(pos) +	if overheat(pos) then return end +	if ignore_event(event, meta) then return end + +	-- Load code & mem from meta +	local mem  = load_memory(meta) +	local code = meta:get_string("code") + +	-- Create environment +	local env = create_environment(pos, mem, event) + +	-- Create the sandbox and execute code +	local f, msg = create_sandbox(code, env) +	if not f then return false, msg end +	local succ, msg = pcall(f) +	if not succ then return false, msg end +	if type(env.port) ~= "table" then +		return false, "Ports set are invalid." +	end + +	-- Actually set the ports +	set_port_states(pos, env.port) + +	-- Save memory. This may burn the luacontroller if a memory overflow occurs. +	save_memory(pos, meta, env.mem) + +	return succ, msg +end + +mesecon.queue:add_function("pipeworks:lc_tube_interrupt", function (pos, luac_id, iid) +	-- There is no lua_tube anymore / it has been reprogrammed / replaced / burnt +	if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end +	if (minetest.registered_nodes[minetest.get_node(pos).name].is_burnt) then return end +	run(pos, {type = "interrupt", iid = iid}) +end) + +local function reset_meta(pos, code, errmsg) +	local meta = minetest.get_meta(pos) +	meta:set_string("code", 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_int("luac_id", math.random(1, 65535)) +end + +local function reset(pos) +	set_port_states(pos, {red = false, blue = false, yellow = false, +		green = false, black = false, white = false}) +end + + +----------------------- +-- Node Registration -- +----------------------- + +local output_rules = {} +local input_rules = {} + +local node_box = { +	type = "fixed", +	fixed = { +		pipeworks.tube_leftstub[1],   -- tube segment against -X face +		pipeworks.tube_rightstub[1],  -- tube segment against +X face +		pipeworks.tube_bottomstub[1], -- tube segment against -Y face +		pipeworks.tube_topstub[1],    -- tube segment against +Y face +		pipeworks.tube_frontstub[1],  -- tube segment against -Z face +		pipeworks.tube_backstub[1],   -- tube segment against +Z face +	} +} + +local selection_box = { +	type = "fixed", +	fixed = pipeworks.tube_selectboxes, +} + +local digiline = { +	receptor = {}, +	effector = { +		action = function(pos, node, channel, msg) +			run(pos, {type = "digiline", channel = channel, msg = msg}) +		end +	} +} +local function on_receive_fields(pos, form_name, fields, sender) +	if not fields.program then +		return +	end +	local name = sender:get_player_name() +	if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then +		minetest.record_protection_violation(pos, name) +		return +	end +	reset(pos) +	reset_meta(pos, fields.code) +	local succ, err = run(pos, {type="program"}) +	if not succ then +		print(err) +		reset_meta(pos, fields.code, err) +	end +end + +local function go_back(velocity) +	local adjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}} +	local speed = math.abs(velocity.x + velocity.y + velocity.z) +	if speed == 0 then +		speed = 1 +	end +	local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed} +	if speed >= 4.1 then +		speed = 4 +	elseif speed >= 1.1 then +		speed = speed - 0.1 +	else +		speed = 1 +	end +	vel.speed = speed +	return pipeworks.notvel(adjlist, vel) +end + +local tiles_base = { +	"pipeworks_mese_tube_plain_4.png", "pipeworks_mese_tube_plain_3.png", +	"pipeworks_mese_tube_plain_2.png", "pipeworks_mese_tube_plain_1.png", +	"pipeworks_mese_tube_plain_6.png", "pipeworks_mese_tube_plain_5.png"} + +for red    = 0, 1 do -- 0 = off  1 = on +for blue   = 0, 1 do +for yellow = 0, 1 do +for green  = 0, 1 do +for black  = 0, 1 do +for white  = 0, 1 do +	local cid = tostring(white)..tostring(black)..tostring(green).. +			tostring(yellow)..tostring(blue)..tostring(red) +	local node_name = BASENAME..cid +	local tiles = table.copy(tiles_base) +	if red == 1 then +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +	else +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +	end +	if blue == 1 then +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +	else +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +	end +	if yellow == 1 then +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +	else +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +		tiles[5] = tiles[5].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +		tiles[6] = tiles[6].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +	end +	if green == 1 then +		tiles[3] = tiles[3].."^pipeworks_lua_tube_port_on.png" +		tiles[4] = tiles[4].."^pipeworks_lua_tube_port_on.png" +		tiles[5] = tiles[5].."^pipeworks_lua_tube_port_on.png" +		tiles[6] = tiles[6].."^pipeworks_lua_tube_port_on.png" +	else +		tiles[3] = tiles[3].."^pipeworks_lua_tube_port_off.png" +		tiles[4] = tiles[4].."^pipeworks_lua_tube_port_off.png" +		tiles[5] = tiles[5].."^pipeworks_lua_tube_port_off.png" +		tiles[6] = tiles[6].."^pipeworks_lua_tube_port_off.png" +	end +	if black == 1 then +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +		tiles[2] = tiles[2].."^pipeworks_lua_tube_port_on.png" +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +	else +		tiles[1] = tiles[1].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +		tiles[2] = tiles[2].."^pipeworks_lua_tube_port_off.png" +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +	end +	if white == 1 then +		tiles[1] = tiles[1].."^pipeworks_lua_tube_port_on.png" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_on.png^[transformR180)" +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_on.png^[transformR270)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_on.png^[transformR90)" +	else +		tiles[1] = tiles[1].."^pipeworks_lua_tube_port_off.png" +		tiles[2] = tiles[2].."^(pipeworks_lua_tube_port_off.png^[transformR180)" +		tiles[3] = tiles[3].."^(pipeworks_lua_tube_port_off.png^[transformR270)" +		tiles[4] = tiles[4].."^(pipeworks_lua_tube_port_off.png^[transformR90)" +	end + +	local groups = {snappy = 3, tube = 1, tubedevice = 1, overheat = 1} +	if red + blue + yellow + green + black + white ~= 0 then +		groups.not_in_creative_inventory = 1 +	end + +	output_rules[cid] = {} +	input_rules[cid] = {} +	if red    == 1 then table.insert(output_rules[cid], rules.red)    end +	if blue   == 1 then table.insert(output_rules[cid], rules.blue)   end +	if yellow == 1 then table.insert(output_rules[cid], rules.yellow) end +	if green  == 1 then table.insert(output_rules[cid], rules.green)  end +	if black  == 1 then table.insert(output_rules[cid], rules.black)  end +	if white  == 1 then table.insert(output_rules[cid], rules.white)  end + +	if red    == 0 then table.insert( input_rules[cid], rules.red)    end +	if blue   == 0 then table.insert( input_rules[cid], rules.blue)   end +	if yellow == 0 then table.insert( input_rules[cid], rules.yellow) end +	if green  == 0 then table.insert( input_rules[cid], rules.green)  end +	if black  == 0 then table.insert( input_rules[cid], rules.black)  end +	if white  == 0 then table.insert( input_rules[cid], rules.white)  end + +	local mesecons = { +		effector = { +			rules = input_rules[cid], +			action_change = function (pos, _, rule_name, new_state) +				update_real_port_states(pos, rule_name, new_state) +				run(pos, {type=new_state, pin=rule_name}) +			end, +		}, +		receptor = { +			state = mesecon.state.on, +			rules = output_rules[cid] +		} +	} + +	minetest.register_node(node_name, { +		description = "Lua controlled Tube", +		drawtype = "nodebox", +		tiles = tiles, +		paramtype = "light", +		groups = groups, +		drop = BASENAME.."000000", +		sunlight_propagates = true, +		selection_box = selection_box, +		node_box = node_box, +		on_construct = reset_meta, +		on_receive_fields = on_receive_fields, +		sounds = default.node_sound_wood_defaults(), +		mesecons = mesecons, +		digiline = digiline, +		-- Virtual portstates are the ports that +		-- the node shows as powered up (light up). +		virtual_portstates = { +			red    = red    == 1, +			blue   = blue   == 1, +			yellow = yellow == 1, +			green  = green  == 1, +			black  = black  == 1, +			white  = white  == 1, +		}, +		after_dig_node = function(pos, node) +			mesecon.do_cooldown(pos) +			mesecon.receptor_off(pos, output_rules) +			pipeworks.after_dig(pos, node) +		end, +		is_luacontroller = true, +		tubelike = 1, +		tube = { +			connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}, +			priority = 50, +			can_go = function(pos, node, velocity, stack) +				local succ, msg = run(pos, { +					type = "item", +					itemstring = stack:to_string(), +					item = stack:to_table(), +					velocity = velocity, +				}) +				if not succ or type(msg) ~= "string" then +					return go_back(velocity) +				end +				local r = rules[msg] +				return r and {r} or go_back(velocity) +			end, +		}, +		after_place_node = pipeworks.after_place, +		on_blast = function(pos, intensity) +			if not intensity or intensity > 1 + 3^0.5 then +				minetest.remove_node(pos) +				return {string.format("%s_%s", name, dropname)} +			end +			minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"}) +			pipeworks.scan_for_tube_objects(pos) +		end, +		on_blast = function(pos, intensity) +			if not intensity or intensity > 1 + 3^0.5 then +				minetest.remove_node(pos) +				return {string.format("%s_%s", name, dropname)} +			end +			minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"}) +			pipeworks.scan_for_tube_objects(pos) +		end, +	}) +end +end +end +end +end +end + +------------------------------------ +-- Overheated Lua controlled Tube -- +------------------------------------ + +local tiles_burnt = table.copy(tiles_base) +tiles_burnt[1] = tiles_burnt[1].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" +tiles_burnt[2] = tiles_burnt[2].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" +tiles_burnt[5] = tiles_burnt[5].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[6] = tiles_burnt[6].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" +tiles_burnt[1] = tiles_burnt[1].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[2] = tiles_burnt[2].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[5] = tiles_burnt[5].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" +tiles_burnt[6] = tiles_burnt[6].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[3] = tiles_burnt[3].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[4] = tiles_burnt[4].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[5] = tiles_burnt[5].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[6] = tiles_burnt[6].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[3] = tiles_burnt[3].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[4] = tiles_burnt[4].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[5] = tiles_burnt[5].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[6] = tiles_burnt[6].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[1] = tiles_burnt[1].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[2] = tiles_burnt[2].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[3] = tiles_burnt[3].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" +tiles_burnt[4] = tiles_burnt[4].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[1] = tiles_burnt[1].."^pipeworks_lua_tube_port_burnt.png" +tiles_burnt[2] = tiles_burnt[2].."^(pipeworks_lua_tube_port_burnt.png^[transformR180)" +tiles_burnt[3] = tiles_burnt[3].."^(pipeworks_lua_tube_port_burnt.png^[transformR270)" +tiles_burnt[4] = tiles_burnt[4].."^(pipeworks_lua_tube_port_burnt.png^[transformR90)" + +minetest.register_node(BASENAME .. "_burnt", { +	drawtype = "nodebox", +	tiles = tiles_burnt, +	is_burnt = true, +	paramtype = "light", +	groups = {snappy = 3, tube = 1, tubedevice = 1, not_in_creative_inventory=1}, +	drop = BASENAME.."000000", +	sunlight_propagates = true, +	selection_box = selection_box, +	node_box = node_box, +	on_construct = reset_meta, +	on_receive_fields = on_receive_fields, +	sounds = default.node_sound_wood_defaults(), +	virtual_portstates = {red = false, blue = false, yellow = false, +		green = false, black = false, white = false}, +	mesecons = { +		effector = { +			rules = mesecon.rules.alldirs, +			action_change = function(pos, _, rule_name, new_state) +				update_real_port_states(pos, rule_name, new_state) +			end, +		}, +	}, +	tubelike = 1, +	tube = { +		connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}, +		priority = 50, +	}, +	after_place_node = pipeworks.after_place, +	after_dig_node = pipeworks.after_dig, +	on_blast = function(pos, intensity) +		if not intensity or intensity > 1 + 3^0.5 then +			minetest.remove_node(pos) +			return {string.format("%s_%s", name, dropname)} +		end +		minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"}) +		pipeworks.scan_for_tube_objects(pos) +	end, +}) + +------------------------ +-- Craft Registration -- +------------------------ + +minetest.register_craft({ +	type = "shapeless", +	output = BASENAME.."000000", +	recipe = {"pipeworks:mese_tube_000000", "mesecons_luacontroller:luacontroller0000"}, +}) @@ -33,8 +33,8 @@ pipeworks.tube_frontstub = {  }  pipeworks.tube_backstub = { -	{ -9/64, -9/64, -9/64,   9/64, 9/64, 32/64 },	-- tube segment against -Z face -}  +	{ -9/64, -9/64, -9/64,   9/64, 9/64, 32/64 },	-- tube segment against +Z face +}  pipeworks.tube_boxes = {pipeworks.tube_leftstub, pipeworks.tube_rightstub, pipeworks.tube_bottomstub, pipeworks.tube_topstub, pipeworks.tube_frontstub, pipeworks.tube_backstub} diff --git a/settingtypes.txt b/settingtypes.txt index 5086bcf..cd6efbc 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -63,6 +63,10 @@ pipeworks_enable_one_way_tube (Enable One Way Tube) bool true  #always go to it if there are multible ways.  pipeworks_enable_priority_tube (Enable High Priority Tube) bool true +#Enable lua controlled tube. +#It is comparable with mesecons luacontroller. +pipeworks_enable_lua_tube (Enable Lua controlled Tube) bool true +  #Enable cyclic mode.  pipeworks_enable_cyclic_mode (Enable Cyclic Mode) bool true diff --git a/textures/pipeworks_lua_tube_port_burnt.png b/textures/pipeworks_lua_tube_port_burnt.pngBinary files differ new file mode 100644 index 0000000..3384eff --- /dev/null +++ b/textures/pipeworks_lua_tube_port_burnt.png diff --git a/textures/pipeworks_lua_tube_port_off.png b/textures/pipeworks_lua_tube_port_off.pngBinary files differ new file mode 100644 index 0000000..03f7069 --- /dev/null +++ b/textures/pipeworks_lua_tube_port_off.png diff --git a/textures/pipeworks_lua_tube_port_on.png b/textures/pipeworks_lua_tube_port_on.pngBinary files differ new file mode 100644 index 0000000..a7e3d09 --- /dev/null +++ b/textures/pipeworks_lua_tube_port_on.png | 
