1 Commits

Author SHA1 Message Date
3a01f3f8ca fix chest duplication bug
closes #118
2024-03-17 20:06:35 +01:00
21 changed files with 1171 additions and 729 deletions

View File

@ -1,7 +1,6 @@
unused_args = false unused_args = false
max_line_length= 240 max_line_length= 240
redefined = false redefined = false
std = "minetest+max"
globals = { globals = {
"pipeworks", "pipeworks",
@ -9,9 +8,19 @@ globals = {
} }
read_globals = { read_globals = {
-- Stdlib
string = {fields = {"split"}},
table = {fields = {"copy", "getn"}},
-- Minetest
"vector", "ItemStack",
"dump", "minetest",
"VoxelManip", "VoxelArea",
-- mods -- mods
"default", "mesecon", "digiline", "default", "mesecon", "digiline",
"screwdriver", "unified_inventory", "screwdriver", "unified_inventory",
"i3", "mcl_experience", "awards", "i3", "mcl_experience", "awards",
"xcompat", "fakelib", "vizlib" "xcompat",
} }

View File

@ -256,11 +256,8 @@ local function run_autocrafter(pos, elapsed)
local inventory = meta:get_inventory() local inventory = meta:get_inventory()
local craft = get_craft(pos, inventory) local craft = get_craft(pos, inventory)
local output_item = craft.output.item local output_item = craft.output.item
-- NALC: existence de limitgroup ?
local limitcraft = minetest.get_item_group(output_item:get_name(), "limitcraft") or 0
-- only use crafts that have an actual result -- only use crafts that have an actual result
-- NALC: ou si l'item n'est pas dans le group limitcraft if output_item:is_empty() then
if output_item:is_empty() or limitcraft > 0 then
meta:set_string("infotext", S("unconfigured Autocrafter: unknown recipe")) meta:set_string("infotext", S("unconfigured Autocrafter: unknown recipe"))
return false return false
end end
@ -601,12 +598,11 @@ minetest.register_node("pipeworks:autocrafter", {
if #msg < 3 then return end if #msg < 3 then return end
local inv = meta:get_inventory() local inv = meta:get_inventory()
for y = 0, 2, 1 do for y = 0, 2, 1 do
local row = msg[y + 1]
for x = 1, 3, 1 do for x = 1, 3, 1 do
local slot = y * 3 + x local slot = y * 3 + x
if type(row) == "table" and minetest.registered_items[row[x]] then if minetest.registered_items[msg[y + 1][x]] then
inv:set_stack("recipe", slot, ItemStack( inv:set_stack("recipe", slot, ItemStack(
row[x])) msg[y + 1][x]))
else else
inv:set_stack("recipe", slot, ItemStack("")) inv:set_stack("recipe", slot, ItemStack(""))
end end

View File

@ -211,7 +211,7 @@ function pipeworks.scan_pipe_surroundings(pos)
pzm = 1 pzm = 1
end end
minetest.log("info", "stage 2 returns "..pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp.. print("stage 2 returns "..pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp..
" for nodes surrounding "..minetest.get_node(pos).name.." at "..minetest.pos_to_string(pos)) " for nodes surrounding "..minetest.get_node(pos).name.." at "..minetest.pos_to_string(pos))
return pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp return pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp
end end

View File

@ -11,7 +11,7 @@ local function nodeside(node, tubedir)
end end
local backdir = minetest.facedir_to_dir(node.param2) local backdir = minetest.facedir_to_dir(node.param2)
local back = vector.dot(backdir, tubedir) local back = pipeworks.vector_dot(backdir, tubedir)
if back == 1 then if back == 1 then
return "back" return "back"
elseif back == -1 then elseif back == -1 then
@ -19,7 +19,7 @@ local function nodeside(node, tubedir)
end end
local topdir = pipeworks.facedir_to_top_dir(node.param2) local topdir = pipeworks.facedir_to_top_dir(node.param2)
local top = vector.dot(topdir, tubedir) local top = pipeworks.vector_dot(topdir, tubedir)
if top == 1 then if top == 1 then
return "top" return "top"
elseif top == -1 then elseif top == -1 then
@ -27,7 +27,7 @@ local function nodeside(node, tubedir)
end end
local rightdir = pipeworks.facedir_to_right_dir(node.param2) local rightdir = pipeworks.facedir_to_right_dir(node.param2)
local right = vector.dot(rightdir, tubedir) local right = pipeworks.vector_dot(rightdir, tubedir)
if right == 1 then if right == 1 then
return "right" return "right"
else else

View File

@ -1,90 +0,0 @@
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_node 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

View File

@ -15,17 +15,7 @@ pipeworks.rules_all = {{x=0, y=0, z=1},{x=0, y=0, z=-1},{x=1, y=0, z=0},{x=-1, y
{x=0, y=1, z=0}, {x=0, y=-1, z=0}} {x=0, y=1, z=0}, {x=0, y=-1, z=0}}
pipeworks.mesecons_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}} pipeworks.mesecons_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}}
pipeworks.digilines_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}}
local digilines_enabled = minetest.get_modpath("digilines") ~= nil
if digilines_enabled and pipeworks.enable_vertical_digilines_connectivity then
pipeworks.digilines_rules=digiline.rules.default
else
-- These rules break vertical connectivity to deployers, node breakers, dispensers, and digiline filter injectors
-- via digiline conducting tubes. Changing them may break some builds on some servers, so the setting was added
-- for server admins to be able to revert to the old "broken" behavior as some builds may use it as a "feature".
-- See https://github.com/mt-mods/pipeworks/issues/64
pipeworks.digilines_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}}
end
pipeworks.liquid_texture = minetest.registered_nodes[pipeworks.liquids.water.flowing].tiles[1] pipeworks.liquid_texture = minetest.registered_nodes[pipeworks.liquids.water.flowing].tiles[1]
if type(pipeworks.liquid_texture) == "table" then pipeworks.liquid_texture = pipeworks.liquid_texture.name end if type(pipeworks.liquid_texture) == "table" then pipeworks.liquid_texture = pipeworks.liquid_texture.name end
@ -101,6 +91,22 @@ function pipeworks.replace_name(tbl,tr,name)
return ntbl return ntbl
end 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 -- -- Facedir functions --
----------------------- -----------------------
@ -116,7 +122,7 @@ function pipeworks.facedir_to_top_dir(facedir)
end end
function pipeworks.facedir_to_right_dir(facedir) function pipeworks.facedir_to_right_dir(facedir)
return vector.cross( return pipeworks.vector_cross(
pipeworks.facedir_to_top_dir(facedir), pipeworks.facedir_to_top_dir(facedir),
minetest.facedir_to_dir(facedir) minetest.facedir_to_dir(facedir)
) )
@ -136,10 +142,29 @@ function directions.side_to_dir(side)
end end
function directions.dir_to_side(dir) function directions.dir_to_side(dir)
local c = vector.dot(dir, vector.new(1, 2, 3)) + 4 local c = pipeworks.vector_dot(dir, vector.new(1, 2, 3)) + 4
return ({6, 2, 4, 0, 3, 1, 5})[c] return ({6, 2, 4, 0, 3, 1, 5})[c]
end 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 -- -- Table functions --
--------------------- ---------------------
@ -183,7 +208,7 @@ pipeworks.fs_helpers = fs_helpers
function fs_helpers.on_receive_fields(pos, fields) function fs_helpers.on_receive_fields(pos, fields)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
for field in pairs(fields) do for field in pairs(fields) do
if field:match("^fs_helpers_cycling:") then if pipeworks.string_startswith(field, "fs_helpers_cycling:") then
local l = field:split(":") local l = field:split(":")
local new_value = tonumber(l[2]) local new_value = tonumber(l[2])
local meta_name = l[3] local meta_name = l[3]
@ -300,5 +325,278 @@ function pipeworks.load_position(pos)
vm:read_from_map(pos, pos) vm:read_from_map(pos, pos)
end end
-- Kept for compatibility with old mods local function delay(...)
pipeworks.create_fake_player = fakelib.create_player 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

