From d5480f5ff0ede03df2d212e2236e2da71c1046da Mon Sep 17 00:00:00 2001 From: Novatux Date: Thu, 14 Aug 2014 16:22:03 +0200 Subject: [PATCH] Major rewrite of items in tubes --- autoplace_tubes.lua | 110 ++++-------- common.lua | 144 ++++++++++++++++ init.lua | 2 + item_transport.lua | 395 +++++++++++++++++++------------------------- luaentity.lua | 335 +++++++++++++++++++++++++++++++++++++ trashcan.lua | 10 +- tubes.lua | 271 ++++++++++++------------------ 7 files changed, 796 insertions(+), 471 deletions(-) mode change 100644 => 100755 autoplace_tubes.lua create mode 100755 common.lua mode change 100644 => 100755 init.lua mode change 100644 => 100755 item_transport.lua create mode 100755 luaentity.lua mode change 100644 => 100755 tubes.lua diff --git a/autoplace_tubes.lua b/autoplace_tubes.lua old mode 100644 new mode 100755 index c9d5d9f..42cf98b --- 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 - - --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" + if node.param2 < 0 or node.param2 > 23 then + node.param2 = 0 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 + local backdir = minetest.facedir_to_dir(node.param2) + local back = vector.dot(backdir, tubedir) + if back == 1 then + return "back" + 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 diff --git a/init.lua b/init.lua old mode 100644 new mode 100755 index f78b41f..b6c91d6 --- a/init.lua +++ b/init.lua @@ -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 old mode 100644 new mode 100755 index f01506b..db4ffb0 --- 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. 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 - 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 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) - 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 itemname = nil if itemtable then itemname = stack:to_table().name 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) + 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: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, - 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 stack = ItemStack(self.itemstring) - local drop_pos = nil - local velocity = self.object:getvelocity() - - if velocity == nil then return end - - local velocitycopy = {x = velocity.x, y = velocity.y, z = velocity.z} + local pos = self:getpos() + local stack = ItemStack(self.itemstring) + local drop_pos + + 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 old mode 100644 new mode 100755 index 97f0237..c0375ef --- 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