Change behavior of push_items function

This commit is contained in:
Joachim Stolberg 2022-09-02 21:12:25 +02:00
parent 1182912724
commit 3426712006
11 changed files with 278 additions and 76 deletions

View File

@ -277,10 +277,17 @@ local function push_item(pos, base_filter, itemstack, num_items, nvm)
num_of_trials = num_of_trials + 1
local push_dir = filter[idx]
local num_to_push = math.min(amount, num_items - num_pushed)
if techage.push_items(pos, push_dir, itemstack:peek_item(num_to_push)) then
num_pushed = num_pushed + num_to_push
nvm.port_counter[push_dir] = (nvm.port_counter[push_dir] or 0) + num_to_push
local leftover = techage.push_items(pos, push_dir, itemstack:peek_item(num_to_push))
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = num_to_push - leftover:get_count()
else -- leftover == true
pushed = num_to_push
end
num_pushed = num_pushed + pushed
nvm.port_counter[push_dir] = (nvm.port_counter[push_dir] or 0) + pushed
-- filter start offset
idx = idx + 1
if idx > num_ports then

View File

@ -0,0 +1,195 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3/TA4 Item Flow Limiter
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local Tube = techage.Tube
local STANDBY_TICKS = 8
local CYCLE_TIME = 8
local function formspec(self, pos, nvm)
return "size[6,3]" ..
"box[0,-0.1;5.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize("#000000", S("Item Flow Limiter")) .. "]" ..
"field[0.3,1.2;3.3,1;number;" .. S("Number of items") .. ";" .. (nvm.limit or 0) .. "]" ..
"button[3.5,0.9;2.5,1;store;" .. S("Store") .. "]" ..
"image_button[2.5,2;1,1;".. self:get_state_button_image(nvm) .. ";state_button;]" ..
"tooltip[2.5,2;1,1;" .. self:get_state_tooltip(nvm) .. "]"
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
CRD(pos).State:is_active(nvm)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if fields.number and fields.store then
nvm.limit = tonumber(fields.number) or 0
nvm.num_items = 0
CRD(pos).State:stop(pos, nvm)
end
CRD(pos).State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
local function can_start(pos, nvm, state)
nvm.num_items = 0
return true
end
local tiles = {}
-- '#' will be replaced by the stage number
-- '{power}' will be replaced by the power PNG
tiles.pas = {
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#_bottom.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_filling_ta#.png^techage_appl_flow_limiter.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_flow_limiter.png^techage_frame_ta#.png",
}
tiles.act = tiles.pas
local tubing = {
-- push item through until limit is reached
on_push_item = function(pos, in_dir, stack)
print("on_push_item", stack:get_name(), stack:get_count())
local nvm = techage.get_nvm(pos)
local count = math.min(stack:get_count(), (nvm.limit or 0) - (nvm.num_items or 0))
if nvm.techage_state == techage.RUNNING and count > 0 and in_dir == M(pos):get_int("push_dir") then
local leftover = techage.safe_push_items(pos, in_dir, ItemStack({name = stack:get_name(), count = count}))
local num_pushed
if not leftover then
num_pushed = 0
elseif leftover == true then
num_pushed = count
else
num_pushed = count - leftover:get_count()
end
if num_pushed == 0 then
return false
else
nvm.num_items = (nvm.num_items or 0) + num_pushed
if nvm.num_items == nvm.limit then
CRD(pos).State:stop(pos, nvm)
end
stack:set_count(stack:get_count() - num_pushed)
return stack
end
end
return false
end,
is_pusher = true, -- is a pulling/pushing node
on_recv_message = function(pos, src, topic, payload)
if topic == "set" then -- set limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
nvm.limit = tonumber(payload) or 0
nvm.num_items = 0
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
return true
elseif topic == "count" then
local nvm = techage.get_nvm(pos)
return nvm.num_items or 0
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 68 and payload then -- set limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
nvm.limit = payload[1] or 0
nvm.num_items = 0
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
return 0
else
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 150 then -- Request count
local nvm = techage.get_nvm(pos)
return 0, {nvm.num_items or 0}
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("item_flow_limiter", S("Item Flow Limiter"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
can_start = can_start,
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", node.param2))
meta:set_int("push_dir", techage.side_to_outdir("R", node.param2))
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
local meta = M(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", new_param2))
meta:set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
on_receive_fields = on_receive_fields,
node_timer = keep_running,
on_rotate = screwdriver.disallow,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
num_items = {0,2,6,12},
tube_sides = {L=1, R=1},
}, {false, false, true, true})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "techage:iron_ingot", ""},
{"techage:baborium_ingot", node_name_ta2, "techage:usmium_nuggets"},
{"", "techage:vacuum_tube", ""},
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "techage:iron_ingot", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})