View File

@ -1,11 +1,34 @@
-- this bit of code overrides the default chests from common games (mtg, hades, minclone*) to be -- this bit of code modifies the default chests and furnaces to be compatible
-- compatible with pipeworks. Where possible, it overrides their formspec to add a splitstacks switch -- with pipeworks.
--
-- the formspecs found here are basically copies of the ones from minetest_game
-- plus bits from pipeworks' sorting tubes
-- Pipeworks Specific
local fs_helpers = pipeworks.fs_helpers local fs_helpers = pipeworks.fs_helpers
local tube_entry = "^pipeworks_tube_connection_wooden.png"
-- formspec helper to add the splitstacks switch -- Chest Locals
local function add_pipeworks_switch(formspec, pos) local open_chests = {}
-- based on the sorting tubes
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 .. formspec = formspec ..
fs_helpers.cycling_button( fs_helpers.cycling_button(
minetest.get_meta(pos), minetest.get_meta(pos),
@ -16,169 +39,271 @@ local function add_pipeworks_switch(formspec, pos)
pipeworks.button_on pipeworks.button_on
} }
)..pipeworks.button_label )..pipeworks.button_label
return formspec 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
if minetest.get_modpath("default") then
-- 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 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]"
end
return out
end end
-- get the fields from the chest formspec, we can do this bc. newest functions are called first function get_chest_formspec(pos)
-- https://github.com/minetest/minetest/blob/d4b10db998ebeb689b3d27368e30952a42169d03/doc/lua_api.md?plain=1#L5840 local spos = pos.x .. "," .. pos.y .. "," .. pos.z
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()
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)
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
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
}
-- 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 = local formspec =
"size[10,9]".. "size[10,9]" ..
"list[nodemeta:".. spos .. ";main;0,0;10,4;]".. "background9[8,8;8,9;hades_chests_chestui.png;true;8]"..
"list[current_player;main;0,5;10,4;]".. "list[nodemeta:" .. spos .. ";main;0,0.3;10,4;]" ..
"listring[]".. "list[current_player;main;0,4.85;10,1;]" ..
"background9[8,8;10,9;hades_chests_chestui.png;true;8]" "list[current_player;main;0,6.08;10,3;10]" ..
"listring[nodemeta:" .. spos .. ";main]" ..
"listring[current_player;main]" ..
get_hotbar_bg(0,4.85)
-- change from pipeworks -- Pipeworks Switch
local new_fs = add_pipeworks_switch(formspec, pos) formspec = formspec ..
return new_fs 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
end
local function has_locked_chest_privilege(meta, player) local function chest_lid_obstructed(pos)
local name = player:get_player_name() local above = { x = pos.x, y = pos.y + 1, z = pos.z }
if name ~= meta:get_string("owner") and not minetest.check_player_privs(name, "protection_bypass") then 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 return false
end end
return true return true
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "pipeworks:chest_formspec" and player then
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)
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 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
end, minetest.after(0.2, function()
on_rotate = screwdriver.rotate_simple if minetest.get_modpath("default") then
} local current_node = minetest.get_node(pos)
if current_node.name ~= "default:" .. swap .. "_open" then
-- get the fields from the chest formspec, we can do this bc. newest functions are called first -- the chest has already been replaced, don't try to replace what's there.
-- https://github.com/minetest/minetest/blob/d4b10db998ebeb689b3d27368e30952a42169d03/doc/lua_api.md?plain=1#L5840 -- see: https://github.com/minetest/minetest_game/pull/3046
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.quit or formname ~= "hades_chests:chest_locked" then
return return
end end
local pn = player:get_player_name() minetest.swap_node(pos, { name = "default:" .. swap, param2 = node.param2 })
local pos = open_chests[pn] end
if pos and pipeworks.may_configure(pos, player) then
-- 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 -- Pipeworks Switch
fs_helpers.on_receive_fields(pos, fields) fs_helpers.on_receive_fields(pos, fields)
minetest.show_formspec(pn, "hades_chests:chest_locked", get_locked_chest_formspec(pos)) minetest.show_formspec(player:get_player_name(), "pipeworks:chest_formspec", get_chest_formspec(pos))
end end
-- Do NOT return true here, the callback from hades still needs to run (if they add one) return true
return false end
end) end
end)
local connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1} -- Original Definitions
pipeworks.override_chest(chestname, override, connect_sides) local old_chest_def, old_chest_open_def, old_chest_locked_def, old_chest_locked_open_def
pipeworks.override_chest(chestname_protected, override_protected, connect_sides) if minetest.get_modpath("default") then
end old_chest_def = table.copy(minetest.registered_items["default:chest"])
elseif minetest.get_modpath("mcl_barrels") then old_chest_open_def = table.copy(minetest.registered_items["default:chest_open"])
-- TODO: bring splitstacks switch in the formspec old_chest_locked_def = table.copy(minetest.registered_items["default:chest_locked"])
-- with the current implementation of mcl_barrels this would mean to duplicate a lot of code from there... old_chest_locked_open_def = table.copy(minetest.registered_items["default:chest_locked_open"])
local connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1} elseif minetest.get_modpath("hades_chests") then
pipeworks.override_chest("mcl_barrels:barrel_closed", {}, connect_sides) old_chest_def = table.copy(minetest.registered_items["hades_chests:chest"])
pipeworks.override_chest("mcl_barrels:barrel_open", {}, connect_sides) 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"])
end 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

