43 Commits

Author SHA1 Message Date
db6d1bd9c1 Merge branch 'master' into 'master'
Make luacheck happy

See merge request VanessaE/pipeworks!41
2021-04-06 09:12:01 +00:00
79dc5f5c7d Make luacheck happy 2021-04-06 21:10:08 +12:00
01d44056a2 Merge branch 'master' into 'master'
Remove deprecated invsize

See merge request VanessaE/pipeworks!40
2021-04-06 09:09:56 +00:00
c7d44272e6 Remove deprecated invsize 2021-04-06 21:07:35 +12:00
5837d62979 Merge branch 'categories' 2021-04-05 22:16:04 -04:00
fc6efb450c add support for Unified Inventory categories 2021-04-02 15:48:28 -04:00
828c50e85d Merge branch 'formspec-improvements' into 'master'
Improve formspecs for better mobile usability and consistency

See merge request VanessaE/pipeworks!39
2021-04-02 19:47:48 +00:00
4add40705f Improve formspecs for better mobile usability and consistency 2021-04-02 19:47:48 +00:00
a6e4f2dceb Make sure item_exit() exists before calling it inside minetest.after()
When a signal/detector tube breaks, its minetest.after() can be triggered
just after that, perhaps several times, causing it to try to execute the
item_exit() callback of whatever node is present at least once, but a
broken tube has just taken its place and has no such callback.
2021-03-30 08:28:47 -04:00
7ad991ce40 Assorted changes to tube breaking/repair behavior
* Tubes can now be intentionally broken using a hammer
* Log messages have been improved slightly for tube repair
* Punching a broken tube now causes damage due to the sharp edges
2021-03-27 19:51:23 -05:00
d2954c5277 Get rid of most 5.4.0 texture warnings
This commit also shortens the lua_tube.lua code a bit
2021-03-24 19:47:30 +01:00
9ad6e5d07a Merge branch 'master' into 'master'
Add luacheck config and ci job

See merge request VanessaE/pipeworks!37
2021-02-25 16:34:42 +00:00
31e1255245 Add luacheck config and ci job 2021-02-25 16:34:42 +00:00
a735d1a155 Merge branch 'm_small_fixes' into 'master'
Various small fixes

See merge request VanessaE/pipeworks!35
2021-02-07 12:46:16 +00:00
a2c0dd1130 Various small fixes
* Save the fakeplayer's wielded item in set_wielded_item
* pipeworks.luaentity: Return the found objects in get_objects_inside_radius
* Remove the invalid and unused on_blast return values in lua_tube.lua
  This should avoid a crash when a strong explosion happens next to a Lua Tube.
* Do not access a global "nodename" in a BUG message.
  This avoids a potential crash, in case the message actually appears in practice.
* Set the Flow Sensor and Fountain Head mesecons connection rules
* pipeworks.luaentity: Use the same function for move_to and set_pos
* (no functional change) Do not save the object returned by tube_inject_item into the "item1" local variable in filter-injector.lua
2021-02-07 11:58:18 +01:00
f0ef43823c Merge branch 'm_unused_loop_vars' into 'master'
Remove unused loop variables, trailing whitespace and fix mixed-whitespace indentations

See merge request VanessaE/pipeworks!34
2021-02-05 18:03:54 +00:00
17a602a5a1 Remove unused loop variables, trailing whitespace and fix mixed-whitespace indentations 2021-02-05 17:17:50 +01:00
2294a23582 Merge branch 'm_unused_code_removal' into 'master'
Remove or comment unused code and declare some variables local

See merge request VanessaE/pipeworks!33
2021-02-03 18:33:32 +00:00
b2d2ccbcba Remove or comment unused code and declare some variables local 2021-02-03 18:08:50 +01:00
8322f256c5 Merge branch 'master' into 'master'
Prevent the symptoms of Issue #33

See merge request VanessaE/pipeworks!31
2020-12-18 21:44:11 +00:00
ba7eb19317 Prevent the symptoms of Issue #33
Try to prevent the crash from issue #33 by
replaving nil velocity or acceleration with (0,0,0).
This does not fix the underlying cause of them being nil,
but should prevent the crash.
2020-12-18 19:28:07 +01:00
065c953eba use the right gear item in node breaker 2020-10-28 12:30:48 -04:00
9a63d17e4a Merge branch 'm_disable_print_message' into 'master'
Log the "Pipeworks loaded!" message to infostream instead of printing it

See merge request VanessaE/pipeworks!30
2020-10-17 18:55:24 +00:00
d814357ddf Merge branch 'm_table_extends_clean' into 'master'
Make pipeworks.table_extend easier to read

See merge request VanessaE/pipeworks!29
2020-10-17 18:55:01 +00:00
c2fe5fe956 Make pipeworks.table_extend easier to read
In my opinion this clarifies that tbl2 is attached at the end of tbl
2020-10-17 20:50:20 +02:00
9dbaa5f4f6 Log the "Pipeworks loaded!" message to infostream instead of printing it 2020-10-17 20:46:44 +02:00
d93396600f Merge branch 'protected-access-to-wielders' into 'master'
Allow protected access to wielder inventories.

Closes #40

See merge request VanessaE/pipeworks!27
2020-09-24 15:33:17 +00:00
c966a8a57d Allow players with the protection_bypass privilege or access to
the protection to access wielder node inventories.

Fixes #40.
2020-09-24 05:12:32 -06:00
61b061f669 Merge branch 'avoid-protection-check-on-chest-close' into 'master'
Avoid protection check on chest close.

Closes #23

See merge request VanessaE/pipeworks!26
2020-09-11 09:45:04 +00:00
fe91d5eb46 Avoid protection check on chest close.
Fixes #23.
2020-09-10 23:12:11 -06:00
eb1064ca6d Merge branch 'patch-1' into 'master'
Update pipeworks.zh_CN.tr

See merge request VanessaE/pipeworks!25
2020-09-05 07:14:04 +00:00
f54e25ec52 Update pipeworks.zh_CN.tr 2020-09-05 06:25:58 +00:00
dedb0dd54e Merge branch 'tptube-api' into 'master'
Expose teleport tube database API

See merge request VanessaE/pipeworks!24
2020-08-10 17:54:28 +00:00
SX
477a024034 Expose teleport tube database API 2020-08-09 23:09:31 +03:00
34cb0e7682 Merge branch 'master' into 'master'
Add "get_recipe" digiline command for querying the current autocrafter recipe.

See merge request VanessaE/pipeworks!23
2020-07-30 00:40:41 +00:00
505fc7cc49 Add "get_recipe" digiline command for querying the current autocrafter recipe.
Useful for having the player teach the luacontroller how to craft various items.
2020-07-23 01:49:37 +02:00
cb58a646cf Merge branch 'undefined' into 'master'
Add Chinese Translation

See merge request VanessaE/pipeworks!22
2020-07-19 03:55:39 +00:00
e3135c53f0 Add Chinese Translation 2020-07-19 02:22:12 +00:00
366d57f4da Merge branch 'fix_connect_sides' into 'master'
Consider connect_sides for item transport

See merge request VanessaE/pipeworks!21
2020-06-30 10:39:52 +00:00
c79e68a80c Consider connect_sides for item transport
Previously connect_sides was only used to choose the correct visual
model, but not during item transport. This allowed items to exit tubes
in directions without a visual connection and enter objects from sides
that should not be connectable according to connect_sides.
For example an item could enter a chest from the front, if a tube passed
there.

This change saves the connect_sides in the meta table of the object
whenever the visual representation is updated. When nothing is cached
yet, it uses the old behavior. That way it does not break existing
builds.
2020-06-30 10:11:22 +00:00
9338c109a6 Merge branch 'rebased_luacontroller' into 'master'
Rebase lua_tube onto upstream luacontroller

See merge request VanessaE/pipeworks!20
2020-06-30 09:41:01 +00:00
63bee98948 Fix typo in luatube update_real_port_states helper 2020-06-30 09:17:46 +00:00
ee6c9991b9 Rebase lua_tube onto upstream luacontroller
Adds:
 - various bug fixes
 - error label on the formspec
 - lightweight interrupts
2020-06-30 09:15:50 +00:00
30 changed files with 833 additions and 322 deletions

8
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,8 @@
stages:
- test
luacheck:
stage: test
image: pipelinecomponents/luacheck:latest
script:
- luacheck .

24
.luacheckrc Normal file
View File

@ -0,0 +1,24 @@
unused_args = false
max_line_length= 240
redefined = false
globals = {
"pipeworks",
"luaentity"
}
read_globals = {
-- Stdlib
string = {fields = {"split"}},
table = {fields = {"copy", "getn"}},
-- Minetest
"vector", "ItemStack",
"dump", "minetest",
"VoxelManip", "VoxelArea",
-- mods
"default", "mesecon", "digiline",
"screwdriver", "unified_inventory"
}

View File

