mirror of
https://github.com/sys4-fr/server-nalc.git
synced 2025-07-18 15:40:25 +02:00
merge server with github
This commit is contained in:
487
mods/pipeworks/item_transport.lua
Normal file
487
mods/pipeworks/item_transport.lua
Normal file
@ -0,0 +1,487 @@
|
||||
local function delay(x)
|
||||
return (function() return x 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)
|
||||
-- Take item in any format
|
||||
local stack = ItemStack(item)
|
||||
local obj = luaentity.add_entity(pos, "pipeworks:tubed_item")
|
||||
obj:set_item(stack:to_string())
|
||||
obj.start_pos = vector.new(start_pos)
|
||||
obj:setvelocity(velocity)
|
||||
--obj:set_color("red") -- todo: this is test-only code
|
||||
return obj
|
||||
end
|
||||
|
||||
-- adding two tube functions
|
||||
-- can_remove(pos,node,stack,dir) returns the maximum number of items of that stack that can be removed
|
||||
-- remove_items(pos,node,stack,dir,count) removes count items and returns them
|
||||
-- both optional w/ sensible defaults and fallback to normal allow_* function
|
||||
-- XXX: possibly change insert_object to insert_item
|
||||
|
||||
local function set_filter_infotext(data, meta)
|
||||
local infotext = data.wise_desc.." Filter-Injector"
|
||||
if meta:get_int("slotseq_mode") == 2 then
|
||||
infotext = infotext .. " (slot #"..meta:get_int("slotseq_index").." next)"
|
||||
end
|
||||
meta:set_string("infotext", infotext)
|
||||
end
|
||||
|
||||
local function set_filter_formspec(data, meta)
|
||||
local itemname = data.wise_desc.." Filter-Injector"
|
||||
local formspec = "size[8,8.5]"..
|
||||
"item_image[0,0;1,1;pipeworks:"..data.name.."]"..
|
||||
"label[1,0;"..minetest.formspec_escape(itemname).."]"..
|
||||
"label[0,1;Prefer item types:]"..
|
||||
"list[current_name;main;0,1.5;8,2;]"..
|
||||
fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode",
|
||||
{"Sequence slots by Priority",
|
||||
"Sequence slots Randomly",
|
||||
"Sequence slots by Rotation"})..
|
||||
"list[current_player;main;0,4.5;8,4;]"
|
||||
meta:set_string("formspec", formspec)
|
||||
end
|
||||
|
||||
-- todo SOON: this function has *way too many* parameters
|
||||
local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,fakePlayer,all)
|
||||
local sposes = {}
|
||||
for spos,stack in ipairs(frominv:get_list(frominvname)) do
|
||||
local matches
|
||||
if filtername == "" then
|
||||
matches = stack:get_name() ~= ""
|
||||
else
|
||||
matches = stack:get_name() == filtername
|
||||
end
|
||||
if matches then table.insert(sposes, spos) end
|
||||
end
|
||||
if #sposes == 0 then return false end
|
||||
if slotseq_mode == 1 then
|
||||
for i = #sposes, 2, -1 do
|
||||
local j = math.random(i)
|
||||
local t = sposes[j]
|
||||
sposes[j] = sposes[i]
|
||||
sposes[i] = t
|
||||
end
|
||||
elseif slotseq_mode == 2 then
|
||||
local headpos = filtmeta:get_int("slotseq_index")
|
||||
table.sort(sposes, function (a, b)
|
||||
if a >= headpos then
|
||||
if b < headpos then return true end
|
||||
else
|
||||
if b >= headpos then return false end
|
||||
end
|
||||
return a < b
|
||||
end)
|
||||
end
|
||||
for _, spos in ipairs(sposes) do
|
||||
local stack = frominv:get_stack(frominvname, spos)
|
||||
local doRemove = stack:get_count()
|
||||
if fromtube.can_remove then
|
||||
doRemove = fromtube.can_remove(frompos, fromnode, stack, dir)
|
||||
elseif fromdef.allow_metadata_inventory_take then
|
||||
doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer)
|
||||
end
|
||||
-- stupid lack of continue statements grumble
|
||||
if doRemove > 0 then
|
||||
if slotseq_mode == 2 then
|
||||
local nextpos = spos + 1
|
||||
if nextpos > frominv:get_size(frominvname) then
|
||||
nextpos = 1
|
||||
end
|
||||
filtmeta:set_int("slotseq_index", nextpos)
|
||||
set_filter_infotext(data, filtmeta)
|
||||
end
|
||||
local item
|
||||
local count
|
||||
if all then
|
||||
count = math.min(stack:get_count(), doRemove)
|
||||
else
|
||||
count = 1
|
||||
end
|
||||
if fromtube.remove_items then
|
||||
-- it could be the entire stack...
|
||||
item = fromtube.remove_items(frompos, fromnode, stack, dir, count)
|
||||
else
|
||||
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)
|
||||
end
|
||||
end
|
||||
local pos = vector.add(frompos, vector.multiply(dir, 1.4))
|
||||
local start_pos = vector.add(frompos, dir)
|
||||
local item1 = pipeworks.tube_inject_item(pos, start_pos, dir, item)
|
||||
return true-- only fire one item, please
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function punch_filter(data, filtpos, filtnode)
|
||||
local filtmeta = minetest.get_meta(filtpos)
|
||||
local filtinv = filtmeta:get_inventory()
|
||||
local owner = filtmeta:get_string("owner")
|
||||
local fakePlayer = {
|
||||
get_player_name = delay(owner),
|
||||
} -- TODO: use a mechanism as the wielder one
|
||||
local dir = minetest.facedir_to_right_dir(filtnode.param2)
|
||||
local frompos = vector.subtract(filtpos, dir)
|
||||
local fromnode = minetest.get_node(frompos)
|
||||
if not fromnode then return end
|
||||
local fromdef = minetest.registered_nodes[fromnode.name]
|
||||
if not fromdef then return end
|
||||
local fromtube = fromdef.tube
|
||||
if not (fromtube and fromtube.input_inventory) then return end
|
||||
local filters = {}
|
||||
for _, filterstack in ipairs(filtinv:get_list("main")) do
|
||||
local filtername = filterstack:get_name()
|
||||
if filtername ~= "" then table.insert(filters, filtername) end
|
||||
end
|
||||
if #filters == 0 then table.insert(filters, "") end
|
||||
local slotseq_mode = filtmeta:get_int("slotseq_mode")
|
||||
local frommeta = minetest.get_meta(frompos)
|
||||
local frominv = frommeta:get_inventory()
|
||||
if fromtube.before_filter then fromtube.before_filter(frompos) end
|
||||
for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do
|
||||
local done = false
|
||||
for _, filtername in ipairs(filters) do
|
||||
if grabAndFire(data, slotseq_mode, filtmeta, frominv, frominvname, frompos, fromnode, filtername, fromtube, fromdef, dir, fakePlayer, data.stackwise) then
|
||||
done = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if done then break end
|
||||
end
|
||||
if fromtube.after_filter then fromtube.after_filter(frompos) end
|
||||
end
|
||||
|
||||
for _, data in ipairs({
|
||||
{
|
||||
name = "filter",
|
||||
wise_desc = "Itemwise",
|
||||
stackwise = false,
|
||||
},
|
||||
{
|
||||
name = "mese_filter",
|
||||
wise_desc = "Stackwise",
|
||||
stackwise = true,
|
||||
},
|
||||
}) do
|
||||
minetest.register_node("pipeworks:"..data.name, {
|
||||
description = data.wise_desc.." Filter-Injector",
|
||||
tiles = {
|
||||
"pipeworks_"..data.name.."_top.png",
|
||||
"pipeworks_"..data.name.."_top.png",
|
||||
"pipeworks_"..data.name.."_output.png",
|
||||
"pipeworks_"..data.name.."_input.png",
|
||||
"pipeworks_"..data.name.."_side.png",
|
||||
"pipeworks_"..data.name.."_top.png",
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, mesecon = 2},
|
||||
legacy_facedir_simple = true,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
set_filter_formspec(data, meta)
|
||||
set_filter_infotext(data, meta)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 8*2)
|
||||
end,
|
||||
after_place_node = function (pos, placer)
|
||||
minetest.get_meta(pos):set_string("owner", placer:get_player_name())
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
fs_helpers.on_receive_fields(pos, fields)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("slotseq_index", 1)
|
||||
set_filter_formspec(data, meta)
|
||||
set_filter_infotext(data, meta)
|
||||
end,
|
||||
can_dig = function(pos, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty("main")
|
||||
end,
|
||||
mesecons = {
|
||||
effector = {
|
||||
action_on = function(pos, node)
|
||||
punch_filter(data, pos, node)
|
||||
end,
|
||||
},
|
||||
},
|
||||
tube = {connect_sides = {right = 1}},
|
||||
on_punch = function (pos, node, puncher)
|
||||
punch_filter(data, pos, node)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
local adjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}}
|
||||
|
||||
function pipeworks.notvel(tbl, vel)
|
||||
local tbl2={}
|
||||
for _,val in ipairs(tbl) do
|
||||
if val.x ~= -vel.x or val.y ~= -vel.y or val.z ~= -vel.z then table.insert(tbl2, val) end
|
||||
end
|
||||
return tbl2
|
||||
end
|
||||
|
||||
local function go_next(pos, velocity, stack)
|
||||
local next_positions = {}
|
||||
local max_priority = 0
|
||||
local cnode = minetest.get_node(pos)
|
||||
local cmeta = minetest.get_meta(pos)
|
||||
local can_go
|
||||
local speed = math.abs(velocity.x + velocity.y + velocity.z)
|
||||
if speed == 0 then
|
||||
speed = 1
|
||||
end
|
||||
local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed}
|
||||
if speed >= 4.1 then
|
||||
speed = 4
|
||||
elseif speed >= 1.1 then
|
||||
speed = speed - 0.1
|
||||
else
|
||||
speed = 1
|
||||
end
|
||||
vel.speed = speed
|
||||
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)
|
||||
else
|
||||
can_go = pipeworks.notvel(adjlist, vel)
|
||||
end
|
||||
for _, vect in ipairs(can_go) do
|
||||
local npos = vector.add(pos, vect)
|
||||
local node = minetest.get_node(npos)
|
||||
local reg_node = minetest.registered_nodes[node.name]
|
||||
if reg_node then
|
||||
local tube_def = reg_node.tube
|
||||
local tubedevice = minetest.get_item_group(node.name, "tubedevice")
|
||||
local tube_priority = (tube_def and tube_def.priority) or 100
|
||||
if tubedevice > 0 and tube_priority >= max_priority then
|
||||
if not tube_def or not tube_def.can_insert or
|
||||
tube_def.can_insert(npos, node, stack, vect) then
|
||||
if tube_priority > max_priority then
|
||||
max_priority = tube_priority
|
||||
next_positions = {}
|
||||
end
|
||||
next_positions[#next_positions + 1] = {pos = npos, vect = vect}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not next_positions[1] then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local n = (cmeta:get_int("tubedir") % (#next_positions)) + 1
|
||||
if pipeworks.enable_cyclic_mode then
|
||||
cmeta:set_int("tubedir", n)
|
||||
end
|
||||
local new_velocity = vector.multiply(next_positions[n].vect, vel.speed)
|
||||
return true, new_velocity
|
||||
end
|
||||
|
||||
minetest.register_entity("pipeworks:tubed_item", {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
physical = false,
|
||||
collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 0.15, y = 0.15},
|
||||
textures = {""},
|
||||
spritediv = {x = 1, y = 1},
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = false,
|
||||
},
|
||||
|
||||
physical_state = false,
|
||||
|
||||
from_data = function(self, itemstring)
|
||||
local stack = ItemStack(itemstring)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
itemname = stack:to_table().name
|
||||
end
|
||||
local item_texture = nil
|
||||
local item_type = ""
|
||||
if minetest.registered_items[itemname] then
|
||||
item_texture = minetest.registered_items[itemname].inventory_image
|
||||
item_type = minetest.registered_items[itemname].type
|
||||
end
|
||||
self.object:set_properties({
|
||||
is_visible = true,
|
||||
textures = {stack:get_name()}
|
||||
})
|
||||
local def = stack:get_definition()
|
||||
self.object:setyaw((def and def.type == "node") and 0 or math.pi * 0.25)
|
||||
end,
|
||||
|
||||
get_staticdata = luaentity.get_staticdata,
|
||||
on_activate = function(self, staticdata) -- Legacy code, should be replaced later by luaentity.on_activate
|
||||
if staticdata == "" or staticdata == nil then
|
||||
return
|
||||
end
|
||||
if staticdata == "toremove" then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local item = minetest.deserialize(staticdata)
|
||||
pipeworks.tube_inject_item(self.object:getpos(), item.start_pos, item.velocity, item.itemstring)
|
||||
self.object:remove()
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_entity("pipeworks:color_entity", {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
physical = false,
|
||||
collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
|
||||
visual = "cube",
|
||||
visual_size = {x = 3.5, y = 3.5, z = 3.5}, -- todo: find correct size
|
||||
textures = {""},
|
||||
is_visible = false,
|
||||
},
|
||||
|
||||
physical_state = false,
|
||||
|
||||
from_data = function(self, color)
|
||||
local t = "pipeworks_color_"..color..".png"
|
||||
local prop = {
|
||||
is_visible = true,
|
||||
visual = "cube",
|
||||
textures = {t, t, t, t, t, t} -- todo: textures
|
||||
}
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = luaentity.get_staticdata,
|
||||
on_activate = luaentity.on_activate,
|
||||
})
|
||||
|
||||
luaentity.register_entity("pipeworks:tubed_item", {
|
||||
itemstring = '',
|
||||
item_entity = nil,
|
||||
color_entity = nil,
|
||||
color = nil,
|
||||
start_pos = nil,
|
||||
|
||||
set_item = function(self, item)
|
||||
local itemstring = ItemStack(item):to_string() -- Accept any input format
|
||||
if self.itemstring == itemstring then
|
||||
return
|
||||
end
|
||||
if self.item_entity then
|
||||
self:remove_attached_entity(self.item_entity)
|
||||
end
|
||||
self.itemstring = itemstring
|
||||
self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring)
|
||||
end,
|
||||
|
||||
set_color = function(self, color)
|
||||
if self.color == color then
|
||||
return
|
||||
end
|
||||
self.color = color
|
||||
if self.color_entity then
|
||||
self:remove_attached_entity(self.color_entity)
|
||||
end
|
||||
if color then
|
||||
self.color_entity = self:add_attached_entity("pipeworks:color_entity", color)
|
||||
else
|
||||
self.color_entity = nil
|
||||
end
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
if self.start_pos == nil then
|
||||
local pos = self:getpos()
|
||||
self.start_pos = vector.round(pos)
|
||||
self:setpos(pos)
|
||||
end
|
||||
|
||||
local pos = self:getpos()
|
||||
local stack = ItemStack(self.itemstring)
|
||||
local drop_pos
|
||||
|
||||
local velocity = self:getvelocity()
|
||||
|
||||
local moved = false
|
||||
local speed = math.abs(velocity.x + velocity.y + velocity.z)
|
||||
if speed == 0 then
|
||||
speed = 1
|
||||
moved = true
|
||||
end
|
||||
local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed}
|
||||
|
||||
if vector.distance(pos, self.start_pos) >= 1 then
|
||||
self.start_pos = vector.add(self.start_pos, vel)
|
||||
moved = true
|
||||
end
|
||||
|
||||
minetest.load_position(self.start_pos)
|
||||
local node = minetest.get_node(self.start_pos)
|
||||
if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then
|
||||
local leftover
|
||||
if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then
|
||||
leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel)
|
||||
else
|
||||
leftover = stack
|
||||
end
|
||||
if leftover:is_empty() then
|
||||
self:remove()
|
||||
return
|
||||
end
|
||||
velocity = vector.multiply(velocity, -1)
|
||||
self:setvelocity(velocity)
|
||||
self:set_item(leftover:to_string())
|
||||
return
|
||||
end
|
||||
|
||||
if moved then
|
||||
local found_next, new_velocity = go_next(self.start_pos, velocity, stack) -- todo: color
|
||||
if not found_next then
|
||||
drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air")
|
||||
if drop_pos then
|
||||
minetest.item_drop(stack, "", drop_pos)
|
||||
self:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if new_velocity and not vector.equals(velocity, new_velocity) then
|
||||
self:setpos(self.start_pos)
|
||||
self:setvelocity(new_velocity)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
if minetest.get_modpath("mesecons_mvps") then
|
||||
mesecon.register_mvps_unmov("pipeworks:tubed_item")
|
||||
mesecon.register_mvps_unmov("pipeworks:color_entity")
|
||||
mesecon.register_on_mvps_move(function(moved_nodes)
|
||||
local moved = {}
|
||||
for _, n in ipairs(moved_nodes) do
|
||||
moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos)
|
||||
end
|
||||
for id, entity in pairs(luaentity.entities) do
|
||||
if entity.name == "pipeworks:tubed_item" then
|
||||
local pos = entity:getpos()
|
||||
local rpos = vector.round(pos)
|
||||
local dir = moved[minetest.hash_node_position(rpos)]
|
||||
if dir then
|
||||
entity:setpos(vector.add(pos, dir))
|
||||
entity.start_pos = vector.add(entity.start_pos, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
Reference in New Issue
Block a user