View File

@ -31,7 +31,6 @@ local settings = {
delete_item_on_clearobject = true, delete_item_on_clearobject = true,
use_real_entities = true, use_real_entities = true,
entity_update_interval = 0, entity_update_interval = 0,
enable_vertical_digilines_connectivity = false,
} }
pipeworks.toggles = {} pipeworks.toggles = {}

View File

@ -84,7 +84,9 @@ local function punch_filter(data, filtpos, filtnode, msg)
local filtmeta = minetest.get_meta(filtpos) local filtmeta = minetest.get_meta(filtpos)
local filtinv = filtmeta:get_inventory() local filtinv = filtmeta:get_inventory()
local owner = filtmeta:get_string("owner") local owner = filtmeta:get_string("owner")
local fakeplayer = fakelib.create_player(owner) local fakePlayer = pipeworks.create_fake_player({
name = owner
})
local dir = pipeworks.facedir_to_right_dir(filtnode.param2) local dir = pipeworks.facedir_to_right_dir(filtnode.param2)
local frompos = vector.subtract(filtpos, dir) local frompos = vector.subtract(filtpos, dir)
local fromnode = minetest.get_node(frompos) local fromnode = minetest.get_node(frompos)
@ -199,13 +201,11 @@ local function punch_filter(data, filtpos, filtnode, msg)
set_filter_formspec(data, filtmeta) set_filter_formspec(data, filtmeta)
end end
if pipeworks.enable_item_tags then
if type(msg.tags) == "table" or type(msg.tags) == "string" then if type(msg.tags) == "table" or type(msg.tags) == "string" then
item_tags = pipeworks.sanitize_tags(msg.tags) item_tags = pipeworks.sanitize_tags(msg.tags)
elseif type(msg.tag) == "string" then elseif type(msg.tag) == "string" then
item_tags = pipeworks.sanitize_tags({msg.tag}) item_tags = pipeworks.sanitize_tags({msg.tag})
end end
end
if msg.nofire then if msg.nofire then
return return
@ -320,7 +320,7 @@ local function punch_filter(data, filtpos, filtnode, msg)
if fromtube.can_remove then if fromtube.can_remove then
doRemove = fromtube.can_remove(frompos, fromnode, stack, dir, frominvname, spos) doRemove = fromtube.can_remove(frompos, fromnode, stack, dir, frominvname, spos)
elseif fromdef.allow_metadata_inventory_take then 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 end
-- stupid lack of continue statements grumble -- stupid lack of continue statements grumble
if doRemove > 0 then if doRemove > 0 then
@ -354,13 +354,13 @@ local function punch_filter(data, filtpos, filtnode, msg)
item = stack:take_item(count) item = stack:take_item(count)
frominv:set_stack(frominvname, spos, stack) frominv:set_stack(frominvname, spos, stack)
if fromdef.on_metadata_inventory_take then 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
end end
local pos = vector.add(frompos, vector.multiply(dir, 1.4)) local pos = vector.add(frompos, vector.multiply(dir, 1.4))
local start_pos = vector.add(frompos, dir) local start_pos = vector.add(frompos, dir)
pipeworks.tube_inject_item(pos, start_pos, dir, item, pipeworks.tube_inject_item(pos, start_pos, dir, item,
fakeplayer:get_player_name(), item_tags) fakePlayer:get_player_name(), item_tags)
return true -- only fire one item, please return true -- only fire one item, please
end end
end end
@ -451,6 +451,11 @@ for _, data in ipairs({
if not pipeworks.may_configure(pos, player) then return 0 end if not pipeworks.may_configure(pos, player) then return 0 end
return count return count
end, end,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("main")
end,
tube = {connect_sides = {right = 1}}, tube = {connect_sides = {right = 1}},
} }

View File

