Major rewrite of items in tubes

This commit is contained in:
Novatux 2014-08-14 16:22:03 +02:00
parent a9866aa5d5
commit d5480f5ff0
7 changed files with 796 additions and 471 deletions

110
autoplace_tubes.lua Normal file → Executable file
View File

@ -1,72 +1,38 @@
-- autorouting for pneumatic tubes -- autorouting for pneumatic tubes
local function in_table(table,element)
for _,el in ipairs(table) do
if el==element then return true end
end
return false
end
local function is_tube(nodename) local function is_tube(nodename)
return in_table(pipeworks.tubenodes,nodename) return table.contains(pipeworks.tubenodes, nodename)
end
if pipeworks == nil then
pipeworks = {}
end end
--a function for determining which side of the node we are on --a function for determining which side of the node we are on
local function nodeside(node, tubedir) local function nodeside(node, tubedir)
if node and (node.param2 < 0 or node.param2 > 23) then node.param2 = 0 end if node.param2 < 0 or node.param2 > 23 then
node.param2 = 0
--get a vector pointing back
local backdir = minetest.facedir_to_dir(node.param2)
--check whether the vector is equivalent to the tube direction; if it is, the tube's on the backside
if backdir.x == tubedir.x and backdir.y == tubedir.y and backdir.z == tubedir.z then
return "back"
end end
--check whether the vector is antiparallel with the tube direction; that indicates the front local backdir = minetest.facedir_to_dir(node.param2)
if backdir.x == -tubedir.x and backdir.y == -tubedir.y and backdir.z == -tubedir.z then local back = vector.dot(backdir, tubedir)
if back == 1 then
return "back"
elseif back == -1 then
return "front" return "front"
end end
--facedir is defined in terms of the top-bottom axis of the node; we'll take advantage of that local topdir = minetest.facedir_to_top_dir(node.param2)
local topdir = ({[0]={x=0, y=1, z=0}, local top = vector.dot(topdir, tubedir)
{x=0, y=0, z=1}, if top == 1 then
{x=0, y=0, z=-1},
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0}})[math.floor(node.param2/4)]
--is this the top?
if topdir.x == tubedir.x and topdir.y == tubedir.y and topdir.z == tubedir.z then
return "top" return "top"
end elseif top == -1 then
--or the bottom?
if topdir.x == -tubedir.x and topdir.y == -tubedir.y and topdir.z == -tubedir.z then
return "bottom" return "bottom"
end end
--we shall apply some maths to obtain the right-facing vector local rightdir = minetest.facedir_to_right_dir(node.param2)
local rightdir = {x=topdir.y*backdir.z - backdir.y*topdir.z, local right = vector.dot(rightdir, tubedir)
y=topdir.z*backdir.x - backdir.z*topdir.x, if right == 1 then
z=topdir.x*backdir.y - backdir.x*topdir.y}
--is this the right side?
if rightdir.x == tubedir.x and rightdir.y == tubedir.y and rightdir.z == tubedir.z then
return "right" return "right"
end else
--or the left?
if rightdir.x == -tubedir.x and rightdir.y == -tubedir.y and rightdir.z == -tubedir.z then
return "left" return "left"
end end
--we should be done by now; initiate panic mode
minetest.log("error", "nodeside has been confused by its parameters; see pipeworks autoplace_tubes.lua, line 78")
end end
local vts = {0, 3, 1, 4, 2, 5} local vts = {0, 3, 1, 4, 2, 5}
@ -78,23 +44,23 @@ local function tube_autoroute(pos)
if not is_tube(nctr.name) then return end if not is_tube(nctr.name) then return end
local adjustments = { local adjustments = {
{ x=-1, y=0, z=0 }, {x = -1, y = 0, z = 0},
{ x=1, y=0, z=0 }, {x = 1, y = 0, z = 0},
{ x=0, y=-1, z=0 }, {x = 0, y = -1, z = 0},
{ x=0, y=1, z=0 }, {x = 0, y = 1, z = 0},
{ x=0, y=0, z=-1 }, {x = 0, y = 0, z = -1},
{ x=0, y=0, z=1 } {x = 0, y = 0, z = 1}
} }
-- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6 -- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6
local positions = {} local positions = {}
local nodes = {} local nodes = {}
for i,adj in ipairs(adjustments) do for i, adj in ipairs(adjustments) do
positions[i] = {x=pos.x+adj.x, y=pos.y+adj.y, z=pos.z+adj.z} positions[i] = vector.add(pos, adj)
nodes[i] = minetest.get_node(positions[i]) nodes[i] = minetest.get_node(positions[i])
end end
for i,node in ipairs(nodes) do for i, node in ipairs(nodes) do
local idef = minetest.registered_nodes[node.name] local idef = minetest.registered_nodes[node.name]
-- handle the tubes themselves -- handle the tubes themselves
if is_tube(node.name) then if is_tube(node.name) then
@ -102,7 +68,9 @@ local function tube_autoroute(pos)
-- handle new style connectors -- handle new style connectors
elseif idef and idef.tube and idef.tube.connect_sides then elseif idef and idef.tube and idef.tube.connect_sides then
local dir = adjustments[i] local dir = adjustments[i]
if idef.tube.connect_sides[nodeside(node, {x=-dir.x, y=-dir.y, z=-dir.z})] then active[i] = 1 end if idef.tube.connect_sides[nodeside(node, vector.multiply(dir, -1))] then
active[i] = 1
end
end end
end end
@ -110,18 +78,17 @@ local function tube_autoroute(pos)
local nodedef = minetest.registered_nodes[nctr.name] local nodedef = minetest.registered_nodes[nctr.name]
local basename = nodedef.basename local basename = nodedef.basename
local newname
if nodedef.style == "old" then if nodedef.style == "old" then
local nsurround = "" local nsurround = ""
for i,n in ipairs(active) do for i, n in ipairs(active) do
nsurround = nsurround .. n nsurround = nsurround..n
end end
nctr.name = basename.."_"..nsurround nctr.name = basename.."_"..nsurround
elseif nodedef.style == "6d" then elseif nodedef.style == "6d" then
local s = 0 local s = 0
for i,n in ipairs(active) do for i, n in ipairs(active) do
if n == 1 then if n == 1 then
s = s+2^vts[i] s = s + 2^vts[i]
end end
end end
nctr.name = basename.."_"..tube_table[s] nctr.name = basename.."_"..tube_table[s]
@ -131,14 +98,9 @@ local function tube_autoroute(pos)
end end
function pipeworks.scan_for_tube_objects(pos) function pipeworks.scan_for_tube_objects(pos)
if not pos or not pos.x or not pos.y or not pos.z then return end for side = 0, 6 do
tube_autoroute({ x=pos.x-1, y=pos.y , z=pos.z }) tube_autoroute(vector.add(pos, directions.side_to_dir(side)))
tube_autoroute({ x=pos.x+1, y=pos.y , z=pos.z }) end
tube_autoroute({ x=pos.x , y=pos.y-1, z=pos.z })
tube_autoroute({ x=pos.x , y=pos.y+1, z=pos.z })
tube_autoroute({ x=pos.x , y=pos.y , z=pos.z-1 })
tube_autoroute({ x=pos.x , y=pos.y , z=pos.z+1 })
tube_autoroute(pos)
end end
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack) minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
@ -157,7 +119,7 @@ minetest.register_on_dignode(function(pos, oldnode, digger)
end end
end) end)
if minetest.get_modpath("mesecons_mvps") ~= nil then if minetest.get_modpath("mesecons_mvps") then
mesecon:register_on_mvps_move(function(moved_nodes) mesecon:register_on_mvps_move(function(moved_nodes)
for _, n in ipairs(moved_nodes) do for _, n in ipairs(moved_nodes) do
pipeworks.scan_for_tube_objects(n.pos) pipeworks.scan_for_tube_objects(n.pos)

144
common.lua Executable file
View File

@ -0,0 +1,144 @@
----------------------
-- Vector functions --
----------------------
function vector.cross(a, b)
return {
x = a.y * b.z - a.z * b.y,
y = a.z * b.x - a.x * b.z,
z = a.x * b.y - a.y * b.x
}
end
function vector.dot(a, b)
return a.x * b.x + a.y * b.y + a.z * b.z
end
-----------------------
-- Facedir functions --
-----------------------
function minetest.facedir_to_top_dir(facedir)
return ({[0] = {x = 0, y = 1, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
{x = 0, y = -1, z = 0}})
[math.floor(facedir / 4)]
end
function minetest.facedir_to_right_dir(facedir)
return vector.cross(
minetest.facedir_to_top_dir(facedir),
minetest.facedir_to_dir(facedir)
)
end
directions = {}
function directions.side_to_dir(side)
return ({[0] = vector.new(),
vector.new( 0, 1, 0),
vector.new( 0, -1, 0),
vector.new( 1, 0, 0),
vector.new(-1, 0, 0),
vector.new( 0, 0, 1),
vector.new( 0, 0, -1)
})[side]
end
function directions.dir_to_side(dir)
local c = vector.dot(dir, vector.new(1, 2, 3)) + 4
return ({6, 2, 4, 0, 3, 1, 5})[c]
end
----------------------
-- String functions --
----------------------
--[[function string.split(str, sep)
local fields = {}
local index = 1
local expr = "([^"..sep.."])+"
string.gsub(str, expr, function(substring)
fields[index] = substring
index = index + 1
end)
return fields
end]]
function string.startswith(str, substr)
return str:sub(1, substr:len()) == substr
end
---------------------
-- Table functions --
---------------------
function table.contains(tbl, element)
for _, elt in pairs(tbl) do
if elt == element then
return true
end
end
return false
end
function table.extend(tbl, tbl2)
local index = #tbl + 1
for _, elt in ipairs(tbl2) do
tbl[index] = elt
index = index + 1
end
end
function table.recursive_replace(tbl, pattern, replace_with)
if type(tbl) == "table" then
local tbl2 = {}
for key, value in pairs(tbl) do
tbl2[key] = table.recursive_replace(value, pattern, replace_with)
end
return tbl2
elseif type(tbl) == "string" then
return tbl:gsub(pattern, replace_with)
else
return tbl
end
end
------------------------
-- Formspec functions --
------------------------
fs_helpers = {}
function fs_helpers.on_receive_fields(pos, fields)
local meta = minetest.get_meta(pos)
for field, value in pairs(fields) do
if field:startswith("fs_helpers_cycling:") then
local l = field:split(":")
local new_value = tonumber(l[2])
local meta_name = l[3]
meta:set_int(meta_name, new_value)
end
end
end
function fs_helpers.cycling_button(meta, base, meta_name, values)
local current_value = meta:get_int(meta_name)
local new_value = (current_value + 1) % (#values)
local text = values[current_value + 1]
local field = "fs_helpers_cycling:"..new_value..":"..meta_name
return base..";"..field..";"..text.."]"
end
---------
-- Env --
---------
function minetest.load_position(pos)
if minetest.get_node_or_nil(pos) then
return
end
local vm = minetest.get_voxel_manip()
vm:read_from_map(pos, pos)
end

2
init.lua Normal file → Executable file
View File

@ -106,9 +106,11 @@ end
------------------------------------------- -------------------------------------------
-- Load the various other parts of the mod -- Load the various other parts of the mod
dofile(pipeworks.modpath.."/common.lua")
dofile(pipeworks.modpath.."/models.lua") dofile(pipeworks.modpath.."/models.lua")
dofile(pipeworks.modpath.."/autoplace_pipes.lua") dofile(pipeworks.modpath.."/autoplace_pipes.lua")
dofile(pipeworks.modpath.."/autoplace_tubes.lua") dofile(pipeworks.modpath.."/autoplace_tubes.lua")
dofile(pipeworks.modpath.."/luaentity.lua")
dofile(pipeworks.modpath.."/item_transport.lua") dofile(pipeworks.modpath.."/item_transport.lua")
dofile(pipeworks.modpath.."/flowing_logic.lua") dofile(pipeworks.modpath.."/flowing_logic.lua")
dofile(pipeworks.modpath.."/crafts.lua") dofile(pipeworks.modpath.."/crafts.lua")

395
item_transport.lua Normal file → Executable file
View File

@ -1,34 +1,17 @@
dofile(pipeworks.modpath.."/compat.lua")
--and an extra function for getting the right-facing vector
local function facedir_to_right_dir(facedir)
--find the other directions
local backdir = minetest.facedir_to_dir(facedir)
local topdir = ({[0]={x=0, y=1, z=0},
{x=0, y=0, z=1},
{x=0, y=0, z=-1},
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0}})[math.floor(facedir/4)]
--return a cross product
return {x=topdir.y*backdir.z - backdir.y*topdir.z,
y=topdir.z*backdir.x - backdir.z*topdir.x,
z=topdir.x*backdir.y - backdir.x*topdir.y}
end
local fakePlayer = { local fakePlayer = {
get_player_name = function() return ":pipeworks" end, get_player_name = function() return ":pipeworks" end,
-- any other player functions called by allow_metadata_inventory_take anywhere... -- any other player functions called by allow_metadata_inventory_take anywhere...
-- perhaps a custom metaclass that errors specially when fakePlayer.<property> is not found? -- perhaps a custom metaclass that errors specially when fakePlayer.<property> is not found?
} }
function pipeworks.tube_item(pos, item) function pipeworks.tube_item(pos, start_pos, velocity, item)
-- Take item in any format -- Take item in any format
local stack = ItemStack(item) local stack = ItemStack(item)
local obj = minetest.add_entity(pos, "pipeworks:tubed_item") local obj = luaentity.add_entity(pos, "pipeworks:tubed_item")
obj:get_luaentity():set_item(stack:to_string()) obj:set_item(stack:to_string())
obj.start_pos = vector.new(start_pos)
obj:setvelocity(velocity)
--obj:set_color("red") -- todo: this is test-only code
return obj return obj
end end
@ -52,19 +35,16 @@ local function set_filter_formspec(data, meta)
"item_image[0,0;1,1;pipeworks:"..data.name.."]".. "item_image[0,0;1,1;pipeworks:"..data.name.."]"..
"label[1,0;"..minetest.formspec_escape(itemname).."]".. "label[1,0;"..minetest.formspec_escape(itemname).."]"..
"label[0,1;Prefer item types:]".. "label[0,1;Prefer item types:]"..
"list[current_name;main;0,1.5;8,2;]" "list[current_name;main;0,1.5;8,2;]"..
local slotseq_mode = meta:get_int("slotseq_mode") fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode",
if slotseq_mode == 1 then {"Sequence slots by Priority",
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode2;Sequence slots Randomly]" "Sequence slots Randomly",
elseif slotseq_mode == 2 then "Sequence slots by Rotation"})..
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode0;Sequence slots by Rotation]" "list[current_player;main;0,4.5;8,4;]"
else
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode1;Sequence slots by Priority]"
end
formspec = formspec .. "list[current_player;main;0,4.5;8,4;]"
meta:set_string("formspec", formspec) meta:set_string("formspec", formspec)
end end
-- todo SOON: this function has *way too many* parameters
local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,all) local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,all)
local sposes = {} local sposes = {}
for spos,stack in ipairs(frominv:get_list(frominvname)) do for spos,stack in ipairs(frominv:get_list(frominvname)) do
@ -130,10 +110,9 @@ local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompo
fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer)
end end
end end
local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item) local pos = vector.add(frompos, vector.multiply(dir, 1.4))
item1:get_luaentity().start_pos = vector.add(frompos, dir) local start_pos = vector.add(frompos, dir)
item1:setvelocity(dir) local item1 = pipeworks.tube_item(pos, start_pos, dir, item)
item1:setacceleration({x=0, y=0, z=0})
return true-- only fire one item, please return true-- only fire one item, please
end end
end end
@ -143,8 +122,8 @@ end
local function punch_filter(data, filtpos, filtnode) local function punch_filter(data, filtpos, filtnode)
local filtmeta = minetest.get_meta(filtpos) local filtmeta = minetest.get_meta(filtpos)
local filtinv = filtmeta:get_inventory() local filtinv = filtmeta:get_inventory()
local dir = facedir_to_right_dir(filtnode.param2) local dir = minetest.facedir_to_right_dir(filtnode.param2)
local frompos = {x=filtpos.x - dir.x, y=filtpos.y - dir.y, z=filtpos.z - dir.z} local frompos = vector.subtract(filtpos, dir)
local fromnode = minetest.get_node(frompos) local fromnode = minetest.get_node(frompos)
if not fromnode then return end if not fromnode then return end
local fromdef = minetest.registered_nodes[fromnode.name] local fromdef = minetest.registered_nodes[fromnode.name]
@ -197,7 +176,7 @@ for _, data in ipairs({
"pipeworks_"..data.name.."_top.png", "pipeworks_"..data.name.."_top.png",
}, },
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2}, groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, mesecon = 2},
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
on_construct = function(pos) on_construct = function(pos)
@ -208,28 +187,17 @@ for _, data in ipairs({
inv:set_size("main", 8*2) inv:set_size("main", 8*2)
end, end,
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
fs_helpers.on_receive_fields(pos, fields)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
for k, _ in pairs(fields) do meta:set_int("slotseq_index", 1)
if k:sub(1, 12) == "slotseq_mode" then
local mode = tonumber(k:sub(13, 13))
meta:set_int("slotseq_mode", mode)
meta:set_int("slotseq_index", mode == 2 and 1 or 0)
end
end
set_filter_formspec(data, meta) set_filter_formspec(data, meta)
set_filter_infotext(data, meta) set_filter_infotext(data, meta)
end, end,
can_dig = function(pos,player) can_dig = function(pos, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
return inv:is_empty("main") return inv:is_empty("main")
end, end,
after_place_node = function(pos)
pipeworks.scan_for_tube_objects(pos)
end,
after_dig_node = function(pos)
pipeworks.scan_for_tube_objects(pos)
end,
mesecons = { mesecons = {
effector = { effector = {
action_on = function(pos, node) action_on = function(pos, node)
@ -237,21 +205,13 @@ for _, data in ipairs({
end, end,
}, },
}, },
tube={connect_sides={right=1}}, tube = {connect_sides = {right = 1}},
on_punch = function (pos, node, puncher) on_punch = function (pos, node, puncher)
punch_filter(data, pos, node) punch_filter(data, pos, node)
end, end,
}) })
end end
local function roundpos(pos)
return {x=math.floor(pos.x+0.5),y=math.floor(pos.y+0.5),z=math.floor(pos.z+0.5)}
end
local function addVect(pos,vect)
return {x=pos.x+vect.x,y=pos.y+vect.y,z=pos.z+vect.z}
end
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 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) function pipeworks.notvel(tbl, vel)
@ -263,18 +223,20 @@ function pipeworks.notvel(tbl, vel)
end end
local function go_next(pos, velocity, stack) local function go_next(pos, velocity, stack)
local chests = {} local next_positions = {}
local tubes = {} local max_priority = 0
local cnode = minetest.get_node(pos) local cnode = minetest.get_node(pos)
local cmeta = minetest.get_meta(pos) local cmeta = minetest.get_meta(pos)
local n
local can_go local can_go
local speed = math.abs(velocity.x + velocity.y + velocity.z) 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} local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed}
if speed >= 4.1 then if speed >= 4.1 then
speed = 4 speed = 4
elseif speed >= 1.1 then elseif speed >= 1.1 then
speed = speed-0.1 speed = speed - 0.1
else else
speed = 1 speed = 1
end end
@ -284,58 +246,40 @@ local function go_next(pos, velocity, stack)
else else
can_go = pipeworks.notvel(adjlist, vel) can_go = pipeworks.notvel(adjlist, vel)
end end
local meta = nil for _, vect in ipairs(can_go) do
for _,vect in ipairs(can_go) do local npos = vector.add(pos, vect)
local npos = addVect(pos,vect)
local node = minetest.get_node(npos) local node = minetest.get_node(npos)
local tube_receiver = minetest.get_item_group(node.name,"tubedevice_receiver") local tubedevice = minetest.get_item_group(node.name, "tubedevice")
meta = minetest.get_meta(npos) local tube_def = minetest.registered_nodes[node.name].tube
local tubelike = meta:get_int("tubelike") local tube_priority = (tube_def and tube_def.priority) or 100
if tube_receiver == 1 then if tubedevice > 0 and tube_priority >= max_priority then
if minetest.registered_nodes[node.name].tube and if not tube_def or not tube_def.can_insert or
minetest.registered_nodes[node.name].tube.can_insert and tubedef.can_insert(npos, node, stack, vect) then
minetest.registered_nodes[node.name].tube.can_insert(npos, node, stack, vect) then if tube_priority > max_priority then
local i = #chests + 1 max_priority = tube_priority
chests[i] = {} next_positions = {}
chests[i].pos = npos end
chests[i].vect = vect next_positions[#next_positions + 1] = {pos = npos, vect = vect}
end end
elseif tubelike == 1 then
local i = #tubes + 1
tubes[i] = {}
tubes[i].pos = npos
tubes[i].vect = vect
end end
end end
if chests[1] == nil then--no chests found
if tubes[1] == nil then if not next_positions[1] then
return 0 return false, nil
else
n = (cmeta:get_int("tubedir")%(#tubes)) + 1
if pipeworks.enable_cyclic_mode then
cmeta:set_int("tubedir",n)
end
velocity.x = tubes[n].vect.x*vel.speed
velocity.y = tubes[n].vect.y*vel.speed
velocity.z = tubes[n].vect.z*vel.speed
end
else
n = (cmeta:get_int("tubedir")%(#chests))+1
if pipeworks.enable_cyclic_mode then
cmeta:set_int("tubedir",n)
end
velocity.x = chests[n].vect.x*speed
velocity.y = chests[n].vect.y*speed
velocity.z = chests[n].vect.z*speed
end end
return 1
local n = (cmeta:get_int("tubedir") % (#next_positions)) + 1
if pipeworks.enable_cyclic_mode then
cmeta:set_int("tubedir", n)
end
local new_velocity = vector.multiply(next_positions[n].vect, vel.speed)
return true, new_velocity
end end
minetest.register_entity("pipeworks:tubed_item", { minetest.register_entity("pipeworks:tubed_item", {
initial_properties = { initial_properties = {
hp_max = 1, hp_max = 1,
physical = false, physical = false,
-- collisionbox = {0,0,0,0,0,0},
collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1}, collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
visual = "wielditem", visual = "wielditem",
visual_size = {x = 0.15, y = 0.15}, visual_size = {x = 0.15, y = 0.15},
@ -343,113 +287,126 @@ minetest.register_entity("pipeworks:tubed_item", {
spritediv = {x = 1, y = 1}, spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0}, initial_sprite_basepos = {x = 0, y = 0},
is_visible = false, is_visible = false,
start_pos = {},
route = {},
removed = false
}, },
itemstring = '',
physical_state = false, physical_state = false,
set_item = function(self, itemstring) from_data = function(self, itemstring)
self.itemstring = itemstring
local stack = ItemStack(itemstring) local stack = ItemStack(itemstring)
self.object:set_properties({
is_visible = true,
textures = { stack:get_name() },
})
local def = stack:get_definition()
self.object:setyaw((def and def.type == "node") and 0 or math.pi * 0.25)
end,
get_staticdata = function(self)
if self.start_pos == nil or self.removed then
return
end
local velocity = self.object:getvelocity()
self.object:setpos(self.start_pos)
return minetest.serialize({
itemstring = self.itemstring,
velocity = velocity,
start_pos = self.start_pos
})
end,
on_activate = function(self, staticdata)
if staticdata=="" or staticdata==nil then return end
local item = minetest.deserialize(staticdata)
local stack = ItemStack(item.itemstring)
local itemtable = stack:to_table() local itemtable = stack:to_table()
local itemname = nil local itemname = nil
if itemtable then if itemtable then
itemname = stack:to_table().name itemname = stack:to_table().name
end end
local item_texture = nil
if itemname then local item_type = ""
self.start_pos=item.start_pos if minetest.registered_items[itemname] then
self.object:setvelocity(item.velocity) item_texture = minetest.registered_items[itemname].inventory_image
self.object:setacceleration({x=0, y=0, z=0}) item_type = minetest.registered_items[itemname].type
self.object:setpos(item.start_pos)
end end
self:set_item(item.itemstring) self.object:set_properties({
is_visible = true,
textures = {stack:get_name()}
})
local def = stack:get_definition()
self.object:setyaw((def and def.type == "node") and 0 or math.pi * 0.25)
end,
get_staticdata = luaentity.get_staticdata,
on_activate = luaentity.on_activate,
})
minetest.register_entity("pipeworks:color_entity", {
initial_properties = {
hp_max = 1,
physical = false,
collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
visual = "cube",
visual_size = {x = 3.5, y = 3.5, z = 3.5}, -- todo: find correct size
textures = {""},
is_visible = false,
},
physical_state = false,
from_data = function(self, color)
local t = "pipeworks_color_"..color..".png"
local prop = {
is_visible = true,
visual = "cube",
textures = {t, t, t, t, t, t} -- todo: textures
}
self.object:set_properties(prop)
end,
get_staticdata = luaentity.get_staticdata,
on_activate = luaentity.on_activate,
})
luaentity.register_entity("pipeworks:tubed_item", {
itemstring = '',
item_entity = nil,
color_entity = nil,
color = nil,
start_pos = nil,
set_item = function(self, item)
local itemstring = ItemStack(item):to_string() -- Accept any input format
if self.itemstring == itemstring then
return
end
if self.item_entity then
self:remove_attached_entity(self.item_entity)
end
self.itemstring = itemstring
self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring)
end, end,
remove = function(self) set_color = function(self, color)
self.object:remove() if self.color == color then
self.removed = true return
self.itemstring = '' end
self.color = color
if self.color_entity then
self:remove_attached_entity(self.color_entity)
end
if color then
self.color_entity = self:add_attached_entity("pipeworks:color_entity", color)
else
self.color_entity = nil
end
end, end,
on_step = function(self, dtime) on_step = function(self, dtime)
if self.removed then
return
end
if self.start_pos == nil then if self.start_pos == nil then
local pos = self.object:getpos() local pos = self:getpos()
self.start_pos = roundpos(pos) self.start_pos = vector.round(pos)
self:setpos(pos)
end end
local pos = self.object:getpos()
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local tubelike = meta:get_int("tubelike")
local stack = ItemStack(self.itemstring)
local drop_pos = nil
local velocity = self.object:getvelocity() local pos = self:getpos()
local stack = ItemStack(self.itemstring)
if velocity == nil then return end local drop_pos
local velocitycopy = {x = velocity.x, y = velocity.y, z = velocity.z} local velocity = self:getvelocity()
local moved = false local moved = false
local speed = math.abs(velocity.x + velocity.y + velocity.z) local speed = math.abs(velocity.x + velocity.y + velocity.z)
if speed == 0 then
speed = 1
moved = true
end
local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed} local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed}
if math.abs(vel.x) == 1 then if vector.distance(pos, self.start_pos) >= 1 then
local next_node = math.abs(pos.x - self.start_pos.x) self.start_pos = vector.add(self.start_pos, vel)
if next_node >= 1 then moved = true
self.start_pos.x = self.start_pos.x + vel.x
moved = true
end
elseif math.abs(vel.y) == 1 then
local next_node = math.abs(pos.y - self.start_pos.y)
if next_node >= 1 then
self.start_pos.y = self.start_pos.y + vel.y
moved = true
end
elseif math.abs(vel.z) == 1 then
local next_node = math.abs(pos.z - self.start_pos.z)
if next_node >= 1 then
self.start_pos.z = self.start_pos.z + vel.z
moved = true
end
end end
local sposcopy = {x = self.start_pos.x, y = self.start_pos.y, z = self.start_pos.z} minetest.load_position(self.start_pos)
local node = minetest.get_node(self.start_pos)
node = minetest.get_node(self.start_pos)
if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then
local leftover = nil local leftover
if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then
leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel) leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel)
else else
@ -459,62 +416,48 @@ minetest.register_entity("pipeworks:tubed_item", {
self:remove() self:remove()
return return
end end
velocity.x = -velocity.x velocity = vector.multiply(velocity, -1)
velocity.y = -velocity.y self:setvelocity(velocity)
velocity.z = -velocity.z
self.object:setvelocity(velocity)
self:set_item(leftover:to_string()) self:set_item(leftover:to_string())
return return
end end
if moved then if moved then
if go_next (self.start_pos, velocity, stack) == 0 then local found_next, new_velocity = go_next(self.start_pos, velocity, stack) -- todo: color
if not found_next then
drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air") drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air")
if drop_pos then if drop_pos then
minetest.item_drop(stack, "", drop_pos) minetest.item_drop(stack, "", drop_pos)
self:remove() self:remove()
return
end end
end end
end
if new_velocity and not vector.equals(velocity, new_velocity) then
if velocity.x~=velocitycopy.x or velocity.y~=velocitycopy.y or velocity.z~=velocitycopy.z or self:setpos(self.start_pos)
self.start_pos.x~=sposcopy.x or self.start_pos.y~=sposcopy.y or self.start_pos.z~=sposcopy.z then self:setvelocity(new_velocity)
self.object:setpos(self.start_pos) end
self.object:setvelocity(velocity)
end end
end end
}) })
if minetest.get_modpath("mesecons_mvps") ~= nil then if minetest.get_modpath("mesecons_mvps") then
local function add_table(table,toadd)
local i = 1
while true do
o = table[i]
if o == toadd then return end
if o == nil then break end
i = i+1
end
table[i] = toadd
end
mesecon:register_mvps_unmov("pipeworks:tubed_item") mesecon:register_mvps_unmov("pipeworks:tubed_item")
mesecon:register_mvps_unmov("pipeworks:color_entity")
mesecon:register_on_mvps_move(function(moved_nodes) mesecon:register_on_mvps_move(function(moved_nodes)
local objects_to_move = {} local moved = {}
for _, n in ipairs(moved_nodes) do for _, n in ipairs(moved_nodes) do
local objects = minetest.get_objects_inside_radius(n.oldpos, 1) moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos)
for _, obj in ipairs(objects) do
local entity = obj:get_luaentity()
if entity and entity.name == "pipeworks:tubed_item" then
--objects_to_move[#objects_to_move+1] = obj
add_table(objects_to_move, obj)
end
end
end end
if #objects_to_move > 0 then for id, entity in pairs(luaentity.entities) do
local dir = vector.subtract(moved_nodes[1].pos, moved_nodes[1].oldpos) if entity.name == "pipeworks:tubed_item" then
for _, obj in ipairs(objects_to_move) do local pos = entity:getpos()
local entity = obj:get_luaentity() local rpos = vector.round(pos)
obj:setpos(vector.add(obj:getpos(), dir)) local dir = moved[minetest.hash_node_position(rpos)]
entity.start_pos = vector.add(entity.start_pos, dir) if dir then
entity:setpos(vector.add(pos, dir))
entity.start_pos = vector.add(entity.start_pos, dir)
end
end end
end end
end) end)

335
luaentity.lua Executable file
View File

@ -0,0 +1,335 @@
local max_entity_id = 1000000000000 -- If you need more, there's a problem with your code
luaentity = {}
luaentity.registered_entities = {}
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()
if t == "" or t == nil then return {} end
return minetest.deserialize(t)
end
local function write_file(tbl)
local f = io.open(filename, "w")
f:write(minetest.serialize(tbl))
f:close()
end
local function read_entities()
local t = read_file()
for _, entity in pairs(t) do
setmetatable(entity, luaentity.registered_entities[entity.name])
end
return t
end
local function write_entities()
for _, entity in pairs(luaentity.entities) do
setmetatable(entity, nil)
for _, attached in pairs(entity._attached_entities) do
if attached.entity then
attached.entity:remove()
attached.entity = nil
end
end
entity._attached_entities_master = nil
end
write_file(luaentity.entities)
end
minetest.after(0, function()
luaentity.entities = read_entities()
end)
minetest.register_on_shutdown(write_entities)
-- todo: load that from file (datastorage?) -> don't forget about metatables (are those serialized?) / do not blindly save -> the attached_entities have to be removed
luaentity.entities_index = 0
local function get_blockpos(pos)
return {x = math.floor(pos.x / 16),
y = math.floor(pos.y / 16),
z = math.floor(pos.z / 16)}
end
local active_blocks = {} -- These only contain active blocks near players (i.e., not forceloaded ones)
local handle_active_blocks_step = 2
local handle_active_blocks_timer = 0
minetest.register_globalstep(function(dtime)
handle_active_blocks_timer = handle_active_blocks_timer + dtime
if handle_active_blocks_timer >= handle_active_blocks_step then
handle_active_blocks_timer = handle_active_blocks_timer - handle_active_blocks_step
local active_block_range = tonumber(minetest.setting_get("active_block_range"))
local new_active_blocks = {}
for _, player in ipairs(minetest.get_connected_players()) do
local blockpos = get_blockpos(player:getpos())
local minp = vector.subtract(blockpos, active_block_range)
local maxp = vector.add(blockpos, active_block_range)
for x = minp.x, maxp.x do
for y = minp.y, maxp.y do
for z = minp.z, maxp.z do
local pos = {x = x, y = y, z = z}
new_active_blocks[minetest.hash_node_position(pos)] = pos
end
end
end
end
active_blocks = new_active_blocks
-- todo: callbacks on block load/unload
end
end)
local function is_active(pos)
return active_blocks[minetest.hash_node_position(get_blockpos(pos))] ~= nil
end
local entitydef_default = {
_attach = function(self, attached, attach_to)
local attached_def = self._attached_entities[attached]
local attach_to_def = self._attached_entities[attach_to]
attached_def.entity:set_attach(
attach_to_def.entity, "",
vector.subtract(attached_def.offset, attach_to_def.offset), -- todo: Does not work because is object space
vector.new(0, 0, 0)
)
end,
_set_master = function(self, index)
self._attached_entities_master = index
if not index then
return
end
local def = self._attached_entities[index]
if not def.entity then
return
end
def.entity:setpos(vector.add(self._pos, def.offset))
def.entity:setvelocity(self._velocity)
def.entity:setacceleration(self._acceleration)
end,
_attach_all = function(self)
local master = self._attached_entities_master
if not master then
return
end
for id, entity in pairs(self._attached_entities) do
if id ~= master and entity.entity then
self:_attach(id, master)
end
end
end,
_detach_all = function(self)
local master = self._attached_entities_master
for id, entity in pairs(self._attached_entities) do
if id ~= master and entity.entity then
entity.entity:set_detach()
end
end
end,
_add_attached = function(self, index)
local entity = self._attached_entities[index]
if entity.entity then
return
end
local entity_pos = vector.add(self._pos, entity.offset)
if not is_active(entity_pos) then
return
end
local ent = minetest.add_entity(entity_pos, entity.name):get_luaentity()
ent:from_data(entity.data)
ent.parent_id = self._id
ent.attached_id = index
entity.entity = ent.object
local master = self._attached_entities_master
if master then
self:_attach(index, master)
else
self:_set_master(index)
end
end,
_remove_attached = function(self, index)
local master = self._attached_entities_master
local entity = self._attached_entities[index]
local ent = entity.entity
entity.entity = nil
if index == master then
self:_detach_all()
local newmaster
for id, attached in pairs(self._attached_entities) do
if id ~= master and attached.entity then
newmaster = id
break
end
end
self:_set_master(newmaster)
self:_attach_all()
elseif master and ent then
ent:set_detach()
end
if ent then
ent:remove()
end
end,
_add_loaded = function(self)
for id, _ in pairs(self._attached_entities) do
self:_add_attached(id)
end
end,
getid = function(self)
return self._id
end,
getpos = function(self)
return vector.new(self._pos)
end,
setpos = function(self, pos)
self._pos = vector.new(pos)
--for _, entity in pairs(self._attached_entities) do
-- if entity.entity then
-- entity.entity:setpos(vector.add(self._pos, entity.offset))
-- end
--end
local master = self._attached_entities_master
if master then
local master_def = self._attached_entities[master]
master_def.entity:setpos(vector.add(self._pos, master_def.offset))
end
end,
getvelocity = function(self)
return vector.new(self._velocity)
end,
setvelocity = function(self, velocity)
self._velocity = vector.new(velocity)
local master = self._attached_entities_master
if master then
self._attached_entities[master].entity:setvelocity(self._velocity)
end
end,
getacceleration = function(self)
return vector.new(self._acceleration)
end,
setacceleration = function(self, acceleration)
self._acceleration = vector.new(acceleration)
local master = self._attached_entities_master
if master then
self._attached_entities[master].entity:setacceleration(self._acceleration)
end
end,
remove = function(self)
self:_detach_all()
for _, entity in pairs(self._attached_entities) do
if entity.entity then
entity.entity:remove()
end
end
luaentity.entities[self._id] = nil
end,
add_attached_entity = function(self, name, data, offset)
local index = #self._attached_entities + 1
self._attached_entities[index] = {
name = name,
data = data,
offset = vector.new(offset),
}
self:_add_attached(index)
return index
end,
remove_attached_entity = function(self, index)
self:_remove_attached(index)
self._attached_entities[index] = nil
end,
}
function luaentity.register_entity(name, prototype)
-- name = check_modname_prefix(name)
prototype.name = name
setmetatable(prototype, {__index = entitydef_default})
prototype.__index = prototype -- Make it possible to use it as metatable
luaentity.registered_entities[name] = prototype
end
-- function luaentity.get_entity_definition(entity)
-- return luaentity.registered_entities[entity.name]
-- end
function luaentity.add_entity(pos, name)
local index = luaentity.entities_index
while luaentity.entities[index] do
index = index + 1
if index >= max_entity_id then
index = 0
end
end
luaentity.entities_index = index
local entity = {
name = name,
_id = index,
_pos = vector.new(pos),
_velocity = {x = 0, y = 0, z = 0},
_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
if entity.on_activate then
entity:on_activate()
end
return entity
end
-- todo: check if remove in get_staticdata works
function luaentity.get_staticdata(self)
local parent = luaentity.entities[self.parent_id]
if parent and parent._remove_attached then
parent:_remove_attached(self.attached_id)
end
return "toremove"
end
function luaentity.on_activate(self, staticdata)
if staticdata == "toremove" then
self.object:remove()
end
end
function luaentity.get_objects_inside_radius(pos, radius)
local objects = {}
local index = 1
for id, entity in pairs(luaentity.entities) do
if vector.distance(pos, entity:getpos()) <= radius then
objects[index] = entity
index = index + 1
end
end
end
minetest.register_globalstep(function(dtime)
for id, entity in pairs(luaentity.entities) do
local master = entity._attached_entities_master
if master then
local master_def = entity._attached_entities[master]
local master_entity = master_def.entity
entity._pos = vector.subtract(master_entity:getpos(), master_def.offset)
entity._velocity = master_entity:getvelocity()
entity._acceleration = master_entity:getacceleration()
else
entity._pos = vector.add(vector.add(
entity._pos,
vector.multiply(entity._velocity, dtime)),
vector.multiply(entity._acceleration, 0.5 * dtime * dtime))
entity._velocity = vector.add(
entity._velocity,
vector.multiply(entity._acceleration, dtime))
end
entity:_add_loaded()
if entity.on_step then
entity:on_step(dtime)
end
end
end)

View File

@ -9,15 +9,13 @@ minetest.register_node("pipeworks:trashcan", {
"pipeworks_trashcan_side.png", "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 = { tube = {
insert_object = function(pos, node, stack, direction) insert_object = function(pos, node, stack, direction)
return ItemStack("") return ItemStack("")
end, end,
can_insert = function(pos, node, stack, direction) connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1},
return true priority = 1, -- Lower than anything else
end,
connect_sides = { left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1 },
}, },
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)

271
tubes.lua Normal file → Executable file
View File

@ -20,7 +20,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
end end
for _, v in ipairs(connects) do for _, v in ipairs(connects) do
pipeworks.add_node_box(outboxes, pipeworks.tube_boxes[v]) table.extend(outboxes, pipeworks.tube_boxes[v])
table.insert(outsel, pipeworks.tube_selectboxes[v]) table.insert(outsel, pipeworks.tube_selectboxes[v])
outimgs[vti[v]] = noctrs[v] outimgs[vti[v]] = noctrs[v]
end end
@ -31,13 +31,13 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
outimgs[vti[v]] = ends[v] outimgs[vti[v]] = ends[v]
end end
local tgroups = {snappy = 3, tube = 1, not_in_creative_inventory = 1} local tgroups = {snappy = 3, tube = 1, tubedevice = 1, not_in_creative_inventory = 1}
local tubedesc = desc.." "..dump(connects).."... You hacker, you." local tubedesc = desc.." "..dump(connects).."... You hacker, you."
local iimg = plain[1] local iimg = plain[1]
local wscale = {x = 1, y = 1, z = 1} local wscale = {x = 1, y = 1, z = 1}
if #connects == 0 then if #connects == 0 then
tgroups = {snappy = 3, tube = 1} tgroups = {snappy = 3, tube = 1, tubedevice = 1}
tubedesc = desc tubedesc = desc
iimg=inv iimg=inv
outimgs = { outimgs = {
@ -50,7 +50,8 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
wscale = {x = 1, y = 1, z = 0.01} wscale = {x = 1, y = 1, z = 0.01}
end end
table.insert(pipeworks.tubenodes, name.."_"..tname) local rname = name.."_"..tname
table.insert(pipeworks.tubenodes, rname)
local nodedef = { local nodedef = {
description = tubedesc, description = tubedesc,
@ -62,7 +63,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
wield_scale = wscale, wield_scale = wscale,
paramtype = "light", paramtype = "light",
selection_box = { selection_box = {
type = "fixed", type = "fixed",
fixed = outsel fixed = outsel
}, },
node_box = { node_box = {
@ -77,26 +78,22 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
style = style, style = style,
drop = name.."_"..dropname, drop = name.."_"..dropname,
tubelike = 1, tubelike = 1,
tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}}, tube = {
on_construct = function(pos) connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1},
local meta = minetest.get_meta(pos) priority = 50
meta:set_int("tubelike", 1) },
if minetest.registered_nodes[name.."_"..tname].on_construct_ then --[[after_place_node = function(pos)
minetest.registered_nodes[name.."_"..tname].on_construct_(pos)
end
end,
after_place_node = function(pos)
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
if minetest.registered_nodes[name.."_"..tname].after_place_node_ then if minetest.registered_nodes[rname].after_place_node_ then
minetest.registered_nodes[name.."_"..tname].after_place_node_(pos) minetest.registered_nodes[rname].after_place_node_(pos)
end end
end, end,
after_dig_node = function(pos) after_dig_node = function(pos)
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
if minetest.registered_nodes[name.."_"..tname].after_dig_node_ then if minetest.registered_nodes[rname].after_dig_node_ then
minetest.registered_nodes[name.."_"..tname].after_dig_node_(pos) minetest.registered_nodes[rname].after_dig_node_(pos)
end end
end end]]
} }
if style == "6d" then if style == "6d" then
nodedef.paramtype2 = "facedir" nodedef.paramtype2 = "facedir"
@ -105,9 +102,9 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
if special == nil then special = {} end if special == nil then special = {} end
for key, value in pairs(special) do for key, value in pairs(special) do
if key == "on_construct" or key == "after_dig_node" or key == "after_place_node" then --if key == "after_dig_node" or key == "after_place_node" then
nodedef[key.."_"] = value -- nodedef[key.."_"] = value
elseif key == "groups" then if key == "groups" then
for group, val in pairs(value) do for group, val in pairs(value) do
nodedef.groups[group] = val nodedef.groups[group] = val
end end
@ -115,19 +112,12 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
for key, val in pairs(value) do for key, val in pairs(value) do
nodedef.tube[key] = val nodedef.tube[key] = val
end end
elseif type(value) == "table" then
nodedef[key] = pipeworks.replace_name(value, "#id", tname)
elseif type(value) == "string" then
nodedef[key] = string.gsub(value, "#id", tname)
else else
nodedef[key] = value nodedef[key] = table.recursive_replace(value, "#id", tname)
end end
end end
local prefix = ":" minetest.register_node(rname, nodedef)
if string.find(name, "pipeworks:") then prefix = "" end
minetest.register_node(prefix..name.."_"..tname, nodedef)
end end
pipeworks.register_tube = function(name, desc, plain, noctrs, ends, short, inv, special, old_registration) pipeworks.register_tube = function(name, desc, plain, noctrs, ends, short, inv, special, old_registration)
@ -181,22 +171,18 @@ pipeworks.register_tube = function(name, desc, plain, noctrs, ends, short, inv,
wield_image = inv, wield_image = inv,
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
description = desc.." (legacy)", description = "Pneumatic tube segment (legacy)",
on_construct = function(pos) --[[after_place_node = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("tubelike", 1)
end,
after_place_node = function(pos)
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
if minetest.registered_nodes[name.."_1"].after_place_node_ then if minetest.registered_nodes[name.."_1"].after_place_node_ then
minetest.registered_nodes[name.."_1"].after_place_node_(pos) minetest.registered_nodes[name.."_1"].after_place_node_(pos)
end end
end, end,]]
groups = {not_in_creative_inventory = 1, tube_to_update = 1}, groups = {not_in_creative_inventory = 1, tube_to_update = 1, tube = 1},
tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}}, tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}},
drop = name.."_1", drop = name.."_1",
}) })
table.insert(pipeworks.tubenodes,cname) table.insert(pipeworks.tubenodes, cname)
for xm = 0, 1 do for xm = 0, 1 do
for xp = 0, 1 do for xp = 0, 1 do
for ym = 0, 1 do for ym = 0, 1 do
@ -221,8 +207,8 @@ if REGISTER_COMPATIBILITY then
interval = 1, interval = 1,
chance = 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)
local minp = {x = pos.x-1, y = pos.y-1, z = pos.z-1} local minp = vector.subtract(pos, 1)
local maxp = {x = pos.x+1, y = pos.y+1, z = pos.z+1} local maxp = vector.add(pos, 1)
if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
end end
@ -241,7 +227,7 @@ local end_textures = {"pipeworks_tube_end.png", "pipeworks_tube_end.png", "pipew
local short_texture = "pipeworks_tube_short.png" local short_texture = "pipeworks_tube_short.png"
local inv_texture = "pipeworks_tube_inv.png" local inv_texture = "pipeworks_tube_inv.png"
pipeworks.register_tube("pipeworks:tube", "Pneumatic Tube Segment", plain_textures, noctr_textures, end_textures, short_texture, inv_texture) pipeworks.register_tube("pipeworks:tube", "Pneumatic tube segment", plain_textures, noctr_textures, end_textures, short_texture, inv_texture)
if pipeworks.enable_mese_tube then if pipeworks.enable_mese_tube then
local mese_noctr_textures = {"pipeworks_mese_tube_noctr_1.png", "pipeworks_mese_tube_noctr_2.png", "pipeworks_mese_tube_noctr_3.png", local mese_noctr_textures = {"pipeworks_mese_tube_noctr_1.png", "pipeworks_mese_tube_noctr_2.png", "pipeworks_mese_tube_noctr_3.png",
@ -252,6 +238,39 @@ if pipeworks.enable_mese_tube then
"pipeworks_mese_tube_end.png", "pipeworks_mese_tube_end.png", "pipeworks_mese_tube_end.png"} "pipeworks_mese_tube_end.png", "pipeworks_mese_tube_end.png", "pipeworks_mese_tube_end.png"}
local mese_short_texture = "pipeworks_mese_tube_short.png" local mese_short_texture = "pipeworks_mese_tube_short.png"
local mese_inv_texture = "pipeworks_mese_tube_inv.png" local mese_inv_texture = "pipeworks_mese_tube_inv.png"
local function update_formspec(pos)
local meta = minetest.get_meta(pos)
local old_formspec = meta:get_string("formspec")
if string.find(old_formspec, "button0") then -- Old version
local inv = meta:get_inventory()
for i = 1, 6 do
for _, stack in ipairs(inv:get_list("line"..i)) do
minetest.item_drop(stack, "", pos)
end
end
end
meta:set_string("formspec",
"size[8,11]"..
"list[current_name;line1;1,0;6,1;]"..
"list[current_name;line2;1,1;6,1;]"..
"list[current_name;line3;1,2;6,1;]"..
"list[current_name;line4;1,3;6,1;]"..
"list[current_name;line5;1,4;6,1;]"..
"list[current_name;line6;1,5;6,1;]"..
"image[0,0;1,1;pipeworks_white.png]"..
"image[0,1;1,1;pipeworks_black.png]"..
"image[0,2;1,1;pipeworks_green.png]"..
"image[0,3;1,1;pipeworks_yellow.png]"..
"image[0,4;1,1;pipeworks_blue.png]"..
"image[0,5;1,1;pipeworks_red.png]"..
fs_helpers.cycling_button(meta, "button[7,0;1,1", "b1s", {"Off", "On"})..
fs_helpers.cycling_button(meta, "button[7,1;1,1", "b2s", {"Off", "On"})..
fs_helpers.cycling_button(meta, "button[7,2;1,1", "b3s", {"Off", "On"})..
fs_helpers.cycling_button(meta, "button[7,3;1,1", "b4s", {"Off", "On"})..
fs_helpers.cycling_button(meta, "button[7,4;1,1", "b5s", {"Off", "On"})..
fs_helpers.cycling_button(meta, "button[7,5;1,1", "b6s", {"Off", "On"})..
"list[current_player;main;0,7;8,4;]")
end
pipeworks.register_tube("pipeworks:mese_tube", "Sorting Pneumatic Tube Segment", mese_plain_textures, mese_noctr_textures, pipeworks.register_tube("pipeworks:mese_tube", "Sorting Pneumatic Tube Segment", mese_plain_textures, mese_noctr_textures,
mese_end_textures, mese_short_texture, mese_inv_texture, mese_end_textures, mese_short_texture, mese_inv_texture,
{tube = {can_go = function(pos, node, velocity, stack) {tube = {can_go = function(pos, node, velocity, stack)
@ -266,6 +285,7 @@ if pipeworks.enable_mese_tube then
if st:get_name() == name then if st:get_name() == name then
found = true found = true
table.insert(tbl, vect) table.insert(tbl, vect)
break
end end
end end
end end
@ -288,71 +308,37 @@ if pipeworks.enable_mese_tube then
meta:set_int("l"..tostring(i).."s", 1) meta:set_int("l"..tostring(i).."s", 1)
inv:set_size("line"..tostring(i), 6*1) inv:set_size("line"..tostring(i), 6*1)
end end
meta:set_string("formspec", update_formspec(pos)
"size[8,11]".. meta:set_string("infotext", "Mese pneumatic tube")
"list[current_name;line1;1,0;6,1;]"..
"list[current_name;line2;1,1;6,1;]"..
"list[current_name;line3;1,2;6,1;]"..
"list[current_name;line4;1,3;6,1;]"..
"list[current_name;line5;1,4;6,1;]"..
"list[current_name;line6;1,5;6,1;]"..
"image[0,0;1,1;pipeworks_white.png]"..
"image[0,1;1,1;pipeworks_black.png]"..
"image[0,2;1,1;pipeworks_green.png]"..
"image[0,3;1,1;pipeworks_yellow.png]"..
"image[0,4;1,1;pipeworks_blue.png]"..
"image[0,5;1,1;pipeworks_red.png]"..
"button[7,0;1,1;button10;On]"..
"button[7,1;1,1;button20;On]"..
"button[7,2;1,1;button30;On]"..
"button[7,3;1,1;button40;On]"..
"button[7,4;1,1;button50;On]"..
"button[7,5;1,1;button60;On]"..
"list[current_player;main;0,7;8,4;]")
meta:set_string("infotext", "Sorting Pneumatic Tube Segment")
end, end,
on_punch = update_formspec,
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos) fs_helpers.on_receive_fields(pos, fields)
local i update_formspec(pos)
if fields.quit then return end
for key, _ in pairs(fields) do
if key:sub(1, 6) == "button" then
local i = key:sub(7, 7)
local s = key:sub(8, 8)
if s == "" then s = 1 - meta:get_int("l"..i.."s") end
meta:set_int("l"..i.."s", s)
end
end
local frm = "size[8,11]"..
"list[current_name;line1;1,0;6,1;]"..
"list[current_name;line2;1,1;6,1;]"..
"list[current_name;line3;1,2;6,1;]"..
"list[current_name;line4;1,3;6,1;]"..
"list[current_name;line5;1,4;6,1;]"..
"list[current_name;line6;1,5;6,1;]"..
"image[0,0;1,1;pipeworks_white.png]"..
"image[0,1;1,1;pipeworks_black.png]"..
"image[0,2;1,1;pipeworks_green.png]"..
"image[0,3;1,1;pipeworks_yellow.png]"..
"image[0,4;1,1;pipeworks_blue.png]"..
"image[0,5;1,1;pipeworks_red.png]"
for i = 1, 6 do
local st = meta:get_int("l"..tostring(i).."s")
if st == 0 then
frm = frm.."button[7,"..tostring(i-1)..";1,1;button"..tostring(i).."1;Off]"
else
frm = frm.."button[7,"..tostring(i-1)..";1,1;button"..tostring(i).."0;On]"
end
end
frm = frm.."list[current_player;main;0,7;8,4;]"
meta:set_string("formspec", frm)
end, end,
can_dig = function(pos, player) can_dig = function(pos, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
return (inv:is_empty("line1") and inv:is_empty("line2") and inv:is_empty("line3") and return (inv:is_empty("line1") and inv:is_empty("line2") and inv:is_empty("line3") and
inv:is_empty("line4") and inv:is_empty("line5") and inv:is_empty("line6")) inv:is_empty("line4") and inv:is_empty("line5") and inv:is_empty("line6"))
end end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local inv = minetest.get_meta(pos):get_inventory()
local stack_copy = ItemStack(stack)
stack_copy:set_count(1)
inv:set_stack(listname, index, stack_copy)
return 0
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local inv = minetest.get_meta(pos):get_inventory()
inv:set_stack(listname, index, ItemStack(""))
return 0
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local inv = minetest.get_meta(pos):get_inventory()
inv:set_stack(from_list, from_index, ItemStack(""))
return 0
end,
}, true) -- Must use old tubes, since the textures are rotated with 6d ones }, true) -- Must use old tubes, since the textures are rotated with 6d ones
end end
@ -360,6 +346,7 @@ if pipeworks.enable_detector_tube then
local detector_plain_textures = {"pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png", local detector_plain_textures = {"pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png",
"pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png"} "pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png", "pipeworks_detector_tube_plain.png"}
local detector_inv_texture = "pipeworks_detector_tube_inv.png" local detector_inv_texture = "pipeworks_detector_tube_inv.png"
local detector_tube_step = 2 * tonumber(minetest.setting_get("dedicated_server_step"))
pipeworks.register_tube("pipeworks:detector_tube_on", "Detecting Pneumatic Tube Segment on (you hacker you)", detector_plain_textures, noctr_textures, pipeworks.register_tube("pipeworks:detector_tube_on", "Detecting Pneumatic Tube Segment on (you hacker you)", detector_plain_textures, noctr_textures,
end_textures, short_texture, detector_inv_texture, end_textures, short_texture, detector_inv_texture,
{tube = {can_go = function(pos, node, velocity, stack) {tube = {can_go = function(pos, node, velocity, stack)
@ -367,12 +354,8 @@ if pipeworks.enable_detector_tube then
local name = minetest.get_node(pos).name local name = minetest.get_node(pos).name
local nitems = meta:get_int("nitems")+1 local nitems = meta:get_int("nitems")+1
meta:set_int("nitems", nitems) meta:set_int("nitems", nitems)
local saved_pos = { x = pos.x, y = pos.y, z = pos.z } local saved_pos = vector.new(pos)
minetest.after(0, function () minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
minetest.after(0, function ()
minetest.after(0, minetest.registered_nodes[name].item_exit, saved_pos)
end)
end)
return pipeworks.notvel(pipeworks.meseadjlist,velocity) return pipeworks.notvel(pipeworks.meseadjlist,velocity)
end}, end},
groups = {mesecon = 2, not_in_creative_inventory = 1}, groups = {mesecon = 2, not_in_creative_inventory = 1},
@ -396,13 +379,11 @@ if pipeworks.enable_detector_tube then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_int("nitems", 1) meta:set_int("nitems", 1)
local name = minetest.get_node(pos).name local name = minetest.get_node(pos).name
local saved_pos = { x = pos.x, y = pos.y, z = pos.z } local saved_pos = vector.new(pos)
minetest.after(0, function () minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
minetest.after(0, function ()
minetest.after(0, minetest.registered_nodes[name].item_exit, saved_pos) end
end) })
end)
end})
pipeworks.register_tube("pipeworks:detector_tube_off", "Detecting Pneumatic Tube Segment", detector_plain_textures, noctr_textures, pipeworks.register_tube("pipeworks:detector_tube_off", "Detecting Pneumatic Tube Segment", detector_plain_textures, noctr_textures,
end_textures, short_texture, detector_inv_texture, end_textures, short_texture, detector_inv_texture,
{tube = {can_go = function(pos, node, velocity, stack) {tube = {can_go = function(pos, node, velocity, stack)
@ -474,7 +455,6 @@ if pipeworks.enable_accelerator_tube then
end end
if pipeworks.enable_crossing_tube then if pipeworks.enable_crossing_tube then
-- FIXME: The textures are not the correct ones
local crossing_noctr_textures = {"pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png", local crossing_noctr_textures = {"pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png",
"pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png"} "pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png", "pipeworks_crossing_tube_noctr.png"}
local crossing_plain_textures = {"pipeworks_crossing_tube_plain.png" ,"pipeworks_crossing_tube_plain.png", "pipeworks_crossing_tube_plain.png", local crossing_plain_textures = {"pipeworks_crossing_tube_plain.png" ,"pipeworks_crossing_tube_plain.png", "pipeworks_crossing_tube_plain.png",
@ -513,10 +493,7 @@ if pipeworks.enable_sand_tube then
for _, object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do for _, object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
if object:get_luaentity().itemstring ~= "" then if object:get_luaentity().itemstring ~= "" then
local titem = pipeworks.tube_item(pos,object:get_luaentity().itemstring) pipeworks.tube_item(pos, pos, vector.new(0, 0, 0), object:get_luaentity().itemstring)
titem:get_luaentity().start_pos = {x = pos.x, y = pos.y-1, z = pos.z}
titem:setvelocity({x = 0.01, y = 1, z = -0.01})
titem:setacceleration({x = 0, y = 0, z = 0})
end end
object:get_luaentity().itemstring = "" object:get_luaentity().itemstring = ""
object:remove() object:remove()
@ -576,10 +553,7 @@ if pipeworks.enable_mese_sand_tube then
for _,object in ipairs(get_objects_with_square_radius(pos, minetest.env:get_meta(pos):get_int("dist"))) do for _,object in ipairs(get_objects_with_square_radius(pos, minetest.env:get_meta(pos):get_int("dist"))) do
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
if object:get_luaentity().itemstring ~= "" then if object:get_luaentity().itemstring ~= "" then
local titem = pipeworks.tube_item(pos, object:get_luaentity().itemstring) pipeworks.tube_item(pos, pos, vector.new(0, 0, 0), object:get_luaentity().itemstring)
titem:get_luaentity().start_pos = {x = pos.x, y = pos.y-1, z = pos.z}
titem:setvelocity({x = 0.01, y = 1, z = -0.01})
titem:setacceleration({x = 0, y = 0, z = 0})
end end
object:get_luaentity().itemstring = "" object:get_luaentity().itemstring = ""
object:remove() object:remove()
@ -589,26 +563,9 @@ if pipeworks.enable_mese_sand_tube then
}) })
end end
local function facedir_to_right_dir(facedir)
--find the other directions
local backdir = minetest.facedir_to_dir(facedir)
local topdir = ({[0] = {x = 0, y = 1, z = 0},
{x = 0, y = 0, z = 1},
{x = 0, y = 0, z = -1},
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
{x = 0, y = -1, z = 0}})[math.floor(facedir/4)]
--return a cross product
return {x = topdir.y*backdir.z - backdir.y*topdir.z,
y = topdir.z*backdir.x - backdir.z*topdir.x,
z = topdir.x*backdir.y - backdir.x*topdir.y}
end
if pipeworks.enable_one_way_tube then if pipeworks.enable_one_way_tube then
minetest.register_node("pipeworks:one_way_tube", { minetest.register_node("pipeworks:one_way_tube", {
description = "One-way Pneumatic Tube Segment", description = "One way tube",
tiles = {"pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_output.png", tiles = {"pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_output.png",
"pipeworks_one_way_tube_input.png", "pipeworks_one_way_tube_side.png", "pipeworks_one_way_tube_top.png"}, "pipeworks_one_way_tube_input.png", "pipeworks_one_way_tube_side.png", "pipeworks_one_way_tube_top.png"},
paramtype2 = "facedir", paramtype2 = "facedir",
@ -616,35 +573,19 @@ if pipeworks.enable_one_way_tube then
paramtype = "light", paramtype = "light",
node_box = {type = "fixed", node_box = {type = "fixed",
fixed = {{-1/2, -9/64, -9/64, 1/2, 9/64, 9/64}}}, fixed = {{-1/2, -9/64, -9/64, 1/2, 9/64, 9/64}}},
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, tubedevice_receiver = 1}, groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1},
legacy_facedir_simple = true, legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
on_construct = function(pos) tube = {
minetest.get_meta(pos):set_int("tubelike", 1) connect_sides = {left = 1, right = 1},
end,
after_place_node = function(pos)
pipeworks.scan_for_tube_objects(pos)
end,
after_dig_node = function(pos)
pipeworks.scan_for_tube_objects(pos)
end,
tube = {connect_sides = {left = 1, right = 1},
can_go = function(pos, node, velocity, stack) can_go = function(pos, node, velocity, stack)
return velocity return {velocity}
end,
insert_object = function(pos, node, stack, direction)
item1 = pipeworks.tube_item(pos, stack)
item1:get_luaentity().start_pos = pos
item1:setvelocity({x = direction.x*direction.speed, y = direction.y*direction.speed, z = direction.z*direction.speed})
item1:setacceleration({x = 0, y = 0, z = 0})
return ItemStack("")
end, end,
can_insert = function(pos, node, stack, direction) can_insert = function(pos, node, stack, direction)
local dir = facedir_to_right_dir(node.param2) local dir = minetest.facedir_to_right_dir(node.param2)
if dir.x == direction.x and dir.y == direction.y and dir.z == direction.z then return vector.equals(dir, direction)
return true end,
end priority = 75 -- Higher than normal tubes, but lower than receivers
return false },
end},
}) })
end end