forked from mtcontrib/pipeworks
Slot sequencing modes for filter-injectors
The filter-injectors used to always prefer to take items from the beginning of the source inventory. Because items also tend to get placed at the beginning of an inventory, this could lead to a chest+injector buffer only passing through a trickle of one type of item, where other item types are flowing in and getting later inventory slots. So now, the sequencing of source inventory slots is configurable, per-injector, by form. In addition to the old priority mode, there's now a random mode and a rotation mode. Incidentally refactor the filter-injector code, to avoid duplication between the itemwise and stackwise variants.
This commit is contained in:
parent
1c3fb6b1c5
commit
b832c0ad06
@ -38,19 +38,81 @@ end
|
|||||||
-- both optional w/ sensible defaults and fallback to normal allow_* function
|
-- both optional w/ sensible defaults and fallback to normal allow_* function
|
||||||
-- XXX: possibly change insert_object to insert_item
|
-- XXX: possibly change insert_object to insert_item
|
||||||
|
|
||||||
-- sname = the current name to allow for, or nil if it allows anything
|
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 grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir,all)
|
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;]"
|
||||||
|
local slotseq_mode = meta:get_int("slotseq_mode")
|
||||||
|
if slotseq_mode == 1 then
|
||||||
|
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode2;Sequence slots Randomly]"
|
||||||
|
elseif slotseq_mode == 2 then
|
||||||
|
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode0;Sequence slots by Rotation]"
|
||||||
|
else
|
||||||
|
formspec = formspec .. "button[0,3.5;4,1;slotseq_mode1;Sequence slots by Priority]"
|
||||||
|
end
|
||||||
|
formspec = formspec .. "list[current_player;main;0,4.5;8,4;]"
|
||||||
|
meta:set_string("formspec", formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,all)
|
||||||
|
local sposes = {}
|
||||||
for spos,stack in ipairs(frominv:get_list(frominvname)) do
|
for spos,stack in ipairs(frominv:get_list(frominvname)) do
|
||||||
if (sname == nil and stack:get_name() ~= "") or stack:get_name() == sname then
|
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()
|
local doRemove = stack:get_count()
|
||||||
if tube.can_remove then
|
if fromtube.can_remove then
|
||||||
doRemove = tube.can_remove(frompos, fromnode, stack, dir)
|
doRemove = fromtube.can_remove(frompos, fromnode, stack, dir)
|
||||||
elseif idef.allow_metadata_inventory_take then
|
elseif fromdef.allow_metadata_inventory_take then
|
||||||
doRemove = idef.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
|
||||||
|
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 item
|
||||||
local count
|
local count
|
||||||
if all then
|
if all then
|
||||||
@ -58,14 +120,14 @@ local function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,
|
|||||||
else
|
else
|
||||||
count = 1
|
count = 1
|
||||||
end
|
end
|
||||||
if tube.remove_items then
|
if fromtube.remove_items then
|
||||||
-- it could be the entire stack...
|
-- it could be the entire stack...
|
||||||
item = tube.remove_items(frompos, fromnode, stack, dir, count)
|
item = fromtube.remove_items(frompos, fromnode, stack, dir, count)
|
||||||
else
|
else
|
||||||
item = stack:take_item(count)
|
item = stack:take_item(count)
|
||||||
frominv:set_stack(frominvname, spos, stack)
|
frominv:set_stack(frominvname, spos, stack)
|
||||||
if idef.on_metadata_inventory_take then
|
if fromdef.on_metadata_inventory_take then
|
||||||
idef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer)
|
fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item)
|
local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item)
|
||||||
@ -75,117 +137,90 @@ local function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,
|
|||||||
return true-- only fire one item, please
|
return true-- only fire one item, please
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_node("pipeworks:filter", {
|
local function punch_filter(data, filtpos, filtnode)
|
||||||
description = "Itemwise Filter-Injector",
|
local filtmeta = minetest.get_meta(filtpos)
|
||||||
tiles = {"pipeworks_filter_top.png", "pipeworks_filter_top.png", "pipeworks_filter_output.png",
|
local filtinv = filtmeta:get_inventory()
|
||||||
"pipeworks_filter_input.png", "pipeworks_filter_side.png", "pipeworks_filter_top.png"},
|
local dir = facedir_to_right_dir(filtnode.param2)
|
||||||
paramtype2 = "facedir",
|
local frompos = {x=filtpos.x - dir.x, y=filtpos.y - dir.y, z=filtpos.z - dir.z}
|
||||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2},
|
local fromnode = minetest.get_node(frompos)
|
||||||
legacy_facedir_simple = true,
|
|
||||||
sounds = default.node_sound_wood_defaults(),
|
|
||||||
on_construct = function(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
meta:set_string("formspec",
|
|
||||||
"invsize[8,6.5;]"..
|
|
||||||
"list[current_name;main;0,0;8,2;]"..
|
|
||||||
"list[current_player;main;0,2.5;8,4;]")
|
|
||||||
meta:set_string("infotext", "Itemwise Filter-Injector")
|
|
||||||
local inv = meta:get_inventory()
|
|
||||||
inv:set_size("main", 8*2)
|
|
||||||
end,
|
|
||||||
can_dig = function(pos,player)
|
|
||||||
local meta = minetest.get_meta(pos);
|
|
||||||
local inv = meta:get_inventory()
|
|
||||||
return inv:is_empty("main")
|
|
||||||
end,
|
|
||||||
after_place_node = function(pos)
|
|
||||||
pipeworks.scan_for_tube_objects(pos)
|
|
||||||
end,
|
|
||||||
after_dig_node = function(pos)
|
|
||||||
pipeworks.scan_for_tube_objects(pos)
|
|
||||||
end,
|
|
||||||
mesecons={effector={action_on=function(pos,node)
|
|
||||||
minetest.registered_nodes[node.name].on_punch(pos,node,nil)
|
|
||||||
end}},
|
|
||||||
tube={connect_sides={right=1}},
|
|
||||||
on_punch = function (pos, node, puncher)
|
|
||||||
local meta = minetest.get_meta(pos);
|
|
||||||
local inv = meta:get_inventory()
|
|
||||||
local dir = facedir_to_right_dir(node.param2)
|
|
||||||
local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z}
|
|
||||||
local fromnode=minetest.get_node(frompos)
|
|
||||||
if not fromnode then return end
|
if not fromnode then return end
|
||||||
local idef = minetest.registered_nodes[fromnode.name]
|
local fromdef = minetest.registered_nodes[fromnode.name]
|
||||||
-- assert(idef)
|
if not fromdef then return end
|
||||||
local tube = idef.tube
|
local fromtube = fromdef.tube
|
||||||
if not (tube and tube.input_inventory) then
|
if not (fromtube and fromtube.input_inventory) then return end
|
||||||
return
|
local filters = {}
|
||||||
end
|
for _, filterstack in ipairs(filtinv:get_list("main")) do
|
||||||
if tube.before_filter then
|
local filtername = filterstack:get_name()
|
||||||
tube.before_filter(frompos)
|
if filtername ~= "" then table.insert(filters, filtername) end
|
||||||
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 frommeta = minetest.get_meta(frompos)
|
||||||
local frominv = frommeta:get_inventory()
|
local frominv = frommeta:get_inventory()
|
||||||
|
if fromtube.before_filter then fromtube.before_filter(frompos) end
|
||||||
local function from_inventory(frominvname)
|
for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do
|
||||||
local sname
|
local done = false
|
||||||
for _,filter in ipairs(inv:get_list("main")) do
|
for _, filtername in ipairs(filters) do
|
||||||
sname = filter:get_name()
|
if grabAndFire(data, slotseq_mode, filtmeta, frominv, frominvname, frompos, fromnode, filtername, fromtube, fromdef, dir, data.stackwise) then
|
||||||
if sname ~= "" then
|
done = true
|
||||||
-- XXX: that's a lot of parameters
|
|
||||||
if grabAndFire(frominv, frominvname, frompos, fromnode, sname, tube, idef, dir) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if inv:is_empty("main") then
|
|
||||||
if grabAndFire(frominv, frominvname, frompos, fromnode, nil, tube, idef, dir) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(tube.input_inventory) == "table" then
|
|
||||||
for _, i in ipairs(tube.input_inventory) do
|
|
||||||
if from_inventory(i) then -- fired an item
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
if done then break end
|
||||||
from_inventory(tube.input_inventory)
|
|
||||||
end
|
end
|
||||||
|
if fromtube.after_filter then fromtube.after_filter(frompos) end
|
||||||
|
end
|
||||||
|
|
||||||
if tube.after_filter then
|
for _, data in ipairs({
|
||||||
tube.after_filter(frompos)
|
{
|
||||||
end
|
name = "filter",
|
||||||
end,
|
wise_desc = "Itemwise",
|
||||||
})
|
stackwise = false,
|
||||||
|
},
|
||||||
minetest.register_node("pipeworks:mese_filter", {
|
{
|
||||||
description = "Stackwise Filter-Injector",
|
name = "mese_filter",
|
||||||
tiles = {"pipeworks_mese_filter_top.png", "pipeworks_mese_filter_top.png", "pipeworks_mese_filter_output.png",
|
wise_desc = "Stackwise",
|
||||||
"pipeworks_mese_filter_input.png", "pipeworks_mese_filter_side.png", "pipeworks_mese_filter_top.png"},
|
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",
|
paramtype2 = "facedir",
|
||||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2},
|
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,tubedevice=1,mesecon=2},
|
||||||
legacy_facedir_simple = true,
|
legacy_facedir_simple = true,
|
||||||
sounds = default.node_sound_wood_defaults(),
|
sounds = default.node_sound_wood_defaults(),
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_string("formspec",
|
set_filter_formspec(data, meta)
|
||||||
"invsize[8,6.5;]"..
|
set_filter_infotext(data, meta)
|
||||||
"list[current_name;main;0,0;8,2;]"..
|
|
||||||
"list[current_player;main;0,2.5;8,4;]")
|
|
||||||
meta:set_string("infotext", "Stackwise Filter-Injector")
|
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
inv:set_size("main", 8*2)
|
inv:set_size("main", 8*2)
|
||||||
end,
|
end,
|
||||||
|
on_receive_fields = function(pos, formname, fields, sender)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
for k, _ in pairs(fields) do
|
||||||
|
if k:sub(1, 12) == "slotseq_mode" then
|
||||||
|
local mode = tonumber(k:sub(13, 13))
|
||||||
|
meta:set_int("slotseq_mode", mode)
|
||||||
|
meta:set_int("slotseq_index", mode == 2 and 1 or 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set_filter_formspec(data, meta)
|
||||||
|
set_filter_infotext(data, meta)
|
||||||
|
end,
|
||||||
can_dig = function(pos,player)
|
can_dig = function(pos,player)
|
||||||
local meta = minetest.get_meta(pos);
|
local meta = minetest.get_meta(pos)
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
return inv:is_empty("main")
|
return inv:is_empty("main")
|
||||||
end,
|
end,
|
||||||
@ -195,63 +230,19 @@ minetest.register_node("pipeworks:mese_filter", {
|
|||||||
after_dig_node = function(pos)
|
after_dig_node = function(pos)
|
||||||
pipeworks.scan_for_tube_objects(pos)
|
pipeworks.scan_for_tube_objects(pos)
|
||||||
end,
|
end,
|
||||||
mesecons={effector={action_on=function(pos,node)
|
mesecons = {
|
||||||
minetest.registered_nodes[node.name].on_punch(pos,node,nil)
|
effector = {
|
||||||
end}},
|
action_on = function(pos, node)
|
||||||
|
punch_filter(data, pos, node)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
tube={connect_sides={right=1}},
|
tube={connect_sides={right=1}},
|
||||||
on_punch = function (pos, node, puncher)
|
on_punch = function (pos, node, puncher)
|
||||||
local meta = minetest.get_meta(pos);
|
punch_filter(data, pos, node)
|
||||||
local inv = meta:get_inventory()
|
|
||||||
local dir = facedir_to_right_dir(node.param2)
|
|
||||||
local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z}
|
|
||||||
local fromnode=minetest.get_node(frompos)
|
|
||||||
local idef = minetest.registered_nodes[fromnode.name]
|
|
||||||
-- assert(idef)
|
|
||||||
local tube = idef.tube
|
|
||||||
if not (tube and tube.input_inventory) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if tube.before_filter then
|
|
||||||
tube.before_filter(frompos)
|
|
||||||
end
|
|
||||||
local frommeta = minetest.get_meta(frompos)
|
|
||||||
local frominv = frommeta:get_inventory()
|
|
||||||
|
|
||||||
local function from_inventory(frominvname)
|
|
||||||
local sname
|
|
||||||
for _,filter in ipairs(inv:get_list("main")) do
|
|
||||||
sname = filter:get_name()
|
|
||||||
if sname ~= "" then
|
|
||||||
-- XXX: that's a lot of parameters
|
|
||||||
if grabAndFire(frominv, frominvname, frompos, fromnode, sname, tube, idef, dir, true) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if inv:is_empty("main") then
|
|
||||||
if grabAndFire(frominv, frominvname, frompos, fromnode, nil, tube, idef, dir, true) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(tube.input_inventory) == "table" then
|
|
||||||
for _, i in ipairs(tube.input_inventory) do
|
|
||||||
if from_inventory(i) then -- fired an item
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
from_inventory(tube.input_inventory)
|
|
||||||
end
|
|
||||||
|
|
||||||
if tube.after_filter then
|
|
||||||
tube.after_filter(frompos)
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
local function roundpos(pos)
|
local function roundpos(pos)
|
||||||
return {x=math.floor(pos.x+0.5),y=math.floor(pos.y+0.5),z=math.floor(pos.z+0.5)}
|
return {x=math.floor(pos.x+0.5),y=math.floor(pos.y+0.5),z=math.floor(pos.z+0.5)}
|
||||||
|
Loading…
Reference in New Issue
Block a user