@ -59,7 +59,6 @@ dofile(pipeworks.modpath.."/luaentity.lua")
dofile(pipeworks.modpath.."/item_transport.lua") dofile(pipeworks.modpath.."/item_transport.lua")
dofile(pipeworks.modpath.."/flowing_logic.lua") dofile(pipeworks.modpath.."/flowing_logic.lua")
dofile(pipeworks.modpath.."/filter-injector.lua") dofile(pipeworks.modpath.."/filter-injector.lua")
dofile(pipeworks.modpath.."/chests.lua")
dofile(pipeworks.modpath.."/trashcan.lua") dofile(pipeworks.modpath.."/trashcan.lua")
dofile(pipeworks.modpath.."/wielder.lua") dofile(pipeworks.modpath.."/wielder.lua")
dofile(pipeworks.modpath.."/tubes/registration.lua") dofile(pipeworks.modpath.."/tubes/registration.lua")
@ -96,12 +95,13 @@ end
if pipeworks.enable_pipe_devices then if pipeworks.enable_pipe_devices then
dofile(pipeworks.modpath.."/devices.lua") dofile(pipeworks.modpath.."/devices.lua")
end end
if pipeworks.enable_redefines then
dofile(pipeworks.modpath.."/compat-chests.lua")
end
if pipeworks.enable_redefines and (minetest.get_modpath("default") or minetest.get_modpath("hades_core")) then if pipeworks.enable_redefines and (minetest.get_modpath("default") or minetest.get_modpath("hades_core")) then
dofile(pipeworks.modpath.."/compat-chests.lua")
dofile(pipeworks.modpath.."/compat-furnaces.lua") dofile(pipeworks.modpath.."/compat-furnaces.lua")
end end
if pipeworks.enable_redefines and minetest.get_modpath("mcl_barrels") then
dofile(pipeworks.modpath.."/mcl_barrels.lua")
end
if pipeworks.enable_redefines and minetest.get_modpath("mcl_furnaces") then if pipeworks.enable_redefines and minetest.get_modpath("mcl_furnaces") then
dofile(pipeworks.modpath.."/mcl_furnaces.lua") dofile(pipeworks.modpath.."/mcl_furnaces.lua")
end end

62
legacy.lua Normal file
View File

@ -0,0 +1,62 @@
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 = false,
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

View File

