diff options
| -rwxr-xr-x[-rw-r--r--] | autoplace_tubes.lua | 108 | ||||
| -rwxr-xr-x | common.lua | 144 | ||||
| -rwxr-xr-x[-rw-r--r--] | init.lua | 2 | ||||
| -rwxr-xr-x[-rw-r--r--] | item_transport.lua | 383 | ||||
| -rwxr-xr-x | luaentity.lua | 335 | ||||
| -rw-r--r-- | trashcan.lua | 10 | ||||
| -rwxr-xr-x[-rw-r--r--] | tubes.lua | 271 | 
7 files changed, 789 insertions, 464 deletions
| diff --git a/autoplace_tubes.lua b/autoplace_tubes.lua index c9d5d9f..42cf98b 100644..100755 --- a/autoplace_tubes.lua +++ b/autoplace_tubes.lua @@ -1,72 +1,38 @@  -- 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) -	return in_table(pipeworks.tubenodes,nodename) -end - -if pipeworks == nil then -	pipeworks = {} +	return table.contains(pipeworks.tubenodes, nodename)  end  --a function for determining which side of the node we are on  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 +	end -	--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 +	local back = vector.dot(backdir, tubedir) +	if back == 1 then  		return "back" -	end - -	--check whether the vector is antiparallel with the tube direction; that indicates the front -	if backdir.x == -tubedir.x and backdir.y == -tubedir.y and backdir.z == -tubedir.z then +	elseif back == -1 then  		return "front"  	end -	--facedir is defined in terms of the top-bottom axis of the node; we'll take advantage of that -	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(node.param2/4)] - -	--is this the top? -	if topdir.x == tubedir.x and topdir.y == tubedir.y and topdir.z == tubedir.z then +	local topdir = minetest.facedir_to_top_dir(node.param2) +	local top = vector.dot(topdir, tubedir) +	if top == 1 then  		return "top" -	end - -	--or the bottom? -	if topdir.x == -tubedir.x and topdir.y == -tubedir.y and topdir.z == -tubedir.z then +	elseif top == -1 then  		return "bottom"  	end -	--we shall apply some maths to obtain the right-facing vector -	local rightdir = {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} - -	--is this the right side? -	if rightdir.x == tubedir.x and rightdir.y == tubedir.y and rightdir.z == tubedir.z then +	local rightdir = minetest.facedir_to_right_dir(node.param2) +	local right = vector.dot(rightdir, tubedir) +	if right == 1 then  		return "right" -	end - -	--or the left? -	if rightdir.x == -tubedir.x and rightdir.y == -tubedir.y and rightdir.z == -tubedir.z then +	else  		return "left"  	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  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  	local adjustments = { -		{ 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=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}, +		{x =  0, y =  1, z =  0}, +		{x =  0, y =  0, z = -1}, +		{x =  0, y =  0, z =  1}  	}  	-- 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] = {x=pos.x+adj.x, y=pos.y+adj.y, z=pos.z+adj.z} +	for i, adj in ipairs(adjustments) do +		positions[i] = vector.add(pos, adj)  		nodes[i] = minetest.get_node(positions[i])  	end -	for i,node in ipairs(nodes) do +	for i, node in ipairs(nodes) do  		local idef = minetest.registered_nodes[node.name]  		-- handle the tubes themselves  		if is_tube(node.name) then @@ -102,7 +68,9 @@ local function tube_autoroute(pos)  		-- 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, {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 @@ -110,18 +78,17 @@ local function tube_autoroute(pos)  	local nodedef = minetest.registered_nodes[nctr.name]  	local basename = nodedef.basename -	local newname  	if nodedef.style == "old" then  		local nsurround = "" -		for i,n in ipairs(active) do -			nsurround = nsurround .. n +		for i, n in ipairs(active) do +			nsurround = nsurround..n  		end  		nctr.name = basename.."_"..nsurround  	elseif nodedef.style == "6d" then  		local s = 0 -		for i,n in ipairs(active) do +		for i, n in ipairs(active) do  			if n == 1 then -				s = s+2^vts[i] +				s = s + 2^vts[i]  			end  		end  		nctr.name = basename.."_"..tube_table[s] @@ -131,14 +98,9 @@ local function tube_autoroute(pos)  end  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 -	tube_autoroute({ x=pos.x-1, y=pos.y  , z=pos.z   }) -	tube_autoroute({ x=pos.x+1, y=pos.y  , z=pos.z   }) -	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) +	for side = 0, 6 do +		tube_autoroute(vector.add(pos, directions.side_to_dir(side))) +	end  end  minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack) @@ -157,7 +119,7 @@ minetest.register_on_dignode(function(pos, oldnode, digger)  	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)  		for _, n in ipairs(moved_nodes) do  			pipeworks.scan_for_tube_objects(n.pos) diff --git a/common.lua b/common.lua new file mode 100755 index 0000000..6a92198 --- /dev/null +++ b/common.lua @@ -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
\ No newline at end of file @@ -106,9 +106,11 @@ end  -------------------------------------------  -- Load the various other parts of the mod +dofile(pipeworks.modpath.."/common.lua")  dofile(pipeworks.modpath.."/models.lua")  dofile(pipeworks.modpath.."/autoplace_pipes.lua")  dofile(pipeworks.modpath.."/autoplace_tubes.lua") +dofile(pipeworks.modpath.."/luaentity.lua")  dofile(pipeworks.modpath.."/item_transport.lua")  dofile(pipeworks.modpath.."/flowing_logic.lua")  dofile(pipeworks.modpath.."/crafts.lua") diff --git a/item_transport.lua b/item_transport.lua index f01506b..db4ffb0 100644..100755 --- a/item_transport.lua +++ b/item_transport.lua @@ -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 = {      get_player_name = function() return ":pipeworks" end,      -- any other player functions called by allow_metadata_inventory_take anywhere...      -- 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  	local stack = ItemStack(item) -	local obj = minetest.add_entity(pos, "pipeworks:tubed_item") -	obj:get_luaentity():set_item(stack:to_string()) +	local obj = luaentity.add_entity(pos, "pipeworks:tubed_item") +	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  end @@ -52,19 +35,16 @@ local function set_filter_formspec(data, meta)  			"item_image[0,0;1,1;pipeworks:"..data.name.."]"..  			"label[1,0;"..minetest.formspec_escape(itemname).."]"..  			"label[0,1;Prefer item types:]".. -			"list[current_name;main;0,1.5;8,2;]" -	local slotseq_mode = meta:get_int("slotseq_mode") -	if slotseq_mode == 1 then -		formspec = formspec .. "button[0,3.5;4,1;slotseq_mode2;Sequence slots Randomly]" -	elseif slotseq_mode == 2 then -		formspec = formspec .. "button[0,3.5;4,1;slotseq_mode0;Sequence slots by Rotation]" -	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;]" +			"list[current_name;main;0,1.5;8,2;]".. +			fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode", +				{"Sequence slots by Priority", +				 "Sequence slots Randomly", +				 "Sequence slots by Rotation"}).. +			"list[current_player;main;0,4.5;8,4;]"  	meta:set_string("formspec", formspec)  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 sposes = {}  	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)  					end  				end -				local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item) -				item1:get_luaentity().start_pos = vector.add(frompos, dir) -				item1:setvelocity(dir) -				item1:setacceleration({x=0, y=0, z=0}) +				local pos = vector.add(frompos, vector.multiply(dir, 1.4)) +				local start_pos = vector.add(frompos, dir) +				local item1 = pipeworks.tube_item(pos, start_pos, dir, item)  				return true-- only fire one item, please  			end  	end @@ -143,8 +122,8 @@ end  local function punch_filter(data, filtpos, filtnode)  	local filtmeta = minetest.get_meta(filtpos)  	local filtinv = filtmeta:get_inventory() -	local dir = facedir_to_right_dir(filtnode.param2) -	local frompos = {x=filtpos.x - dir.x, y=filtpos.y - dir.y, z=filtpos.z - dir.z} +	local dir = minetest.facedir_to_right_dir(filtnode.param2) +	local frompos = vector.subtract(filtpos, dir)  	local fromnode = minetest.get_node(frompos)  	if not fromnode then return end  	local fromdef = minetest.registered_nodes[fromnode.name] @@ -197,7 +176,7 @@ for _, data in ipairs({  			"pipeworks_"..data.name.."_top.png",  		},  		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,  		sounds = default.node_sound_wood_defaults(),  		on_construct = function(pos) @@ -208,28 +187,17 @@ for _, data in ipairs({  			inv:set_size("main", 8*2)  		end,  		on_receive_fields = function(pos, formname, fields, sender) +			fs_helpers.on_receive_fields(pos, fields)  			local meta = minetest.get_meta(pos) -			for k, _ in pairs(fields) do -				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 +			meta:set_int("slotseq_index", 1)  			set_filter_formspec(data, meta)  			set_filter_infotext(data, meta)  		end, -		can_dig = function(pos,player) +		can_dig = function(pos, player)  			local meta = minetest.get_meta(pos)  			local inv = meta:get_inventory()  			return inv:is_empty("main")  		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 = {  			effector = {  				action_on = function(pos, node) @@ -237,21 +205,13 @@ for _, data in ipairs({  				end,  			},  		}, -		tube={connect_sides={right=1}}, +		tube = {connect_sides = {right = 1}},  		on_punch = function (pos, node, puncher)  			punch_filter(data, pos, node)  		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}}  function pipeworks.notvel(tbl, vel) @@ -263,18 +223,20 @@ function pipeworks.notvel(tbl, vel)  end  local function go_next(pos, velocity, stack) -	local chests = {} -	local tubes = {} +	local next_positions = {} +	local max_priority = 0  	local cnode = minetest.get_node(pos)  	local cmeta = minetest.get_meta(pos) -	local n  	local can_go  	local speed = math.abs(velocity.x + velocity.y + velocity.z) +	if speed == 0 then +		speed = 1 +	end  	local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed}  	if speed >= 4.1 then  		speed = 4  	elseif speed >= 1.1 then -		speed = speed-0.1 +		speed = speed - 0.1  	else  		speed = 1  	end @@ -284,58 +246,40 @@ local function go_next(pos, velocity, stack)  	else  		can_go = pipeworks.notvel(adjlist, vel)  	end -	local meta = nil -	for _,vect in ipairs(can_go) do -		local npos = addVect(pos,vect) +	for _, vect in ipairs(can_go) do +		local npos = vector.add(pos, vect)  		local node = minetest.get_node(npos) -		local tube_receiver = minetest.get_item_group(node.name,"tubedevice_receiver") -		meta = minetest.get_meta(npos) -		local tubelike = meta:get_int("tubelike") -		if tube_receiver == 1 then -			if minetest.registered_nodes[node.name].tube and -				minetest.registered_nodes[node.name].tube.can_insert and -				minetest.registered_nodes[node.name].tube.can_insert(npos, node, stack, vect) then -				local i = #chests + 1 -				chests[i] = {} -				chests[i].pos = npos -				chests[i].vect = vect +		local tubedevice = minetest.get_item_group(node.name, "tubedevice") +		local tube_def = minetest.registered_nodes[node.name].tube +		local tube_priority = (tube_def and tube_def.priority) or 100 +		if tubedevice > 0 and tube_priority >= max_priority then +			if not tube_def or not tube_def.can_insert or +					tubedef.can_insert(npos, node, stack, vect) then +				if tube_priority > max_priority then +					max_priority = tube_priority +					next_positions = {} +				end +				next_positions[#next_positions + 1] = {pos = npos, vect = vect}  			end -		elseif tubelike == 1 then -			local i = #tubes + 1 -			tubes[i] = {} -			tubes[i].pos = npos -			tubes[i].vect = vect  		end  	end -	if chests[1] == nil then--no chests found -		if tubes[1] == nil then -			return 0 -		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 + +	if not next_positions[1] then +		return false, nil +	end +	 +	local n = (cmeta:get_int("tubedir") % (#next_positions)) + 1 +	if pipeworks.enable_cyclic_mode then +		cmeta:set_int("tubedir", n)  	end -	return 1 +	local new_velocity = vector.multiply(next_positions[n].vect, vel.speed) +	return true, new_velocity  end  minetest.register_entity("pipeworks:tubed_item", {  	initial_properties = {  		hp_max = 1,  		physical = false, ---		collisionbox = {0,0,0,0,0,0},  		collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},  		visual = "wielditem",  		visual_size = {x = 0.15, y = 0.15}, @@ -343,113 +287,126 @@ minetest.register_entity("pipeworks:tubed_item", {  		spritediv = {x = 1, y = 1},  		initial_sprite_basepos = {x = 0, y = 0},  		is_visible = false, -		start_pos = {}, -		route = {}, -		removed = false  	}, -	 -	itemstring = '', +  	physical_state = false, -	set_item = function(self, itemstring) -		self.itemstring = itemstring +	from_data = function(self, itemstring)  		local stack = ItemStack(itemstring) +		local itemtable = stack:to_table() +		local itemname = nil +		if itemtable then +			itemname = stack:to_table().name +		end +		local item_texture = nil +		local item_type = "" +		if minetest.registered_items[itemname] then +			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() }, +			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 -		}) +	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, -	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 itemname = nil -		if itemtable then -			itemname = stack:to_table().name +	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 itemname then  -		self.start_pos=item.start_pos -		self.object:setvelocity(item.velocity) -		self.object:setacceleration({x=0, y=0, z=0}) -		self.object:setpos(item.start_pos) +		if self.item_entity then +			self:remove_attached_entity(self.item_entity)  		end -		self:set_item(item.itemstring) +		self.itemstring = itemstring +		self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring)  	end, -	remove = function(self) -		self.object:remove() -		self.removed = true -		self.itemstring = '' +	set_color = function(self, color) +		if self.color == color then +			return +		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,  	on_step = function(self, dtime) -		if self.removed then -			return -		end  		if self.start_pos == nil then -			local pos = self.object:getpos() -			self.start_pos = roundpos(pos) +			local pos = self:getpos() +			self.start_pos = vector.round(pos) +			self:setpos(pos)  		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 pos = self:getpos()  		local stack = ItemStack(self.itemstring) -		local drop_pos = nil +		local drop_pos -		local velocity = self.object:getvelocity() -	 -		if velocity == nil then return end -	 -		local velocitycopy = {x = velocity.x, y = velocity.y, z = velocity.z} +		local velocity = self:getvelocity()  		local moved = false  		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} -		if math.abs(vel.x) == 1 then -			local next_node = math.abs(pos.x - self.start_pos.x) -			if next_node >= 1 then  -				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 +		if vector.distance(pos, self.start_pos) >= 1 then +			self.start_pos = vector.add(self.start_pos, vel) +			moved = true  		end -		local sposcopy = {x = self.start_pos.x, y = self.start_pos.y, z = self.start_pos.z} -		 -		node = minetest.get_node(self.start_pos) +		minetest.load_position(self.start_pos) +		local node = minetest.get_node(self.start_pos)  		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  				leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel)  			else @@ -459,62 +416,48 @@ minetest.register_entity("pipeworks:tubed_item", {  				self:remove()  				return  			end -			velocity.x = -velocity.x -			velocity.y = -velocity.y -			velocity.z = -velocity.z -			self.object:setvelocity(velocity) +			velocity = vector.multiply(velocity, -1) +			self:setvelocity(velocity)  			self:set_item(leftover:to_string())  			return  		end  		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")  				if drop_pos then   					minetest.item_drop(stack, "", drop_pos)  					self:remove() +					return  				end  			end -		end -		 -		if velocity.x~=velocitycopy.x or velocity.y~=velocitycopy.y or velocity.z~=velocitycopy.z or  -				self.start_pos.x~=sposcopy.x or self.start_pos.y~=sposcopy.y or self.start_pos.z~=sposcopy.z then -			self.object:setpos(self.start_pos) -			self.object:setvelocity(velocity) +			 +			if new_velocity and not vector.equals(velocity, new_velocity) then +				self:setpos(self.start_pos) +				self:setvelocity(new_velocity) +			end  		end  	end  }) -if minetest.get_modpath("mesecons_mvps") ~= nil 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 +if minetest.get_modpath("mesecons_mvps") then  	mesecon:register_mvps_unmov("pipeworks:tubed_item") +	mesecon:register_mvps_unmov("pipeworks:color_entity")  	mesecon:register_on_mvps_move(function(moved_nodes) -		local objects_to_move = {} +		local moved = {}  		for _, n in ipairs(moved_nodes) do -			local objects = minetest.get_objects_inside_radius(n.oldpos, 1) -			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 +			moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos)  		end -		if #objects_to_move > 0 then -			local dir = vector.subtract(moved_nodes[1].pos, moved_nodes[1].oldpos) -			for _, obj in ipairs(objects_to_move) do -				local entity = obj:get_luaentity() -				obj:setpos(vector.add(obj:getpos(), dir)) -				entity.start_pos = vector.add(entity.start_pos, dir) +		for id, entity in pairs(luaentity.entities) do +			if entity.name == "pipeworks:tubed_item" then +				local pos = entity:getpos() +				local rpos = vector.round(pos) +				local dir = moved[minetest.hash_node_position(rpos)] +				if dir then +					entity:setpos(vector.add(pos, dir)) +					entity.start_pos = vector.add(entity.start_pos, dir) +				end  			end  		end  	end) diff --git a/luaentity.lua b/luaentity.lua new file mode 100755 index 0000000..a4ef4a0 --- /dev/null +++ b/luaentity.lua @@ -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) diff --git a/trashcan.lua b/trashcan.lua index 880ab59..fdec79f 100644 --- a/trashcan.lua +++ b/trashcan.lua @@ -9,15 +9,13 @@ minetest.register_node("pipeworks:trashcan", {  		"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,  -		can_insert = function(pos, node, stack, direction) -			return true -		end,  -		connect_sides = { left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1 }, +		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) diff --git a/tubes.lua b/tubes.lua index 97f0237..c0375ef 100644..100755 --- a/tubes.lua +++ b/tubes.lua @@ -20,7 +20,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e  	end  	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])  		outimgs[vti[v]] = noctrs[v]  	end @@ -31,13 +31,13 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e  		outimgs[vti[v]] = ends[v]  	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 iimg = plain[1]  	local wscale = {x = 1, y = 1, z = 1}  	if #connects == 0 then -		tgroups = {snappy = 3, tube = 1} +		tgroups = {snappy = 3, tube = 1, tubedevice = 1}  		tubedesc = desc  		iimg=inv  		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}  	end -	table.insert(pipeworks.tubenodes, name.."_"..tname) +	local rname = name.."_"..tname +	table.insert(pipeworks.tubenodes, rname)  	local nodedef = {  		description = tubedesc, @@ -62,7 +63,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e  		wield_scale = wscale,  		paramtype = "light",  		selection_box = { -	             	type = "fixed", +			type = "fixed",  			fixed = outsel  		},  		node_box = { @@ -77,26 +78,22 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e  		style = style,  		drop = name.."_"..dropname,  		tubelike = 1, -		tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}}, -		on_construct = function(pos) -			local meta = minetest.get_meta(pos) -			meta:set_int("tubelike", 1) -			if minetest.registered_nodes[name.."_"..tname].on_construct_ then -				minetest.registered_nodes[name.."_"..tname].on_construct_(pos) -			end -		end, -		after_place_node = function(pos) +		tube = { +			connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}, +			priority = 50 +		}, +		--[[after_place_node = function(pos)  			pipeworks.scan_for_tube_objects(pos) -			if minetest.registered_nodes[name.."_"..tname].after_place_node_ then -				minetest.registered_nodes[name.."_"..tname].after_place_node_(pos) +			if minetest.registered_nodes[rname].after_place_node_ then +				minetest.registered_nodes[rname].after_place_node_(pos)  			end  		end,  		after_dig_node = function(pos)  			pipeworks.scan_for_tube_objects(pos) -			if minetest.registered_nodes[name.."_"..tname].after_dig_node_ then -				minetest.registered_nodes[name.."_"..tname].after_dig_node_(pos) +			if minetest.registered_nodes[rname].after_dig_node_ then +				minetest.registered_nodes[rname].after_dig_node_(pos)  			end -		end +		end]]  	}  	if style == "6d" then  		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  	for key, value in pairs(special) do -		if key == "on_construct" or key == "after_dig_node" or key == "after_place_node" then -			nodedef[key.."_"] = value -		elseif key == "groups" then +		--if key == "after_dig_node" or key == "after_place_node" then +		--	nodedef[key.."_"] = value +		if key == "groups" then  			for group, val in pairs(value) do  				nodedef.groups[group] = val  			end @@ -115,19 +112,12 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e  			for key, val in pairs(value) do  				nodedef.tube[key] = val  			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 -			nodedef[key] = value +			nodedef[key] = table.recursive_replace(value, "#id", tname)  		end  	end -	local prefix = ":" -	if string.find(name, "pipeworks:") then prefix = "" end - -	minetest.register_node(prefix..name.."_"..tname, nodedef) +	minetest.register_node(rname, nodedef)  end  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,  				paramtype = "light",  				sunlight_propagates = true, -				description = desc.." (legacy)", -				on_construct = function(pos) -					local meta = minetest.get_meta(pos) -					meta:set_int("tubelike", 1) -				end, -				after_place_node = function(pos) +				description = "Pneumatic tube segment (legacy)", +				--[[after_place_node = function(pos)  					pipeworks.scan_for_tube_objects(pos)  					if minetest.registered_nodes[name.."_1"].after_place_node_ then  						minetest.registered_nodes[name.."_1"].after_place_node_(pos)  					end -				end, -				groups = {not_in_creative_inventory = 1, tube_to_update = 1}, +				end,]] +				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}},  				drop = name.."_1",  			}) -			table.insert(pipeworks.tubenodes,cname) +			table.insert(pipeworks.tubenodes, cname)  			for xm = 0, 1 do  			for xp = 0, 1 do  			for ym = 0, 1 do @@ -221,8 +207,8 @@ if REGISTER_COMPATIBILITY then  		interval = 1,  		chance = 1,  		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 maxp = {x = pos.x+1, y = pos.y+1, z = pos.z+1} +			local minp = vector.subtract(pos, 1) +			local maxp = vector.add(pos, 1)  			if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then  				pipeworks.scan_for_tube_objects(pos)  			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 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  	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"}  	local mese_short_texture = "pipeworks_mese_tube_short.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,  				mese_end_textures, mese_short_texture, mese_inv_texture,  				{tube = {can_go = function(pos, node, velocity, stack) @@ -266,6 +285,7 @@ if pipeworks.enable_mese_tube then  									 if st:get_name() == name then  										 found = true  										 table.insert(tbl, vect) +										 break  									 end  								 end  							 end @@ -288,71 +308,37 @@ if pipeworks.enable_mese_tube then  						 meta:set_int("l"..tostring(i).."s", 1)  						 inv:set_size("line"..tostring(i), 6*1)  					 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]".. -							 "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") +				 	 update_formspec(pos) +					 meta:set_string("infotext", "Mese pneumatic tube")  				 end, +				 on_punch = update_formspec,  				 on_receive_fields = function(pos, formname, fields, sender) -					 local meta = minetest.get_meta(pos) -					 local i -					 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) +					 fs_helpers.on_receive_fields(pos, fields) +					 update_formspec(pos)  				 end,  				 can_dig = function(pos, player)  					 local meta = minetest.get_meta(pos)  					 local inv = meta:get_inventory()  					 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")) -				 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  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",  					 "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_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,  				end_textures, short_texture, detector_inv_texture,  				{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 nitems = meta:get_int("nitems")+1  						 meta:set_int("nitems", nitems) -						 local saved_pos = { x = pos.x, y = pos.y, z = pos.z } -						 minetest.after(0, function () -						 minetest.after(0, function () -							minetest.after(0, minetest.registered_nodes[name].item_exit, saved_pos) -						 end) -						 end) +						 local saved_pos = vector.new(pos) +					 	 minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)  						 return pipeworks.notvel(pipeworks.meseadjlist,velocity)  					end},  				 groups = {mesecon = 2, not_in_creative_inventory = 1}, @@ -396,13 +379,11 @@ if pipeworks.enable_detector_tube then  					 local meta = minetest.get_meta(pos)  					 meta:set_int("nitems", 1)  					 local name = minetest.get_node(pos).name -					 local saved_pos = { x = pos.x, y = pos.y, z = pos.z } -					 minetest.after(0, function () -					 minetest.after(0, function () -						minetest.after(0, minetest.registered_nodes[name].item_exit, saved_pos) -					 end) -					 end) -	end}) +					 local saved_pos = vector.new(pos) +					 minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos) +				 +				end +	})  	pipeworks.register_tube("pipeworks:detector_tube_off", "Detecting Pneumatic Tube Segment", detector_plain_textures, noctr_textures,  				end_textures, short_texture, detector_inv_texture,  				{tube = {can_go = function(pos, node, velocity, stack) @@ -474,7 +455,6 @@ if pipeworks.enable_accelerator_tube then  end  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",  					 "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", @@ -513,10 +493,7 @@ if pipeworks.enable_sand_tube then  				       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 object:get_luaentity().itemstring ~= "" then -							       local titem = pipeworks.tube_item(pos,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}) +							       pipeworks.tube_item(pos, pos, vector.new(0, 0, 0), object:get_luaentity().itemstring)  						       end  						       object:get_luaentity().itemstring = ""  						       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  					       if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then  						       if object:get_luaentity().itemstring ~= "" then -							       local titem = pipeworks.tube_item(pos, 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}) +							       pipeworks.tube_item(pos, pos, vector.new(0, 0, 0), object:get_luaentity().itemstring)  						       end  						       object:get_luaentity().itemstring = ""  						       object:remove() @@ -589,26 +563,9 @@ if pipeworks.enable_mese_sand_tube then  	})  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  	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",  			"pipeworks_one_way_tube_input.png", "pipeworks_one_way_tube_side.png", "pipeworks_one_way_tube_top.png"},  		paramtype2 = "facedir", @@ -616,35 +573,19 @@ if pipeworks.enable_one_way_tube then  		paramtype = "light",  		node_box = {type = "fixed",  			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,  		sounds = default.node_sound_wood_defaults(), -		on_construct = function(pos) -			minetest.get_meta(pos):set_int("tubelike", 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}, +		tube = { +			connect_sides = {left = 1, right = 1},  			can_go = function(pos, node, velocity, stack) -				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("") +				return {velocity}  			end,  			can_insert = function(pos, node, stack, direction) -				local dir = facedir_to_right_dir(node.param2) -				if dir.x == direction.x and dir.y == direction.y and dir.z == direction.z then -					return true -				end -				return false -			end}, +				local dir = minetest.facedir_to_right_dir(node.param2) +				return vector.equals(dir, direction) +			end, +			priority = 75 -- Higher than normal tubes, but lower than receivers +		},  	})  end | 
