forked from mtcontrib/pipeworks
Add lua controlled tube (#199)
* add lua controlled tube * make textures and fix some bugs
This commit is contained in:
parent
05c0a8670b
commit
e8e9de04dd
191
LICENSE
191
LICENSE
@ -500,3 +500,194 @@ necessary. Here is a sample; alter the names:
|
|||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
That's all there is to it!
|
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.
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ local settings = {
|
|||||||
enable_mese_sand_tube = true,
|
enable_mese_sand_tube = true,
|
||||||
enable_one_way_tube = true,
|
enable_one_way_tube = true,
|
||||||
enable_priority_tube = true,
|
enable_priority_tube = true,
|
||||||
|
enable_lua_tube = true,
|
||||||
enable_cyclic_mode = true,
|
enable_cyclic_mode = true,
|
||||||
drop_on_routing_fail = false,
|
drop_on_routing_fail = false,
|
||||||
|
|
||||||
|
1
init.lua
1
init.lua
@ -119,6 +119,7 @@ if pipeworks.enable_redefines then
|
|||||||
dofile(pipeworks.modpath.."/compat-furnaces.lua")
|
dofile(pipeworks.modpath.."/compat-furnaces.lua")
|
||||||
end
|
end
|
||||||
if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.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")
|
minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty")
|
||||||
|
|
||||||
|
850
lua_tube.lua
Normal file
850
lua_tube.lua
Normal file
@ -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,7 +33,7 @@ pipeworks.tube_frontstub = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pipeworks.tube_backstub = {
|
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}
|
pipeworks.tube_boxes = {pipeworks.tube_leftstub, pipeworks.tube_rightstub, pipeworks.tube_bottomstub, pipeworks.tube_topstub, pipeworks.tube_frontstub, pipeworks.tube_backstub}
|
||||||
|
@ -63,6 +63,10 @@ pipeworks_enable_one_way_tube (Enable One Way Tube) bool true
|
|||||||
#always go to it if there are multible ways.
|
#always go to it if there are multible ways.
|
||||||
pipeworks_enable_priority_tube (Enable High Priority Tube) bool true
|
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.
|
#Enable cyclic mode.
|
||||||
pipeworks_enable_cyclic_mode (Enable Cyclic Mode) bool true
|
pipeworks_enable_cyclic_mode (Enable Cyclic Mode) bool true
|
||||||
|
|
||||||
|
BIN
textures/pipeworks_lua_tube_port_burnt.png
Normal file
BIN
textures/pipeworks_lua_tube_port_burnt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
BIN
textures/pipeworks_lua_tube_port_off.png
Normal file
BIN
textures/pipeworks_lua_tube_port_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
BIN
textures/pipeworks_lua_tube_port_on.png
Normal file
BIN
textures/pipeworks_lua_tube_port_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
Loading…
Reference in New Issue
Block a user