@ -1,121 +0,0 @@
# textdomain: pipeworks
# License: CC-by-SA 4.0
# Author: VinAdmin ovvitalik@gmail.com
## generic interaction
Set=Установить
Cancel=Отмена
## digilines interfacing
Channel=Канал
## init
Allow splitting incoming stacks from tubes=Разрешить разделение входящих стопок из трубок
## autocrafter
Unknown item=Неизвестный предмет
unconfigured Autocrafter: unknown recipe=ненастроенный автокрафтер: неизвестный рецепт
unconfigured Autocrafter=ненастроенный автокрафтер
'@1' Autocrafter (@2)='@1' Автокрафтер (@2)
Save=Сохранить
paused '@1' Autocrafter=приостановлено '@1' Автокрафтер
Autocrafter=Автокрафтер
## compat-furnaces
Allow splitting incoming material (not fuel) stacks from tubes=Разрешить разделение стопок поступающего материала (не топлива) из трубок.
## decorative tubes
Airtight steelblock embedded tube=Герметичная встроенная трубка из стального блока
Airtight panel embedded tube=Герметичная встроенная в панель трубка
## devices
Pump/Intake Module=Модуль насоса/впуска
Valve=Клапан
Decorative grating=Декоративная решетка
Spigot outlet=Выходной патрубок
Airtight Pipe entry/exit=Вход/выход герметичной трубы
Flow Sensor=Датчик потока
Flow sensor (on)=Датчик расхода (вкл.)
empty=пустой
@1% full=@1% заполнено
Expansion Tank (@1)=Расширительный бак (@1)
Fluid Storage Tank (@1)=Резервуар для хранения жидкости (@1)
Fountainhead=Источник
Straight-only Pipe=Только прямая труба
## filter-injector
(slot #@1 next)=(слот #@1 следующий)
@1 Filter-Injector=@1 фильтр-инжектор
Sequence slots by Priority=Последовательность слотов по приоритету
Sequence slots Randomly=Слоты последовательности Случайный
Sequence slots by Rotation=Последовательность слотов по вращению
Exact match - off=Точное совпадение выключено
Exact match - on=Точное совпадение - включено
Prefer item types:=Предпочитаете типы предметов:
Itemwise=По пунктам
Stackwise=Стекообразно
Digiline=Диджилайн
## legacy
Auto-Tap=Авто-нажатие
## pipes
Pipe Segment=Сегмент трубы
Pipe Segment (legacy)=Сегмент трубы (устаревший)
## routing tubes
Pneumatic tube segment=Сегмент пневматической трубки
Broken Tube=Сломанная трубка
High Priority Tube Segment=Сегмент трубы с высоким приоритетом
Accelerating Pneumatic Tube Segment=Ускорительный сегмент пневматической трубки
Crossing Pneumatic Tube Segment=Пересечение сегмента пневматической трубы
One way tube=Односторонняя трубка
## signal tubes
Detecting Pneumatic Tube Segment on=Обнаружение сегмента пневматической трубки включено
Detecting Pneumatic Tube Segment=Обнаружение сегмента пневматической трубки
Digiline Detecting Pneumatic Tube Segment=Digiline обнаруживает сегмент пневматической трубки
Digiline Detecting Tube=Детекторная трубка Digiline
Conducting Pneumatic Tube Segment=Проводящий сегмент пневматической трубки
Conducting Pneumatic Tube Segment on=Проводящий сегмент пневматической трубки на
Digiline Conducting Pneumatic Tube Segment=Сегмент проводящей пневматической трубки Digiline
Mesecon and Digiline Conducting Pneumatic Tube Segment=Сегмент токопроводящей пневматической трубки Mesecon и Digiline
Mesecon and Digiline Conducting Pneumatic Tube Segment on=Сегмент проводящей пневматической трубки Mesecon и Digiline на
Tag Sorting Pneumatic Tube Segment=Сегмент пневматической трубки для сортировки тегов
Lua controlled Tube=Трубка, управляемая Lua
## sorting tubes
Sorting Pneumatic Tube Segment=Сортировка сегментов пневматической трубки
Sorting pneumatic tube=Сортировочная пневматическая труба
## teleport tube
Receive=Получить
Channels are public by default=По умолчанию каналы являются общедоступными
Use <player>:<channel> for fully private channels=Используйте <игрок>:<канал> для полностью приватных каналов
Use <player>;<channel> for private receivers=Используйте <игрок>;<канал> для частных приемников
Teleporting Pneumatic Tube Segment=Сегмент пневматической трубы для телепортации
Teleporting Tube=Телепортационная труба
Unconfigured Teleportation Tube=Неконфигурированная телепортационная труба
Sorry, channel '@1' is reserved for exclusive use by @2=Извините, канал '@1' зарезервирован исключительно для использования @2
Sorry, receiving from channel '@1' is reserved for @2=Извините, прием с канала '@1' зарезервирован для @2
Teleportation Tube @1 on '@2'=Трубка телепортации @1 на '@2'
## trashcan
Trash Can=Мусорное ведро
## tube registration
Pneumatic tube segment (legacy)=Сегмент пневматической трубы (устаревший)
## vacuum tubes
Radius=Радиус
Vacuuming Pneumatic Tube Segment=Сегмент пневматической трубки для вакуумирования
Adjustable Vacuuming Tube=Регулируемая вакуумная трубка
Adjustable Vacuuming Pneumatic Tube Segment=Регулируемый сегмент вакуумной пневматической трубки
Adjustable Vacuuming Pneumatic Tube Segment (@1m)=Регулируемый сегмент вакуумной пневматической трубки (@1m)
## wielder
Node Breaker=Разрушитель узла
Deployer=Развертыватель
Dispenser=Распылитель

View File

@ -67,41 +67,36 @@ end
minetest.register_on_shutdown(write_entities) minetest.register_on_shutdown(write_entities)
luaentity.entities_index = 0 luaentity.entities_index = 0
local function get_blockpos(pos)
return {x = math.floor(pos.x / 16),
y = math.floor(pos.y / 16),
z = math.floor(pos.z / 16)}
end
local move_entities_globalstep_part1 local move_entities_globalstep_part1
local is_active local is_active
if pipeworks.use_real_entities then if pipeworks.use_real_entities then
local active_blocks = {} -- These only contain active blocks near players (i.e., not forceloaded ones) local active_blocks = {} -- These only contain active blocks near players (i.e., not forceloaded ones)
local function get_blockpos(pos)
return {x = math.floor(pos.x / 16),
y = math.floor(pos.y / 16),
z = math.floor(pos.z / 16)}
end
move_entities_globalstep_part1 = function(dtime) move_entities_globalstep_part1 = function(dtime)
local active_block_range = tonumber(minetest.settings:get("active_block_range")) or 2 local active_block_range = tonumber(minetest.settings:get("active_block_range")) or 2
for key in pairs(active_blocks) do local new_active_blocks = {}
active_blocks[key] = nil
end
for _, player in ipairs(minetest.get_connected_players()) do for _, player in ipairs(minetest.get_connected_players()) do
local blockpos = get_blockpos(player:get_pos()) local blockpos = get_blockpos(player:get_pos())
local minpx = blockpos.x - active_block_range local minp = vector.subtract(blockpos, active_block_range)
local minpy = blockpos.y - active_block_range local maxp = vector.add(blockpos, active_block_range)
local minpz = blockpos.z - active_block_range
local maxpx = blockpos.x + active_block_range
local maxpy = blockpos.y + active_block_range
local maxpz = blockpos.z + active_block_range
for x = minpx, maxpx do for x = minp.x, maxp.x do
for y = minpy, maxpy do for y = minp.y, maxp.y do
for z = minpz, maxpz do for z = minp.z, maxp.z do
local pos = {x = x, y = y, z = z} local pos = {x = x, y = y, z = z}
active_blocks[minetest.hash_node_position(pos)] = true new_active_blocks[minetest.hash_node_position(pos)] = pos
end end
end end
end end
end end
active_blocks = new_active_blocks
-- todo: callbacks on block load/unload -- todo: callbacks on block load/unload
end end

72
mcl_barrels.lua Normal file
View File

@ -0,0 +1,72 @@
-- 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)

View File

@ -1,5 +1,5 @@
name = pipeworks 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. 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, xcompat, fakelib depends = basic_materials, xcompat
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, vizlib 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 min_minetest_version = 5.5.0

View File

@ -85,17 +85,5 @@ pipeworks_use_real_entities (Use Real Entities) bool true
#A value 0.2 or above may cause issues with accelerator tubes. #A value 0.2 or above may cause issues with accelerator tubes.
pipeworks_entity_update_interval (Entity Update Interval) float 0 0 0.8 pipeworks_entity_update_interval (Entity Update Interval) float 0 0 0.8
# Use the default rules from the digilines mod.
# If enabled the following devices will connect to digiline networks in the vertical direction:
# digiline filter injector, deployer, dispenser, node breaker, autocrafter
# This breaks expected behavior with digiline conducting tubes.
# If disabled, the devices will not be able to send or recieve digiline signals from the top
# or bottom faces, regardless of the node rotation.
enable_vertical_digilines_connectivity (Use the default rules from the digilines mod) bool false
# if set to true, items passing through teleport tubes will log log where they came from and where they went. # if set to true, items passing through teleport tubes will log log where they came from and where they went.
pipeworks_log_teleport_tubes (Log Teleport Tubes) bool false pipeworks_log_teleport_tubes (Log Teleport Tubes) bool false
# Behavior of print() inside a lua tube. By default, this emits a message into actionstream.
# Set it to noop if you wish to disable that behavior.
pipeworks_lua_tube_print_behavior (Behavior of print in Lua Tube) enum log log,noop