@ -47,7 +47,7 @@ local function autocraft(inventory, craft)
end
-- consume material
for itemname, number in pairs(consumption) do
for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
for _ = 1, number do -- We have to do that since remove_item does not work if count > stack_max
inventory:remove_item("src", ItemStack(itemname))
end
end
@ -73,7 +73,7 @@ local function run_autocrafter(pos, elapsed)
return false
end
for step = 1, math.floor(elapsed/craft_time) do
for _ = 1, math.floor(elapsed/craft_time) do
local continue = autocraft(inventory, craft)
if not continue then return false end
end
@ -106,7 +106,6 @@ local function after_recipe_change(pos, inventory)
inventory:set_stack("output", 1, "")
return
end
local recipe_changed = false
local recipe = inventory:get_list("recipe")
local hash = minetest.hash_node_position(pos)
@ -389,6 +388,27 @@ minetest.register_node("pipeworks:autocrafter", {
end
end
after_recipe_change(pos,inv)
elseif msg == "get_recipe" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local recipe = {}
for y=0,2,1 do
local row = {}
for x=1,3,1 do
local slot = y*3+x
table.insert(row, inv:get_stack("recipe",slot):get_name())
end
table.insert(recipe, row)
end
local setchan = meta:get_string("channel")
local output = inv:get_stack("output", 1)
digiline:receptor_send(pos, digiline.rules.default, setchan, {
recipe = recipe,
result = {
name = output:get_name(),
count = output:get_count(),
}
})
elseif msg == "off" then
update_meta(meta, false)
minetest.get_node_timer(pos):stop()
@ -403,6 +423,7 @@ minetest.register_node("pipeworks:autocrafter", {
},
},
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:autocrafter"
minetest.register_craft( {
output = "pipeworks:autocrafter 2",

View File

@ -53,34 +53,35 @@ local function tube_autoroute(pos)
}
-- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6
local positions = {}
local nodes = {}
for i, adj in ipairs(adjustments) do
positions[i] = vector.add(pos, adj)
nodes[i] = minetest.get_node(positions[i])
end
local adjlist = {} -- this will be used in item_transport
for i, adj in ipairs(adjustments) do
local position = vector.add(pos, adj)
local node = minetest.get_node(position)
for i, node in ipairs(nodes) do
local idef = minetest.registered_nodes[node.name]
-- handle the tubes themselves
if is_tube(node.name) then
active[i] = 1
table.insert(adjlist, adj)
-- handle new style connectors
elseif idef and idef.tube and idef.tube.connect_sides then
local dir = adjustments[i]
if idef.tube.connect_sides[nodeside(node, vector.multiply(dir, -1))] then
if idef.tube.connect_sides[nodeside(node, vector.multiply(adj, -1))] then
active[i] = 1
table.insert(adjlist, adj)
end
end
end
minetest.get_meta(pos):set_string("adjlist", minetest.serialize(adjlist))
-- all sides checked, now figure which tube to use.
local nodedef = minetest.registered_nodes[nctr.name]
local basename = nodedef.basename
if nodedef.style == "old" then
local nsurround = ""
for i, n in ipairs(active) do
for _, n in ipairs(active) do
nsurround = nsurround..n
end
nctr.name = basename.."_"..nsurround

View File

@ -86,10 +86,9 @@ function pipeworks.table_contains(tbl, element)
end
function pipeworks.table_extend(tbl, tbl2)
local index = #tbl + 1
for _, elt in ipairs(tbl2) do
tbl[index] = elt
index = index + 1
local oldlength = #tbl
for i = 1,#tbl2 do
tbl[oldlength + i] = tbl2[i]
end
end
@ -115,7 +114,7 @@ local fs_helpers = {}
pipeworks.fs_helpers = fs_helpers
function fs_helpers.on_receive_fields(pos, fields)
local meta = minetest.get_meta(pos)
for field, value in pairs(fields) do
for field in pairs(fields) do
if pipeworks.string_startswith(field, "fs_helpers_cycling:") then
local l = field:split(":")
local new_value = tonumber(l[2])
@ -224,7 +223,7 @@ function pipeworks.create_fake_player(def, is_dynamic)
return self._inventory:set_stack(def.wield_list,
self._wield_index, item)
end
_wielded_item = ItemStack(item)
self._wielded_item = ItemStack(item)
end,
get_wielded_item = function(self, item)
if self._inventory and def.wield_list then
@ -243,17 +242,18 @@ function pipeworks.create_fake_player(def, is_dynamic)
set_bone_position = delay(),
hud_change = delay(),
}
local _trash
-- Getter & setter functions
p.get_inventory_formspec, p.set_inventory_formspec
= get_set_wrap("formspec", is_dynamic)
p.get_breath, p.set_breath = get_set_wrap("breath", is_dynamic)
p.get_hp, p.set_hp = get_set_wrap("hp", is_dynamic)
p.get_pos, p.set_pos = get_set_wrap("pos", is_dynamic)
_trash, p.move_to = get_set_wrap("pos", is_dynamic)
p.get_wield_index, p.set_wield_index = get_set_wrap("wield_index", true)
p.get_properties, p.set_properties = get_set_wrap("properties", false)
-- For players, move_to and get_pos do the same
p.move_to = p.get_pos
-- Backwards compatibilty
p.getpos = p.get_pos
p.setpos = p.set_pos

View File

@ -65,7 +65,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local node = minetest.get_node(pos)
open_chests[pn] = nil
for k, v in pairs(open_chests) do
for _, v in pairs(open_chests) do
if v.pos.x == pos.x and v.pos.y == pos.y and v.pos.z == pos.z then
return true
end
@ -77,10 +77,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
pipeworks.after_place(pos)
end)
minetest.sound_play(sound, {gain = 0.3, pos = pos, max_hear_distance = 10})
end
-- Pipeworks Switch
if pipeworks.may_configure(pos, player) and not fields.quit then
elseif pipeworks.may_configure(pos, player) then
-- Pipeworks Switch
fs_helpers.on_receive_fields(pos, fields)
minetest.show_formspec(player:get_player_name(), "pipeworks:chest_formspec", get_chest_formspec(pos))
end
@ -232,7 +230,7 @@ override.tiles = {
}
-- Add the extra groups
for i,v in ipairs({override_protected, override, override_open, override_protected_open}) do
for _,v in ipairs({override_protected, override, override_open, override_protected_open}) do
v.groups.tubedevice = 1
v.groups.tubedevice_receiver = 1
end

View File

@ -7,7 +7,7 @@ local DS = minetest.get_translator("default")
local fs_helpers = pipeworks.fs_helpers
tube_entry = "^pipeworks_tube_connection_stony.png"
local tube_entry = "^pipeworks_tube_connection_stony.png"
local function active_formspec(fuel_percent, item_percent, pos, meta)
local formspec =

View File

@ -28,6 +28,7 @@ minetest.register_node("pipeworks:steel_block_embedded_tube", {
after_dig_node = pipeworks.after_dig,
on_rotate = pipeworks.on_rotate,
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:steel_block_embedded_tube"
minetest.register_craft( {
output = "pipeworks:steel_block_embedded_tube 1",
@ -45,6 +46,10 @@ local pane_box = {
{ -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 } -- pane
}
}
local texture_alpha_mode = minetest.features.use_texture_alpha_string_modes
and "clip" or true
minetest.register_node("pipeworks:steel_pane_embedded_tube", {
drawtype = "nodebox",
description = S("Airtight panel embedded tube"),
@ -55,6 +60,7 @@ minetest.register_node("pipeworks:steel_pane_embedded_tube", {
"pipeworks_pane_embedded_tube_sides.png",
"pipeworks_pane_embedded_tube_ends.png", "pipeworks_pane_embedded_tube_ends.png",
},
use_texture_alpha = texture_alpha_mode,
node_box = pane_box,
selection_box = pane_box,
collision_box = pane_box,
@ -76,6 +82,7 @@ minetest.register_node("pipeworks:steel_pane_embedded_tube", {
after_dig_node = pipeworks.after_dig,
on_rotate = pipeworks.on_rotate,
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:steel_pane_embedded_tube"
minetest.register_craft( {
output = "pipeworks:steel_pane_embedded_tube 1",

View File

@ -10,7 +10,7 @@ function pipeworks.fix_after_rotation(pos, node, user, mode, new_param2)
if string.find(node.name, "spigot") then new_param2 = new_param2 % 4 end
newnode = string.gsub(node.name, "_on", "_off")
local newnode = string.gsub(node.name, "_on", "_off")
minetest.swap_node(pos, { name = newnode, param2 = new_param2 })
pipeworks.scan_for_pipe_objects(pos)
@ -20,7 +20,7 @@ end
function pipeworks.rotate_on_place(itemstack, placer, pointed_thing)
local playername = placer:get_player_name()
if not minetest.is_protected(pointed_thing.under, playername)
if not minetest.is_protected(pointed_thing.under, playername)
and not minetest.is_protected(pointed_thing.above, playername) then
local node = minetest.get_node(pointed_thing.under)
@ -36,9 +36,7 @@ function pipeworks.rotate_on_place(itemstack, placer, pointed_thing)
local under = pointed_thing.under
local fdir = minetest.dir_to_facedir(placer:get_look_dir())
local undernode = minetest.get_node(under)
local abovenode = minetest.get_node(above)
local uname = undernode.name
local aname = abovenode.name
local isabove = (above.x == under.x) and (above.z == under.z) and (pitch > 0)
local pos1 = above
@ -105,6 +103,7 @@ if minetest.get_modpath("mesecons") then
}
end
--[[
local pipes_devicelist = {
"pump",
"valve",
@ -120,14 +119,15 @@ local pipes_devicelist = {
"storage_tank_9",
"storage_tank_10"
}
--]]
-- Now define the nodes.
local states = { "on", "off" }
local dgroups = ""
for s in ipairs(states) do
local dgroups
if states[s] == "off" then
dgroups = {snappy=3, pipe=1}
else
@ -187,11 +187,11 @@ for s in ipairs(states) do
paramtype = "light",
paramtype2 = "facedir",
selection_box = {
type = "fixed",
type = "fixed",
fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 }
},
collision_box = {
type = "fixed",
type = "fixed",
fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 }
},
groups = dgroups,
@ -222,6 +222,8 @@ for s in ipairs(states) do
new_flow_logic_register.directional_horizonal_rotate(nodename_valve_empty, true)
end
end
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:pump_off"
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:valve_off_empty"
local nodename_valve_loaded = "pipeworks:valve_on_loaded"
minetest.register_node(nodename_valve_loaded, {
@ -233,11 +235,11 @@ minetest.register_node(nodename_valve_loaded, {
paramtype = "light",
paramtype2 = "facedir",
selection_box = {
type = "fixed",
type = "fixed",
fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 }
},
collision_box = {
type = "fixed",
type = "fixed",
fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 }
},
groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
@ -301,6 +303,7 @@ minetest.register_node("pipeworks:grating", {
end,
on_rotate = false
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:grating"
-- outlet spigot
@ -378,6 +381,8 @@ minetest.register_node(nodename_spigot_loaded, {
drop = "pipeworks:spigot",
on_rotate = pipeworks.fix_after_rotation
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:spigot"
-- new flow logic does not currently distinguish between these two visual states.
-- register both so existing flowing spigots continue to work (even if the visual doesn't match the spigot's behaviour).
new_flow_logic_register.directional_horizonal_rotate(nodename_spigot_empty, false)
@ -441,6 +446,9 @@ minetest.register_node(nodename_panel_loaded, {
drop = "pipeworks:entry_panel_empty",
on_rotate = pipeworks.fix_after_rotation
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:entry_panel_empty"
-- TODO: AFAIK the two panels have no visual difference, so are redundant under new flow logic - alias?
new_flow_logic_register.directional_horizonal_rotate(nodename_panel_empty, true)
new_flow_logic_register.directional_horizonal_rotate(nodename_panel_loaded, true)
@ -465,7 +473,7 @@ minetest.register_node(nodename_sensor_empty, {
end,
on_construct = function(pos)
if mesecon then
mesecon.receptor_off(pos, rules)
mesecon.receptor_off(pos, pipeworks.mesecons_rules)
end
end,
selection_box = {
@ -504,7 +512,7 @@ minetest.register_node(nodename_sensor_loaded, {
end,
on_construct = function(pos)
if mesecon then
mesecon.receptor_on(pos, rules)
mesecon.receptor_on(pos, pipeworks.mesecons_rules)
end
end,
selection_box = {
@ -525,6 +533,8 @@ minetest.register_node(nodename_sensor_loaded, {
mesecons = pipereceptor_on,
on_rotate = pipeworks.fix_after_rotation
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:flow_sensor_empty"
new_flow_logic_register.directional_horizonal_rotate(nodename_sensor_empty, true)
new_flow_logic_register.directional_horizonal_rotate(nodename_sensor_loaded, true)
-- activate flow sensor at roughly half the pressure pumps drive pipes
@ -603,6 +613,7 @@ for fill = 0, 10 do
on_rotate = false
})
end
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:storage_tank_0"
-- fountainhead
@ -626,7 +637,7 @@ minetest.register_node(nodename_fountain_empty, {
end,
on_construct = function(pos)
if mesecon then
mesecon.receptor_on(pos, rules)
mesecon.receptor_on(pos, pipeworks.mesecons_rules)
end
end,
selection_box = {
@ -639,6 +650,7 @@ minetest.register_node(nodename_fountain_empty, {
},
on_rotate = false
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:fountainhead"
local nodename_fountain_loaded = "pipeworks:fountainhead_pouring"
minetest.register_node(nodename_fountain_loaded, {
@ -661,7 +673,7 @@ minetest.register_node(nodename_fountain_loaded, {
end,
on_construct = function(pos)
if mesecon then
mesecon.receptor_on(pos, rules)
mesecon.receptor_on(pos, pipeworks.mesecons_rules)
end
end,
selection_box = {
@ -734,6 +746,7 @@ minetest.register_node(nodename_sp_loaded, {
check_for_pole = pipeworks.check_for_vert_pipe,
check_for_horiz_pole = pipeworks.check_for_horiz_pipe
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:straight_pipe_empty"
new_flow_logic_register.directional_horizonal_rotate(nodename_sp_empty, true)
new_flow_logic_register.directional_horizonal_rotate(nodename_sp_loaded, true)

View File

@ -1,10 +1,6 @@
local S = minetest.get_translator("pipeworks")
local fs_helpers = pipeworks.fs_helpers
local function delay(x)
return (function() return x end)
end
local function set_filter_infotext(data, meta)
local infotext = S("@1 Filter-Injector", data.wise_desc)
if meta:get_int("slotseq_mode") == 2 then
@ -18,17 +14,20 @@ local function set_filter_formspec(data, meta)
local formspec
if data.digiline then
formspec = "size[8,2.7]"..
"item_image[0,0;1,1;pipeworks:"..data.name.."]"..
"label[1,0;"..minetest.formspec_escape(itemname).."]"..
"field[0.3,1.5;8.0,1;channel;"..S("Channel")..";${channel}]"..
fs_helpers.cycling_button(meta, "button[0,2;4,1", "slotseq_mode",
formspec =
"size[8.5,3]"..
"item_image[0.2,0;1,1;pipeworks:"..data.name.."]"..
"label[1.2,0.2;"..minetest.formspec_escape(itemname).."]"..
"field[0.5,1.6;4.6,1;channel;"..S("Channel")..";${channel}]"..
"button[4.8,1.3;1.5,1;set_channel;"..S("Set").."]"..
fs_helpers.cycling_button(meta, "button[0.2,2.3;4.05,1", "slotseq_mode",
{S("Sequence slots by Priority"),
S("Sequence slots Randomly"),
S("Sequence slots by Rotation")})..
fs_helpers.cycling_button(meta, "button[4,2;4,1", "exmatch_mode",
fs_helpers.cycling_button(meta, "button[4.25,2.3;4.05,1", "exmatch_mode",
{S("Exact match - off"),
S("Exact match - on")})
S("Exact match - on")})..
"button_exit[6.3,1.3;2,1;close;"..S("Close").."]"
else
local exmatch_button = ""
if data.stackwise then
@ -326,7 +325,8 @@ local function punch_filter(data, filtpos, filtnode, msg)
end
local pos = vector.add(frompos, vector.multiply(dir, 1.4))
local start_pos = vector.add(frompos, dir)
local item1 = pipeworks.tube_inject_item(pos, start_pos, dir, item, fakePlayer:get_player_name())
pipeworks.tube_inject_item(pos, start_pos, dir, item,
fakePlayer:get_player_name())
return true -- only fire one item, please
end
end
@ -428,10 +428,14 @@ for _, data in ipairs({
end
node.on_receive_fields = function(pos, formname, fields, sender)
if not pipeworks.may_configure(pos, sender) then return end
if (fields.quit and not fields.key_enter_field)
or not pipeworks.may_configure(pos, sender) then
return
end
fs_helpers.on_receive_fields(pos, fields)
if fields.channel then
if fields.channel and (fields.key_enter_field == "channel" or fields.set_channel) then
minetest.get_meta(pos):set_string("channel", fields.channel)
end
@ -475,6 +479,7 @@ for _, data in ipairs({
minetest.register_node("pipeworks:"..data.name, node)
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:"..data.name
end
minetest.register_craft( {

View File

@ -60,8 +60,8 @@ pipeworks.check_for_inflows = function(pos,node)
end
end
end
if newnode then
minetest.add_node(pos,{name=newnode, param2 = node.param2})
if newnode then
minetest.add_node(pos,{name=newnode, param2 = node.param2})
minetest.get_meta(pos):set_string("source",minetest.pos_to_string(source))
end
end
@ -75,15 +75,15 @@ pipeworks.check_sources = function(pos,node)
newnode = string.gsub(node.name,"loaded","empty")
end
if newnode then
minetest.add_node(pos,{name=newnode, param2 = node.param2})
if newnode then
minetest.add_node(pos,{name=newnode, param2 = node.param2})
minetest.get_meta(pos):set_string("source","")
end
end
pipeworks.spigot_check = function(pos, node)
local belowname = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name
if belowname and (belowname == "air" or belowname == "default:water_flowing" or belowname == "default:water_source") then
if belowname and (belowname == "air" or belowname == "default:water_flowing" or belowname == "default:water_source") then
local spigotname = minetest.get_node(pos).name
local fdir=node.param2 % 4
local check = {
@ -113,7 +113,7 @@ end
pipeworks.fountainhead_check = function(pos, node)
local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name
if abovename and (abovename == "air" or abovename == "default:water_flowing" or abovename == "default:water_source") then
if abovename and (abovename == "air" or abovename == "default:water_flowing" or abovename == "default:water_source") then
local fountainhead_name = minetest.get_node(pos).name
local near_node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z})
if near_node and string.find(near_node.name, "_loaded") then

View File

@ -5,8 +5,7 @@
--
pipeworks = {}
local DEBUG = false
pipeworks.ui_cat_tube_list = {}
pipeworks.worldpath = minetest.get_worldpath()
pipeworks.modpath = minetest.get_modpath("pipeworks")
@ -71,8 +70,8 @@ function pipeworks.may_configure(pos, player)
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if owner ~= "" then -- wielders and filters
return owner == name
if owner ~= "" and owner == name then -- wielders and filters
return true
end
return not minetest.is_protected(pos, name)
end
@ -150,4 +149,16 @@ end
minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty")
print("Pipeworks loaded!")
-- Unified Inventory categories integration
if unified_inventory and unified_inventory.registered_categories then
if not unified_inventory.registered_categories["automation"] then
unified_inventory.register_category("automation", {
symbol = "pipeworks:lua_tube000000",
label = "Automation components"
})
end
unified_inventory.add_category_items("automation", pipeworks.ui_cat_tube_list)
end
minetest.log("info", "Pipeworks loaded!")

View File

@ -25,7 +25,7 @@ end
-- both optional w/ sensible defaults and fallback to normal allow_* function
-- XXX: possibly change insert_object to insert_item
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 default_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}}
function pipeworks.notvel(tbl, vel)
local tbl2={}
@ -42,7 +42,7 @@ minetest.register_globalstep(function(dtime)
return
end
tube_item_count = {}
for id, entity in pairs(luaentity.entities) do
for _, entity in pairs(luaentity.entities) do
if entity.name == "pipeworks:tubed_item" then
local h = minetest.hash_node_position(vector.round(entity._pos))
tube_item_count[h] = (tube_item_count[h] or 0) + 1
@ -55,15 +55,22 @@ end)
-- tube overload mechanism:
-- when the tube's item count (tracked in the above tube_item_count table)
-- exceeds the limit configured per tube, replace it with a broken one.
function pipeworks.break_tube(pos)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
meta:set_string("the_tube_was", minetest.serialize(node))
minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"})
pipeworks.scan_for_tube_objects(pos)
end
local crunch_tube = function(pos, cnode, cmeta)
if enable_max_limit then
local h = minetest.hash_node_position(pos)
local itemcount = tube_item_count[h] or 0
if itemcount > max_tube_limit then
cmeta:set_string("the_tube_was", minetest.serialize(cnode))
pipeworks.logger("Warning - a tube at "..minetest.pos_to_string(pos).." broke due to too many items ("..itemcount..")")
minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"})
pipeworks.scan_for_tube_objects(pos)
pipeworks.break_tube(pos)
end
end
end
@ -80,6 +87,9 @@ local function go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner)
if minetest.registered_nodes[cnode.name] and minetest.registered_nodes[cnode.name].tube and minetest.registered_nodes[cnode.name].tube.can_go then
can_go = minetest.registered_nodes[cnode.name].tube.can_go(pos, cnode, vel, stack)
else
local adjlist_string = minetest.get_meta(pos):get_string("adjlist")
local adjlist = minetest.deserialize(adjlist_string) or default_adjlist -- backward compat: if not found, use old behavior: all directions
can_go = pipeworks.notvel(adjlist, vel)
end
-- can_go() is expected to return an array-like table of candidate offsets.
@ -191,6 +201,7 @@ minetest.register_entity("pipeworks:tubed_item", {
from_data = function(self, itemstring)
local stack = ItemStack(itemstring)
--[[
local itemtable = stack:to_table()
local itemname = nil
if itemtable then
@ -202,6 +213,7 @@ minetest.register_entity("pipeworks:tubed_item", {
item_texture = minetest.registered_items[itemname].inventory_image
item_type = minetest.registered_items[itemname].type
end
--]]
self.object:set_properties({
is_visible = true,
textures = {stack:get_name()}
@ -388,7 +400,7 @@ if minetest.get_modpath("mesecons_mvps") then
for _, n in ipairs(moved_nodes) do
moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos)
end
for id, entity in pairs(luaentity.entities) do
for _, entity in pairs(luaentity.entities) do
if entity.name == "pipeworks:tubed_item" then
local pos = entity:get_pos()
local rpos = vector.round(pos)

View File

@ -1,6 +1,6 @@
local S = minetest.get_translator("pipeworks")
if not minetest.get_modpath("auto_tree_tap") and
if not minetest.get_modpath("auto_tree_tap") and
minetest.get_modpath("technic") then
minetest.register_abm({
@ -38,10 +38,10 @@ if not minetest.get_modpath("auto_tree_tap") and
after_place_node = function (pos, placer)
pipeworks.scan_for_tube_objects(pos, placer)
local placer_pos = placer:get_pos()
--correct for the player's height
if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
--correct for 6d facedir
if placer_pos then
local dir = {

View File

@ -3,6 +3,10 @@
# License: CC-by-SA 4.0
# Author: Louis Royer <4259825-lroyer@users.noreply.gitlab.com>
## generic interaction
Set=Fixer
Close=Fermer
## digilines interfacing
Channel=Canal
@ -86,11 +90,12 @@ Sorting pneumatic tube=Tuyau pneumatique triant
## teleport tube
Receive=Reception
channels are public by default=Les canaux sont publics par défaut
use <player>:<channel> for fully private channels=Utilisez <joueur>:<canal> pour un canal entièrement privé
use <player>;<channel> for private receivers=Utilisez <joueur>;<canal> pour une réception privée
Channels are public by default=Les canaux sont publics par défaut
Use <player>:<channel> for fully private channels=Utilisez <joueur>:<canal> pour un canal entièrement privé
Use <player>;<channel> for private receivers=Utilisez <joueur>;<canal> pour une réception privée
Teleporting Pneumatic Tube Segment=Segment de tuyau pneumatique téléporteur
unconfigured Teleportation Tube=Tuyau téléporteur non-configuré
Teleporting Tube=Tuyau pneumatique téléporteur
Unconfigured Teleportation Tube=Tuyau téléporteur non-configuré
Sorry, channel '@1' is reserved for exclusive use by @2=Désolé, le canal '@1' est réservé exclusivement à lutilisateur @2.
Sorry, receiving from channel '@1' is reserved for @2=Désolé, la réception depuis le canal '@1' est réservée pour @2.
Teleportation Tube @1 on '@2'=Tuyau de téléportation @1 sur '@2'
@ -102,7 +107,9 @@ Trash Can=Poubelle
Pneumatic tube segment (legacy)=Segment de tuyau pneumatique (obsolète)
## vacuum tubes
Radius=Rayon
Vacuuming Pneumatic Tube Segment=Segment de tuyau pneumatique aspirant
Adjustable Vacuuming Tube=Tuyau pneumatique aspirant réglable
Adjustable Vacuuming Pneumatic Tube Segment=Segment de tuyau pneumatique aspirant réglable
Adjustable Vacuuming Pneumatic Tube Segment (@1m)=Segment de tuyau pneumatique aspirant réglable (@1 m)

117
locale/pipeworks.zh_CN.tr Normal file
View File

@ -0,0 +1,117 @@
# textdomain: pipeworks
# License: CC-by-SA 4.0
# Author: pevernow <3450354617@qq.com>
## generic interaction
Set=
Cancel=
## digilines interfacing
Channel=频道
## init
Allow splitting incoming stacks from tubes=允许从管道中拆分传入堆栈
## autocrafter
Unknown item=通道
unconfigured Autocrafter: unknown recipe=未配置的自动工作台: 未知配方
unconfigured Autocrafter=未配置的自动工作台
'@1' Autocrafter (@2)=自动工作台 '@1' (@2)
Save=保存
paused '@1' Autocrafter=暂停的自动工作台
Autocrafter=自动工作台
## compat-furnaces
Allow splitting incoming material (not fuel) stacks from tubes=允许从管子中分离进来的材料(不是燃料)堆
## decorative tubes
Airtight steelblock embedded tube=密封嵌入式铁块管道
Airtight panel embedded tube=密封嵌入式片状管道
## devices
Pump/Intake Module=泵/进气模块
Valve=阀门
Decorative grating=Decorative grating
Spigot outlet=龙头
Airtight Pipe entry/exit=密闭管进/出
Flow Sensor=流量传感器
Flow sensor (on)=流量传感器(上)
empty=空的
@1% full=满的@1 %
Expansion Tank (@1)=扩展水箱 (@1)
Fluid Storage Tank (@1)=储液罐 (@1)
Fountainhead=源泉
Straight-only Pipe=直管
## filter-injector
(slot #@1 next)=(下一个插槽 : #@1)
@1 Filter-Injector=@1取物器
Sequence slots by Priority=优先顺序排列
Sequence slots Randomly=随机排列时隙
Sequence slots by Rotation=旋转顺序槽
Exact match - off=完全匹配-关闭
Exact match - on=完全匹配-开启
Prefer item types:=偏好物品类型 :
Itemwise=逐项
Stackwise=堆叠方式
Digiline=Digiline
## legacy
Auto-Tap=自动轴阀
## pipes
Pipe Segment=管道
Pipe Segment (legacy)=管道(旧版)
## routing tubes
Pneumatic tube segment=普通管道
Broken Tube=断管
High Priority Tube Segment=高优先级管段
Accelerating Pneumatic Tube Segment=加速管道
Crossing Pneumatic Tube Segment=定向管道
One way tube=单向管
## signal tubes
Detecting Pneumatic Tube Segment on=检测管道(运行中)
Detecting Pneumatic Tube Segment=检测管道
Digiline Detecting Pneumatic Tube Segment=Digiline检测管道
Digiline Detecting Tube=Digiline检测管
Conducting Pneumatic Tube Segment=传导管道
Conducting Pneumatic Tube Segment on=传导管道(运行中)
Digiline Conducting Pneumatic Tube Segment=Digiline传导式气动管道
Mesecon and Digiline Conducting Pneumatic Tube Segment=Mesecon和Digiline传导管道
Mesecon and Digiline Conducting Pneumatic Tube Segment on=Mesecon和Digiline传导管道运行中
## sorting tubes
Sorting Pneumatic Tube Segment=分类管道
Sorting pneumatic tube=分类管道
## teleport tube
Receive=接收
Channels are public by default=频道默认为公开
Use <player>:<channel> for fully private channels=将<player>:<channel>用于完全私人的频道
Use <player>;<channel> for private receivers=使用<player>;<channel>作为私人接收器
Teleporting Pneumatic Tube Segment=传送管道
Teleporting Tube=
Unconfigured Teleportation Tube=未配置的传送管道
Sorry, channel '@1' is reserved for exclusive use by @2=抱歉,频道‘@1保留供@2专用
Sorry, receiving from channel '@1' is reserved for @2=抱歉,从频道'@1'接收的内容已保留给'@2'
Teleportation Tube @1 on '@2'=传送管'@1'在'@2'上
## trashcan
Trash Can=垃圾箱
## tube registration
Pneumatic tube segment (legacy)=普通管道(旧式)
## vacuum tubes
Radius=
Vacuuming Pneumatic Tube Segment=拾取管道
Adjustable Vacuuming Tube=
Adjustable Vacuuming Pneumatic Tube Segment=高级拾取管道
Adjustable Vacuuming Pneumatic Tube Segment (@1m)=高级拾取管道(@1m)
## wielder
Node Breaker=方块破坏器
Deployer=放置器
Dispenser=投掷器

View File

@ -3,6 +3,10 @@
# License: CC-by-SA 4.0
# Author:
## generic interaction
Set=
Cancel=
## digilines interfacing
Channel=
@ -86,11 +90,12 @@ Sorting pneumatic tube=
## teleport tube
Receive=
channels are public by default=
use <player>:<channel> for fully private channels=
use <player>;<channel> for private receivers=
Channels are public by default=
Use <player>:<channel> for fully private channels=
Use <player>;<channel> for private receivers=
Teleporting Pneumatic Tube Segment=
unconfigured Teleportation Tube=
Teleporting Tube=
Unconfigured Teleportation Tube=
Sorry, channel '@1' is reserved for exclusive use by @2=
Sorry, receiving from channel '@1' is reserved for @2=
Teleportation Tube @1 on '@2'=
@ -102,7 +107,9 @@ Trash Can=
Pneumatic tube segment (legacy)=
## vacuum tubes
Radius=
Vacuuming Pneumatic Tube Segment=
Adjustable Vacuuming Tube=
Adjustable Vacuuming Pneumatic Tube Segment=
Adjustable Vacuuming Pneumatic Tube Segment (@1m)=

View File

@ -13,8 +13,10 @@
-- 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
-- run_inner(pos, code, event): runs code on the controller at pos and event
-- reset_formspec(pos, code, errmsg): installs new code and prints error messages, without resetting LCID
-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error message
-- run(pos, event): a wrapper for run_inner which gets code & handles errors via reset_meta
-- resetn(pos): performs a hardware reset, turns off all ports
--
-- The Sandbox
@ -77,7 +79,7 @@ local function update_real_port_states(pos, rule_name, new_state)
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
L[port] = (new_state == "on") and 1 or 0
end
else
local port = pos_to_side[rule_name.x + (2 * rule_name.y) + (3 * rule_name.z) + 4]
@ -168,7 +170,7 @@ local function set_port_states(pos, ports)
-- 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 {}
local ign = minetest.deserialize(meta:get_string("ignore_offevents"), true) 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
@ -214,7 +216,7 @@ end
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 {}
local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents"), true) or {}
if ignore_offevents[event.pin.name] then
ignore_offevents[event.pin.name] = nil
meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents))
@ -227,7 +229,11 @@ end
-------------------------
local function safe_print(param)
local string_meta = getmetatable("")
local sandbox = string_meta.__index
string_meta.__index = string -- Leave string sandbox temporarily
print(dump(param))
string_meta.__index = sandbox -- Restore string sandbox
end
local function safe_date()
@ -267,6 +273,7 @@ local function remove_functions(x)
local seen = {}
local function rfuncs(x)
if x == nil then return end
if seen[x] then return end
seen[x] = true
if type(x) ~= "table" then return end
@ -290,49 +297,174 @@ local function remove_functions(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)
-- 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
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, "pipeworks:lc_tube_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).
--
-- The cleaning comprises the following:
-- 1. Functions (and userdata, though user scripts ought not to get hold of
-- those in the first place) are removed, because they break the model of
-- Digilines as a network that carries basic data, and they could exfiltrate
-- references to mutable objects from one Luacontroller to another, allowing
-- inappropriate high-bandwidth, no-wires communication.
-- 2. Tables are duplicated because, being mutable, they could otherwise be
-- modified after the send is complete in order to change what data arrives
-- at the recipient, perhaps in violation of the previous cleaning rule or
-- in violation of the message size limit.
--
-- The cost indication is only approximate; its not a perfect measurement of
-- the number of bytes of memory used by the message object.
--
-- Parameters:
-- msg -- the message to clean
-- back_references -- for internal use only; do not provide
--
-- Returns:
-- 1. The cleaned object.
-- 2. The approximate cost of the object.
local function clean_and_weigh_digiline_message(msg, back_references)
local t = type(msg)
if t == "string" then
-- Strings are immutable so can be passed by reference, and cost their
-- length plus the size of the Lua object header (24 bytes on a 64-bit
-- platform) plus one byte for the NUL terminator.
return msg, #msg + 25
elseif t == "number" then
-- Numbers are passed by value so need not be touched, and cost 8 bytes
-- as all numbers in Lua are doubles.
return msg, 8
elseif t == "boolean" then
-- Booleans are passed by value so need not be touched, and cost 1
-- byte.
return msg, 1
elseif t == "table" then
-- Tables are duplicated. Check if this table has been seen before
-- (self-referential or shared table); if so, reuse the cleaned value
-- of the previous occurrence, maintaining table topology and avoiding
-- infinite recursion, and charge zero bytes for this as the object has
-- already been counted.
back_references = back_references or {}
local bref = back_references[msg]
if bref then
return bref, 0
end
-- Construct a new table by cleaning all the keys and values and adding
-- up their costs, plus 8 bytes as a rough estimate of table overhead.
local cost = 8
local ret = {}
back_references[msg] = ret
for k, v in pairs(msg) do
local k_cost, v_cost
k, k_cost = clean_and_weigh_digiline_message(k, back_references)
v, v_cost = clean_and_weigh_digiline_message(v, back_references)
if k ~= nil and v ~= nil then
-- Only include an element if its key and value are of legal
-- types.
ret[k] = v
end
-- If we only counted the cost of a table element when we actually
-- used it, we would be vulnerable to the following attack:
-- 1. Construct a huge table (too large to pass the cost limit).
-- 2. Insert it somewhere in a table, with a function as a key.
-- 3. Insert it somewhere in another table, with a number as a key.
-- 4. The first occurrence doesnt pay the cost because functions
-- are stripped and therefore the element is dropped.
-- 5. The second occurrence doesnt pay the cost because its in
-- back_references.
-- By counting the costs regardless of whether the objects will be
-- included, we avoid this attack; it may overestimate the cost of
-- some messages, but only those that wont be delivered intact
-- anyway because they contain illegal object types.
cost = cost + k_cost + v_cost
end
return ret, cost
else
return nil, 0
end
return interrupt
end
local function get_digiline_send(pos)
if not digiline then return end
-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
local function get_digiline_send(pos, itbl, send_warning)
if not minetest.global_exists("digilines") then return end
local chan_maxlen = mesecon.setting("luacontroller_digiline_channel_maxlen", 256)
local maxlen = mesecon.setting("luacontroller_digiline_maxlen", 50000)
return function(channel, msg)
-- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
-- or via anything that could.
-- Make sure channel is string, number or boolean
if (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then
if type(channel) == "string" then
if #channel > chan_maxlen then
send_warning("Channel string too long.")
return false
end
elseif (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then
send_warning("Channel must be string, number or boolean.")
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
local msg_cost
msg, msg_cost = clean_and_weigh_digiline_message(msg)
if msg == nil or msg_cost > maxlen then
send_warning("Message was too complex, or contained invalid data.")
return false
end
minetest.after(0, function()
digilines.receptor_send(pos, digiline_rules_luatube, channel, msg)
table.insert(itbl, function ()
-- Runs outside of string metatable sandbox
local luac_id = minetest.get_meta(pos):get_int("luac_id")
mesecon.queue:add_action(pos, "pipeworks:lt_digiline_relay", {channel, luac_id, msg})
end)
return true
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",
"tonumber", "tostring", "type", "unpack", "_VERSION"
}
local function create_environment(pos, mem, event)
local function create_environment(pos, mem, event, itbl, send_warning)
-- Make sure the tube hasn't broken.
local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates
if not vports then return {} end
@ -352,8 +484,8 @@ local function create_environment(pos, mem, event)
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),
interrupt = get_interrupt(pos, itbl, send_warning),
digiline_send = get_digiline_send(pos, itbl, send_warning),
string = {
byte = string.byte,
char = string.char,
@ -441,10 +573,11 @@ local function create_sandbox(code, env)
jit.off(f, true)
end
local maxevents = mesecon.setting("luacontroller_maxevents", 10000)
return function(...)
-- NOTE: This runs within string metatable sandbox, so the setting's been moved out for safety
-- 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
@ -455,7 +588,7 @@ end
local function load_memory(meta)
return minetest.deserialize(meta:get_string("lc_memory")) or {}
return minetest.deserialize(meta:get_string("lc_memory"), true) or {}
end
@ -465,6 +598,7 @@ local function save_memory(pos, meta, mem)
if (#memstring <= memsize_max) then
meta:set_string("lc_memory", memstring)
meta:mark_as_private("lc_memory")
else
print("Error: lua_tube memory overflow. "..memsize_max.." bytes available, "
..#memstring.." required. Controller overheats.")
@ -472,26 +606,42 @@ local function save_memory(pos, meta, mem)
end
end
local function run(pos, event)
-- Returns success (boolean), errmsg (string), retval(any, return value of the user supplied code)
-- run (as opposed to run_inner) is responsible for setting up meta according to this output
local function run_inner(pos, code, event)
local meta = minetest.get_meta(pos)
if overheat(pos) then return end
if ignore_event(event, meta) then return end
-- Note: These return success, presumably to avoid changing LC ID.
if overheat(pos) then return true, "", nil end
if ignore_event(event, meta) then return true, "", nil end
-- Load code & mem from meta
local mem = load_memory(meta)
local code = meta:get_string("code")
-- 'Last warning' label.
local warning = ""
local function send_warning(str)
warning = "Warning: " .. str
end
-- Create environment
local env = create_environment(pos, mem, event)
local itbl = {}
local env = create_environment(pos, mem, event, itbl, send_warning)
-- 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 not f then return false, msg, nil end
-- Start string true sandboxing
local onetruestring = getmetatable("")
-- If a string sandbox is already up yet inconsistent, something is very wrong
assert(onetruestring.__index == string)
onetruestring.__index = env.string
local success, msg = pcall(f)
onetruestring.__index = string
-- End string true sandboxing
if not success then return false, msg, nil end
if type(env.port) ~= "table" then
return false, "Ports set are invalid."
return false, "Ports set are invalid.", nil
end
-- Actually set the ports
@ -500,35 +650,81 @@ local function run(pos, event)
-- Save memory. This may burn the luacontroller if a memory overflow occurs.
save_memory(pos, meta, env.mem)
return succ, msg
-- Execute deferred tasks
for _, v in ipairs(itbl) do
local failure = v()
if failure then
return false, failure, nil
end
end
return true, warning, 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_formspec(meta, code, errmsg)
meta:set_string("code", code)
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]"
.."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)
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.."]")
reset_formspec(meta, code, errmsg)
meta:set_int("luac_id", math.random(1, 65535))
end
-- Wraps run_inner with LC-reset-on-error
local function run(pos, event)
local meta = minetest.get_meta(pos)
local code = meta:get_string("code")
local ok, errmsg, retval = run_inner(pos, code, event)
if not ok then
reset_meta(pos, code, errmsg)
else
reset_formspec(meta, code, errmsg)
end
return ok, errmsg, retval
end
local function reset(pos)
set_port_states(pos, {red = false, blue = false, yellow = false,
green = false, black = false, white = 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 --
-----------------------
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)
mesecon.queue:add_function("pipeworks:lt_digiline_relay", function (pos, channel, luac_id, msg)
if not digiline then return end
-- This check is only really necessary because in case of server crash, old actions can be thrown into the future
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
-- The actual work
digiline:receptor_send(pos, digiline_rules_luatube, channel, msg)
end)
-----------------------
-- Node Registration --
@ -558,6 +754,7 @@ local digiline = {
receptor = {},
effector = {
action = function(pos, node, channel, msg)
msg = clean_and_weigh_digiline_message(msg)
run(pos, {type = "digiline", channel = channel, msg = msg})
end
},
@ -565,6 +762,18 @@ local digiline = {
rules = pipeworks.digilines_rules
},
}
local function get_program(pos)
local meta = minetest.get_meta(pos)
return meta:get_string("code")
end
local function set_program(pos, code)
reset(pos)
reset_meta(pos, code)
return run(pos, {type="program"})
end
local function on_receive_fields(pos, form_name, fields, sender)
if not fields.program then
return
@ -574,12 +783,10 @@ local function on_receive_fields(pos, form_name, fields, sender)
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)
local ok, err = set_program(pos, fields.code)
if not ok then
-- it's not an error from the server perspective
minetest.log("action", "Lua controller programming error: " .. tostring(err))
end
end
@ -606,82 +813,56 @@ local tiles_base = {
"pipeworks_mese_tube_plain_2.png", "pipeworks_mese_tube_plain_1.png",
"pipeworks_mese_tube_plain_6.png", "pipeworks_mese_tube_plain_5.png"}
local tiles_on_off = {
R__0 = "^pipeworks_lua_tube_port_%s.png",
R_90 = "^(pipeworks_lua_tube_port_%s.png^[transformR90)",
R180 = "^(pipeworks_lua_tube_port_%s.png^[transformR180)",
R270 = "^(pipeworks_lua_tube_port_%s.png^[transformR270)"
}
local texture_alpha_mode = minetest.features.use_texture_alpha_string_modes
and "clip" or true
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 cid = white..black..green..yellow..blue..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
-- Red
tiles[1] = tiles[1]..tiles_on_off.R_90:format(red == 1 and "on" or "off");
tiles[2] = tiles[2]..tiles_on_off.R_90:format(red == 1 and "on" or "off");
tiles[5] = tiles[5]..tiles_on_off.R270:format(red == 1 and "on" or "off");
tiles[6] = tiles[6]..tiles_on_off.R_90:format(red == 1 and "on" or "off");
-- Blue
tiles[1] = tiles[1]..tiles_on_off.R270:format(blue == 1 and "on" or "off");
tiles[2] = tiles[2]..tiles_on_off.R270:format(blue == 1 and "on" or "off");
tiles[5] = tiles[5]..tiles_on_off.R_90:format(blue == 1 and "on" or "off");
tiles[6] = tiles[6]..tiles_on_off.R270:format(blue == 1 and "on" or "off");
-- Yellow
tiles[1] = tiles[1]..tiles_on_off.R180:format(yellow == 1 and "on" or "off");
tiles[2] = tiles[2]..tiles_on_off.R180:format(yellow == 1 and "on" or "off");
tiles[5] = tiles[5]..tiles_on_off.R180:format(yellow == 1 and "on" or "off");
tiles[6] = tiles[6]..tiles_on_off.R180:format(yellow == 1 and "on" or "off");
-- Green
tiles[3] = tiles[3]..tiles_on_off.R__0:format(green == 1 and "on" or "off");
tiles[4] = tiles[4]..tiles_on_off.R__0:format(green == 1 and "on" or "off");
tiles[5] = tiles[5]..tiles_on_off.R__0:format(green == 1 and "on" or "off");
tiles[6] = tiles[6]..tiles_on_off.R__0:format(green == 1 and "on" or "off");
-- Black
tiles[1] = tiles[1]..tiles_on_off.R180:format(black == 1 and "on" or "off");
tiles[2] = tiles[2]..tiles_on_off.R__0:format(black == 1 and "on" or "off");
tiles[3] = tiles[3]..tiles_on_off.R_90:format(black == 1 and "on" or "off");
tiles[4] = tiles[4]..tiles_on_off.R270:format(black == 1 and "on" or "off");
-- White
tiles[1] = tiles[1]..tiles_on_off.R__0:format(white == 1 and "on" or "off");
tiles[2] = tiles[2]..tiles_on_off.R180:format(white == 1 and "on" or "off");
tiles[3] = tiles[3]..tiles_on_off.R270:format(white == 1 and "on" or "off");
tiles[4] = tiles[4]..tiles_on_off.R_90:format(white == 1 and "on" or "off");
local groups = {snappy = 3, tube = 1, tubedevice = 1, overheat = 1}
if red + blue + yellow + green + black + white ~= 0 then
@ -715,14 +896,20 @@ for white = 0, 1 do
receptor = {
state = mesecon.state.on,
rules = output_rules[cid]
}
},
luacontroller = {
get_program = get_program,
set_program = set_program,
},
}
minetest.register_node(node_name, {
description = "Lua controlled Tube",
drawtype = "nodebox",
tiles = tiles,
use_texture_alpha = texture_alpha_mode,
paramtype = "light",
is_ground_content = false,
groups = groups,
drop = BASENAME.."000000",
sunlight_propagates = true,
@ -749,6 +936,7 @@ for white = 0, 1 do
pipeworks.after_dig(pos, node)
end,
is_luacontroller = true,
on_timer = node_timer,
tubelike = 1,
tube = {
connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1},
@ -756,13 +944,13 @@ for white = 0, 1 do
can_go = function(pos, node, velocity, stack)
local src = {name = nil}
-- add color of the incoming tube explicitly; referring to rules, in case they change later
for color, rule in pairs(rules) do
for _, rule in pairs(rules) do
if (-velocity.x == rule.x and -velocity.y == rule.y and -velocity.z == rule.z) then
src.name = rule.name
break
end
end
local succ, msg = run(pos, {
local succ, _, msg = run(pos, {
type = "item",
pin = src,
itemstring = stack:to_string(),
@ -780,15 +968,7 @@ for white = 0, 1 do
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)}
return
end
minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"})
pipeworks.scan_for_tube_objects(pos)
@ -801,6 +981,8 @@ end
end
end
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = BASENAME.."000000"
------------------------------------
-- Overheated Lua controlled Tube --
------------------------------------
@ -834,8 +1016,10 @@ tiles_burnt[4] = tiles_burnt[4].."^(pipeworks_lua_tube_port_burnt.png^[transform
minetest.register_node(BASENAME .. "_burnt", {
drawtype = "nodebox",
tiles = tiles_burnt,
use_texture_alpha = texture_alpha_mode,
is_burnt = true,
paramtype = "light",
is_ground_content = false,
groups = {snappy = 3, tube = 1, tubedevice = 1, not_in_creative_inventory=1},
drop = BASENAME.."000000",
sunlight_propagates = true,
@ -864,7 +1048,7 @@ minetest.register_node(BASENAME .. "_burnt", {
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)}
return
end
minetest.swap_node(pos, {name = "pipeworks:broken_tube_1"})
pipeworks.scan_for_tube_objects(pos)

View File

@ -9,16 +9,16 @@ local filename = minetest.get_worldpath().."/luaentities"
local function read_file()
local f = io.open(filename, "r")
if f == nil then return {} end
local t = f:read("*all")
f:close()
local t = f:read("*all")
f:close()
if t == "" or t == nil then return {} end
return minetest.deserialize(t) or {}
end
local function write_file(tbl)
local f = io.open(filename, "w")
f:write(minetest.serialize(tbl))
f:close()
f:write(minetest.serialize(tbl))
f:close()
end
local function read_entities()
@ -36,7 +36,7 @@ local function read_entities()
y=math.min(30927,y)
z=math.min(30927,z)
entity.start_pos.x = x
entity.start_pos.x = x
entity.start_pos.y = y
entity.start_pos.z = z
@ -211,7 +211,7 @@ local entitydef_default = {
end
end,
get_velocity = function(self)
return vector.new(self._velocity)
return vector.new(self._velocity)
end,
set_velocity = function(self, velocity)
self._velocity = vector.new(velocity)
@ -289,7 +289,7 @@ function luaentity.add_entity(pos, name)
_acceleration = {x = 0, y = 0, z = 0},
_attached_entities = {},
}
local prototype = luaentity.registered_entities[name]
setmetatable(entity, prototype) -- Default to prototype for other methods
luaentity.entities[index] = entity
@ -318,19 +318,20 @@ end
function luaentity.get_objects_inside_radius(pos, radius)
local objects = {}
local index = 1
for id, entity in pairs(luaentity.entities) do
for _, entity in pairs(luaentity.entities) do
if vector.distance(pos, entity:get_pos()) <= radius then
objects[index] = entity
index = index + 1
end
end
return objects
end
local move_entities_globalstep_part2 = function(dtime)
if not luaentity.entities then
luaentity.entities = read_entities()
end
for id, entity in pairs(luaentity.entities) do
for _, entity in pairs(luaentity.entities) do
local master = entity._attached_entities_master
local master_def = master and entity._attached_entities[master]
local master_entity = master_def and master_def.entity
@ -340,6 +341,8 @@ local move_entities_globalstep_part2 = function(dtime)
entity._velocity = master_entity:get_velocity()
entity._acceleration = master_entity:get_acceleration()
else
entity._velocity = entity._velocity or vector.new(0,0,0)
entity._acceleration = entity._acceleration or vector.new(0,0,0)
entity._pos = vector.add(vector.add(
entity._pos,
vector.multiply(entity._velocity, dtime)),

View File

@ -1,5 +1,5 @@
name = pipeworks
description = This mod uses mesh nodes and nodeboxes to supply a complete set of 3D pipes and tubes, along with devices that work with them.
depends = default, basic_materials, screwdriver
optional_depends = mesecons, mesecons_mvps, digilines, signs_lib
optional_depends = mesecons, mesecons_mvps, digilines, signs_lib, unified_inventory
min_minetest_version = 5.2.0

View File

@ -11,11 +11,11 @@ local new_flow_logic_register = pipeworks.flowables.register
local polys = ""
if pipeworks.enable_lowpoly then polys = "_lowpoly" end
local vti = {4, 3, 2, 1, 6, 5}
--~ local vti = {4, 3, 2, 1, 6, 5}
local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}}
for index, connects in ipairs(cconnects) do
local outsel = {}
local jx = 0
local jy = 0
local jz = 0
@ -30,11 +30,13 @@ for index, connects in ipairs(cconnects) do
table.insert(outsel, pipeworks.pipe_selectboxes[v])
end
--[[
if #connects == 1 then
local v = connects[1]
v = v-1 + 2*(v%2) -- Opposite side
end
--]]
local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1}
local pipedesc = S("Pipe Segment").." "..dump(connects)
@ -42,11 +44,11 @@ for index, connects in ipairs(cconnects) do
pgroups = {snappy = 3, tube = 1}
pipedesc = S("Pipe Segment")
end
local outimg_e = { "pipeworks_pipe_plain.png" }
local outimg_l = { "pipeworks_pipe_plain.png" }
if index == 3 then
if index == 3 then
outimg_e = { "pipeworks_pipe_3_empty.png" }
outimg_l = { "pipeworks_pipe_3_loaded.png" }
end
@ -88,7 +90,7 @@ for index, connects in ipairs(cconnects) do
check_for_horiz_pole = pipeworks.check_for_horiz_pipe,
pipenumber = index
})
local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1}
minetest.register_node("pipeworks:pipe_"..index.."_loaded", {
@ -123,7 +125,7 @@ for index, connects in ipairs(cconnects) do
check_for_horiz_pole = pipeworks.check_for_horiz_pipe,
pipenumber = index
})
local emptypipe = "pipeworks:pipe_"..index.."_empty"
local fullpipe = "pipeworks:pipe_"..index.."_loaded"
table.insert(pipes_empty_nodenames, emptypipe)
@ -131,7 +133,7 @@ for index, connects in ipairs(cconnects) do
new_flow_logic_register.simple(emptypipe)
new_flow_logic_register.simple(fullpipe)
end
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:pipe_1_empty"
if REGISTER_COMPATIBILITY then
@ -239,7 +241,7 @@ minetest.register_abm({
nodenames = {"pipeworks:spigot","pipeworks:spigot_pouring"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
action = function(pos, node, active_object_count, active_object_count_wider)
pipeworks.spigot_check(pos,node)
end
})
@ -248,7 +250,7 @@ minetest.register_abm({
nodenames = {"pipeworks:fountainhead","pipeworks:fountainhead_pouring"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
action = function(pos, node, active_object_count, active_object_count_wider)
pipeworks.fountainhead_check(pos,node)
end
})

View File

@ -29,7 +29,7 @@ end
local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end
--~ local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end
@ -39,7 +39,7 @@ local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..
local check_for_liquids_v2 = function(pos, limit)
local coords = make_coords_offsets(pos, false)
local total = 0
for index, tpos in ipairs(coords) do
for _, tpos in ipairs(coords) do
if total >= limit then break end
local name = minetest.get_node(tpos).name
if name == "default:water_source" then
@ -69,11 +69,13 @@ end
-- logging is unreliable when something is crashing...
--[[
local nilexplode = function(caller, label, value)
if value == nil then
error(caller..": "..label.." was nil")
end
end
--]]
@ -151,7 +153,7 @@ local get_neighbour_positions = function(pos, node)
-- then, check each possible neighbour to see if they can be reached from this node.
local connections = {}
for index, offset in ipairs(candidates) do
for _, offset in ipairs(candidates) do
local npos = vector.add(pos, offset)
local neighbour = minetest.get_node(npos)
local nodename = neighbour.name
@ -185,13 +187,12 @@ flowlogic.balance_pressure = function(pos, node, currentpressure)
-- local dname = "flowlogic.balance_pressure()@"..formatvec(pos).." "
-- check the pressure of all nearby flowable nodes, and average it out.
-- pressure handles to average over
local connections = {}
-- unconditionally include self in nodes to average over.
-- result of averaging will be returned as new pressure for main flow logic callback
local totalv = currentpressure
local totalc = 1
-- pressure handles to average over
local connections = get_neighbour_positions(pos, node)
-- for each neighbour, add neighbour's pressure to the total to balance out
@ -287,7 +288,7 @@ flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputd
local upper = outputdef.upper
local lower = outputdef.lower
local result = currentpressure
local threshold = nil
local threshold
if finitemode then threshold = lower else threshold = upper end
if currentpressure > threshold then
local takenpressure = outputdef.outputfn(pos, node, currentpressure, finitemode)
@ -316,7 +317,7 @@ flowlogic.run_transition = function(node, currentpressure)
local nodename_prev = simplesetdef[1].nodename
local result_nodename = node.name
for index, element in ipairs(simplesetdef) do
for _, element in ipairs(simplesetdef) do
-- find the highest element that is below the current pressure.
local threshold = element.threshold
if threshold > currentpressure then
@ -338,7 +339,9 @@ flowlogic.run_transition = function(node, currentpressure)
end
if not found then
pipeworks.logger("flowlogic.run_transition() BUG no transition definitions found! nodename="..nodename.." currentpressure="..tostring(currentpressure))
pipeworks.logger("flowlogic.run_transition() BUG no transition " ..
"definitions found! node.name=" .. node.name ..
" currentpressure=" .. tostring(currentpressure))
end
return result

View File

@ -26,8 +26,8 @@ local insertbase = function(nodename)
end
local regwarning = function(kind, nodename)
local tail = ""
if pipeworks.toggles.pipe_mode ~= "pressure" then tail = " but pressure logic not enabled" end
--~ local tail = ""
--~ if pipeworks.toggles.pipe_mode ~= "pressure" then tail = " but pressure logic not enabled" end
--pipeworks.logger(kind.." flow logic registry requested for "..nodename..tail)
end
@ -106,7 +106,7 @@ register.directional_horizonal_rotate = function(nodename, doubleended)
end
local directionfn = function(node, direction)
local result = false
for index, endvec in ipairs(getends(node)) do
for _, endvec in ipairs(getends(node)) do
if vector.equals(direction, endvec) then result = true end
end
return result

View File

@ -10,6 +10,35 @@ minetest.register_craft( {
},
})
-- The hammers that can be used to break/repair tubes
local allowed_hammers = {
"anvil:hammer",
"cottages:hammer",
"glooptest:hammer_steel",
"glooptest:hammer_bronze",
"glooptest:hammer_diamond",
"glooptest:hammer_mese",
"glooptest:hammer_alatro",
"glooptest:hammer_arol"
}
-- Convert the above list to a format that's easier to look up
for _,hammer in ipairs(allowed_hammers) do
allowed_hammers[hammer] = true
end
-- Check if the player is holding a suitable hammer or not - if they are, apply wear to it
function pipeworks.check_and_wear_hammer(player)
local itemstack = player:get_wielded_item()
local wieldname = itemstack:get_name()
if allowed_hammers[wieldname] then
itemstack:add_wear(1000)
player:set_wielded_item(itemstack)
return true
end
return false
end
local nodecolor = 0xffff3030
pipeworks.register_tube("pipeworks:broken_tube", {
@ -36,29 +65,27 @@ pipeworks.register_tube("pipeworks:broken_tube", {
local wieldname = itemstack:get_name()
local playername = puncher:get_player_name()
local log_msg = playername.." struck a broken tube at "..minetest.pos_to_string(pos).."\n"
if wieldname == "anvil:hammer"
or wieldname == "cottages:hammer"
or wieldname == "glooptest:hammer_steel"
or wieldname == "glooptest:hammer_bronze"
or wieldname == "glooptest:hammer_diamond"
or wieldname == "glooptest:hammer_mese"
or wieldname == "glooptest:hammer_alatro"
or wieldname == "glooptest:hammer_arol" then
local meta = minetest.get_meta(pos)
local was_node = minetest.deserialize(meta:get_string("the_tube_was"))
if was_node and was_node ~= "" then
pipeworks.logger(log_msg.." with "..wieldname.." to repair it.")
minetest.swap_node(pos, { name = was_node.name, param2 = was_node.param2 })
pipeworks.scan_for_tube_objects(pos)
itemstack:add_wear(1000)
puncher:set_wielded_item(itemstack)
return itemstack
else
pipeworks.logger(log_msg.." but it can't be repaired.")
end
else
pipeworks.logger(log_msg.." with "..wieldname.." but that tool is too weak.")
local meta = minetest.get_meta(pos)
local was_node = minetest.deserialize(meta:get_string("the_tube_was"))
if not was_node then
pipeworks.logger(log_msg.." but it can't be repaired.")
return
end
if not pipeworks.check_and_wear_hammer(puncher) then
if wieldname == "" then
pipeworks.logger(log_msg.." by hand. It's not very effective.")
if minetest.settings:get_bool("enable_damage") then
minetest.chat_send_player(playername,S("Broken tubes may be a bit sharp. Perhaps try with a hammer?"))
puncher:set_hp(puncher:get_hp()-1)
end
else
pipeworks.logger(log_msg.." with "..wieldname.." but that tool is too weak.")
end
return
end
pipeworks.logger(log_msg.." with "..wieldname.." to repair it.")
minetest.swap_node(pos, { name = was_node.name, param2 = was_node.param2 })
pipeworks.scan_for_tube_objects(pos)
end
}
})
@ -165,6 +192,7 @@ if pipeworks.enable_one_way_tube then
check_for_pole = pipeworks.check_for_vert_tube,
check_for_horiz_pole = pipeworks.check_for_horiz_tube
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:one_way_tube"
minetest.register_craft({
output = "pipeworks:one_way_tube 2",
recipe = {

View File

@ -1,4 +1,16 @@
local S = minetest.get_translator("pipeworks")
-- the minetest.after() calls below can sometimes trigger after a tube
-- breaks, at which point item_exit() is no longer valid, so we have to make
-- sure that there even IS a callback to run, first.
local function after_break(pos)
local name = minetest.get_node(pos).name
if minetest.registered_nodes[name].item_exit then
minetest.registered_nodes[name].item_exit(pos)
end
end
if pipeworks.enable_detector_tube then
local detector_tube_step = 5 * tonumber(minetest.settings:get("dedicated_server_step"))
pipeworks.register_tube("pipeworks:detector_tube_on", {
@ -8,11 +20,10 @@ if pipeworks.enable_detector_tube then
node_def = {
tube = {can_go = function(pos, node, velocity, stack)
local meta = minetest.get_meta(pos)
local name = minetest.get_node(pos).name
local nitems = meta:get_int("nitems")+1
meta:set_int("nitems", nitems)
local saved_pos = vector.new(pos)
minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
minetest.after(detector_tube_step, after_break, saved_pos)
return pipeworks.notvel(pipeworks.meseadjlist,velocity)
end},
groups = {mesecon = 2, not_in_creative_inventory = 1},
@ -34,9 +45,7 @@ if pipeworks.enable_detector_tube then
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("nitems", 1)
local name = minetest.get_node(pos).name
local saved_pos = vector.new(pos)
minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
minetest.after(detector_tube_step, after_break, pos)
end,
},
})
@ -87,13 +96,20 @@ if digiline_enabled and pipeworks.enable_digiline_detector_tube then
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"size[8.6,2.2]"..
"field[0.6,0.6;8,1;channel;"..S("Channel")..";${channel}]"..
"image[0.3,1.3;1,1;pipeworks_digiline_detector_tube_inv.png]"..
"label[1.6,1.2;"..S("Digiline Detecting Tube").."]"
"size[8.5,2.2]"..
"image[0.2,0;1,1;pipeworks_digiline_detector_tube_inv.png]"..
"label[1.2,0.2;"..S("Digiline Detecting Tube").."]"..
"field[0.5,1.6;4.6,1;channel;"..S("Channel")..";${channel}]"..
"button[4.8,1.3;1.5,1;set_channel;"..S("Set").."]"..
"button_exit[6.3,1.3;2,1;close;"..S("Close").."]"
)
end,
on_receive_fields = function(pos, formname, fields, sender)
if (fields.quit and not fields.key_enter_field)
or (fields.key_enter_field ~= "channel" and not fields.set_channel)
or not pipeworks.may_configure(pos, sender) then
return
end
if fields.channel then
minetest.get_meta(pos):set_string("channel", fields.channel)
end

View File

@ -23,7 +23,7 @@ end
local function migrate_tube_db()
local tmp_db = {}
tp_tube_db.version = nil
for key, val in pairs(tp_tube_db) do
for _, val in pairs(tp_tube_db) do
if(val.channel ~= "") then -- skip unconfigured tubes
tmp_db[hash(val)] = val
end
@ -127,16 +127,22 @@ end
local function update_meta(meta, can_receive)
meta:set_int("can_receive", can_receive and 1 or 0)
local cr_state = can_receive and "on" or "off"
meta:set_string("formspec","size[8.6,2.2]"..
"field[0.6,0.6;7,1;channel;"..S("Channel")..";${channel}]"..
"label[7.3,0;"..S("Receive").."]"..
"image_button[7.3,0.3;1,0.6;pipeworks_button_" .. cr_state .. ".png;cr" .. (can_receive and 0 or 1) .. ";;;false;pipeworks_button_interm.png]"..
"image[0.3,1.3;1,1;pipeworks_teleport_tube_inv.png]"..
"label[1.6,1.2;"..S("channels are public by default").."]" ..
"label[1.6,1.5;"..S("use <player>:<channel> for fully private channels").."]" ..
"label[1.6,1.8;"..S("use <player>\\;<channel> for private receivers").."]" ..
default.gui_bg..
default.gui_bg_img)
local itext = S("Channels are public by default").."\n"..
S("Use <player>:<channel> for fully private channels").."\n"..
S("Use <player>\\;<channel> for private receivers")
meta:set_string("formspec",
"size[8.5,3.5]"..
"image[0.2,o;1,1;pipeworks_teleport_tube_inv.png]"..
"label[1.2,0.2;"..S("Teleporting Tube").."]"..
"field[0.5,1.6;4.6,1;channel;"..S("Channel")..";${channel}]"..
"button[4.8,1.3;1.5,1;set_channel;"..S("Set").."]"..
"label[7.0,0;"..S("Receive").."]"..
"image_button[7.0,0.5;1,0.6;pipeworks_button_" .. cr_state .. ".png;cr" .. (can_receive and 0 or 1) .. ";;;false;pipeworks_button_interm.png]"..
"button_exit[6.3,1.3;2,1;close;"..S("Close").."]"..
"label[0.2,2.3;"..itext.."]"..
default.gui_bg..
default.gui_bg_img)
end
pipeworks.register_tube("pipeworks:teleport_tube", {
@ -170,10 +176,11 @@ pipeworks.register_tube("pipeworks:teleport_tube", {
on_construct = function(pos)
local meta = minetest.get_meta(pos)
update_meta(meta, true)
meta:set_string("infotext", S("unconfigured Teleportation Tube"))
meta:set_string("infotext", S("Unconfigured Teleportation Tube"))
end,
on_receive_fields = function(pos,formname,fields,sender)
if not fields.channel -- ignore escaping or clientside manipulation of the form
or (fields.quit and not fields.key_enter_field)
or not pipeworks.may_configure(pos, sender) then
return
end
@ -193,7 +200,7 @@ pipeworks.register_tube("pipeworks:teleport_tube", {
minetest.chat_send_player(sender_name, S("Sorry, channel '@1' is reserved for exclusive use by @2",
new_channel, name))
return
--channels starting with '[name];' can be used by other players, but cannot be received from
elseif mode == ";" and (fields.cr1 or (can_receive ~= 0 and not fields.cr0)) then
minetest.chat_send_player(sender_name, S("Sorry, receiving from channel '@1' is reserved for @2",
@ -207,7 +214,7 @@ pipeworks.register_tube("pipeworks:teleport_tube", {
-- was the channel changed?
local channel = meta:get_string("channel")
if new_channel ~= channel then
if new_channel ~= channel and (fields.key_enter_field == "channel" or fields.set_channel) then
channel = new_channel
meta:set_string("channel", channel)
dirty = true
@ -233,7 +240,7 @@ pipeworks.register_tube("pipeworks:teleport_tube", {
else
-- remove empty channel tubes, to not have to search through them
remove_tube(pos)
meta:set_string("infotext", S("unconfigured Teleportation Tube"))
meta:set_string("infotext", S("Unconfigured Teleportation Tube"))
end
end
end,
@ -261,3 +268,11 @@ if minetest.get_modpath("mesecons_mvps") ~= nil then
end
end)
end
-- Expose teleport tube database API for other mods
pipeworks.tptube = {
hash = hash,
save_tube_db = save_tube_db,
get_db = function() return tp_tube_db or read_tube_db() end,
tp_tube_db_version = tp_tube_db_version
}

View File

@ -1,7 +1,7 @@
local S = minetest.get_translator("pipeworks")
minetest.register_node("pipeworks:trashcan", {
description = S("Trash Can"),
drawtype = "normal",
description = S("Trash Can"),
drawtype = "normal",
tiles = {
"pipeworks_trashcan_bottom.png",
"pipeworks_trashcan_bottom.png",
@ -9,15 +9,15 @@ minetest.register_node("pipeworks:trashcan", {
"pipeworks_trashcan_side.png",
"pipeworks_trashcan_side.png",
"pipeworks_trashcan_side.png",
},
groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
},
groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
tube = {
insert_object = function(pos, node, stack, direction)
return ItemStack("")
end,
connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1},
priority = 1, -- Lower than anything else
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
@ -33,13 +33,14 @@ minetest.register_node("pipeworks:trashcan", {
"listring[]")
meta:set_string("infotext", S("Trash Can"))
meta:get_inventory():set_size("trash", 1)
end,
end,
after_place_node = pipeworks.after_place,
after_dig_node = pipeworks.after_dig,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
minetest.get_meta(pos):get_inventory():set_stack(listname, index, ItemStack(""))
end,
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:trashcan"
minetest.register_craft({
output = "pipeworks:trashcan",

View File

@ -26,6 +26,11 @@ local texture_mt = {
end
}
-- This will remove any semi-transparent pixels
-- because that is still buggy in Minetest, force this as default
local texture_alpha_mode = minetest.features.use_texture_alpha_string_modes
and "clip" or true
local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, ends, short, inv, special, connects, style)
noctrs = noctrs or default_noctrs
setmetatable(noctrs, texture_mt)
@ -82,6 +87,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
description = tubedesc,
drawtype = "nodebox",
tiles = outimgs,
use_texture_alpha = texture_alpha_mode,
sunlight_propagates = true,
inventory_image = iimg,
wield_image = iimg,
@ -107,6 +113,18 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1},
priority = 50
},
on_punch = function(pos, node, player, pointed)
local playername = player:get_player_name()
if minetest.is_protected(pos, playername) and not minetest.check_player_privs(playername, {protection_bypass=true}) then
return minetest.node_punch(pos, node, player, pointed)
end
if pipeworks.check_and_wear_hammer(player) then
local wieldname = player:get_wielded_item():get_name()
pipeworks.logger(string.format("%s struck a tube at %s with %s to break it.", playername, minetest.pos_to_string(pos), wieldname))
pipeworks.break_tube(pos)
end
return minetest.node_punch(pos, node, player, pointed)
end,
after_place_node = pipeworks.after_place,
after_dig_node = pipeworks.after_dig,
on_rotate = false,
@ -182,6 +200,7 @@ local register_all_tubes = function(name, desc, plain, noctrs, ends, short, inv,
end
end
end
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = name.."_000000"
else
-- 6d tubes: uses only 10 nodes instead of 64, but the textures must be rotated
local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}}
@ -204,6 +223,7 @@ local register_all_tubes = function(name, desc, plain, noctrs, ends, short, inv,
tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}},
drop = name.."_1",
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = name.."_1"
table.insert(tubenodes, cname)
for xm = 0, 1 do
for xp = 0, 1 do

View File

@ -40,22 +40,31 @@ if pipeworks.enable_mese_sand_tube then
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("dist", 0)
meta:set_string("formspec", "size[2.1,0.8]"..
"image[0,0;1,1;pipeworks_mese_sand_tube_inv.png]"..
"field[1.3,0.4;1,1;dist;radius;${dist}]"..
default.gui_bg..
default.gui_bg_img)
meta:set_string("formspec",
"size[6.0,2.2]"..
"image[0.2,0;1,1;pipeworks_mese_sand_tube_inv.png]"..
"label[1.2,0.2;"..S("Adjustable Vacuuming Tube").."]"..
"field[0.5,1.6;2.1,1;dist;"..S("Radius")..";${dist}]"..
"button[2.3,1.3;1.5,1;set_dist;"..S("Set").."]"..
"button_exit[3.8,1.3;2,1;close;"..S("Close").."]"..
default.gui_bg..
default.gui_bg_img)
meta:set_string("infotext", S("Adjustable Vacuuming Pneumatic Tube Segment"))
end,
on_receive_fields = function(pos,formname,fields,sender)
if not pipeworks.may_configure(pos, sender) then return end
if (fields.quit and not fields.key_enter_field)
or (fields.key_enter_field ~= "dist" and not fields.set_dist)
or not pipeworks.may_configure(pos, sender) then
return
end
local meta = minetest.get_meta(pos)
local dist = tonumber(fields.dist)
if dist then
dist = math.max(0, dist)
dist = math.min(8, dist)
meta:set_int("dist", dist)
meta:set_string("infotext", (S("Adjustable Vacuuming Pneumatic Tube Segment (@1m)", dist)))
meta:set_string("infotext", S("Adjustable Vacuuming Pneumatic Tube Segment (@1m)", dist))
end
end,
},

View File

@ -1,17 +1,13 @@
local S = minetest.get_translator("pipeworks")
local assumed_eye_pos = vector.new(0, 1.5, 0)
local function vector_copy(v)
return { x = v.x, y = v.y, z = v.z }
end
local function delay(x)
return (function() return x end)
end
local function set_wielder_formspec(data, meta)
meta:set_string("formspec",
"invsize[8,"..(6+data.wield_inv_height)..";]"..
"size[8,"..(6+data.wield_inv_height)..";]"..
"item_image[0,0;1,1;"..data.name_base.."_off]"..
"label[1,0;"..minetest.formspec_escape(data.description).."]"..
"list[current_name;"..minetest.formspec_escape(data.wield_inv_name)..";"..((8-data.wield_inv_width)*0.5)..",1;"..data.wield_inv_width..","..data.wield_inv_height..";]"..
@ -353,7 +349,7 @@ if pipeworks.enable_node_breaker then
{pos=pointed_thing.under, gain=sound.gain})
end
wieldstack = virtplayer:get_wielded_item()
else
--~ else
--pipeworks.logger(dname.."couldn't dig node!")
end
end
@ -375,10 +371,11 @@ if pipeworks.enable_node_breaker then
eject_drops = true,
}
register_wielder(data)
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:nodebreaker_off"
minetest.register_craft({
output = "pipeworks:nodebreaker_off",
recipe = {
{ "pipeworks:gear", "pipeworks:gear", "pipeworks:gear" },
{ "basic_materials:gear_steel", "basic_materials:gear_steel", "basic_materials:gear_steel" },
{ "default:stone", "mesecons:piston", "default:stone" },
{ "group:wood", "mesecons:mesecon", "group:wood" },
}
@ -426,6 +423,7 @@ if pipeworks.enable_deployer then
end,
eject_drops = false,
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:deployer_off"
minetest.register_craft({
output = "pipeworks:deployer_off",
recipe = {
@ -461,6 +459,7 @@ if pipeworks.enable_dispenser then
end,
eject_drops = false,
})
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:dispenser_off"
minetest.register_craft({
output = "pipeworks:dispenser_off",
recipe = {