View File

@ -73,11 +73,17 @@ minetest.register_node("techage:itemsource", {
local stack = inv:get_stack('main', 1)
if stack:get_count() > 0 then
local push_dir = meta:get_int("push_dir")
if techage.push_items(pos, push_dir, stack) then
local cnt = meta:get_int("counter") + stack:get_count()
meta:set_int("counter", cnt)
meta:set_string("infotext", "Techage Item Source: "..cnt)
local leftover = techage.push_items(pos, push_dir, stack)
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = stack:get_count() - leftover:get_count()
else -- leftover == true
pushed = stack:get_count()
end
meta:set_int("counter", pushed)
meta:set_string("infotext", "Techage Item Source: "..pushed)
end
return true
end,

View File

@ -93,11 +93,18 @@ local function pushing(pos, crd, meta, nvm)
local num = nvm.item_count or nvm.num_items or crd.num_items
local items = techage.pull_items(pos, pull_dir, num, nvm.item_name)
if items ~= nil then
if techage.push_items(pos, push_dir, items) ~= true then
local leftover = techage.push_items(pos, push_dir, items)
print("leftover", dump(leftover))
if not leftover then
-- place item back
techage.unpull_items(pos, pull_dir, items)
crd.State:blocked(pos, nvm)
return
elseif leftover ~= true then
-- place item back
techage.unpull_items(pos, pull_dir, leftover)
crd.State:blocked(pos, nvm)
return
end
if nvm.item_count then -- remote job?
nvm.item_count = nil

View File

@ -18,7 +18,7 @@ local M = minetest.get_meta
local S = techage.S
local DESCRIPTION = S("TA4 8x2000 Chest")
local STACK_SIZE = 2000
local STACK_SIZE = 200
local function gen_stack(inv, idx)
inv[idx] = {name = "", count = 0}
@ -133,7 +133,7 @@ local function doesItemStackMatchNvmStack(itemstack, nvmstack)
-- The following seems to be the most reliable approach to compare meta.
local nvm_meta = ItemStack():get_meta()
nvm_meta:from_table(minetest.deserialize(nvmstack.meta))
nvm_meta:from_table(minetest.deserialize(nvmstack.meta or ""))
if not nvm_meta:equals(itemstack:get_meta()) then
return false, "Mismatching meta"
end
@ -197,7 +197,7 @@ local function take_from_chest(pos, idx, output_stack, max_total_count, keep_ass
count = count,
wear = nvm_stack.wear,
}))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta or ""))
nvm_stack.count = nvm_stack.count - count
if nvm_stack.count == 0 then
gen_stack(nvm.inventory or {}, idx)
@ -210,21 +210,14 @@ local function tube_add_to_chest(pos, input_stack)
local nvm = techage.get_nvm(pos)
nvm.inventory = nvm.inventory or {}
-- Backup some values needed for restoring the old
-- state if items can't fully be added to chest.
local orig_count = input_stack:get_count()
local backup = table.copy(nvm.inventory)
for idx = 1,8 do
input_stack:take_item(add_to_chest(pos, input_stack, idx))
end
if input_stack:get_count() > 0 then
nvm.inventory = backup -- Restore old nvm inventory
input_stack:set_count(orig_count) -- Restore input_stack
return false -- No items were added to chest
return input_stack -- Not all items were added to chest
else
return true -- Items were added successfully
return true -- All items were added
end
end

View File