View File

@ -229,13 +229,11 @@ end
------------------------- -------------------------
local function safe_print(param) local function safe_print(param)
if (minetest.settings:get("pipeworks_lua_tube_print_behavior") or "log") == "log" then
local string_meta = getmetatable("") local string_meta = getmetatable("")
local sandbox = string_meta.__index local sandbox = string_meta.__index
string_meta.__index = string -- Leave string sandbox temporarily string_meta.__index = string -- Leave string sandbox temporarily
minetest.log("action", string.format("[pipeworks.tubes.lua] print(%s)", dump(param))) print(dump(param))
string_meta.__index = sandbox -- Restore string sandbox string_meta.__index = sandbox -- Restore string sandbox
end
end end
local function safe_date() local function safe_date()
@ -605,7 +603,7 @@ local function save_memory(pos, meta, mem)
meta:set_string("lc_memory", memstring) meta:set_string("lc_memory", memstring)
meta:mark_as_private("lc_memory") meta:mark_as_private("lc_memory")
else else
minetest.log("info", "lua_tube memory overflow. "..memsize_max.." bytes available, " print("Error: lua_tube memory overflow. "..memsize_max.." bytes available, "
..#memstring.." required. Controller overheats.") ..#memstring.." required. Controller overheats.")
burn_controller(pos) burn_controller(pos)
end end

View File

@ -112,6 +112,7 @@ local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, e
key = "node_sound_wood_defaults", key = "node_sound_wood_defaults",
}, },
walkable = true, walkable = true,
stack_max = 99,
basename = name, basename = name,
style = style, style = style,
drop = string.format("%s_%s", name, dropname), drop = string.format("%s_%s", name, dropname),

View File

@ -1,8 +1,6 @@
local S = minetest.get_translator("pipeworks") local S = minetest.get_translator("pipeworks")
local has_vislib = minetest.get_modpath("vizlib")
local enable_max = minetest.settings:get_bool("pipeworks_enable_items_per_tube_limit", true) local enable_max = minetest.settings:get_bool("pipeworks_enable_items_per_tube_limit", true)
local max_items = tonumber(minetest.settings:get("pipeworks_max_items_per_tube")) or 30 local max_items = tonumber(minetest.settings:get("pipeworks_max_items_per_tube")) or 30
max_items = math.ceil(max_items / 2) -- Limit vacuuming to half the max limit max_items = math.ceil(max_items / 2) -- Limit vacuuming to half the max limit
@ -40,15 +38,6 @@ local function repair_tube(pos, was_node)
set_timer(pos) set_timer(pos)
end end
local function show_area(pos, node, player)
if not player or player:get_wielded_item():get_name() ~= "" then
-- Only show area when using an empty hand
return
end
local radius = tonumber(minetest.get_meta(pos):get("dist")) or 2
vizlib.draw_cube(pos, radius + 0.5, {player = player})
end
if pipeworks.enable_sand_tube then if pipeworks.enable_sand_tube then
pipeworks.register_tube("pipeworks:sand_tube", { pipeworks.register_tube("pipeworks:sand_tube", {
description = S("Vacuuming Pneumatic Tube Segment"), description = S("Vacuuming Pneumatic Tube Segment"),
@ -67,7 +56,6 @@ if pipeworks.enable_sand_tube then
vacuum(pos, 2) vacuum(pos, 2)
set_timer(pos) set_timer(pos)
end, end,
on_punch = has_vislib and show_area or nil,
}, },
}) })
end end
@ -113,7 +101,6 @@ if pipeworks.enable_mese_sand_tube then
meta:set_int("dist", dist) meta:set_int("dist", dist)
meta:set_string("infotext", S("Adjustable Vacuuming Tube (@1m)", dist)) meta:set_string("infotext", S("Adjustable Vacuuming Tube (@1m)", dist))
end, end,
on_punch = has_vislib and show_area or nil,
}, },
}) })
end end

View File

