diff --git a/crafts.lua b/crafts.lua index 6cef9e5..4ad7edc 100644 --- a/crafts.lua +++ b/crafts.lua @@ -223,17 +223,26 @@ if pipeworks.enable_mese_tube then }) end -if pipeworks.enable_item_tags and pipeworks.enable_tags_tube then - local book_item = "default:book" - minetest.register_craft({ - output = "pipeworks:tags_tube_000000", +if pipeworks.enable_item_tags and pipeworks.enable_tag_tube then + minetest.register_craft( { + output = "pipeworks:tag_tube_000000 2", recipe = { - { book_item, book_item, book_item }, - { book_item, "pipeworks:mese_tube_000000", book_item }, - { book_item, book_item, book_item }, - } + { "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }, + { materials.book, materials.mese_crystal, materials.book }, + { "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" } + }, + }) + + minetest.register_craft( { + type = "shapeless", + output = "pipeworks:tag_tube_000000", + recipe = { + "pipeworks:mese_tube_000000", + materials.book, + }, }) end + if pipeworks.enable_sand_tube then minetest.register_craft( { output = "pipeworks:sand_tube_1 2", diff --git a/default_settings.lua b/default_settings.lua index 72de318..c48d852 100644 --- a/default_settings.lua +++ b/default_settings.lua @@ -5,7 +5,7 @@ local prefix = "pipeworks_" local settings = { enable_pipes = true, enable_item_tags = true, - enable_tags_tube = true, + enable_tag_tube = true, enable_lowpoly = false, enable_autocrafter = true, enable_deployer = true, diff --git a/filter-injector.lua b/filter-injector.lua index f8479f7..6f38e60 100644 --- a/filter-injector.lua +++ b/filter-injector.lua @@ -34,8 +34,8 @@ local function set_filter_formspec(data, meta) ("button_exit[6.3,%f;2,1;close;" .. S("Close") .. "]"):format(form_height - 1.7) if pipeworks.enable_item_tags then formspec = formspec .. - ("field[0.5,%f;4.6,1;items_tag;"):format(form_height - 1.4) .. S("Items tag") .. ";${items_tag}]" .. - ("button[4.8,%f;1.5,1;set_items_tag;"):format(form_height - 1.7) .. S("Set") .. "]" + ("field[0.5,%f;4.6,1;item_tags;"):format(form_height - 1.4) .. S("Item Tags") .. ";${item_tags}]" .. + ("button[4.8,%f;1.5,1;set_item_tags;"):format(form_height - 1.7) .. S("Set") .. "]" end else local exmatch_button = "" @@ -73,8 +73,8 @@ local function set_filter_formspec(data, meta) "listring[]" if pipeworks.enable_item_tags then formspec = formspec .. - "field[5.8,0.5;3,0.8;items_tag;" .. S("Items tag") .. ";${items_tag}]" .. - "button[9,0.3;1,1.1;set_items_tag;" .. S("Set") .. "]" + "field[5.8,0.5;3,0.8;item_tags;" .. S("Item Tags") .. ";${item_tags}]" .. + "button[9,0.3;1,1.1;set_item_tags;" .. S("Set") .. "]" end end meta:set_string("formspec", formspec) @@ -137,7 +137,7 @@ local function punch_filter(data, filtpos, filtnode, msg) local slotseq_mode local exmatch_mode - local item_tag = filtmeta:get_string("items_tag") + local item_tags = pipeworks.sanitize_tags(filtmeta:get_string("item_tags")) local filters = {} if data.digiline then local function add_filter(name, group, count, wear, metadata) @@ -201,9 +201,12 @@ local function punch_filter(data, filtpos, filtnode, msg) set_filter_formspec(data, filtmeta) end - if msg.tag then - item_tag = msg.tag + if type(msg.tags) == "table" then + item_tags = pipeworks.sanitize_tags(msg.tags) + elseif type(msg.tag) == "string" then + item_tags = pipeworks.sanitize_tags({msg.tag}) end + if msg.nofire then return end @@ -356,11 +359,8 @@ local function punch_filter(data, filtpos, filtnode, msg) end local pos = vector.add(frompos, vector.multiply(dir, 1.4)) local start_pos = vector.add(frompos, dir) - if pipeworks.enable_item_tags then - pipeworks.set_item_tag(item, item_tag) - end pipeworks.tube_inject_item(pos, start_pos, dir, item, - fakePlayer:get_player_name()) + fakePlayer:get_player_name(), item_tags) return true -- only fire one item, please end end @@ -478,8 +478,9 @@ for _, data in ipairs({ end local meta = minetest.get_meta(pos) - if pipeworks.enable_item_tags and fields.items_tag and (fields.key_enter_field == "items_tag" or fields.set_items_tag) then - meta:set_string("items_tag", fields.items_tag) + if pipeworks.enable_item_tags and fields.item_tags and (fields.key_enter_field == "item_tags" or fields.set_item_tags) then + local tags = pipeworks.sanitize_tags(fields.item_tags) + meta:set_string("item_tags", table.concat(tags, ",")) end --meta:set_int("slotseq_index", 1) set_filter_formspec(data, meta) @@ -502,8 +503,9 @@ for _, data in ipairs({ fs_helpers.on_receive_fields(pos, fields) local meta = minetest.get_meta(pos) meta:set_int("slotseq_index", 1) - if pipeworks.enable_item_tags and fields.items_tag and (fields.key_enter_field == "items_tag" or fields.set_items_tag) then - meta:set_string("items_tag", fields.items_tag) + if pipeworks.enable_item_tags and fields.item_tags and (fields.key_enter_field == "item_tags" or fields.set_item_tags) then + local tags = pipeworks.sanitize_tags(fields.item_tags) + meta:set_string("item_tags", table.concat(tags, ",")) end set_filter_formspec(data, meta) set_filter_infotext(data, meta) diff --git a/item_transport.lua b/item_transport.lua index c3713a1..7577741 100644 --- a/item_transport.lua +++ b/item_transport.lua @@ -4,31 +4,35 @@ local max_tube_limit = tonumber(minetest.settings:get("pipeworks_max_items_per_t if enable_max_limit == nil then enable_max_limit = true end if pipeworks.enable_item_tags then - local item_tag_name = "pipeworks:item_tag" - local item_tag_name_limit = tonumber(minetest.settings:get("pipeworks_item_tag_name_limit") or "30") + local max_tag_length = tonumber(minetest.settings:get("pipeworks_max_item_tag_length")) or 32 + local max_tags = tonumber(minetest.settings:get("pipeworks_max_item_tags")) or 16 - pipeworks.safe_tag = function(tag) - if tag == nil or type(tag) ~= "string" or tag == "" then return nil end - tag = tag:gsub(",", "_") -- replace commas with underscores - tag = tag:trim() -- trim leading and trailing spaces - return tag:sub(1, item_tag_name_limit) - end - - pipeworks.set_item_tag = function(item_stack, tag) - if item_stack == nil then return end - item_stack:get_meta():set_string(item_tag_name, pipeworks.safe_tag(tag)) - end - - pipeworks.get_item_tag = function(item_stack) - if item_stack == nil then return nil end - return item_stack:get_meta():get_string(item_tag_name) + function pipeworks.sanitize_tags(tags) + if type(tags) == "string" then + tags = tags:split(",") + end + local sanitized = {} + for i, tag in ipairs(tags) do + if type(tag) == "string" then + tag = tag:gsub("[%s,]", "") -- Remove whitespace and commas + tag = tag:gsub("%$%b%{%}", "") -- Remove special ${key} values + if tag ~= "" then + table.insert(sanitized, tag:sub(1, max_tag_length)) + end + end + if #sanitized >= max_tags then + break + end + end + return sanitized end end + function pipeworks.tube_item(pos, item) error("obsolete pipeworks.tube_item() called; change caller to use pipeworks.tube_inject_item() instead") end -function pipeworks.tube_inject_item(pos, start_pos, velocity, item, owner) +function pipeworks.tube_inject_item(pos, start_pos, velocity, item, owner, tags) -- Take item in any format local stack = ItemStack(item) local obj = luaentity.add_entity(pos, "pipeworks:tubed_item") @@ -36,6 +40,7 @@ function pipeworks.tube_inject_item(pos, start_pos, velocity, item, owner) obj.start_pos = vector.new(start_pos) obj:set_velocity(velocity) obj.owner = owner + obj.tags = tags --obj:set_color("red") -- todo: this is test-only code return obj end @@ -100,13 +105,14 @@ end -- compatibility behaviour for the existing can_go() callbacks, -- which can only specify a list of possible positions. -local function go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner) +local function go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner, tags) local next_positions = {} local max_priority = 0 local can_go - if minetest.registered_nodes[cnode.name] and minetest.registered_nodes[cnode.name].tube and minetest.registered_nodes[cnode.name].tube.can_go then - can_go = minetest.registered_nodes[cnode.name].tube.can_go(pos, cnode, vel, stack) + local def = minetest.registered_nodes[cnode.name] + if def and def.tube and def.tube.can_go then + can_go = def.tube.can_go(pos, cnode, vel, stack, tags) else local adjlist_string = minetest.get_meta(pos):get_string("adjlist") local adjlist = minetest.deserialize(adjlist_string) or default_adjlist -- backward compat: if not found, use old behavior: all directions @@ -165,7 +171,7 @@ end -- * a "multi-mode" data table (or nil if N/A) where a stack was split apart. -- if this is not nil, the luaentity spawns new tubed items for each new fragment stack, -- then deletes itself (i.e. the original item stack). -local function go_next(pos, velocity, stack, owner) +local function go_next(pos, velocity, stack, owner, tags) local cnode = minetest.get_node(pos) local cmeta = minetest.get_meta(pos) local speed = math.abs(velocity.x + velocity.y + velocity.z) @@ -193,7 +199,7 @@ local function go_next(pos, velocity, stack, owner) -- n is the new value of the cycle counter. -- XXX: this probably needs cleaning up after being split out, -- seven args is a bit too many - local n, found, new_velocity, multimode = go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner) + local n, found, new_velocity, multimode = go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner, tags) -- if not using output cycling, -- don't update the field so it stays the same for the next item. @@ -297,6 +303,7 @@ luaentity.register_entity("pipeworks:tubed_item", { color_entity = nil, color = nil, start_pos = nil, + tags = nil, set_item = function(self, item) local itemstring = ItemStack(item):to_string() -- Accept any input format @@ -358,13 +365,9 @@ luaentity.register_entity("pipeworks:tubed_item", { local node = minetest.get_node(self.start_pos) if minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then local leftover - if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then - local item_tag = nil - if pipeworks.enable_item_tags then - item_tag = pipeworks.get_item_tag(stack) - pipeworks.set_item_tag(stack, nil) - end - leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel, self.owner, item_tag) + local def = minetest.registered_nodes[node.name] + if def.tube and def.tube.insert_object then + leftover = def.tube.insert_object(self.start_pos, node, stack, vel, self.owner) else leftover = stack end @@ -379,8 +382,14 @@ luaentity.register_entity("pipeworks:tubed_item", { return end - local found_next, new_velocity, multimode = go_next(self.start_pos, velocity, stack, self.owner) -- todo: color - self.itemstring = stack:to_string() + local tags + if pipeworks.enable_item_tags then + tags = self.tags or {} + end + local found_next, new_velocity, multimode = go_next(self.start_pos, velocity, stack, self.owner, tags) -- todo: color + if pipeworks.enable_item_tags then + self.tags = #tags > 0 and pipeworks.sanitize_tags(tags) or nil + end local rev_vel = vector.multiply(velocity, -1) local rev_dir = vector.direction(self.start_pos,vector.add(self.start_pos,rev_vel)) local rev_node = minetest.get_node(vector.round(vector.add(self.start_pos,rev_dir))) @@ -391,9 +400,6 @@ luaentity.register_entity("pipeworks:tubed_item", { -- Using add_item instead of item_drop since this makes pipeworks backward -- compatible with Minetest 0.4.13. -- Using item_drop here makes Minetest 0.4.13 crash. - if pipeworks.enable_item_tags then - pipeworks.set_item_tag(stack, nil) - end local dropped_item = minetest.add_item(self.start_pos, stack) if dropped_item then dropped_item:set_velocity(vector.multiply(velocity, 5)) diff --git a/materials.lua b/materials.lua index ca9adf5..28691dd 100644 --- a/materials.lua +++ b/materials.lua @@ -10,7 +10,8 @@ local materials = { mese_crystal = "default:mese_crystal", mese_crystal_fragment = "default:mese_crystal_fragment", teleporter = "default:mese", - glass = "default:glass" + glass = "default:glass", + book = "default:book", } if minetest.get_modpath("mcl_core") then @@ -27,6 +28,7 @@ if minetest.get_modpath("mcl_core") then teleporter = "mesecons_torch:redstoneblock", copper_ingot = "mcl_copper:copper_ingot", glass = "mcl_core:glass", + book = "mcl_core:book", } elseif minetest.get_modpath("fl_ores") and minetest.get_modpath("fl_stone") then materials = { @@ -58,6 +60,7 @@ elseif minetest.get_modpath("hades_core") then copper_ingot = "hades_core:copper_ingot", tin_ingot = "hades_core:tin_ingot", glass = "hades_core:glass", + book = "hades_core:book", } if minetest.get_modpath("hades_default") then materials.desert_sand = "hades_default:desert_sand" diff --git a/tubes/lua.lua b/tubes/lua.lua index abb1060..50782bf 100644 --- a/tubes/lua.lua +++ b/tubes/lua.lua @@ -809,45 +809,6 @@ local function go_back(velocity) return pipeworks.notvel(adjlist, vel) end -local function get_item_table(stack) - local item = stack:to_table() - if pipeworks.enable_item_tags then - item.tag = pipeworks.get_item_tag(stack) - end - return item -end - -local function parse_returned_msg_v1(msg, _, velocity) - if type(msg) ~= "string" then - return false - end - local r = rules[msg] - return true, r and { r } or go_back(velocity) -end - -local function parse_returned_msg_v2(msg, stack, velocity) - if type(msg) ~= "table" or type(msg.side) ~= "string" then - return false - end - local r = rules[msg.side] - if pipeworks.enable_item_tags and r and type(msg.tag) == "string" then - pipeworks.set_item_tag(stack, msg.tag) - end - return true, r and { r } or go_back(velocity) -end - -local function parse_returned_msg(msg, stack, velocity) - local parsers = { - parse_returned_msg_v2, - parse_returned_msg_v1, - } - for _, parser in ipairs(parsers) do - local is_processed, result = parser(msg, stack, velocity) - if is_processed then return result end - end - return go_back(velocity) -end - local tiles_base = { "pipeworks_mese_tube_plain_4.png", "pipeworks_mese_tube_plain_3.png", "pipeworks_mese_tube_plain_2.png", "pipeworks_mese_tube_plain_1.png", @@ -984,7 +945,7 @@ for white = 0, 1 do tube = { connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}, priority = 50, - can_go = function(pos, node, velocity, stack) + can_go = function(pos, node, velocity, stack, tags) local src = {name = nil} -- add color of the incoming tube explicitly; referring to rules, in case they change later for _, rule in pairs(rules) do @@ -997,13 +958,35 @@ for white = 0, 1 do type = "item", pin = src, itemstring = stack:to_string(), - item = get_item_table(stack), + item = stack:to_table(), velocity = velocity, + tags = table.copy(tags), + side = src.name, }) if not succ then return go_back(velocity) end - return parse_returned_msg(msg, stack, velocity) + if type(msg) == "string" then + local side = rules[msg] + return side and {side} or go_back(velocity) + elseif type(msg) == "table" then + if pipeworks.enable_item_tags then + local new_tags + if type(msg.tags) == "table" then + new_tags = msg.tags + elseif type(msg.tag) == "string" then + new_tags = {msg.tag} + end + if new_tags then + for i=1, math.max(#tags, #new_tags) do + tags[i] = new_tags[i] + end + end + end + local side = rules[msg.side] + return side and {side} or go_back(velocity) + end + return go_back(velocity) end, }, after_place_node = pipeworks.after_place, diff --git a/tubes/tags.lua b/tubes/tags.lua index 3f91be6..ffd7ec7 100644 --- a/tubes/tags.lua +++ b/tubes/tags.lua @@ -1,61 +1,51 @@ local S = minetest.get_translator("pipeworks") local fs_helpers = pipeworks.fs_helpers -if not pipeworks.enable_tags_tube then return end +if not pipeworks.enable_item_tags or not pipeworks.enable_tag_tube then return end -local notag_name = "<>" -local tube_name = "pipeworks:tags_tube" -local tube_description = S("Tags Sorting Pneumatic Tube Segment") - -local safe_tags = function(tags) - local length_limit = tonumber(minetest.settings:get("pipeworks_item_tag_name_limit") or "30") - return tags:sub(1, length_limit * 6) -end - -local function escape(s) - return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]', '%%%1')) -end +local help_text = minetest.formspec_escape( + S("Separate multiple tags using commas.").."\n".. + S("Use \"\" to match items without tags.") +) local update_formspec = function(pos) local meta = minetest.get_meta(pos) local buttons_formspec = "" for i = 0, 5 do buttons_formspec = buttons_formspec .. fs_helpers.cycling_button(meta, - "image_button[9," .. (i + (i * 0.25) + 1.5) .. ";1,0.6", "l" .. (i + 1) .. "s", + "image_button[9," .. (i + (i * 0.25) + 0.5) .. ";1,0.6", "l" .. (i + 1) .. "s", { pipeworks.button_off, pipeworks.button_on } ) end - local size = "10.2,10" + local size = "10.2,9" meta:set_string("formspec", "formspec_version[2]" .. "size[" .. size .. "]" .. - "item_image[0.2,0.2;1,1; " .. tube_name .. "]" .. - "label[1.5,0.75;" .. minetest.formspec_escape(tube_description) .. "]" .. pipeworks.fs_helpers.get_prepends(size) .. - "field[1.5,1.25;7.25,1;tags1;;${tags1}]" .. - "field[1.5,2.5;7.25,1;tags2;;${tags2}]" .. - "field[1.5,3.75;7.25,1;tags3;;${tags3}]" .. - "field[1.5,5.0;7.25,1;tags4;;${tags4}]" .. - "field[1.5,6.25;7.25,1;tags5;;${tags5}]" .. - "field[1.5,7.5;7.25,1;tags6;;${tags6}]" .. + "field[1.5,0.25;7.25,1;tags1;;${tags1}]" .. + "field[1.5,1.5;7.25,1;tags2;;${tags2}]" .. + "field[1.5,2.75;7.25,1;tags3;;${tags3}]" .. + "field[1.5,4.0;7.25,1;tags4;;${tags4}]" .. + "field[1.5,5.25;7.25,1;tags5;;${tags5}]" .. + "field[1.5,6.5;7.25,1;tags6;;${tags6}]" .. - "image[0.22,1.25;1,1;pipeworks_white.png]" .. - "image[0.22,2.50;1,1;pipeworks_black.png]" .. - "image[0.22,3.75;1,1;pipeworks_green.png]" .. - "image[0.22,5.00;1,1;pipeworks_yellow.png]" .. - "image[0.22,6.25;1,1;pipeworks_blue.png]" .. - "image[0.22,7.50;1,1;pipeworks_red.png]" .. + "image[0.22,0.25;1,1;pipeworks_white.png]" .. + "image[0.22,1.50;1,1;pipeworks_black.png]" .. + "image[0.22,2.75;1,1;pipeworks_green.png]" .. + "image[0.22,4.00;1,1;pipeworks_yellow.png]" .. + "image[0.22,5.25;1,1;pipeworks_blue.png]" .. + "image[0.22,6.50;1,1;pipeworks_red.png]" .. buttons_formspec .. - "button[6,8.75;1.5,1;set_items_tags;" .. S("Set") .. "]" .. - "button_exit[7.75,8.75;2,1;close;" .. S("Close") .. "]" + "label[0.22,7.9;"..help_text.."]".. + "button[7.25,7.8;1.5,0.8;set_item_tags;" .. S("Set") .. "]" ) end -pipeworks.register_tube(tube_name, { - description = tube_description, +pipeworks.register_tube("pipeworks:tag_tube", { + description = S("Tag Sorting Pneumatic Tube Segment"), inventory_image = "pipeworks_tag_tube_inv.png", noctr = { "pipeworks_tag_tube_noctr_1.png", "pipeworks_tag_tube_noctr_2.png", "pipeworks_tag_tube_noctr_3.png", "pipeworks_tag_tube_noctr_4.png", "pipeworks_tag_tube_noctr_5.png", "pipeworks_tag_tube_noctr_6.png" }, @@ -66,15 +56,18 @@ pipeworks.register_tube(tube_name, { no_facedir = true, -- Must use old tubes, since the textures are rotated with 6d ones node_def = { tube = { - can_go = function(pos, node, velocity, stack) + can_go = function(pos, node, velocity, stack, tags) local tbl, tbln = {}, 0 local found, foundn = {}, 0 local meta = minetest.get_meta(pos) - local stack_tag = pipeworks.get_item_tag(stack) - if not stack_tag or stack_tag == "" then - stack_tag = notag_name + local tag_hash = {} + if #tags > 0 then + for _,tag in ipairs(tags) do + tag_hash[tag] = true + end + else + tag_hash[""] = true -- Matches items without tags end - stack_tag = pipeworks.safe_tag(stack_tag) for i, vect in ipairs(pipeworks.meseadjlist) do local npos = vector.add(pos, vect) local node = minetest.get_node(npos) @@ -83,19 +76,17 @@ pipeworks.register_tube(tube_name, { local tube_def = reg_node.tube if not tube_def or not tube_def.can_insert or tube_def.can_insert(npos, node, stack, vect) then - local tags_name = "tags" .. i - local tags = meta:get_string(tags_name) - local is_empty = tags == nil or tags == "" - if not is_empty then - for tag in string.gmatch(tags, "[^,]+") do - tag = pipeworks.safe_tag(tag) - if tag and (tag == stack_tag or stack_tag:find(("^%s%%."):format(escape(tag)))) then + local side_tags = meta:get_string("tags" .. i) + if side_tags ~= "" then + side_tags = pipeworks.sanitize_tags(side_tags) + for _,tag in ipairs(side_tags) do + if tag_hash[tag] then foundn = foundn + 1 found[foundn] = vect + break end end - end - if is_empty then + else tbln = tbln + 1 tbl[tbln] = vect end @@ -107,13 +98,11 @@ pipeworks.register_tube(tube_name, { }, on_construct = function(pos) local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() for i = 1, 6 do meta:set_int("l" .. tostring(i) .. "s", 1) - inv:set_size("line" .. tostring(i), 6 * 1) end update_formspec(pos) - meta:set_string("infotext", S("Tags Sorting pneumatic tube")) + meta:set_string("infotext", S("Tag sorting pneumatic tube")) end, after_place_node = function(pos, placer, itemstack, pointed_thing) if placer and placer:is_player() and placer:get_player_control().aux1 then @@ -135,8 +124,8 @@ pipeworks.register_tube(tube_name, { for i = 1, 6 do local field_name = "tags" .. tostring(i) if fields[field_name] then - local safe_tags = safe_tags(fields[field_name]) - meta:set_string(field_name, safe_tags) + local tags = pipeworks.sanitize_tags(fields[field_name]) + meta:set_string(field_name, table.concat(tags, ",")) end end