@ -460,7 +460,7 @@ function techage.push_items(pos, out_dir, stack, idx)
minetest.add_item(npos, stack)
return true
end
return false
return stack
end
-- Check for recursion and too long distances
@ -485,7 +485,7 @@ function techage.safe_push_items(pos, out_dir, stack, idx)
end
end
end
return false
return stack
end
function techage.unpull_items(pos, out_dir, stack)
@ -496,37 +496,6 @@ function techage.unpull_items(pos, out_dir, stack)
return false
end
-------------------------------------------------------------------
-- Client side Push/Pull item functions for hopper like nodes
-- (nodes with no tube support)
-------------------------------------------------------------------
function techage.neighbour_pull_items(pos, out_dir, num)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_pull_item then
return NodeDef[name].on_pull_item(npos, in_dir, num)
end
end
function techage.neighbour_push_items(pos, out_dir, stack)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_push_item then
return NodeDef[name].on_push_item(npos, in_dir, stack)
elseif name == "air" then
minetest.add_item(npos, stack)
return true
end
return false
end
function techage.neighbour_unpull_items(pos, out_dir, stack)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_unpull_item then
return NodeDef[name].on_unpull_item(npos, in_dir, stack)
end
return false
end
-------------------------------------------------------------------
-- Server side helper functions
-------------------------------------------------------------------
@ -554,23 +523,33 @@ function techage.get_items(pos, inv, listname, num)
return nil
end
-- Put the given stack into the given ItemList.
-- Function returns false if ItemList is full.
-- Put the given stack into the given ItemList/inventory.
-- Function returns:
-- - true, if all items are moved
-- - false, if no item is moved
-- - leftover, if less than all items are moved
-- (true/false is the legacy mode and can't be removed)
function techage.put_items(inv, listname, item, idx)
local leftover
if idx and inv and idx <= inv:get_size(listname) then
local stack = inv:get_stack(listname, idx)
if stack:item_fits(item) then
stack:add_item(item)
leftover = stack:add_item(item)
inv:set_stack(listname, idx, stack)
return true
end
elseif inv then
leftover = inv:add_item(listname, item)
else
if inv and inv:room_for_item(listname, item) then
inv:add_item(listname, item)
return true
end
end
return false
end
local cnt = leftover:get_count()
if cnt == item:get_count() then
return false
elseif cnt == 0 then
return true
else
return leftover
end
end
-- Return "full", "loaded", or "empty" depending

View File

@ -79,11 +79,12 @@ function inv_lib.put_items(pos, inv, listname, item, stacks, idx)
for _, i in ipairs(stacks or {}) do
if not idx or idx == i then
local stack = inv:get_stack(listname, i)
if stack:item_fits(item) then
stack:add_item(item)
local leftover = stack:add_item(item)
inv:set_stack(listname, i, stack)
if leftover:get_count() == 0 then
return true
end
return leftover
end
end
return false

View File

@ -198,6 +198,7 @@ dofile(MP.."/basic_machines/recycler.lua")
dofile(MP.."/basic_machines/concentrator.lua")
dofile(MP.."/basic_machines/recipeblock.lua")
dofile(MP.."/basic_machines/ta5_chest.lua")
dofile(MP.."/basic_machines/flow_limiter.lua")
-- Liquids II
dofile(MP.."/liquids/tank.lua")
@ -316,6 +317,7 @@ if techage.recipe_checker_enabled then
end
dofile(MP.."/.test/sink.lua")
dofile(MP.."/.test/testblock.lua")
dofile(MP.."/.test/minichest.lua")
-- Solar
dofile(MP.."/solar/minicell.lua")

View File

@ -249,12 +249,13 @@ minetest.register_craft({
techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, {
on_push_item = function(pos, in_dir, stack)
if techage.safe_push_items(pos, in_dir, stack) then
local leftover = techage.safe_push_items(pos, in_dir, stack)
if leftover then
local inv = minetest.get_inventory({type = "node", pos = pos})
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
switch_on(pos)
end
return true
return leftover
end
return false
end,
@ -263,11 +264,19 @@ techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, {
techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, {
on_push_item = function(pos, in_dir, stack)
if techage.safe_push_items(pos, in_dir, stack) then
local leftover = techage.safe_push_items(pos, in_dir, stack)
if leftover then
local inv = minetest.get_inventory({type = "node", pos = pos})
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
switch_on(pos)
local nvm = techage.get_nvm(pos)
if leftover == true then
nvm.counter = (nvm.counter or 0) + stack:get_count()
return true
else
nvm.counter = (nvm.counter or 0) + stack:get_count() - leftover:get_count()
end
end
return leftover
end
return false
end,

View File

@ -158,11 +158,14 @@ techage.register_node({"techage:ta5_tele_tube"}, {
local rmt_nvm = techage.get_nvm(rmt_pos)
if techage.is_operational(rmt_nvm) then
local tube_dir = M(rmt_pos):get_int("tube_dir")
if techage.push_items(rmt_pos, tube_dir, stack) then
local leftover = techage.push_items(rmt_pos, tube_dir, stack)
-- Moved any items
if leftover then
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
State:keep_running(rmt_pos, rmt_nvm, COUNTDOWN_TICKS)
return true
end
return leftover
else
State:blocked(pos, nvm, S("Remote block error"))
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B