@ -1,201 +1,247 @@
local S = minetest.get_translator("pipeworks") local S = minetest.get_translator("pipeworks")
local has_digilines = minetest.get_modpath("digilines") local assumed_eye_pos = vector.new(0, 1.5, 0)
local function set_wielder_formspec(def, meta) local function delay(x)
local width, height = def.wield_inv.width, def.wield_inv.height return (function() return x end)
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_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
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
meta:set_string("formspec", fs)
meta:set_string("infotext", def.description)
end end
local function wielder_action(def, pos, node, index) local function set_wielder_formspec(data, meta)
local meta = minetest.get_meta(pos) local size = "10.2,"..(7+data.wield_inv_height)
local inv = meta:get_inventory() local list_background = ""
local list = inv:get_list(def.wield_inv.name) if minetest.get_modpath("i3") or minetest.get_modpath("mcl_formspec") then
local wield_index list_background = "style_type[box;colors=#666]"
if index then for i=0, data.wield_inv_height-1 do
if list[index] and (def.wield_hand or not list[index]:is_empty()) then for j=0, data.wield_inv_width-1 do
wield_index = index list_background = list_background .. "box[".. ((10-data.wield_inv_width)*0.5)+(i*1.25) ..",".. 1+(j*1.25) ..";1,1;]"
end end
else end
for i, stack in ipairs(list) do 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
end
return diggable
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 if not stack:is_empty() then
wield_index = i wieldindex = i
break break
end 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
end end
if not wield_index and not def.wield_hand then local dir = minetest.facedir_to_dir(wielder_node.param2)
return -- 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 end
local dir = minetest.facedir_to_dir(node.param2) local virtplayer = pipeworks.create_fake_player({
local fakeplayer = fakelib.create_player({ name = data.masquerade_as_owner and wielder_meta:get_string("owner")
name = meta:get_string("owner"), or ":pipeworks:" .. minetest.pos_to_string(wielder_pos),
direction = vector.multiply(dir, -1), formspec = wielder_meta:get_string("formspec"),
position = pos, look_dir = vector.multiply(dir, -1),
look_pitch = pitch,
look_yaw = yaw,
sneak = data.sneak,
position = vector.subtract(wielder_pos, assumed_eye_pos),
inventory = inv, inventory = inv,
wield_index = wield_index or 1, wield_index = wieldindex,
wield_list = def.wield_inv.name, wield_list = wield_inv_name
}) })
-- Under and above positions are intentionally switched.
local pointed = { local pointed_thing = { type="node", under=under_pos, above=above_pos }
type = "node", data.act(virtplayer, pointed_thing)
under = vector.subtract(pos, dir), if data.eject_drops then
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 for i, stack in ipairs(inv:get_list("main")) do
if not stack:is_empty() then if not stack:is_empty() then
pipeworks.tube_inject_item(pos, pos, dir, stack) pipeworks.tube_inject_item(wielder_pos, wielder_pos, dir, stack)
inv:set_stack("main", i, ItemStack("")) inv:set_stack("main", i, ItemStack(""))
end end
end end
end end
end end
local function wielder_on(def, pos, node) local function wielder_off(data, pos, node)
if node.name ~= def.name.."_off" then if node.name == data.name_base.."_on" then
return node.name = data.name_base.."_off"
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.swap_node(pos, node)
minetest.check_for_falling(pos)
end end
end end
local function wielder_digiline_action(def, pos, channel, msg) local function register_wielder(data)
local meta = minetest.get_meta(pos) data.fixup_node = data.fixup_node or function (pos, node) end
local set_channel = meta:get_string("channel") data.fixup_oldmetadata = data.fixup_oldmetadata or function (m) return m end
if channel ~= set_channel then for _, state in ipairs({ "off", "on" }) do
return 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")
end end
if type(msg) ~= "table" then minetest.register_node(data.name_base.."_"..state, {
if type(msg) == "string" then description = data.description,
if msg:sub(1, 8) == "activate" then tiles = tile_images,
msg = {command = "activate", slot = tonumber(msg:sub(9))}
end
else
return
end
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 = { mesecons = {
effector = { effector = {
rules = pipeworks.rules_all, rules = pipeworks.rules_all,
action_on = function(pos, node) action_on = function (pos, node)
wielder_on(def, pos, node) wielder_on(data, pos, node)
end, end,
action_off = function(pos, node) action_off = function (pos, node)
wielder_off(def, pos, node) wielder_off(data, pos, node)
end,
},
},
digilines = {
receptor = {},
effector = {
action = function(pos, _, channel, msg)
wielder_digiline_action(def, pos, channel, msg)
end, end,
}, },
}, },
tube = { tube = {
can_insert = function(pos, node, stack, direction) can_insert = function(pos, node, stack, tubedir)
if def.eject_drops then if not data.tube_permit_anteroposterior_insert then
-- Prevent ejected items from being inserted local nodedir = minetest.facedir_to_dir(node.param2)
local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then
if vector.equals(direction, dir) then
return false return false
end end
end end
local inv = minetest.get_meta(pos):get_inventory() local meta = minetest.get_meta(pos)
return inv:room_for_item(def.wield_inv.name, stack) local inv = meta:get_inventory()
return inv:room_for_item(data.wield_inv_name, stack)
end, end,
insert_object = function(pos, node, stack) insert_object = function(pos, node, stack, tubedir)
local inv = minetest.get_meta(pos):get_inventory() if not data.tube_permit_anteroposterior_insert then
return inv:add_item(def.wield_inv.name, stack) 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)
end, end,
input_inventory = def.wield_inv.name, input_inventory = data.wield_inv_name,
connect_sides = def.connect_sides, connect_sides = data.tube_connect_sides,
can_remove = function(pos, node, stack) can_remove = function(pos, node, stack, tubedir)
return stack:get_count() return stack:get_count()
end, end,
}, },
is_ground_content = false,
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) on_construct = function(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
set_wielder_formspec(data, meta)
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size(def.wield_inv.name, def.wield_inv.width * def.wield_inv.height) inv:set_size(data.wield_inv_name, data.wield_inv_width*data.wield_inv_height)
if def.eject_drops then if data.ghost_inv_name then
inv:set_size("main", 32) inv:set_size(data.ghost_inv_name, 1)
end
if data.eject_drops then
inv:set_size("main", 100)
end end
set_wielder_formspec(def, meta)
end, end,
after_place_node = function(pos, placer) after_place_node = function (pos, placer)
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
if not placer then local placer_pos = placer:get_pos()
return if placer_pos and placer:is_player() then placer_pos = vector.add(placer_pos, assumed_eye_pos) end
end if placer_pos then
local dir = vector.subtract(pos, placer_pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(placer:get_look_dir(), true) node.param2 = minetest.dir_to_facedir(dir, true)
minetest.set_node(pos, node) minetest.set_node(pos, node)
end
minetest.get_meta(pos):set_string("owner", placer:get_player_name()) minetest.get_meta(pos):set_string("owner", placer:get_player_name())
end, 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) after_dig_node = function(pos, oldnode, oldmetadata, digger)
for _,stack in ipairs(oldmetadata.inventory[def.wield_inv.name] or {}) do -- 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
if not stack:is_empty() then if not stack:is_empty() then
minetest.add_item(pos, stack) minetest.add_item(pos, stack)
end end
@ -203,6 +249,7 @@ function pipeworks.register_wielder(def)
pipeworks.scan_for_tube_objects(pos) pipeworks.scan_for_tube_objects(pos)
end, end,
on_rotate = pipeworks.on_rotate, on_rotate = pipeworks.on_rotate,
on_punch = data.fixup_node,
allow_metadata_inventory_put = function(pos, listname, index, stack, player) allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if not pipeworks.may_configure(pos, player) then return 0 end if not pipeworks.may_configure(pos, player) then return 0 end
return stack:get_count() return stack:get_count()
@ -214,141 +261,212 @@ function pipeworks.register_wielder(def)
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) 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 if not pipeworks.may_configure(pos, player) then return 0 end
return count return count
end,
on_receive_fields = function(pos, _, fields, sender)
if not fields.channel or not pipeworks.may_configure(pos, sender) then
return
end end
minetest.get_meta(pos):set_string("channel", fields.channel)
end,
}) })
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 end
if pipeworks.enable_node_breaker then if pipeworks.enable_node_breaker then
pipeworks.register_wielder({ local data
name = "pipeworks:nodebreaker", -- 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,
description = S("Node Breaker"), description = S("Node Breaker"),
tiles = get_tiles("nodebreaker", {top = 1, bottom = 1, side2 = 1, side1 = 1, front = 1}), texture_base = "pipeworks_nodebreaker",
connect_sides = {top = 1, bottom = 1, left = 1, right = 1, back = 1}, texture_stateful = { top = true, bottom = true, side2 = true, side1 = true, front = true },
wield_inv = {name = "pick", width = 1, height = 1}, tube_connect_sides = { top=1, bottom=1, left=1, right=1, back=1 },
wield_hand = true, tube_permit_anteroposterior_insert = false,
eject_drops = true, wield_inv_name = wield_inv_name,
action = function(fakeplayer, pointed) wield_inv_width = 1,
local stack = fakeplayer:get_wielded_item() wield_inv_height = 1,
local old_stack = ItemStack(stack) can_dig_nonempty_wield_inv = true,
local item_def = minetest.registered_items[stack:get_name()] ghost_inv_name = "ghost_pick",
if item_def.on_use then ghost_tool = ":", -- hand by default
stack = item_def.on_use(stack, fakeplayer, pointed) or stack fixup_node = function (pos, node)
fakeplayer:set_wielded_item(stack) 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 }
else else
local node = minetest.get_node(pointed.under) return oldmetadata
local node_def = minetest.registered_nodes[node.name]
if not node_def or not node_def.on_dig then
return
end
-- 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
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
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
fakeplayer:set_wielded_item(old_stack)
end
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
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
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})
end
wieldstack = virtplayer:get_wielded_item()
--~ else
--pipeworks.logger(dname.."couldn't dig node!")
end
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)
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(""))
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_off", "pipeworks:nodebreaker_off")
minetest.register_alias("technic:nodebreaker_on", "pipeworks:nodebreaker_on") 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_off", "pipeworks:nodebreaker_off")
minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on") minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on")
minetest.register_alias("auto_tree_tap:off", "pipeworks:nodebreaker_off") -- turn legacy auto-tree-taps into node breakers
minetest.register_alias("auto_tree_tap:on", "pipeworks:nodebreaker_on") 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
})
end end
if pipeworks.enable_deployer then if pipeworks.enable_deployer then
pipeworks.register_wielder({ register_wielder({
name = "pipeworks:deployer", name_base = "pipeworks:deployer",
description = S("Deployer"), description = S("Deployer"),
tiles = get_tiles("deployer", {front = 1}), texture_base = "pipeworks_deployer",
connect_sides = {back = 1}, texture_stateful = { front = true },
wield_inv = {name = "main", width = 3, height = 3}, tube_connect_sides = { back=1 },
action = function(fakeplayer, pointed) tube_permit_anteroposterior_insert = true,
local stack = fakeplayer:get_wielded_item() wield_inv_name = "main",
local def = minetest.registered_items[stack:get_name()] wield_inv_width = 3,
if def and def.on_place then wield_inv_height = 3,
local new_stack, placed_pos = def.on_place(stack, fakeplayer, pointed) can_dig_nonempty_wield_inv = false,
fakeplayer:set_wielded_item(new_stack or stack) masquerade_as_owner = true,
-- minetest.item_place_node doesn't play sound to the placer sneak = false,
local sound = placed_pos and def.sounds and def.sounds.place act = function(virtplayer, pointed_thing)
local name = fakeplayer:get_player_name() if minetest.is_protected(vector.add(virtplayer:get_pos(), assumed_eye_pos), virtplayer:get_player_name()) then
if sound and name ~= "" then return
minetest.sound_play(sound, {pos = placed_pos, to_player = name}, true)
end
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, 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_off", "pipeworks:deployer_off")
minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on") minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on")
end end
if pipeworks.enable_dispenser then if pipeworks.enable_dispenser then
-- Override minetest.item_drop to negate its hardcoded offset register_wielder({
-- when the dropper is a fake player. name_base = "pipeworks:dispenser",
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"), description = S("Dispenser"),
tiles = get_tiles("dispenser", {front = 1}), texture_base = "pipeworks_dispenser",
connect_sides = {back = 1}, texture_stateful = { front = true },
wield_inv = {name = "main", width = 3, height = 3}, tube_connect_sides = { back=1 },
action = function(fakeplayer) tube_permit_anteroposterior_insert = true,
local stack = fakeplayer:get_wielded_item() wield_inv_name = "main",
local def = minetest.registered_items[stack:get_name()] wield_inv_width = 3,
if def and def.on_drop then wield_inv_height = 3,
local pos = fakeplayer:get_pos() can_dig_nonempty_wield_inv = false,
fakeplayer:set_wielded_item(def.on_drop(stack, fakeplayer, pos) or stack) masquerade_as_owner = false,
end 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)
end, end,
eject_drops = false,
}) })
pipeworks.ui_cat_tube_list[#pipeworks.ui_cat_tube_list+1] = "pipeworks:dispenser_off"
end end