diff --git a/.luacheckrc b/.luacheckrc index 86d542a..26f18ef 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -12,5 +12,6 @@ read_globals = { -- mods "default", "mesecon", "digiline", "screwdriver", "unified_inventory", - "i3", "mcl_experience", "awards" + "i3", "mcl_experience", "awards", + "xcompat", "fakelib" } diff --git a/autocrafter.lua b/autocrafter.lua index 37c109c..014c4a5 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -4,6 +4,7 @@ local S = minetest.get_translator("pipeworks") local autocrafterCache = {} local craft_time = 1 +local next = next local function count_index(invlist) local index = {} @@ -48,7 +49,9 @@ local function get_matching_craft(output_name, example_recipe) elseif recipe_item_name:sub(1, 6) == "group:" then group = recipe_item_name:sub(7) for example_item_name, _ in pairs(index_example) do - if minetest.get_item_group(example_item_name, group) > 0 then + if minetest.get_item_group( + example_item_name, group) ~= 0 + then score = score + 1 break end @@ -89,22 +92,27 @@ local function get_craft(pos, inventory, hash) return craft end --- From a consumption table with groups and an inventory index, build --- a consumption table without groups +-- From a consumption table with groups and an inventory index, +-- build a consumption table without groups local function calculate_consumption(inv_index, consumption_with_groups) inv_index = table.copy(inv_index) consumption_with_groups = table.copy(consumption_with_groups) + -- table of items to actually consume local consumption = {} - local groups = {} + -- table of ingredients defined as one or more groups each + local grouped_ingredients = {} -- First consume all non-group requirements - -- This is done to avoid consuming a non-group item which is also - -- in a group + -- This is done to avoid consuming a non-group item which + -- is also in a group for key, count in pairs(consumption_with_groups) do if key:sub(1, 6) == "group:" then - groups[#groups + 1] = key:sub(7, #key) + -- build table with group recipe items while looping + grouped_ingredients[key] = key:sub(7):split(',') else + -- if the item to consume doesn't exist in inventory + -- or not enough of them, abort crafting if not inv_index[key] or inv_index[key] < count then return nil end @@ -118,28 +126,45 @@ local function calculate_consumption(inv_index, consumption_with_groups) end end + -- helper function to resolve matching ingredients with multiple group + -- requirements + local function ingredient_groups_match_item(ingredient_groups, name) + local found = 0 + local count_ingredient_groups = #ingredient_groups + for i = 1, count_ingredient_groups do + if minetest.get_item_group(name, + ingredient_groups[i]) ~= 0 + then + found = found + 1 + end + end + return found == count_ingredient_groups + end + -- Next, resolve groups using the remaining items in the inventory - local take - if #groups > 0 then + if next(grouped_ingredients) ~= nil then + local take for itemname, count in pairs(inv_index) do if count > 0 then - local def = minetest.registered_items[itemname] - local item_groups = def and def.groups or {} - for i = 1, #groups do - local group = groups[i] - local groupname = "group:" .. group - if item_groups[group] and item_groups[group] >= 1 - and consumption_with_groups[groupname] > 0 + -- groupname is the string as defined by recipe. + -- e.g. group:dye,color_blue + -- groups holds the group names split into a list + -- ready to be passed to core.get_item_group() + for groupname, groups in pairs(grouped_ingredients) do + if consumption_with_groups[groupname] > 0 + and ingredient_groups_match_item(groups, itemname) then - take = math.min(count, consumption_with_groups[groupname]) + take = math.min(count, + consumption_with_groups[groupname]) consumption_with_groups[groupname] = - consumption_with_groups[groupname] - take + consumption_with_groups[groupname] - take assert(consumption_with_groups[groupname] >= 0) consumption[itemname] = - (consumption[itemname] or 0) + take + (consumption[itemname] or 0) + take - inv_index[itemname] = inv_index[itemname] - take + inv_index[itemname] = + inv_index[itemname] - take assert(inv_index[itemname] >= 0) end end @@ -433,6 +458,7 @@ minetest.register_node("pipeworks:autocrafter", { drawtype = "normal", tiles = {"pipeworks_autocrafter.png"}, groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1, dig_generic = 1, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, tube = {insert_object = function(pos, node, stack, direction) local meta = minetest.get_meta(pos) diff --git a/autoplace_tubes.lua b/autoplace_tubes.lua index 8348430..9f4e112 100644 --- a/autoplace_tubes.lua +++ b/autoplace_tubes.lua @@ -11,7 +11,7 @@ local function nodeside(node, tubedir) end local backdir = minetest.facedir_to_dir(node.param2) - local back = pipeworks.vector_dot(backdir, tubedir) + local back = vector.dot(backdir, tubedir) if back == 1 then return "back" elseif back == -1 then @@ -19,7 +19,7 @@ local function nodeside(node, tubedir) end local topdir = pipeworks.facedir_to_top_dir(node.param2) - local top = pipeworks.vector_dot(topdir, tubedir) + local top = vector.dot(topdir, tubedir) if top == 1 then return "top" elseif top == -1 then @@ -27,7 +27,7 @@ local function nodeside(node, tubedir) end local rightdir = pipeworks.facedir_to_right_dir(node.param2) - local right = pipeworks.vector_dot(rightdir, tubedir) + local right = vector.dot(rightdir, tubedir) if right == 1 then return "right" else diff --git a/changelog.txt b/changelog.txt index 59ea40d..76a1755 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,11 @@ Changelog +2024-02-26 (SwissalpS) +set is_ground_content to false for various nodes. + + + 2023-06-22 (SwissalpS, rubenwardy) groups support in recipe. Set recipe as usual via recipe formspec or digilines. Autocrafter now resolves matching recipe using groups so that items in input diff --git a/chests.lua b/chests.lua new file mode 100644 index 0000000..ed7b061 --- /dev/null +++ b/chests.lua @@ -0,0 +1,90 @@ +pipeworks.chests = {} + +-- register a chest to connect with pipeworks tubes. +-- will autoconnect to tubes and add tube inlets to the textures +-- it is highly recommended to allow the user to change the "splitstacks" int (1 to enable) in the node meta +-- but that can't be done by this function + +-- @param override: additional overrides, such as stuff to modify the node formspec +-- @param connect_sides: which directions the chests shall connect to +function pipeworks.override_chest(chestname, override, connect_sides) + local old_def = minetest.registered_nodes[chestname] + + local tube_entry = "^pipeworks_tube_connection_wooden.png" + override.tiles = override.tiles or old_def.tiles + -- expand the tiles table if it has been shortened + if #override.tiles < 6 then + for i = #override.tiles, 6 do + override.tiles[i] = override.tiles[#override.tiles] + end + end + -- add inlets to the sides that connect to tubes + local tile_directions = {"top", "bottom", "right", "left", "back", "front"} + for i, direction in ipairs(tile_directions) do + if connect_sides[direction] then + if type(override.tiles[i]) == "string" then + override.tiles[i] = override.tiles[i] .. tube_entry + elseif type(override.tiles[i]) == "table" and not override.tiles[i].animation then + override.tiles[i].name = override.tiles[i].name .. tube_entry + end + end + end + + local old_after_place_node = override.after_place_node or old_def.after_place_node or function() end + override.after_place_node = function(pos, placer, itemstack, pointed_thing) + old_after_place_node(pos, placer, itemstack, pointed_thing) + pipeworks.after_place(pos) + end + + local old_after_dig = override.after_dig or old_def.after_dig or function() end + override.after_dig_node = function(pos, oldnode, oldmetadata, digger) + old_after_dig(pos, oldnode, oldmetadata, digger) + pipeworks.after_dig(pos, oldnode, oldmetadata, digger) + end + + local old_on_rotate + if override.on_rotate ~= nil then + old_on_rotate = override.on_rotate + elseif old_def.on_rotate ~= nil then + old_on_rotate = old_def.on_rotate + else + old_on_rotate = function() end + end + -- on_rotate = false -> rotation disabled, no need to update tubes + -- everything else: undefined by the most common screwdriver mods + if type(old_on_rotate) == "function" then + override.on_rotate = function(pos, node, user, mode, new_param2) + if old_on_rotate(pos, node, user, mode, new_param2) ~= false then + return pipeworks.on_rotate(pos, node, user, mode, new_param2) + else + return false + end + end + end + + override.tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("main", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if meta:get_int("splitstacks") == 1 then + stack = stack:peek_item(1) + end + return inv:room_for_item("main", stack) + end, + input_inventory = "main", + connect_sides = connect_sides + } + + -- Add the extra groups + override.groups = override.groups or old_def.groups or {} + override.groups.tubedevice = 1 + override.groups.tubedevice_receiver = 1 + + minetest.override_item(chestname, override) + pipeworks.chests[chestname] = true +end \ No newline at end of file diff --git a/common.lua b/common.lua index 5db3feb..dcf2c7f 100644 --- a/common.lua +++ b/common.lua @@ -91,22 +91,6 @@ function pipeworks.replace_name(tbl,tr,name) return ntbl end ----------------------- --- Vector functions -- ----------------------- - -function pipeworks.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 pipeworks.vector_dot(a, b) - return a.x * b.x + a.y * b.y + a.z * b.z -end - ----------------------- -- Facedir functions -- ----------------------- @@ -122,7 +106,7 @@ function pipeworks.facedir_to_top_dir(facedir) end function pipeworks.facedir_to_right_dir(facedir) - return pipeworks.vector_cross( + return vector.cross( pipeworks.facedir_to_top_dir(facedir), minetest.facedir_to_dir(facedir) ) @@ -142,29 +126,10 @@ function directions.side_to_dir(side) end function directions.dir_to_side(dir) - local c = pipeworks.vector_dot(dir, vector.new(1, 2, 3)) + 4 + local c = vector.dot(dir, vector.new(1, 2, 3)) + 4 return ({6, 2, 4, 0, 3, 1, 5})[c] end ----------------------- --- String functions -- ----------------------- - ---[[function pipeworks.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 pipeworks.string_startswith(str, substr) - return str:sub(1, substr:len()) == substr -end - --------------------- -- Table functions -- --------------------- @@ -208,7 +173,7 @@ pipeworks.fs_helpers = fs_helpers function fs_helpers.on_receive_fields(pos, fields) local meta = minetest.get_meta(pos) for field in pairs(fields) do - if pipeworks.string_startswith(field, "fs_helpers_cycling:") then + if field:match("^fs_helpers_cycling:") then local l = field:split(":") local new_value = tonumber(l[2]) local meta_name = l[3] @@ -325,278 +290,5 @@ function pipeworks.load_position(pos) vm:read_from_map(pos, pos) end -local function delay(...) - local args = {...} - return (function() return unpack(args) end) -end - -local function get_set_wrap(name, is_dynamic) - return (function(self) - return self["_" .. name] - end), (function(self, value) - if is_dynamic then - self["_" .. name] = type(value) == "table" - and table.copy(value) or value - end - end) -end - -local fake_player_metatable = { - is_player = delay(true), - is_fake_player = true, - - -- dummy implementation of the rest of the player API: - add_player_velocity = delay(), -- deprecated - add_velocity = delay(), - get_acceleration = delay(), -- no-op for players - get_animation = delay({x = 0, y = 0}, 0, 0, false), - get_armor_groups = delay({}), - get_attach = delay(), - get_attribute = delay(), -- deprecated - get_bone_position = delay(vector.zero(), vector.zero()), - get_children = delay({}), - get_clouds = delay({ - ambient = { r = 0, b = 0, g = 0, a = 0 }, - color = { r = 0, b = 0, g = 0, a = 0 }, - density = 0, - height = 120, - thickness = 10, - speed = vector.zero(), - }), - get_day_night_ratio = delay(), - get_entity_name = delay(), - get_formspec_prepend = delay(""), - get_fov = delay(0, false, 0), - get_lighting = delay({ - exposure = { - center_weight_power = 1, - exposure_correction = 0, - luminance_max = -3, - luminance_min = -3, - speed_bright_dark = 1000, - speed_dark_bright = 1000, - }, - saturation = 1, - shadows = { - intensity = .6212, - }, - }), - get_local_animation = delay({x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, 30), - get_luaentity = delay(), - get_meta = delay({ - contains = delay(false), - get = delay(), - set_string = delay(), - get_string = delay(""), - set_int = delay(), - get_int = delay(0), - set_float = delay(), - get_float = delay(0), - get_keys = delay({}), - to_table = delay({fields = {}}), - from_table = delay(false), - equals = delay(false), - }), - get_moon = delay({ - scale = 1, - texture = "", - tonemap = "", - visible = false, - }), - get_physics_override = delay({ - acceleration_air = 1, - acceleration_default = 1, - gravity = 1, - jump = 1, - liquid_fluidity = 1, - liquid_fluidity_smooth = 1, - liquid_sink = 1, - new_move = true, - sneak = true, - sneak_glitch = false, - speed = 1, - speed_climb = 1, - speed_crouch = 1, - }), - get_player_velocity = vector.zero, -- deprecated - get_rotation = delay(), -- no-op for players - get_sky = delay({ r = 0, g = 0, b = 0, a = 0 }, "regular", {}, true), - get_sky_color = delay({ - dawn_horizon = { r = 0, g = 0, b = 0, a = 0 }, - dawn_sky = { r = 0, g = 0, b = 0, a = 0 }, - day_horizon = { r = 0, g = 0, b = 0, a = 0 }, - day_sky = { r = 0, g = 0, b = 0, a = 0 }, - fog_moon_tint = { r = 0, g = 0, b = 0, a = 0 }, - fog_sun_tint = { r = 0, g = 0, b = 0, a = 0 }, - fog_tint_type = "default", - indoors = { r = 0, g = 0, b = 0, a = 0 }, - night_horizon = { r = 0, g = 0, b = 0, a = 0 }, - night_sky = { r = 0, g = 0, b = 0, a = 0 }, - }), - get_stars = delay({ - count = 1000, - day_opacity = 0, - scale = 1, - star_color = { r = 0, g = 0, b = 0, a = 0 }, - visible = true, - }), - get_sun = delay({ - scale = 1, - sunrise = "", - sunrise_visible = true, - texture = "", - tonemap = "", - visible = true, - }), - get_texture_mod = delay(), -- no-op for players - get_velocity = vector.zero, - get_yaw = delay(), -- no-op for players - getacceleration = delay(), -- backward compatibility - getvelocity = vector.zero, -- backward compatibility - getyaw = delay(), -- backward compatibility - hud_add = delay(), - hud_change = delay(), - hud_get = delay(), - hud_get_flags = delay({ - basic_debug = false, - breathbar = false, - chat = false, - crosshair = false, - healthbar = false, - hotbar = false, - minimap = false, - minimap_radar = false, - wielditem = false, - }), - hud_get_hotbar_image = delay(""), - hud_get_hotbar_itemcount = delay(1), - hud_get_hotbar_selected_image = delay(""), - hud_remove = delay(), - hud_set_flags = delay(), - hud_set_hotbar_image = delay(), - hud_set_hotbar_itemcount = delay(), - hud_set_hotbar_selected_image = delay(), - override_day_night_ratio = delay(), - punch = delay(), - remove = delay(), - respawn = delay(), - right_click = delay(), - send_mapblock = delay(), - set_acceleration = delay(), - set_animation = delay(), - set_animation_frame_speed = delay(), - set_armor_groups = delay(), - set_attach = delay(), - set_attribute = delay(), -- deprecated - set_bone_position = delay(), - set_clouds = delay(), - set_detach = delay(), - set_formspec_prepend = delay(), - set_fov = delay(), - set_lighting = delay(), - set_local_animation = delay(), - set_look_horizontal = delay(), - set_look_pitch = delay(), - set_look_vertical = delay(), - set_look_yaw = delay(), - set_minimap_modes = delay(), - set_moon = delay(), - set_nametag_attributes = delay(), - set_physics_override = delay(), - set_rotation = delay(), -- no-op for players - set_sky = delay(), - set_sprite = delay(), -- no-op for players - set_stars = delay(), - set_sun = delay(), - set_texture_mod = delay(), -- no-op for players - set_velocity = delay(), -- no-op for players - set_yaw = delay(), -- no-op for players - setacceleration = delay(), -- backward compatibility - setsprite = delay(), -- backward compatibility - settexturemod = delay(), -- backward compatibility - setvelocity = delay(), -- backward compatibility - setyaw = delay(), -- backward compatibility -} - -function pipeworks.create_fake_player(def, is_dynamic) - local wielded_item = ItemStack("") - if def.inventory and def.wield_list then - wielded_item = def.inventory:get_stack(def.wield_list, def.wield_index or 1) - end - local p = { - get_player_name = delay(def.name), - - _formspec = def.formspec or "", - _hp = def.hp or 20, - _breath = 11, - _pos = def.position and table.copy(def.position) or vector.new(), - _properties = def.properties or { eye_height = def.eye_height or 1.47 }, - _inventory = def.inventory, - _wield_index = def.wield_index or 1, - _wielded_item = wielded_item, - - -- Model and view - _eye_offset1 = vector.new(), - _eye_offset3 = vector.new(), - set_eye_offset = function(self, first, third) - self._eye_offset1 = table.copy(first) - self._eye_offset3 = table.copy(third) - end, - get_eye_offset = function(self) - return self._eye_offset1, self._eye_offset3 - end, - get_look_dir = delay(def.look_dir or vector.new()), - get_look_pitch = delay(def.look_pitch or 0), - get_look_yaw = delay(def.look_yaw or 0), - get_look_horizontal = delay(def.look_yaw or 0), - get_look_vertical = delay(-(def.look_pitch or 0)), - - -- Controls - get_player_control = delay({ - jump=false, right=false, left=false, LMB=false, RMB=false, - sneak=def.sneak, aux1=false, down=false, up=false - }), - get_player_control_bits = delay(def.sneak and 64 or 0), - - -- Inventory and ItemStacks - get_inventory = delay(def.inventory), - set_wielded_item = function(self, item) - if self._inventory and def.wield_list then - return self._inventory:set_stack(def.wield_list, - self._wield_index, item) - end - self._wielded_item = ItemStack(item) - end, - get_wielded_item = function(self, item) - if self._inventory and def.wield_list then - return self._inventory:get_stack(def.wield_list, - self._wield_index) - end - return ItemStack(self._wielded_item) - end, - get_wield_list = delay(def.wield_list), - get_nametag_attributes = delay({ - bgcolor = false, - color = { r = 0, g = 0, b = 0, a = 0 }, - text = def.name, - }), - } - -- Getter & setter functions - p.get_inventory_formspec, p.set_inventory_formspec - = get_set_wrap("formspec", is_dynamic) - p.get_breath, p.set_breath = get_set_wrap("breath", is_dynamic) - p.get_hp, p.set_hp = get_set_wrap("hp", is_dynamic) - p.get_pos, p.set_pos = get_set_wrap("pos", is_dynamic) - p.get_wield_index, p.set_wield_index = get_set_wrap("wield_index", true) - p.get_properties, p.set_properties = get_set_wrap("properties", false) - - -- For players, move_to and get_pos do the same - p.move_to = p.get_pos - - -- Backwards compatibility - p.getpos = p.get_pos - p.setpos = p.set_pos - p.moveto = p.move_to - setmetatable(p, { __index = fake_player_metatable }) - return p -end +-- Kept for compatibility with old mods +pipeworks.create_fake_player = fakelib.create_player diff --git a/compat-chests.lua b/compat-chests.lua index 0448660..5465bfb 100644 --- a/compat-chests.lua +++ b/compat-chests.lua @@ -1,303 +1,184 @@ --- this bit of code modifies the default chests and furnaces to be compatible --- with pipeworks. --- --- the formspecs found here are basically copies of the ones from minetest_game --- plus bits from pipeworks' sorting tubes +-- this bit of code overrides the default chests from common games (mtg, hades, minclone*) to be +-- compatible with pipeworks. Where possible, it overrides their formspec to add a splitstacks switch --- Pipeworks Specific local fs_helpers = pipeworks.fs_helpers -local tube_entry = "^pipeworks_tube_connection_wooden.png" --- Chest Locals -local open_chests = {} +-- formspec helper to add the splitstacks switch +local function add_pipeworks_switch(formspec, pos) + -- based on the sorting tubes + formspec = formspec .. + fs_helpers.cycling_button( + minetest.get_meta(pos), + pipeworks.button_base, + "splitstacks", + { + pipeworks.button_off, + pipeworks.button_on + } + )..pipeworks.button_label + return formspec +end + +-- helper to add the splitstacks switch to a node-formspec +local function update_node_formspec(pos) + local meta = minetest.get_meta(pos) + local old_fs = meta:get_string("formspec") + local new_fs = add_pipeworks_switch(old_fs, pos) + meta:set_string("formspec", new_fs) +end -local get_chest_formspec if minetest.get_modpath("default") then - function get_chest_formspec(pos) - local spos = pos.x .. "," .. pos.y .. "," .. pos.z - local formspec = - "size[8,9]" .. - default.gui_bg .. - default.gui_bg_img .. - default.gui_slots .. - "list[nodemeta:" .. spos .. ";main;0,0.3;8,4;]" .. - "list[current_player;main;0,4.85;8,1;]" .. - "list[current_player;main;0,6.08;8,3;8]" .. - "listring[nodemeta:" .. spos .. ";main]" .. - "listring[current_player;main]" .. - default.get_hotbar_bg(0,4.85) - - -- Pipeworks Switch - formspec = formspec .. - fs_helpers.cycling_button( - minetest.get_meta(pos), - pipeworks.button_base, - "splitstacks", - { - pipeworks.button_off, - pipeworks.button_on - } - )..pipeworks.button_label - - return formspec - end -else - local function get_hotbar_bg(x,y) - local out = "" - for i=0,7,1 do - out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]" + -- add the pipeworks switch into the default chest formspec + local old_get_chest_formspec = default.chest.get_chest_formspec + -- luacheck: ignore 122 + default.chest.get_chest_formspec = function(pos) + local old_fs = old_get_chest_formspec(pos) + local node = minetest.get_node(pos) + -- not all chests using this formspec necessary connect to pipeworks + if pipeworks.chests[node.name] then + local new_fs = add_pipeworks_switch(old_fs, pos) + return new_fs + else + return old_fs end - return out end - function get_chest_formspec(pos) - local spos = pos.x .. "," .. pos.y .. "," .. pos.z - local formspec = - "size[10,9]" .. - "background9[8,8;8,9;hades_chests_chestui.png;true;8]".. - "list[nodemeta:" .. spos .. ";main;0,0.3;10,4;]" .. - "list[current_player;main;0,4.85;10,1;]" .. - "list[current_player;main;0,6.08;10,3;10]" .. - "listring[nodemeta:" .. spos .. ";main]" .. - "listring[current_player;main]" .. - get_hotbar_bg(0,4.85) - - -- Pipeworks Switch - formspec = formspec .. - fs_helpers.cycling_button( - minetest.get_meta(pos), - pipeworks.button_base, - "splitstacks", - { - pipeworks.button_off, - pipeworks.button_on - } - )..pipeworks.button_label - - return formspec - end -end - -local function chest_lid_obstructed(pos) - local above = { x = pos.x, y = pos.y + 1, z = pos.z } - local def = minetest.registered_nodes[minetest.get_node(above).name] - -- allow ladders, signs, wallmounted things and torches to not obstruct - if not def then return true end - if def.drawtype == "airlike" or - def.drawtype == "signlike" or - def.drawtype == "torchlike" or - (def.drawtype == "nodebox" and def.paramtype2 == "wallmounted") then - return false - end - return true -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - if formname == "pipeworks:chest_formspec" and player then + -- get the fields from the chest formspec, we can do this bc. newest functions are called first + -- https://github.com/minetest/minetest/blob/d4b10db998ebeb689b3d27368e30952a42169d03/doc/lua_api.md?plain=1#L5840 + minetest.register_on_player_receive_fields(function(player, formname, fields) + if fields.quit or formname ~= "default:chest" then + return + end local pn = player:get_player_name() - if open_chests[pn] then - local pos = open_chests[pn].pos - if fields.quit then - local sound = open_chests[pn].sound - local swap = open_chests[pn].swap - local node = minetest.get_node(pos) + local chest_open = default.chest.open_chests[pn] + if not chest_open or not chest_open.pos then + -- chest already closed before formspec + return + end + local pos = chest_open.pos + local node = minetest.get_node(pos) + if pipeworks.chests[node.name] and pipeworks.may_configure(pos, player) then + -- Pipeworks Switch + fs_helpers.on_receive_fields(pos, fields) + minetest.show_formspec(pn, + "default:chest", + default.chest.get_chest_formspec(pos)) + end + -- Do NOT return true here, the callback from default still needs to run + return false + end) - open_chests[pn] = nil - for _, v in pairs(open_chests) do - if v.pos.x == pos.x and v.pos.y == pos.y and v.pos.z == pos.z then - return true - end + local connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1} + local connect_sides_open = {left = 1, right = 1, back = 1, bottom = 1} + + pipeworks.override_chest("default:chest", {}, connect_sides) + pipeworks.override_chest("default:chest_open", {}, connect_sides_open) + pipeworks.override_chest("default:chest_locked", {}, connect_sides) + pipeworks.override_chest("default:chest_locked_open", {}, connect_sides_open) +elseif minetest.get_modpath("hades_chests") then + local chest_colors = {"", "white", "grey", "dark_grey", "black", "blue", "cyan", "dark_green", "green", "magenta", + "orange", "pink", "red", "violet", "yellow"} + for _, color in ipairs(chest_colors) do + local chestname = (color == "" and "hades_chests:chest") + or "hades_chests:chest_" .. color + local chestname_protected = (color == "" and "hades_chests:chest_locked") + or "hades_chests:chest_" .. color .. "_locked" + local old_def = minetest.registered_nodes[chestname] + + -- chest formspec-creation functions are local, we need to find other ways + -- normal chests use node formspecs, we can hack into these + local old_on_construct = old_def.on_construct + local override = { + on_construct = function(pos) + old_on_construct(pos) + update_node_formspec(pos) + end, + on_receive_fields = function(pos, formname, fields, player) + if not fields.quit and pipeworks.may_configure(pos, player) then + -- Pipeworks Switch + fs_helpers.on_receive_fields(pos, fields) + update_node_formspec(pos) end - minetest.after(0.2, function() - if minetest.get_modpath("default") then - minetest.swap_node(pos, { name = "default:" .. swap, param2 = node.param2 }) - end + end, + -- chest's on_rotate is "simple", but we assumed the api from the mtg screwdriver mod + -- this will keep the same behavior, but supports the code above + on_rotate = screwdriver.rotate_simple + } - -- Pipeworks notification - pipeworks.after_place(pos) - end) - minetest.sound_play(sound, {gain = 0.3, pos = pos, max_hear_distance = 10}) - elseif pipeworks.may_configure(pos, player) then - -- Pipeworks Switch - fs_helpers.on_receive_fields(pos, fields) - minetest.show_formspec(player:get_player_name(), "pipeworks:chest_formspec", get_chest_formspec(pos)) + -- locked chests uses local functions to create their formspec - we need to copy these + -- https://codeberg.org/Wuzzy/Hades_Revisited/src/branch/master/mods/hades_chests/init.lua + local function get_locked_chest_formspec(pos) + local spos = pos.x .. "," .. pos.y .. "," ..pos.z + local formspec = + "size[10,9]".. + "list[nodemeta:".. spos .. ";main;0,0;10,4;]".. + "list[current_player;main;0,5;10,4;]".. + "listring[]".. + "background9[8,8;10,9;hades_chests_chestui.png;true;8]" + + -- change from pipeworks + local new_fs = add_pipeworks_switch(formspec, pos) + return new_fs + end + + local function has_locked_chest_privilege(meta, player) + local name = player:get_player_name() + if name ~= meta:get_string("owner") and not minetest.check_player_privs(name, "protection_bypass") then + return false end return true end + + -- store, which chest a formspec submission belongs to + -- {player1 = pos1, player2 = pos2, ...} + local open_chests = {} + minetest.register_on_leaveplayer(function(player) + open_chests[player:get_player_name()] = nil + end) + + local override_protected = { + on_rightclick = function(pos, node, clicker) + local meta = minetest.get_meta(pos) + if has_locked_chest_privilege(meta, clicker) then + minetest.show_formspec( + clicker:get_player_name(), + "hades_chests:chest_locked", + get_locked_chest_formspec(pos) + ) + open_chests[clicker:get_player_name()] = pos + else + minetest.sound_play({ name = "hades_chests_locked", gain = 0.3 }, { max_hear_distance = 10 }, true) + end + end, + on_rotate = screwdriver.rotate_simple + } + + -- get the fields from the chest formspec, we can do this bc. newest functions are called first + -- https://github.com/minetest/minetest/blob/d4b10db998ebeb689b3d27368e30952a42169d03/doc/lua_api.md?plain=1#L5840 + minetest.register_on_player_receive_fields(function(player, formname, fields) + if fields.quit or formname ~= "hades_chests:chest_locked" then + return + end + local pn = player:get_player_name() + local pos = open_chests[pn] + if pos and pipeworks.may_configure(pos, player) then + -- Pipeworks Switch + fs_helpers.on_receive_fields(pos, fields) + minetest.show_formspec(pn, "hades_chests:chest_locked", get_locked_chest_formspec(pos)) + end + -- Do NOT return true here, the callback from hades still needs to run (if they add one) + return false + end) + + local connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1} + pipeworks.override_chest(chestname, override, connect_sides) + pipeworks.override_chest(chestname_protected, override_protected, connect_sides) end -end) - --- Original Definitions -local old_chest_def, old_chest_open_def, old_chest_locked_def, old_chest_locked_open_def -if minetest.get_modpath("default") then - old_chest_def = table.copy(minetest.registered_items["default:chest"]) - old_chest_open_def = table.copy(minetest.registered_items["default:chest_open"]) - old_chest_locked_def = table.copy(minetest.registered_items["default:chest_locked"]) - old_chest_locked_open_def = table.copy(minetest.registered_items["default:chest_locked_open"]) -elseif minetest.get_modpath("hades_chests") then - old_chest_def = table.copy(minetest.registered_items["hades_chests:chest"]) - old_chest_open_def = table.copy(minetest.registered_items["hades_chests:chest"]) - old_chest_locked_def = table.copy(minetest.registered_items["hades_chests:chest_locked"]) - old_chest_locked_open_def = table.copy(minetest.registered_items["hades_chests:chest_locked"]) +elseif minetest.get_modpath("mcl_barrels") then + -- TODO: bring splitstacks switch in the formspec + -- with the current implementation of mcl_barrels this would mean to duplicate a lot of code from there... + local connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1} + pipeworks.override_chest("mcl_barrels:barrel_closed", {}, connect_sides) + pipeworks.override_chest("mcl_barrels:barrel_open", {}, connect_sides) end - --- Override Construction -local override_protected, override, override_open, override_protected_open -override_protected = { - tiles = { - "default_chest_top.png"..tube_entry, - "default_chest_top.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_lock.png", - "default_chest_inside.png" - }, - after_place_node = function(pos, placer) - old_chest_locked_def.after_place_node(pos, placer) - pipeworks.after_place(pos) - end, - on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) - if not default.can_interact_with_node(clicker, pos) then - return itemstack - end - - minetest.sound_play(old_chest_locked_def.sound_open, {gain = 0.3, - pos = pos, max_hear_distance = 10}) - if not chest_lid_obstructed(pos) then - if minetest.get_modpath("default") then - minetest.swap_node(pos, - { name = "default:" .. "chest_locked" .. "_open", - param2 = node.param2 }) - end - end - minetest.after(0.2, minetest.show_formspec, - clicker:get_player_name(), - "pipeworks:chest_formspec", get_chest_formspec(pos)) - open_chests[clicker:get_player_name()] = { pos = pos, - sound = old_chest_locked_def.sound_close, swap = "chest_locked" } - end, - groups = table.copy(old_chest_locked_def.groups), - tube = { - insert_object = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:add_item("main", stack) - end, - can_insert = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - if meta:get_int("splitstacks") == 1 then - stack = stack:peek_item(1) - end - return inv:room_for_item("main", stack) - end, - input_inventory = "main", - connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1} - }, - after_dig_node = pipeworks.after_dig, - on_rotate = pipeworks.on_rotate -} -override = { - tiles = { - "default_chest_top.png"..tube_entry, - "default_chest_top.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_front.png", - "default_chest_inside.png" - }, - on_rightclick = function(pos, node, clicker) - minetest.sound_play(old_chest_def.sound_open, {gain = 0.3, pos = pos, - max_hear_distance = 10}) - if not chest_lid_obstructed(pos) then - if minetest.get_modpath("default") then - minetest.swap_node(pos, { - name = "default:" .. "chest" .. "_open", - param2 = node.param2 }) - end - end - minetest.after(0.2, minetest.show_formspec, - clicker:get_player_name(), - "pipeworks:chest_formspec", get_chest_formspec(pos)) - open_chests[clicker:get_player_name()] = { pos = pos, - sound = old_chest_def.sound_close, swap = "chest" } - end, - groups = table.copy(old_chest_def.groups), - tube = { - insert_object = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:add_item("main", stack) - end, - can_insert = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - if meta:get_int("splitstacks") == 1 then - stack = stack:peek_item(1) - end - return inv:room_for_item("main", stack) - end, - input_inventory = "main", - connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1} - }, - after_place_node = pipeworks.after_place, - after_dig_node = pipeworks.after_dig, - on_rotate = pipeworks.on_rotate -} ---[[local override_common = { - -} -for k,v in pairs(override_common) do - override_protected[k] = v - override[k] = v -end]] - -override_open = table.copy(override) -override_open.groups = table.copy(old_chest_open_def.groups) -override_open.tube = table.copy(override.tube) -override_open.tube.connect_sides = table.copy(override.tube.connect_sides) -override_open.tube.connect_sides.top = nil - -override_protected_open = table.copy(override_protected) -override_protected_open.groups = table.copy(old_chest_locked_open_def.groups) -override_protected_open.tube = table.copy(override_protected.tube) -override_protected_open.tube.connect_sides = table.copy(override_protected.tube.connect_sides) -override_protected_open.tube.connect_sides.top = nil - -override_protected.tiles = { -- Rearranged according to the chest registration in Minetest_Game. - "default_chest_top.png"..tube_entry, - "default_chest_top.png"..tube_entry, - "default_chest_side.png"..tube_entry.."^[transformFX", - "default_chest_side.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_lock.png", -} -override.tiles = { - "default_chest_top.png"..tube_entry, - "default_chest_top.png"..tube_entry, - "default_chest_side.png"..tube_entry.."^[transformFX", - "default_chest_side.png"..tube_entry, - "default_chest_side.png"..tube_entry, - "default_chest_front.png", -} - --- Add the extra groups -for _,v in ipairs({override_protected, override, override_open, override_protected_open}) do - v.groups.tubedevice = 1 - v.groups.tubedevice_receiver = 1 -end - --- Override with the new modifications. -if minetest.get_modpath("default") then - minetest.override_item("default:chest", override) - minetest.override_item("default:chest_open", override_open) - minetest.override_item("default:chest_locked", override_protected) - minetest.override_item("default:chest_locked_open", override_protected_open) -elseif minetest.get_modpath("hades_chests") then - minetest.override_item("hades_chests:chest", override) - --minetest.override_item("hades_chests:chest_open", override_open) - minetest.override_item("hades_chests:chest_locked", override_protected) - --minetest.override_item("hades_chests:chest_locked_open", override_protected_open) -end - diff --git a/crafts.lua b/crafts.lua index 7ed9671..45f642c 100644 --- a/crafts.lua +++ b/crafts.lua @@ -1,5 +1,5 @@ -- Crafting recipes for pipes -local materials = ... +local materials = xcompat.materials minetest.register_craft( { output = "pipeworks:pipe_1_empty 12", @@ -151,7 +151,7 @@ minetest.register_craft( { output = "pipeworks:teleport_tube_1 2", recipe = { { "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }, - { materials.desert_stone, materials.teleporter, materials.desert_stone }, + { materials.desert_stone, materials.mese, materials.desert_stone }, { "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" } }, }) @@ -223,6 +223,26 @@ if pipeworks.enable_mese_tube then }) end +if pipeworks.enable_item_tags and pipeworks.enable_tag_tube then + minetest.register_craft( { + output = "pipeworks:tag_tube_000000 2", + recipe = { + { "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 6bf0a67..c48d852 100644 --- a/default_settings.lua +++ b/default_settings.lua @@ -4,6 +4,8 @@ local prefix = "pipeworks_" local settings = { enable_pipes = true, + enable_item_tags = true, + enable_tag_tube = true, enable_lowpoly = false, enable_autocrafter = true, enable_deployer = true, diff --git a/devices.lua b/devices.lua index 5384b7d..9d0a2a1 100644 --- a/devices.lua +++ b/devices.lua @@ -148,6 +148,7 @@ for s in ipairs(states) do paramtype = "light", paramtype2 = "facedir", groups = dgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -203,6 +204,7 @@ for s in ipairs(states) do fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 } }, groups = dgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -254,10 +256,11 @@ minetest.register_node(nodename_valve_loaded, { fixed = { -5/16, -4/16, -8/16, 5/16, 5/16, 8/16 } }, groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -307,10 +310,11 @@ minetest.register_node("pipeworks:grating", { sunlight_propagates = true, paramtype = "light", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, pipe_connections = { top = 1 }, after_place_node = function(pos) @@ -335,10 +339,11 @@ minetest.register_node(nodename_spigot_empty, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, pipe_connections = { left=1, right=1, front=1, back=1, left_param2 = 3, right_param2 = 1, front_param2 = 2, back_param2 = 0 }, @@ -373,10 +378,11 @@ minetest.register_node(nodename_spigot_loaded, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, pipe_connections = { left=1, right=1, front=1, back=1, left_param2 = 3, right_param2 = 1, front_param2 = 2, back_param2 = 0 }, @@ -432,10 +438,11 @@ minetest.register_node(nodename_panel_empty, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -455,10 +462,11 @@ minetest.register_node(nodename_panel_loaded, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -488,10 +496,11 @@ minetest.register_node(nodename_sensor_empty, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -530,10 +539,11 @@ minetest.register_node(nodename_sensor_loaded, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -600,6 +610,7 @@ for fill = 0, 10 do paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, tankfill=fill+1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -631,6 +642,7 @@ for fill = 0, 10 do paramtype = "light", paramtype2 = "facedir", groups = sgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -661,10 +673,11 @@ minetest.register_node(nodename_fountain_empty, { sunlight_propagates = true, paramtype = "light", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, pipe_connections = { bottom = 1 }, after_place_node = function(pos) @@ -699,10 +712,11 @@ minetest.register_node(nodename_fountain_loaded, { sunlight_propagates = true, paramtype = "light", groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, pipe_connections = { bottom = 1 }, after_place_node = function(pos) @@ -752,10 +766,11 @@ minetest.register_node(nodename_sp_empty, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) @@ -777,10 +792,11 @@ minetest.register_node(nodename_sp_loaded, { paramtype = "light", paramtype2 = "facedir", groups = {snappy=3, pipe=1, not_in_creative_inventory=1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { - key = "node_sound_metal_defaults", - }, + key = "node_sound_metal_defaults", + }, walkable = true, on_place = pipeworks.rotate_on_place, after_dig_node = function(pos) diff --git a/filter-injector.lua b/filter-injector.lua index 22e8b86..293a066 100644 --- a/filter-injector.lua +++ b/filter-injector.lua @@ -14,20 +14,29 @@ local function set_filter_formspec(data, meta) local formspec if data.digiline then + local form_height = 3 + if pipeworks.enable_item_tags then + form_height = 4 + end formspec = - "size[8.5,3]".. + ("size[8.5,%f]"):format(form_height) .. "item_image[0.2,0;1,1;pipeworks:"..data.name.."]".. "label[1.2,0.2;"..minetest.formspec_escape(itemname).."]".. "field[0.5,1.6;4.6,1;channel;"..S("Channel")..";${channel}]".. "button[4.8,1.3;1.5,1;set_channel;"..S("Set").."]".. - fs_helpers.cycling_button(meta, "button[0.2,2.3;4.05,1", "slotseq_mode", + fs_helpers.cycling_button(meta, ("button[0.2,%f;4.05,1"):format(form_height - 0.7), "slotseq_mode", {S("Sequence slots by Priority"), S("Sequence slots Randomly"), S("Sequence slots by Rotation")}).. - fs_helpers.cycling_button(meta, "button[4.25,2.3;4.05,1", "exmatch_mode", + fs_helpers.cycling_button(meta, ("button[4.25,%f;4.05,1"):format(form_height - 0.7), "exmatch_mode", {S("Exact match - off"), S("Exact match - on")}).. - "button_exit[6.3,1.3;2,1;close;"..S("Close").."]" + ("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;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 = "" if data.stackwise then @@ -62,6 +71,11 @@ local function set_filter_formspec(data, meta) exmatch_button.. pipeworks.fs_helpers.get_inv(6).. "listring[]" + if pipeworks.enable_item_tags then + formspec = formspec .. + "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) end @@ -70,9 +84,7 @@ local function punch_filter(data, filtpos, filtnode, msg) local filtmeta = minetest.get_meta(filtpos) local filtinv = filtmeta:get_inventory() local owner = filtmeta:get_string("owner") - local fakePlayer = pipeworks.create_fake_player({ - name = owner - }) + local fakeplayer = fakelib.create_player(owner) local dir = pipeworks.facedir_to_right_dir(filtnode.param2) local frompos = vector.subtract(filtpos, dir) local fromnode = minetest.get_node(frompos) @@ -123,6 +135,7 @@ local function punch_filter(data, filtpos, filtnode, msg) local slotseq_mode local exmatch_mode + 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) @@ -186,6 +199,14 @@ local function punch_filter(data, filtpos, filtnode, msg) set_filter_formspec(data, filtmeta) end + if pipeworks.enable_item_tags then + if type(msg.tags) == "table" or type(msg.tags) == "string" then + item_tags = pipeworks.sanitize_tags(msg.tags) + elseif type(msg.tag) == "string" then + item_tags = pipeworks.sanitize_tags({msg.tag}) + end + end + if msg.nofire then return end @@ -299,7 +320,7 @@ local function punch_filter(data, filtpos, filtnode, msg) if fromtube.can_remove then doRemove = fromtube.can_remove(frompos, fromnode, stack, dir, frominvname, spos) elseif fromdef.allow_metadata_inventory_take then - doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer) + doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname, spos, stack, fakeplayer) end -- stupid lack of continue statements grumble if doRemove > 0 then @@ -333,13 +354,13 @@ local function punch_filter(data, filtpos, filtnode, msg) item = stack:take_item(count) frominv:set_stack(frominvname, spos, stack) if fromdef.on_metadata_inventory_take then - fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) + fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakeplayer) end end local pos = vector.add(frompos, vector.multiply(dir, 1.4)) local start_pos = vector.add(frompos, dir) 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 @@ -389,6 +410,7 @@ for _, data in ipairs({ }, paramtype2 = "facedir", groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, mesecon = 2, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, legacy_facedir_simple = true, _sound_def = { @@ -456,6 +478,10 @@ for _, data in ipairs({ end local meta = minetest.get_meta(pos) + 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) set_filter_infotext(data, meta) @@ -477,6 +503,10 @@ 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.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) end diff --git a/init.lua b/init.lua index 5a86a01..6d85a06 100644 --- a/init.lua +++ b/init.lua @@ -59,17 +59,16 @@ dofile(pipeworks.modpath.."/luaentity.lua") dofile(pipeworks.modpath.."/item_transport.lua") dofile(pipeworks.modpath.."/flowing_logic.lua") dofile(pipeworks.modpath.."/filter-injector.lua") +dofile(pipeworks.modpath.."/chests.lua") dofile(pipeworks.modpath.."/trashcan.lua") dofile(pipeworks.modpath.."/wielder.lua") - -local materials = loadfile(pipeworks.modpath.."/materials.lua")() - dofile(pipeworks.modpath.."/tubes/registration.lua") dofile(pipeworks.modpath.."/tubes/routing.lua") dofile(pipeworks.modpath.."/tubes/sorting.lua") dofile(pipeworks.modpath.."/tubes/signal.lua") -loadfile(pipeworks.modpath.."/tubes/embedded_tube.lua")(materials) +dofile(pipeworks.modpath.."/tubes/embedded_tube.lua") dofile(pipeworks.modpath.."/tubes/pane_embedded_tube.lua") +dofile(pipeworks.modpath.."/tubes/tags.lua") if pipeworks.enable_teleport_tube then dofile(pipeworks.modpath.."/tubes/teleport.lua") @@ -97,12 +96,11 @@ end if pipeworks.enable_pipe_devices then dofile(pipeworks.modpath.."/devices.lua") end -if pipeworks.enable_redefines and (minetest.get_modpath("default") or minetest.get_modpath("hades_core")) then +if pipeworks.enable_redefines then dofile(pipeworks.modpath.."/compat-chests.lua") - dofile(pipeworks.modpath.."/compat-furnaces.lua") end -if pipeworks.enable_redefines and minetest.get_modpath("mcl_barrels") then - dofile(pipeworks.modpath.."/mcl_barrels.lua") +if pipeworks.enable_redefines and (minetest.get_modpath("default") or minetest.get_modpath("hades_core")) then + dofile(pipeworks.modpath.."/compat-furnaces.lua") end if pipeworks.enable_redefines and minetest.get_modpath("mcl_furnaces") then dofile(pipeworks.modpath.."/mcl_furnaces.lua") @@ -111,7 +109,7 @@ if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.lua") end -loadfile(pipeworks.modpath.."/crafts.lua")(materials) +dofile(pipeworks.modpath.."/crafts.lua") minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty") diff --git a/item_transport.lua b/item_transport.lua index 7e83d95..ddf2a08 100644 --- a/item_transport.lua +++ b/item_transport.lua @@ -3,11 +3,36 @@ local enable_max_limit = minetest.settings:get_bool("pipeworks_enable_items_per_ local max_tube_limit = tonumber(minetest.settings:get("pipeworks_max_items_per_tube")) or 30 if enable_max_limit == nil then enable_max_limit = true end +if pipeworks.enable_item_tags then + 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 + + 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") @@ -15,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 @@ -79,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 @@ -144,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) @@ -172,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. @@ -276,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 @@ -337,8 +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 - leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel, self.owner) + 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 @@ -353,7 +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 + 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 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))) diff --git a/legacy.lua b/legacy.lua deleted file mode 100644 index fdaa0de..0000000 --- a/legacy.lua +++ /dev/null @@ -1,62 +0,0 @@ -local S = minetest.get_translator("pipeworks") - -if not minetest.get_modpath("auto_tree_tap") and - minetest.get_modpath("technic") then - - minetest.register_abm({ - nodenames = { "auto_tree_tap:off", "auto_tree_tap:on" }, - chance = 1, - interval = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - local fdir = node.param2 - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - inv:set_size("pick", 1) - inv:set_size("ghost_pick", 1) - inv:set_size("main", 100) - minetest.set_node(pos, {name = "pipeworks:nodebreaker_off", param2 = fdir}) - minetest.registered_nodes["pipeworks:nodebreaker_off"].on_punch(pos, node) - inv:set_stack("pick", 1, ItemStack("technic:treetap")) - end - }) - - minetest.register_node(":auto_tree_tap:off", { - description = S("Auto-Tap"), - tiles = {"pipeworks_nodebreaker_top_off.png","pipeworks_nodebreaker_bottom_off.png","pipeworks_nodebreaker_side2_off.png","pipeworks_nodebreaker_side1_off.png", - "pipeworks_nodebreaker_back.png","pipeworks_nodebreaker_front_off.png"}, - is_ground_content = true, - paramtype2 = "facedir", - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2, mesecon = 2,tubedevice=1, not_in_creative_inventory=1, axey=1, handy=1, pickaxey=1}, - _mcl_hardness=0.8, - _sound_def = { - key = "node_sound_stone_defaults", - }, - tube = {connect_sides={back=1}}, - on_construct = function(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - inv:set_size("pick", 1) - inv:set_stack("pick", 1, ItemStack("default:pick_mese")) - end, - after_place_node = function (pos, placer) - pipeworks.scan_for_tube_objects(pos, placer) - local placer_pos = placer:get_pos() - - --correct for the player's height - if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end - - --correct for 6d facedir - if placer_pos then - local dir = { - x = pos.x - placer_pos.x, - y = pos.y - placer_pos.y, - z = pos.z - placer_pos.z - } - local node = minetest.get_node(pos) - node.param2 = minetest.dir_to_facedir(dir, true) - minetest.set_node(pos, node) - end - end, - after_dig_node = pipeworks.scan_for_tube_objects, - }) -end diff --git a/materials.lua b/materials.lua deleted file mode 100644 index ca9adf5..0000000 --- a/materials.lua +++ /dev/null @@ -1,67 +0,0 @@ -local materials = { - stone = "default:stone", - desert_stone = "default:desert_stone", - desert_sand = "default:desert_sand", - chest = "default:chest", - copper_ingot = "default:copper_ingot", - steel_ingot = "default:steel_ingot", - gold_ingot = "default:gold_ingot", - mese = "default:mese", - mese_crystal = "default:mese_crystal", - mese_crystal_fragment = "default:mese_crystal_fragment", - teleporter = "default:mese", - glass = "default:glass" -} - -if minetest.get_modpath("mcl_core") then - materials = { - stone = "mcl_core:stone", - desert_stone = "mcl_core:redsandstone", - desert_sand = "mcl_core:sand", - chest = "mcl_chests:chest", - steel_ingot = "mcl_core:iron_ingot", - gold_ingot = "mcl_core:gold_ingot", - mese = "mesecons_torch:redstoneblock", - mese_crystal = "mesecons:redstone", - mese_crystal_fragment = "mesecons:redstone", - teleporter = "mesecons_torch:redstoneblock", - copper_ingot = "mcl_copper:copper_ingot", - glass = "mcl_core:glass", - } -elseif minetest.get_modpath("fl_ores") and minetest.get_modpath("fl_stone") then - materials = { - stone = "fl_stone:stone", - desert_stone = "fl_stone:desert_stone", - desert_sand = "fl_stone:desert_sand", - chest = "fl_storage:wood_chest", - steel_ingot = "fl_ores:iron_ingot", - gold_ingot = "fl_ores:gold_ingot", - mese = "fl_ores:iron_ingot", - mese_crystal = "fl_ores:iron_ingot", - mese_crystal_fragment = "fl_ores:iron_ingot", - teleporter = "fl_ores:iron_ingot", - copper_ingot = "fl_ores:copper_ingot", - glass = "fl_glass:framed_glass", - } -elseif minetest.get_modpath("hades_core") then - materials = { - stone = "hades_core:stone", - desert_stone = "hades_core:stone_baked", - desert_sand = "hades_core:volcanic_sand", - chest = "hades_chests:chest"; - steel_ingot = "hades_core:steel_ingot", - gold_ingot = "hades_core:gold_ingot", - mese = "hades_core:mese", - mese_crystal = "hades_core:mese_crystal", - mese_crystal_fragment = "hades_core:mese_crystal_fragment", - teleporter = "hades_materials:teleporter_device", - copper_ingot = "hades_core:copper_ingot", - tin_ingot = "hades_core:tin_ingot", - glass = "hades_core:glass", - } - if minetest.get_modpath("hades_default") then - materials.desert_sand = "hades_default:desert_sand" - end -end - -return materials \ No newline at end of file diff --git a/mcl_barrels.lua b/mcl_barrels.lua deleted file mode 100644 index 423dab3..0000000 --- a/mcl_barrels.lua +++ /dev/null @@ -1,72 +0,0 @@ --- this bit of code modifies the mcl barrels to be compatible with --- pipeworks. - --- Pipeworks Specific -local tube_entry = "^pipeworks_tube_connection_wooden.png" - --- Original Definitions -local old_barrel = table.copy(minetest.registered_items["mcl_barrels:barrel_closed"]) - -local groups = old_barrel.groups -groups["tubedevice"] = 1 -groups["tubedevice_receiver"] = 1 -local groups_open = table.copy(groups) -groups_open["not_in_creative_inventory"] = 1 - - --- Override Construction -local override_barrel = {} - -override_barrel.tiles = { - "mcl_barrels_barrel_top.png^[transformR270", - "mcl_barrels_barrel_bottom.png"..tube_entry, - "mcl_barrels_barrel_side.png"..tube_entry -} - -override_barrel.after_place_node = function(pos, placer, itemstack, pointed_thing) - old_barrel.after_place_node(pos, placer, itemstack, pointed_thing) - pipeworks.after_place(pos, placer, itemstack, pointed_thing) -end - -override_barrel.tube = { - insert_object = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:add_item("main", stack) - end, - can_insert = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - if meta:get_int("splitstacks") == 1 then - stack = stack:peek_item(1) - end - return inv:room_for_item("main", stack) - end, - input_inventory = "main", - connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1} -} - -override_barrel.after_dig_node = function(pos, oldnode, oldmetadata, digger) - old_barrel.after_dig_node(pos, oldnode, oldmetadata, digger) - pipeworks.after_dig(pos) -end - -override_barrel.groups = table.copy(old_barrel.groups) - -override_barrel.on_rotate = pipeworks.on_rotate - - -local override_barrel_open = table.copy(override_barrel) - -override_barrel_open.tiles = { - "mcl_barrels_barrel_top_open.png", - "mcl_barrels_barrel_bottom.png"..tube_entry, - "mcl_barrels_barrel_side.png"..tube_entry -} - -override_barrel_open.groups = groups_open - - --- Override with the new modifications. -minetest.override_item("mcl_barrels:barrel_closed", override_barrel) -minetest.override_item("mcl_barrels:barrel_open", override_barrel_open) diff --git a/mod.conf b/mod.conf index 3e57efe..ea1a06d 100644 --- a/mod.conf +++ b/mod.conf @@ -1,5 +1,5 @@ name = pipeworks description = This mod uses mesh nodes and nodeboxes to supply a complete set of 3D pipes and tubes, along with devices that work with them. -depends = basic_materials +depends = basic_materials, xcompat, fakelib optional_depends = mesecons, mesecons_mvps, digilines, signs_lib, unified_inventory, default, screwdriver, fl_mapgen, sound_api, i3, hades_core, hades_furnaces, hades_chests, mcl_mapgen_core, mcl_barrels, mcl_furnaces, mcl_experience min_minetest_version = 5.5.0 diff --git a/pipes.lua b/pipes.lua index 8b9f01b..45d5b8f 100644 --- a/pipes.lua +++ b/pipes.lua @@ -76,6 +76,7 @@ for index, connects in ipairs(cconnects) do fixed = outsel }, groups = pgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -113,6 +114,7 @@ for index, connects in ipairs(cconnects) do fixed = outsel }, groups = pgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_metal_defaults", @@ -151,6 +153,7 @@ if REGISTER_COMPATIBILITY then paramtype = "light", description = S("Pipe Segment (legacy)"), groups = {not_in_creative_inventory = 1, pipe_to_update = 1}, + is_ground_content = false, drop = "pipeworks:pipe_1_empty", after_place_node = function(pos) pipeworks.scan_for_pipe_objects(pos) @@ -163,6 +166,7 @@ if REGISTER_COMPATIBILITY then sunlight_propagates = true, paramtype = "light", groups = {not_in_creative_inventory = 1, pipe_to_update = 1}, + is_ground_content = false, drop = "pipeworks:pipe_1_empty", after_place_node = function(pos) pipeworks.scan_for_pipe_objects(pos) diff --git a/textures/pipeworks_tag_tube_end.png b/textures/pipeworks_tag_tube_end.png new file mode 100644 index 0000000..db131bc Binary files /dev/null and b/textures/pipeworks_tag_tube_end.png differ diff --git a/textures/pipeworks_tag_tube_inv.png b/textures/pipeworks_tag_tube_inv.png new file mode 100644 index 0000000..7fd2c31 Binary files /dev/null and b/textures/pipeworks_tag_tube_inv.png differ diff --git a/textures/pipeworks_tag_tube_noctr_1.png b/textures/pipeworks_tag_tube_noctr_1.png new file mode 100644 index 0000000..80e3e22 Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_1.png differ diff --git a/textures/pipeworks_tag_tube_noctr_2.png b/textures/pipeworks_tag_tube_noctr_2.png new file mode 100644 index 0000000..b529740 Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_2.png differ diff --git a/textures/pipeworks_tag_tube_noctr_3.png b/textures/pipeworks_tag_tube_noctr_3.png new file mode 100644 index 0000000..0eac5e5 Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_3.png differ diff --git a/textures/pipeworks_tag_tube_noctr_4.png b/textures/pipeworks_tag_tube_noctr_4.png new file mode 100644 index 0000000..0143033 Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_4.png differ diff --git a/textures/pipeworks_tag_tube_noctr_5.png b/textures/pipeworks_tag_tube_noctr_5.png new file mode 100644 index 0000000..d4c33ba Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_5.png differ diff --git a/textures/pipeworks_tag_tube_noctr_6.png b/textures/pipeworks_tag_tube_noctr_6.png new file mode 100644 index 0000000..1a09462 Binary files /dev/null and b/textures/pipeworks_tag_tube_noctr_6.png differ diff --git a/textures/pipeworks_tag_tube_plain_1.png b/textures/pipeworks_tag_tube_plain_1.png new file mode 100644 index 0000000..69f9d66 Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_1.png differ diff --git a/textures/pipeworks_tag_tube_plain_2.png b/textures/pipeworks_tag_tube_plain_2.png new file mode 100644 index 0000000..76aa726 Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_2.png differ diff --git a/textures/pipeworks_tag_tube_plain_3.png b/textures/pipeworks_tag_tube_plain_3.png new file mode 100644 index 0000000..98d68cb Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_3.png differ diff --git a/textures/pipeworks_tag_tube_plain_4.png b/textures/pipeworks_tag_tube_plain_4.png new file mode 100644 index 0000000..b05fd69 Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_4.png differ diff --git a/textures/pipeworks_tag_tube_plain_5.png b/textures/pipeworks_tag_tube_plain_5.png new file mode 100644 index 0000000..9801a38 Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_5.png differ diff --git a/textures/pipeworks_tag_tube_plain_6.png b/textures/pipeworks_tag_tube_plain_6.png new file mode 100644 index 0000000..458fe5d Binary files /dev/null and b/textures/pipeworks_tag_tube_plain_6.png differ diff --git a/textures/pipeworks_tag_tube_short.png b/textures/pipeworks_tag_tube_short.png new file mode 100644 index 0000000..c38ccd9 Binary files /dev/null and b/textures/pipeworks_tag_tube_short.png differ diff --git a/trashcan.lua b/trashcan.lua index 29a4d08..c8ae9b2 100644 --- a/trashcan.lua +++ b/trashcan.lua @@ -11,6 +11,7 @@ minetest.register_node("pipeworks:trashcan", { "pipeworks_trashcan_side.png", }, groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1, dig_generic = 4, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, tube = { insert_object = function(pos, node, stack, direction) diff --git a/tubes/embedded_tube.lua b/tubes/embedded_tube.lua index cc4c259..0ca6e36 100644 --- a/tubes/embedded_tube.lua +++ b/tubes/embedded_tube.lua @@ -1,4 +1,4 @@ -local materials = ... +local materials = xcompat.materials local S = minetest.get_translator("pipeworks") local straight = function(pos, node, velocity, stack) return {velocity} end @@ -27,6 +27,7 @@ function pipeworks.register_embedded_tube(nodename, opts) pickaxey=1, handy=1 }, + is_ground_content = false, _mcl_hardness = 0.8, legacy_facedir_simple = true, _sound_def = { diff --git a/tubes/lua.lua b/tubes/lua.lua index 7c02e9e..7a76fe9 100644 --- a/tubes/lua.lua +++ b/tubes/lua.lua @@ -370,7 +370,10 @@ local function clean_and_weigh_digiline_message(msg, back_references) return msg, #msg + 25 elseif t == "number" then -- Numbers are passed by value so need not be touched, and cost 8 bytes - -- as all numbers in Lua are doubles. + -- as all numbers in Lua are doubles. NaN values are removed. + if msg ~= msg then + return nil, 0 + end return msg, 8 elseif t == "boolean" then -- Booleans are passed by value so need not be touched, and cost 1 @@ -945,7 +948,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 @@ -960,12 +963,33 @@ for white = 0, 1 do itemstring = stack:to_string(), item = stack:to_table(), velocity = velocity, + tags = table.copy(tags), + side = src.name, }) - if not succ or type(msg) ~= "string" then + if not succ then return go_back(velocity) end - local r = rules[msg] - return r and {r} or go_back(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" or type(msg.tags) == "string" then + new_tags = pipeworks.sanitize_tags(msg.tags) + elseif type(msg.tag) == "string" then + new_tags = pipeworks.sanitize_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/pane_embedded_tube.lua b/tubes/pane_embedded_tube.lua index b52aa58..4bc1e83 100644 --- a/tubes/pane_embedded_tube.lua +++ b/tubes/pane_embedded_tube.lua @@ -31,11 +31,12 @@ minetest.register_node("pipeworks:steel_pane_embedded_tube", { paramtype = "light", paramtype2 = "facedir", groups = {cracky=1, oddly_breakable_by_hand = 1, tubedevice = 1, dig_glass = 2, pickaxey=1, handy=1}, + is_ground_content = false, _mcl_hardness=0.8, legacy_facedir_simple = true, _sound_def = { - key = "node_sound_stone_defaults", - }, + key = "node_sound_stone_defaults", + }, tube = { connect_sides = {front = 1, back = 1,}, priority = 50, diff --git a/tubes/registration.lua b/tubes/registration.lua index b837cb8..14a5df5 100644 --- a/tubes/registration.lua +++ b/tubes/registration.lua @@ -106,6 +106,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e fixed = outboxes }, groups = tgroups, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_wood_defaults", @@ -227,6 +228,7 @@ local register_all_tubes = function(name, desc, plain, noctrs, ends, short, inv, description = S("Pneumatic tube segment (legacy)"), after_place_node = pipeworks.after_place, groups = {not_in_creative_inventory = 1, tube_to_update = 1, tube = 1}, + is_ground_content = false, tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}}, drop = name.."_1", }) diff --git a/tubes/routing.lua b/tubes/routing.lua index ae84e7d..e0a90aa 100644 --- a/tubes/routing.lua +++ b/tubes/routing.lua @@ -50,6 +50,7 @@ pipeworks.register_tube("pipeworks:broken_tube", { node_def = { drop = "pipeworks:tube_1", groups = {not_in_creative_inventory = 1, tubedevice_receiver = 1}, + is_ground_content = false, tube = { insert_object = function(pos, node, stack, direction) minetest.item_drop(stack, nil, pos) @@ -179,6 +180,7 @@ if pipeworks.enable_one_way_tube then 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, axey=1, handy=1, pickaxey=1}, + is_ground_content = false, _mcl_hardness=0.8, _sound_def = { key = "node_sound_wood_defaults", diff --git a/tubes/tags.lua b/tubes/tags.lua new file mode 100644 index 0000000..ffd7ec7 --- /dev/null +++ b/tubes/tags.lua @@ -0,0 +1,139 @@ +local S = minetest.get_translator("pipeworks") +local fs_helpers = pipeworks.fs_helpers + +if not pipeworks.enable_item_tags or not pipeworks.enable_tag_tube then return 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) + 0.5) .. ";1,0.6", "l" .. (i + 1) .. "s", + { + pipeworks.button_off, + pipeworks.button_on + } + ) + end + local size = "10.2,9" + meta:set_string("formspec", + "formspec_version[2]" .. + "size[" .. size .. "]" .. + pipeworks.fs_helpers.get_prepends(size) .. + "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,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 .. + "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("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" }, + plain = { "pipeworks_tag_tube_plain_1.png", "pipeworks_tag_tube_plain_2.png", "pipeworks_tag_tube_plain_3.png", + "pipeworks_tag_tube_plain_4.png", "pipeworks_tag_tube_plain_5.png", "pipeworks_tag_tube_plain_6.png" }, + ends = { "pipeworks_tag_tube_end.png" }, + short = "pipeworks_tag_tube_short.png", + 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, tags) + local tbl, tbln = {}, 0 + local found, foundn = {}, 0 + local meta = minetest.get_meta(pos) + 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 + for i, vect in ipairs(pipeworks.meseadjlist) do + local npos = vector.add(pos, vect) + local node = minetest.get_node(npos) + local reg_node = minetest.registered_nodes[node.name] + if meta:get_int("l" .. i .. "s") == 1 and reg_node then + 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 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 + else + tbln = tbln + 1 + tbl[tbln] = vect + end + end + end + end + return (foundn > 0) and found or tbl + end + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + for i = 1, 6 do + meta:set_int("l" .. tostring(i) .. "s", 1) + end + update_formspec(pos) + 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 + local meta = minetest.get_meta(pos) + for i = 1, 6 do + meta:set_int("l" .. tostring(i) .. "s", 0) + end + update_formspec(pos) + end + return pipeworks.after_place(pos, placer, itemstack, pointed_thing) + end, + on_receive_fields = function(pos, formname, fields, sender) + if (fields.quit and not fields.key_enter_field) + or not pipeworks.may_configure(pos, sender) then + return + end + + local meta = minetest.get_meta(pos) + for i = 1, 6 do + local field_name = "tags" .. tostring(i) + if fields[field_name] then + local tags = pipeworks.sanitize_tags(fields[field_name]) + meta:set_string(field_name, table.concat(tags, ",")) + end + end + + fs_helpers.on_receive_fields(pos, fields) + update_formspec(pos) + end, + can_dig = function(pos, player) + return true + end, + }, +}) diff --git a/wielder.lua b/wielder.lua index 0cc26f9..ef26a97 100644 --- a/wielder.lua +++ b/wielder.lua @@ -1,247 +1,201 @@ local S = minetest.get_translator("pipeworks") -local assumed_eye_pos = vector.new(0, 1.5, 0) +local has_digilines = minetest.get_modpath("digilines") -local function delay(x) - return (function() return x end) -end - -local function set_wielder_formspec(data, meta) - local size = "10.2,"..(7+data.wield_inv_height) - local list_background = "" +local function set_wielder_formspec(def, meta) + local width, height = def.wield_inv.width, def.wield_inv.height + local offset = 5.22 - width * 0.625 + local size = "10.2,"..(6.5 + height * 1.25 + (has_digilines and 1.25 or 0)) + local list_bg = "" if minetest.get_modpath("i3") or minetest.get_modpath("mcl_formspec") then - list_background = "style_type[box;colors=#666]" - for i=0, data.wield_inv_height-1 do - for j=0, data.wield_inv_width-1 do - list_background = list_background .. "box[".. ((10-data.wield_inv_width)*0.5)+(i*1.25) ..",".. 1+(j*1.25) ..";1,1;]" + list_bg = "style_type[box;colors=#666]" + for i=0, height-1 do + for j=0, width-1 do + list_bg = list_bg.."box["..offset+(i*1.25)..","..1.25+(j*1.25)..";1,1;]" end end end - meta:set_string("formspec", - "formspec_version[2]" .. - "size["..size.."]".. - pipeworks.fs_helpers.get_prepends(size).. - "item_image[0.5,0.5;1,1;"..data.name_base.."_off]".. - "label[1.5,1;"..minetest.formspec_escape(data.description).."]".. - list_background .. - "list[context;"..minetest.formspec_escape(data.wield_inv_name)..";"..((10-data.wield_inv_width)*0.5)..",1;"..data.wield_inv_width..","..data.wield_inv_height..";]".. - pipeworks.fs_helpers.get_inv((2+data.wield_inv_height)) .. - "listring[context;"..minetest.formspec_escape(data.wield_inv_name).."]" .. - "listring[current_player;main]" - ) - meta:set_string("infotext", data.description) -end - -local can_tool_dig_node = function(nodename, toolcaps, toolname) - --pipeworks.logger("can_tool_dig_node() STUB nodename="..tostring(nodename).." toolname="..tostring(toolname).." toolcaps: "..dump(toolcaps)) - -- brief documentation of minetest.get_dig_params() as it's not yet documented in lua_api.txt: - -- takes two arguments, a node's block groups and a tool's capabilities, - -- both as they appear in their respective definitions. - -- returns a table with the following fields: - -- diggable: boolean, can this tool dig this node at all - -- time: float, time needed to dig with this tool - -- wear: int, number of wear points to inflict on the item - local nodedef = minetest.registered_nodes[nodename] - -- don't explode due to nil def in event of unknown node! - if (nodedef == nil) then return false end - - local nodegroups = nodedef.groups - local diggable = minetest.get_dig_params(nodegroups, toolcaps).diggable - if not diggable then - -- a pickaxe can't actually dig leaves based on it's groups alone, - -- but a player holding one can - the game seems to fall back to the hand. - -- fall back to checking the hand's properties if the tool isn't the correct one. - local hand_caps = minetest.registered_items[""].tool_capabilities - diggable = minetest.get_dig_params(nodegroups, hand_caps).diggable + local inv_offset = 1.5 + height * 1.25 + local fs = "formspec_version[2]size["..size.."]".. + pipeworks.fs_helpers.get_prepends(size)..list_bg.. + "item_image[0.5,0.3;1,1;"..def.name.."_off]".. + "label[1.75,0.8;"..minetest.formspec_escape(def.description).."]".. + "list[context;"..def.wield_inv.name..";"..offset..",1.25;"..width..","..height..";]" + if has_digilines then + fs = fs.."field[1.5,"..inv_offset..";5,0.8;channel;"..S("Channel")..";${channel}]".. + "button_exit[6.5,"..inv_offset..";2,0.8;save;"..S("Save").."]".. + pipeworks.fs_helpers.get_inv(inv_offset + 1.25).."listring[]" + else + fs = fs..pipeworks.fs_helpers.get_inv(inv_offset).."listring[]" end - return diggable + meta:set_string("formspec", fs) + meta:set_string("infotext", def.description) end -local function wielder_on(data, wielder_pos, wielder_node) - data.fixup_node(wielder_pos, wielder_node) - if wielder_node.name ~= data.name_base.."_off" then return end - wielder_node.name = data.name_base.."_on" - minetest.swap_node(wielder_pos, wielder_node) - minetest.check_for_falling(wielder_pos) - local wielder_meta = minetest.get_meta(wielder_pos) - local inv = wielder_meta:get_inventory() - local wield_inv_name = data.wield_inv_name - local wieldindex - for i, stack in ipairs(inv:get_list(wield_inv_name)) do - if not stack:is_empty() then - wieldindex = i - break +local function wielder_action(def, pos, node, index) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local list = inv:get_list(def.wield_inv.name) + local wield_index + if index then + if list[index] and (def.wield_hand or not list[index]:is_empty()) then + wield_index = index + end + else + for i, stack in ipairs(list) do + if not stack:is_empty() then + wield_index = i + break + end end end - if not wieldindex then - if not data.ghost_inv_name then return end - wield_inv_name = data.ghost_inv_name - inv:set_stack(wield_inv_name, 1, ItemStack(data.ghost_tool)) - wieldindex = 1 + if not wield_index and not def.wield_hand then + return end - local dir = minetest.facedir_to_dir(wielder_node.param2) - -- under/above is currently intentionally left switched - -- even though this causes some problems with deployers and e.g. seeds - -- as there are some issues related to nodebreakers otherwise breaking 2 nodes afar. - -- solidity would have to be checked as well, - -- but would open a whole can of worms related to difference in nodebreaker/deployer behavior - -- and the problems of wielders acting on themselves if below is solid - local under_pos = vector.subtract(wielder_pos, dir) - local above_pos = vector.subtract(under_pos, dir) - local pitch - local yaw - if dir.z < 0 then - yaw = 0 - pitch = 0 - elseif dir.z > 0 then - yaw = math.pi - pitch = 0 - elseif dir.x < 0 then - yaw = 3*math.pi/2 - pitch = 0 - elseif dir.x > 0 then - yaw = math.pi/2 - pitch = 0 - elseif dir.y > 0 then - yaw = 0 - pitch = -math.pi/2 - else - yaw = 0 - pitch = math.pi/2 - end - local virtplayer = pipeworks.create_fake_player({ - name = data.masquerade_as_owner and wielder_meta:get_string("owner") - or ":pipeworks:" .. minetest.pos_to_string(wielder_pos), - formspec = wielder_meta:get_string("formspec"), - look_dir = vector.multiply(dir, -1), - look_pitch = pitch, - look_yaw = yaw, - sneak = data.sneak, - position = vector.subtract(wielder_pos, assumed_eye_pos), + local dir = minetest.facedir_to_dir(node.param2) + local fakeplayer = fakelib.create_player({ + name = meta:get_string("owner"), + direction = vector.multiply(dir, -1), + position = pos, inventory = inv, - wield_index = wieldindex, - wield_list = wield_inv_name + wield_index = wield_index or 1, + wield_list = def.wield_inv.name, }) - - local pointed_thing = { type="node", under=under_pos, above=above_pos } - data.act(virtplayer, pointed_thing) - if data.eject_drops then + -- Under and above positions are intentionally switched. + local pointed = { + type = "node", + under = vector.subtract(pos, dir), + above = vector.subtract(pos, vector.multiply(dir, 2)), + } + def.action(fakeplayer, pointed) + if def.eject_drops then for i, stack in ipairs(inv:get_list("main")) do if not stack:is_empty() then - pipeworks.tube_inject_item(wielder_pos, wielder_pos, dir, stack) + pipeworks.tube_inject_item(pos, pos, dir, stack) inv:set_stack("main", i, ItemStack("")) end end end end -local function wielder_off(data, pos, node) - if node.name == data.name_base.."_on" then - node.name = data.name_base.."_off" +local function wielder_on(def, pos, node) + if node.name ~= def.name.."_off" then + return + end + node.name = def.name.."_on" + minetest.swap_node(pos, node) + wielder_action(def, pos, node) +end + +local function wielder_off(def, pos, node) + if node.name == def.name.."_on" then + node.name = def.name.."_off" minetest.swap_node(pos, node) - minetest.check_for_falling(pos) end end -local function register_wielder(data) - data.fixup_node = data.fixup_node or function (pos, node) end - data.fixup_oldmetadata = data.fixup_oldmetadata or function (m) return m end - for _, state in ipairs({ "off", "on" }) do - local groups = { snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon=2, tubedevice=1, tubedevice_receiver=1, axey=1, handy=1, pickaxey=1 } - if state == "on" then groups.not_in_creative_inventory = 1 end - local tile_images = {} - for _, face in ipairs({ "top", "bottom", "side2", "side1", "back", "front" }) do - table.insert(tile_images, data.texture_base.."_"..face..(data.texture_stateful[face] and "_"..state or "")..".png") +local function wielder_digiline_action(def, pos, channel, msg) + local meta = minetest.get_meta(pos) + local set_channel = meta:get_string("channel") + if channel ~= set_channel then + return + end + if type(msg) ~= "table" then + if type(msg) == "string" then + if msg:sub(1, 8) == "activate" then + msg = {command = "activate", slot = tonumber(msg:sub(9))} + end + else + return end - minetest.register_node(data.name_base.."_"..state, { - description = data.description, - tiles = tile_images, + end + if msg.command == "activate" then + local node = minetest.get_node(pos) + local index = type(msg.slot) == "number" and msg.slot or nil + wielder_action(def, pos, node, index) + end +end + +function pipeworks.register_wielder(def) + for _,state in ipairs({"off", "on"}) do + local groups = { + snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, + mesecon = 2, tubedevice = 1, tubedevice_receiver = 1, + axey = 1, handy = 1, pickaxey = 1, + not_in_creative_inventory = state == "on" and 1 or nil + } + minetest.register_node(def.name.."_"..state, { + description = def.description, + tiles = def.tiles[state], + paramtype2 = "facedir", + groups = groups, + is_ground_content = false, + _mcl_hardness = 0.6, + _sound_def = { + key = "node_sound_stone_defaults", + }, + drop = def.name.."_off", mesecons = { effector = { rules = pipeworks.rules_all, - action_on = function (pos, node) - wielder_on(data, pos, node) + action_on = function(pos, node) + wielder_on(def, pos, node) end, - action_off = function (pos, node) - wielder_off(data, pos, node) + action_off = function(pos, node) + wielder_off(def, pos, node) + end, + }, + }, + digilines = { + receptor = {}, + effector = { + action = function(pos, _, channel, msg) + wielder_digiline_action(def, pos, channel, msg) end, }, }, tube = { - can_insert = function(pos, node, stack, tubedir) - if not data.tube_permit_anteroposterior_insert then - local nodedir = minetest.facedir_to_dir(node.param2) - if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then + can_insert = function(pos, node, stack, direction) + if def.eject_drops then + -- Prevent ejected items from being inserted + local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + if vector.equals(direction, dir) then return false end end - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:room_for_item(data.wield_inv_name, stack) + local inv = minetest.get_meta(pos):get_inventory() + return inv:room_for_item(def.wield_inv.name, stack) end, - insert_object = function(pos, node, stack, tubedir) - if not data.tube_permit_anteroposterior_insert then - local nodedir = minetest.facedir_to_dir(node.param2) - if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then - return stack - end - end - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:add_item(data.wield_inv_name, stack) + insert_object = function(pos, node, stack) + local inv = minetest.get_meta(pos):get_inventory() + return inv:add_item(def.wield_inv.name, stack) end, - input_inventory = data.wield_inv_name, - connect_sides = data.tube_connect_sides, - can_remove = function(pos, node, stack, tubedir) + input_inventory = def.wield_inv.name, + connect_sides = def.connect_sides, + can_remove = function(pos, node, stack) return stack:get_count() end, }, - is_ground_content = true, - paramtype2 = "facedir", - tubelike = 1, - groups = groups, - _mcl_hardness=0.6, - _sound_def = { - key = "node_sound_stone_defaults", - }, - drop = data.name_base.."_off", on_construct = function(pos) local meta = minetest.get_meta(pos) - set_wielder_formspec(data, meta) local inv = meta:get_inventory() - inv:set_size(data.wield_inv_name, data.wield_inv_width*data.wield_inv_height) - if data.ghost_inv_name then - inv:set_size(data.ghost_inv_name, 1) - end - if data.eject_drops then - inv:set_size("main", 100) + inv:set_size(def.wield_inv.name, def.wield_inv.width * def.wield_inv.height) + if def.eject_drops then + inv:set_size("main", 32) end + set_wielder_formspec(def, meta) end, - after_place_node = function (pos, placer) + after_place_node = function(pos, placer) pipeworks.scan_for_tube_objects(pos) - local placer_pos = placer:get_pos() - if placer_pos and placer:is_player() then placer_pos = vector.add(placer_pos, assumed_eye_pos) end - if placer_pos then - local dir = vector.subtract(pos, placer_pos) - local node = minetest.get_node(pos) - node.param2 = minetest.dir_to_facedir(dir, true) - minetest.set_node(pos, node) + if not placer then + return end + local node = minetest.get_node(pos) + node.param2 = minetest.dir_to_facedir(placer:get_look_dir(), true) + minetest.set_node(pos, node) minetest.get_meta(pos):set_string("owner", placer:get_player_name()) end, - can_dig = (data.can_dig_nonempty_wield_inv and delay(true) or function(pos, player) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:is_empty(data.wield_inv_name) - end), after_dig_node = function(pos, oldnode, oldmetadata, digger) - -- The legacy-node fixup is done here in a - -- different form from the standard fixup, - -- rather than relying on a standard fixup - -- in an on_dig callback, because some - -- non-standard diggers (such as technic's - -- mining drill) don't respect on_dig. - oldmetadata = data.fixup_oldmetadata(oldmetadata) - for _, stack in ipairs(oldmetadata.inventory[data.wield_inv_name] or {}) do + for _,stack in ipairs(oldmetadata.inventory[def.wield_inv.name] or {}) do if not stack:is_empty() then minetest.add_item(pos, stack) end @@ -249,7 +203,6 @@ local function register_wielder(data) pipeworks.scan_for_tube_objects(pos) end, on_rotate = pipeworks.on_rotate, - on_punch = data.fixup_node, allow_metadata_inventory_put = function(pos, listname, index, stack, player) if not pipeworks.may_configure(pos, player) then return 0 end return stack:get_count() @@ -261,212 +214,141 @@ local function register_wielder(data) allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) if not pipeworks.may_configure(pos, player) then return 0 end return count - end + end, + on_receive_fields = function(pos, _, fields, sender) + if not fields.channel or not pipeworks.may_configure(pos, sender) then + return + end + minetest.get_meta(pos):set_string("channel", fields.channel) + end, }) end + table.insert(pipeworks.ui_cat_tube_list, def.name.."_off") +end + +local function get_tiles(name, stateful) + local tiles = {on = {}, off = {}} + for _,state in ipairs({"off", "on"}) do + for _,side in ipairs({"top", "bottom", "side2", "side1", "back", "front"}) do + local suffix = stateful[side] and "_"..state or "" + table.insert(tiles[state], "pipeworks_"..name.."_"..side..suffix..".png") + end + end + return tiles end if pipeworks.enable_node_breaker then - local data - -- see after end of data table for other use of these variables - local name_base = "pipeworks:nodebreaker" - local wield_inv_name = "pick" - data = { - name_base = name_base, + pipeworks.register_wielder({ + name = "pipeworks:nodebreaker", description = S("Node Breaker"), - texture_base = "pipeworks_nodebreaker", - texture_stateful = { top = true, bottom = true, side2 = true, side1 = true, front = true }, - tube_connect_sides = { top=1, bottom=1, left=1, right=1, back=1 }, - tube_permit_anteroposterior_insert = false, - wield_inv_name = wield_inv_name, - wield_inv_width = 1, - wield_inv_height = 1, - can_dig_nonempty_wield_inv = true, - ghost_inv_name = "ghost_pick", - ghost_tool = ":", -- hand by default - fixup_node = function (pos, node) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - -- Node breakers predating the visible pick slot - -- may have been partially updated. This code - -- fully updates them. Some have been observed - -- to have no pick slot at all; first add one. - if inv:get_size("pick") ~= 1 then - inv:set_size("pick", 1) - end - -- Originally, they had a ghost pick in a "pick" - -- inventory, no other inventory, and no form. - -- The partial update of early with-form node - -- breaker code gives them "ghost_pick" and "main" - -- inventories, but leaves the old ghost pick in - -- the "pick" inventory, and doesn't add a form. - -- First perform that partial update. - if inv:get_size("ghost_pick") ~= 1 then - inv:set_size("ghost_pick", 1) - inv:set_size("main", 100) - end - -- If the node breaker predates the visible pick - -- slot, which we can detect by it not having a - -- form, then the pick slot needs to be cleared - -- of the old ghost pick. - if (meta:get_string("formspec") or "") == "" then - inv:set_stack("pick", 1, ItemStack("")) - end - -- Finally, unconditionally set the formspec - -- and infotext. This not only makes the - -- pick slot visible for node breakers where - -- it wasn't before; it also updates the form - -- for node breakers that had an older version - -- of the form, and sets infotext where it was - -- missing for early with-form node breakers. - set_wielder_formspec(data, meta) - end, - fixup_oldmetadata = function (oldmetadata) - -- Node breakers predating the visible pick slot, - -- with node form, kept their ghost pick in an - -- inventory named "pick", the same name as the - -- later visible pick slot. The pick must be - -- removed to avoid spilling it. - if not oldmetadata.fields.formspec then - return { inventory = { pick = {} }, fields = oldmetadata.fields } + tiles = get_tiles("nodebreaker", {top = 1, bottom = 1, side2 = 1, side1 = 1, front = 1}), + connect_sides = {top = 1, bottom = 1, left = 1, right = 1, back = 1}, + wield_inv = {name = "pick", width = 1, height = 1}, + wield_hand = true, + eject_drops = true, + action = function(fakeplayer, pointed) + local stack = fakeplayer:get_wielded_item() + local old_stack = ItemStack(stack) + local item_def = minetest.registered_items[stack:get_name()] + if item_def.on_use then + fakeplayer:set_wielded_item(item_def.on_use(stack, fakeplayer, pointed) or stack) else - return oldmetadata - end - end, - masquerade_as_owner = true, - sneak = false, - act = function(virtplayer, pointed_thing) - if minetest.is_protected(vector.add(virtplayer:get_pos(), assumed_eye_pos), virtplayer:get_player_name()) then - return - end - - --local dname = "nodebreaker.act() " - local wieldstack = virtplayer:get_wielded_item() - local oldwieldstack = ItemStack(wieldstack) - local on_use = (minetest.registered_items[wieldstack:get_name()] or {}).on_use - if on_use then - --pipeworks.logger(dname.."invoking on_use "..tostring(on_use)) - wieldstack = on_use(wieldstack, virtplayer, pointed_thing) or wieldstack - virtplayer:set_wielded_item(wieldstack) - else - local under_node = minetest.get_node(pointed_thing.under) - local def = minetest.registered_nodes[under_node.name] - if not def then - -- do not dig an unknown node + local node = minetest.get_node(pointed.under) + local node_def = minetest.registered_nodes[node.name] + if not node_def or not node_def.on_dig then return end - -- check that the current tool is capable of destroying the - -- target node. - -- if we can't, don't dig, and leave the wield stack unchanged. - -- note that wieldstack:get_tool_capabilities() returns hand - -- properties if the item has none of it's own. - if can_tool_dig_node(under_node.name, - wieldstack:get_tool_capabilities(), - wieldstack:get_name()) then - def.on_dig(pointed_thing.under, under_node, virtplayer) - local sound = def.sounds and def.sounds.dug - if sound then - minetest.sound_play(sound.name, - {pos=pointed_thing.under, gain=sound.gain}) + -- Check if the tool can dig the node + local tool = stack:get_tool_capabilities() + if not minetest.get_dig_params(node_def.groups, tool).diggable then + -- Try using hand if tool can't dig the node + local hand = ItemStack():get_tool_capabilities() + if not minetest.get_dig_params(node_def.groups, hand).diggable then + return end - wieldstack = virtplayer:get_wielded_item() - --~ else - --pipeworks.logger(dname.."couldn't dig node!") end + -- This must only check for false, because `on_dig` returning nil is the same as returning true. + if node_def.on_dig(pointed.under, node, fakeplayer) == false then + return + end + local sound = node_def.sounds and node_def.sounds.dug + if sound then + minetest.sound_play(sound, {pos = pointed.under}, true) + end + stack = fakeplayer:get_wielded_item() end - local wieldname = wieldstack:get_name() - if wieldname == oldwieldstack:get_name() then - -- don't mechanically wear out tool - if wieldstack:get_count() == oldwieldstack:get_count() and - wieldstack:get_metadata() == oldwieldstack:get_metadata() and - ((minetest.registered_items[wieldstack:get_name()] or {}).wear_represents or "mechanical_wear") == "mechanical_wear" then - virtplayer:set_wielded_item(oldwieldstack) + if stack:get_name() == old_stack:get_name() then + -- Don't mechanically wear out tool + if stack:get_wear() ~= old_stack:get_wear() and stack:get_count() == old_stack:get_count() + and (item_def.wear_represents == nil or item_def.wear_represents == "mechanical_wear") then + print("replaced") + fakeplayer:set_wielded_item(old_stack) end - elseif wieldname ~= "" then - -- tool got replaced by something else: - -- treat it as a drop - virtplayer:get_inventory():add_item("main", wieldstack) - virtplayer:set_wielded_item(ItemStack("")) + elseif not stack:is_empty() then + -- Tool got replaced by something else, treat it as a drop. + fakeplayer:get_inventory():add_item("main", stack) + fakeplayer:set_wielded_item("") end end, - eject_drops = true, - } - register_wielder(data) - pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:nodebreaker_off" - -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks + }) minetest.register_alias("technic:nodebreaker_off", "pipeworks:nodebreaker_off") minetest.register_alias("technic:nodebreaker_on", "pipeworks:nodebreaker_on") minetest.register_alias("technic:node_breaker_off", "pipeworks:nodebreaker_off") minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on") - -- turn legacy auto-tree-taps into node breakers - dofile(pipeworks.modpath.."/legacy.lua") - - -- register LBM for transition to cheaper node breakers - local lbm_id = "pipeworks:refund_node_breaker_pick" - minetest.register_lbm({ - name = lbm_id, - label = "Give back mese pick for pre-transition node breakers", - run_at_every_load = false, - nodenames = { name_base.."_on", name_base.."_off" }, - action = function(pos, node) - pipeworks.logger(lbm_id.." entry, nodename="..node.name) - local invref = minetest.get_meta(pos):get_inventory() - invref:add_item(wield_inv_name, ItemStack("default:pick_mese")) - end - }) + minetest.register_alias("auto_tree_tap:off", "pipeworks:nodebreaker_off") + minetest.register_alias("auto_tree_tap:on", "pipeworks:nodebreaker_on") end if pipeworks.enable_deployer then - register_wielder({ - name_base = "pipeworks:deployer", + pipeworks.register_wielder({ + name = "pipeworks:deployer", description = S("Deployer"), - texture_base = "pipeworks_deployer", - texture_stateful = { front = true }, - tube_connect_sides = { back=1 }, - tube_permit_anteroposterior_insert = true, - wield_inv_name = "main", - wield_inv_width = 3, - wield_inv_height = 3, - can_dig_nonempty_wield_inv = false, - masquerade_as_owner = true, - sneak = false, - act = function(virtplayer, pointed_thing) - if minetest.is_protected(vector.add(virtplayer:get_pos(), assumed_eye_pos), virtplayer:get_player_name()) then - return + tiles = get_tiles("deployer", {front = 1}), + connect_sides = {back = 1}, + wield_inv = {name = "main", width = 3, height = 3}, + action = function(fakeplayer, pointed) + local stack = fakeplayer:get_wielded_item() + local def = minetest.registered_items[stack:get_name()] + if def and def.on_place then + local new_stack, placed_pos = def.on_place(stack, fakeplayer, pointed) + fakeplayer:set_wielded_item(new_stack or stack) + -- minetest.item_place_node doesn't play sound to the placer + local sound = placed_pos and def.sounds and def.sounds.place + local name = fakeplayer:get_player_name() + if sound and name ~= "" then + minetest.sound_play(sound, {pos = placed_pos, to_player = name}, true) + end end - - local wieldstack = virtplayer:get_wielded_item() - virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or {on_place=minetest.item_place}).on_place(wieldstack, virtplayer, pointed_thing) or wieldstack) end, - eject_drops = false, }) - pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:deployer_off" - -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off") minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on") end if pipeworks.enable_dispenser then - register_wielder({ - name_base = "pipeworks:dispenser", + -- Override minetest.item_drop to negate its hardcoded offset + -- when the dropper is a fake player. + local item_drop = minetest.item_drop + -- luacheck: ignore 122 + function minetest.item_drop(stack, dropper, pos) + if dropper and dropper.is_fake_player then + pos = vector.new(pos.x, pos.y - 1.2, pos.z) + end + return item_drop(stack, dropper, pos) + end + pipeworks.register_wielder({ + name = "pipeworks:dispenser", description = S("Dispenser"), - texture_base = "pipeworks_dispenser", - texture_stateful = { front = true }, - tube_connect_sides = { back=1 }, - tube_permit_anteroposterior_insert = true, - wield_inv_name = "main", - wield_inv_width = 3, - wield_inv_height = 3, - can_dig_nonempty_wield_inv = false, - masquerade_as_owner = false, - sneak = true, - act = function(virtplayer, pointed_thing) - local wieldstack = virtplayer:get_wielded_item() - virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or - {on_drop=minetest.item_drop}).on_drop(wieldstack, virtplayer, virtplayer:get_pos()) or - wieldstack) + tiles = get_tiles("dispenser", {front = 1}), + connect_sides = {back = 1}, + wield_inv = {name = "main", width = 3, height = 3}, + action = function(fakeplayer) + local stack = fakeplayer:get_wielded_item() + local def = minetest.registered_items[stack:get_name()] + if def and def.on_drop then + local pos = fakeplayer:get_pos() + fakeplayer:set_wielded_item(def.on_drop(stack, fakeplayer, pos) or stack) + end end, - eject_drops = false, }) - pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:dispenser_off" end