Rewrite drawer controller scanning

This fixes the issue that some drawers have not been found by the
controller.
This commit is contained in:
Linus Jahn 2019-05-18 23:02:00 +02:00
parent 3a12b831a0
commit 885f8daf7b
No known key found for this signature in database
GPG Key ID: 4663231A91A1E27B
11 changed files with 563 additions and 444 deletions

@ -4,7 +4,7 @@ Version 0.4.3
License of source code: License of source code:
----------------------- -----------------------
Copyright (C) 2017 LNJ <git@lnj.li> Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
Copyright (C) 2016 Mango Tango <mtango688@gmail.com> Copyright (C) 2016 Mango Tango <mtango688@gmail.com>
MIT License MIT License
@ -76,6 +76,9 @@ Copyright (C) 2014 Justin Aquadro (MIT):
textures/drawers_birch_wood_front_2.png textures/drawers_birch_wood_front_2.png
textures/drawers_birch_wood_front_4.png textures/drawers_birch_wood_front_4.png
textures/drawers_birch_wood.png textures/drawers_birch_wood.png
textures/drawers_controller_front.png
textures/drawers_controller_side.png
textures/drawers_controller_top.png
textures/drawers_dark_oak_wood_front_1.png textures/drawers_dark_oak_wood_front_1.png
textures/drawers_dark_oak_wood_front_2.png textures/drawers_dark_oak_wood_front_2.png
textures/drawers_dark_oak_wood_front_4.png textures/drawers_dark_oak_wood_front_4.png
@ -109,8 +112,6 @@ Copyright (C) 2014 Justin Aquadro (MIT):
textures/drawers_wood_front_2.png textures/drawers_wood_front_2.png
textures/drawers_wood_front_4.png textures/drawers_wood_front_4.png
textures/drawers_wood.png textures/drawers_wood.png
textures/drawer_controller_side.png
textures/drawer_controller_top_bottom.png
Everything not listed in here: Everything not listed in here:
Copyright (C) 2017 LNJ <git@lnj.li> (MIT) Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im> (MIT)

@ -40,5 +40,5 @@ alternatively you can also [email](mailto:git@lnj.li) me.
* [Minetest Forums](https://forum.minetest.net/viewtopic.php?f=9&t=17134) * [Minetest Forums](https://forum.minetest.net/viewtopic.php?f=9&t=17134)
* [Minetest Wiki](http://wiki.minetest.net/Mods/Storage_Drawers) * [Minetest Wiki](http://wiki.minetest.net/Mods/Storage_Drawers)
* [Weblate](https://hosted.weblate.org/projects/minetest/mod-storage-drawers/) * [Weblate](https://hosted.weblate.org/projects/minetest/mod-storage-drawers/)
* [GitHub](http://github.com/lnj2/drawers/) * [GitHub](http://github.com/minetest-mods/drawers/)

@ -1,7 +1,7 @@
--[[ --[[
Minetest Mod Storage Drawers - A Mod adding storage drawers Minetest Mod Storage Drawers - A Mod adding storage drawers
Copyright (C) 2017 LNJ <git@lnj.li> Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
MIT License MIT License
@ -51,6 +51,7 @@ drawers.enable_1x1 = not core.settings:get_bool("drawers_disable_1x1")
drawers.enable_1x2 = not core.settings:get_bool("drawers_disable_1x2") drawers.enable_1x2 = not core.settings:get_bool("drawers_disable_1x2")
drawers.enable_2x2 = not core.settings:get_bool("drawers_disable_2x2") drawers.enable_2x2 = not core.settings:get_bool("drawers_disable_2x2")
drawers.CONTROLLER_RANGE = 8
-- --
-- GUI -- GUI
@ -334,7 +335,7 @@ if core.get_modpath("mcl_core") and mcl_core then
core.register_node("drawers:trim", { core.register_node("drawers:trim", {
description = S("Wooden Trim"), description = S("Wooden Trim"),
tiles = {"drawers_trim.png"}, tiles = {"drawers_trim.png"},
groups = {handy = 1, axey = 1, flammable = 3, wood = 1, building_block = 1, material_wood = 1}, groups = {drawer_connector = 1, handy = 1, axey = 1, flammable = 3, wood = 1, building_block = 1, material_wood = 1},
_mcl_blast_resistance = 15, _mcl_blast_resistance = 15,
_mcl_hardness = 2, _mcl_hardness = 2,
}) })
@ -342,7 +343,7 @@ else
core.register_node("drawers:trim", { core.register_node("drawers:trim", {
description = S("Wooden Trim"), description = S("Wooden Trim"),
tiles = {"drawers_trim.png"}, tiles = {"drawers_trim.png"},
groups = {drawer = 1, choppy = 3, oddly_breakable_by_hand = 2}, groups = {drawer_connector = 1, choppy = 3, oddly_breakable_by_hand = 2},
}) })
end end

@ -1,7 +1,7 @@
--[[ --[[
Minetest Mod Storage Drawers - A Mod adding storage drawers Minetest Mod Storage Drawers - A Mod adding storage drawers
Copyright (C) 2017 LNJ <git@lnj.li> Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
Copyright (C) 2016 Mango Tango <mtango688@gmail.com> Copyright (C) 2016 Mango Tango <mtango688@gmail.com>
MIT License MIT License

@ -1,8 +1,8 @@
--[[ --[[
Minetest Mod Storage Drawers - A Mod adding storage drawers Minetest Mod Storage Drawers - A Mod adding storage drawers
Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
Copyright (C) 2018 isaiah658 Copyright (C) 2018 isaiah658
Copyright (C) 2017 LNJ <git@lnj.li>
MIT License MIT License
@ -32,49 +32,23 @@ counts and such. It is necessary to change both at once otherwise in some cases
the entity values are used and in other cases the node metadata is used. the entity values are used and in other cases the node metadata is used.
The gist of how the controller works is this. The drawer controller scans the The gist of how the controller works is this. The drawer controller scans the
adjacent tiles (length and height is configurable) and puts the item names and adjacent tiles and puts the item names and other info such as coordinates and
other info such as coordinates and the visualid of the entity in a table. That the visualid of the entity in a table. That table is saved in the controllers
table is saved in the controllers metadata. The table is used to help prevent metadata. The table is used to help prevent needing to scan all the drawers to
needing to scan all the drawers to deposit an item in certain situations. The deposit an item in certain situations. The table is only updated on an as needed
table is only updated on an as needed basis, not by a specific time/interval. basis, not by a specific time/interval. Controllers that have no items will not
Controllers that have no items will not continue scanning drawers. ]]-- continue scanning drawers. ]]--
-- Load support for intllib. -- Load support for intllib.
local MP = core.get_modpath(core.get_current_modname()) local MP = core.get_modpath(core.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua") local S, NS = dofile(MP.."/intllib.lua")
local default_loaded = core.get_modpath("default") and default
local mcl_loaded = core.get_modpath("mcl_core") and mcl_core
local pipeworks_loaded = core.get_modpath("pipeworks") and pipeworks
local controller_interval = tonumber(core.setting_get("drawers_controller_interval")) or 7.0 local controller_interval = tonumber(core.setting_get("drawers_controller_interval")) or 7.0
local function controller_can_dig(pos, player)
local meta = core.get_meta(pos);
local inv = meta:get_inventory()
return inv:is_empty("src")
end
local function controller_allow_metadata_inventory_put(pos, listname, index, stack, player)
if core.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
return stack:get_count()
end
end
local function controller_allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
return controller_allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local function controller_allow_metadata_inventory_take(pos, listname, index, stack, player)
if core.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function controller_formspec(pos, meta_current_state) local function controller_formspec(pos, meta_current_state)
local formspec = local formspec =
"size[8,8.5]".. "size[8,8.5]"..
@ -91,8 +65,140 @@ local function controller_formspec(pos, meta_current_state)
return formspec return formspec
end end
local function controller_index_slot(pos, visualid)
return {
drawer_pos_x = pos.x,
drawer_pos_y = pos.y,
drawer_pos_z = pos.z,
visualid = visualid
}
end
local function compare_pos(pos1, pos2)
return pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z
end
local function contains_pos(list, p)
for _,v in ipairs(list) do
if compare_pos(v, p) then
return true
end
end
return false
end
-- iterator for iterating from 1 -> to
local function range(to)
local i = 0
return function()
if i == to then
return nil
end
i = i + 1
return i, i
end
end
local function pos_in_range(pos1, pos2)
local diff = {
pos1.x - pos2.x,
pos1.y - pos2.y,
pos1.z - pos2.z
}
for _,v in ipairs(diff) do
if v < 0 then
v = v * -1
end
if v > drawers.CONTROLLER_RANGE then
return false
end
end
return true
end
local function add_drawer_to_inventory(controllerInventory, pos)
-- the number of slots is saved as drawer group
local slots = core.get_item_group(core.get_node(pos).name, "drawer")
if not slots then
return
end
local meta = core.get_meta(pos)
if not meta then
return
end
local i = 1
while i <= slots do
-- nothing is appended in case the drawer has only one slot
local slot_id = ""
if slots ~= 1 then
slot_id = tostring(i)
end
local item_id = meta:get_string("name" .. slot_id)
local drawer_meta_entity_infotext = meta:get_string("entity_infotext" .. slot_id)
if item_id == "" and not controllerInventory["empty"] then
controllerInventory["empty"] = controller_index_slot(pos, slot_id)
elseif item_id ~= "" then
-- If we already indexed this item previously, check which drawer
-- has the most space and have that one be the one indexed
if controllerInventory[item_id] then
local indexed_drawer_meta = core.get_meta({
x = controllerInventory[item_id]["drawer_pos_x"],
y = controllerInventory[item_id]["drawer_pos_y"],
z = controllerInventory[item_id]["drawer_pos_z"]}
)
local indexed_drawer_meta_count = indexed_drawer_meta:get_int(
"count" .. controllerInventory[item_id]["visualid"])
local indexed_drawer_meta_max_count = indexed_drawer_meta:get_int(
"max_count" .. controllerInventory[item_id]["visualid"])
local drawer_meta_count = meta:get_int("count" .. slot_id)
local drawer_meta_max_count = meta:get_int("max_count" .. slot_id)
-- If the already indexed drawer has less space, we override the table index for that item with the new drawer
if (indexed_drawer_meta_max_count - indexed_drawer_meta_count)
< (drawer_meta_max_count - drawer_meta_count) then
controllerInventory[item_id] = controller_index_slot(pos, slot_id)
end
else
controllerInventory[item_id] = controller_index_slot(pos, slot_id)
end
end
i = i + 1
end
end
local function find_connected_drawers(controller_pos, pos, foundPositions)
foundPositions = foundPositions or {}
pos = pos or controller_pos
local newPositions = core.find_nodes_in_area(
{x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
{x = pos.x + 1, y = pos.y + 1, z = pos.z + 1},
{"group:drawer", "group:drawer_connector"}
)
for _,p in ipairs(newPositions) do
-- check that this node hasn't been scanned yet
if not compare_pos(pos, p) and not contains_pos(foundPositions, p)
and pos_in_range(controller_pos, pos) then
-- add new position
table.insert(foundPositions, p)
-- search for other drawers from the new pos
find_connected_drawers(controller_pos, p, foundPositions)
end
end
return foundPositions
end
local function index_drawers(pos) local function index_drawers(pos)
--[[ The pos parameter is the controllers position --[[
The pos parameter is the controllers position
We store the item name as a string key and the value is a table with position x, We store the item name as a string key and the value is a table with position x,
position y, position z, and visualid. Those are all strings as well with the position y, position z, and visualid. Those are all strings as well with the
@ -100,98 +206,14 @@ local function index_drawers(pos)
the table. The count and max count are not stored as those values have a high the table. The count and max count are not stored as those values have a high
potential of being outdated quickly. It's better to grab the values from the potential of being outdated quickly. It's better to grab the values from the
drawer when needed so you know you are working with accurate numbers. drawer when needed so you know you are working with accurate numbers.
]]
Indexing starts on the row (meaning same y coordinate) of the controller on the local controllerInventory = {}
adjacent sides and moves each column on the same y level. A row is searched until for _,drawerPos in ipairs(find_connected_drawers(pos)) do
it either hits the max length setting size or until a node that isn't a drawer is add_drawer_to_inventory(controllerInventory, drawerPos)
indexed and then moves up on (y coordinate increases by 1) and starts the process
until the y coord is reaches the max height or until a node that isn't a drawer
is indexed and at the point it stops indexing all together. This makes it so all
drawers need to be next to each other on the rows without spacing or other blocks
in between. ]]--
local drawers_table_index = {}
local x_or_z_axis = 1
-- Variables for managing the max length and max height that is searched in each adjacent direction from the controller
-- These could potentially be exposed to the user through the formspec, allowed to bigger with upgrades, etc
local max_search_length = 8
local max_search_height = 8
-- Index the x axis and z axis in both the positive and negative directions
for x_z = 1,4 do
for y = 1,max_search_height do
for x_or_z = 1,max_search_length do
-- x_z if for controlling which axis and direction is being searched
-- x_or_z is for the column in each row that is searched
-- x_or_z_axis is used for breaking out of the loop if the first block searched in a row is not a drawer
x_or_z_axis = x_or_z
local drawer_pos
-- If x_z is 1, we check the positive x axis
if x_z == 1 then
drawer_pos = {x = pos.x + x_or_z, y = pos.y + y - 1, z = pos.z}
-- If x_z is 2, we check the negative x axis
elseif x_z == 2 then
drawer_pos = {x = pos.x - x_or_z, y = pos.y + y - 1, z = pos.z}
-- If x_z is 3, we check the positive z axis
elseif x_z == 3 then
drawer_pos = {x = pos.x, y = pos.y + y - 1, z = pos.z + x_or_z}
-- If x_z is 4, we check the negative z axis
elseif x_z == 4 then
drawer_pos = {x = pos.x, y = pos.y + y - 1, z = pos.z - x_or_z}
end
local drawer_meta = core.get_meta(drawer_pos)
local drawer_node = core.get_node(drawer_pos)
-- There might be a better way to know if the node is a drawer other than matching a string in the node name
-- Can't trust metadata only in case another mod has a block with the same metadata strings
if string.match(drawer_node.name, 'drawers:') and drawer_node.name ~= "drawers:controller" and drawer_meta ~= nil then
for i = 0,4 do
-- This is needed for the special case where drawers that store one item don't have an id appended to them
local visualid = i
if i == 0 then
visualid = ""
end
local drawer_meta_name = drawer_meta:get_string("name" .. visualid)
local drawer_meta_entity_infotext = drawer_meta:get_string("entity_infotext" .. visualid)
-- Only one empty drawer needs to be indexed because everything is indexed again when an item isn't found in the index
if drawer_meta_name == "" and not drawers_table_index["empty"] and drawer_meta_entity_infotext ~= "" then
drawers_table_index["empty"] = {drawer_pos_x = drawer_pos.x, drawer_pos_y = drawer_pos.y, drawer_pos_z = drawer_pos.z, visualid = visualid}
elseif drawer_meta_name ~= "" then
-- If we already indexed this item previously, check which drawer has the most space and have that one be the one indexed
if drawers_table_index[drawer_meta_name] then
local indexed_drawer_meta = core.get_meta({x = drawers_table_index[drawer_meta_name]["drawer_pos_x"], y = drawers_table_index[drawer_meta_name]["drawer_pos_y"], z = drawers_table_index[drawer_meta_name]["drawer_pos_z"]})
local indexed_drawer_meta_count = indexed_drawer_meta:get_int("count" .. drawers_table_index[drawer_meta_name]["visualid"])
local indexed_drawer_meta_max_count = indexed_drawer_meta:get_int("max_count" .. drawers_table_index[drawer_meta_name]["visualid"])
local drawer_meta_count = drawer_meta:get_int("count" .. visualid)
local drawer_meta_max_count = drawer_meta:get_int("max_count" .. visualid)
-- If the already indexed drawer has less space, we override the table index for that item with the new drawer
if indexed_drawer_meta_max_count - indexed_drawer_meta_count < drawer_meta_max_count - drawer_meta_count then
drawers_table_index[drawer_meta_name] = {drawer_pos_x = drawer_pos.x, drawer_pos_y = drawer_pos.y, drawer_pos_z = drawer_pos.z, visualid = visualid}
end
else
drawers_table_index[drawer_meta_name] = {drawer_pos_x = drawer_pos.x, drawer_pos_y = drawer_pos.y, drawer_pos_z = drawer_pos.z, visualid = visualid}
end
-- If the drawer contained something and was a drawer type that only holds one item, stop the loop as there is no need to search through other drawer types
if i == 0 then
break
end
end
end
-- If the node isn't a drawer or doesn't have metadata, we break the loop to stop searching the row
else
break
end
end
-- If we break out of the above loop while x or z is 1, it means the first block searched in a row did not contain a drawer.
-- All searching for an axis is stopped when a row starts with a non-drawer.
if x_or_z_axis == 1 then
break
end
end
end end
return drawers_table_index return controllerInventory
end end
local function controller_node_timer(pos, elapsed) local function controller_node_timer(pos, elapsed)
@ -204,7 +226,8 @@ local function controller_node_timer(pos, elapsed)
local src = inv:get_stack("src", 1) local src = inv:get_stack("src", 1)
local src_name = src:get_name() local src_name = src:get_name()
--[[ There are four scenarios for the item slot in the controller. --[[
There are four scenarios for the item slot in the controller.
1: No item is in the controller. 1: No item is in the controller.
2: Item is not stackable. 2: Item is not stackable.
3. Item is allowed and there is either an existing drawer for that item with room or an empty drawer. 3. Item is allowed and there is either an existing drawer for that item with room or an empty drawer.
@ -213,33 +236,40 @@ local function controller_node_timer(pos, elapsed)
There are three different possibilities for "current_state". There are three different possibilities for "current_state".
1: "running" which means means it's operating normally. 1: "running" which means means it's operating normally.
2: "stopped" meaning the controller makes no attempt to put in the item possibly due to being unallowed for various reasons. 2: "stopped" meaning the controller makes no attempt to put in the item possibly due to being unallowed for various reasons.
3: "jammed" meaning the item is allowed in to drawers, but there was no space to deposit it last time it ran. ]]-- 3: "jammed" meaning the item is allowed in to drawers, but there was no space to deposit it last time it ran.
]]
--[[ If current state is jammed, the item that jammed it is the same item in the --[[
If current state is jammed, the item that jammed it is the same item in the
src inv slot, and the amount of times ran while jammed is 8 or higher, we src inv slot, and the amount of times ran while jammed is 8 or higher, we
set the current state to stopped. Will possibly want to make an option in the set the current state to stopped. Will possibly want to make an option in the
formspec to ignore this an continue running if the user plans on using the formspec to ignore this an continue running if the user plans on using the
system in a way that may cause frequent jams making it a hassle to manually system in a way that may cause frequent jams making it a hassle to manually
clear it each time ]]-- clear it each time
if meta_current_state == "jammed" and meta_jammed_item_name == src_name and meta_times_ran_while_jammed >= 8 then ]]
if meta_current_state == "jammed" and meta_jammed_item_name == src_name and meta_times_ran_while_jammed >= 2 then
meta:set_string("current_state", "stopped") meta:set_string("current_state", "stopped")
meta:set_string("formspec", controller_formspec(pos, S("Stopped"))) meta:set_string("formspec", controller_formspec(pos, S("Stopped")))
return true return true
end end
-- If current state is stopped, and the item that jammed it is the same item in the src inv slot, we don't do anything -- If current state is stopped, and the item that jammed it is the same
-- item in the src inv slot, we don't do anything
if meta_current_state == "stopped" and meta_jammed_item_name == src_name then if meta_current_state == "stopped" and meta_jammed_item_name == src_name then
return true return true
end end
-- If current state is stopped, and the item that jammed it is not the same item in the src inv slot, we set the current state to running and clear the jam counter -- If current state is stopped, and the item that jammed it is not the
-- same item in the src inv slot, we set the current state to running and
-- clear the jam counter.
if meta_current_state == "stopped" and meta_jammed_item_name ~= src_name then if meta_current_state == "stopped" and meta_jammed_item_name ~= src_name then
meta:set_string("current_state", "running") meta:set_string("current_state", "running")
meta:set_string("formspec", controller_formspec(pos, S("Running"))) meta:set_string("formspec", controller_formspec(pos, S("Running")))
meta:set_float("times_ran_while_jammed", 0) meta:set_float("times_ran_while_jammed", 0)
end end
-- If no item is in the controller, nothing is searched and current_state is set to running and no jams -- If no item is in the controller, nothing is searched and current_state
-- is set to running and no jams.
if inv:is_empty("src") then if inv:is_empty("src") then
meta:set_string("current_state", "running") meta:set_string("current_state", "running")
meta:set_string("formspec", controller_formspec(pos, S("Running"))) meta:set_string("formspec", controller_formspec(pos, S("Running")))
@ -247,7 +277,8 @@ local function controller_node_timer(pos, elapsed)
return true return true
end end
-- If a non stackable item is in the controller, such as a written book, set the current_state to stopped because they are not allowed in drawers -- If a non stackable item is in the controller, such as a written book,
-- set the current_state to stopped because they are not allowed in drawers
if src:get_stack_max() == 1 then if src:get_stack_max() == 1 then
meta:set_string("current_state", "stopped") meta:set_string("current_state", "stopped")
meta:set_string("formspec", controller_formspec(pos, S("Stopped"))) meta:set_string("formspec", controller_formspec(pos, S("Stopped")))
@ -256,17 +287,23 @@ local function controller_node_timer(pos, elapsed)
return true return true
end end
-- If the index has not been created, the item isn't in the index, the item in the drawer is no longer the same item in the index, or the item is in the index but it's full, run the index_drawers function -- If the index has not been created, the item isn't in the index, the
-- item in the drawer is no longer the same item in the index, or the item
-- is in the index but it's full, run the index_drawers function.
local drawers_table_index = core.deserialize(meta:get_string("drawers_table_index")) local drawers_table_index = core.deserialize(meta:get_string("drawers_table_index"))
-- If the index has not been created -- If the index has not been created
if not drawers_table_index then if not drawers_table_index then
drawers_table_index = index_drawers(pos) drawers_table_index = index_drawers(pos)
meta:set_string("drawers_table_index", core.serialize(drawers_table_index)) meta:set_string("drawers_table_index", core.serialize(drawers_table_index))
-- If the item isn't in the index -- If the item isn't in the index
elseif not drawers_table_index[src_name] then elseif not drawers_table_index[src_name] then
drawers_table_index = index_drawers(pos) drawers_table_index = index_drawers(pos)
meta:set_string("drawers_table_index", core.serialize(drawers_table_index)) meta:set_string("drawers_table_index", core.serialize(drawers_table_index))
-- If the item is in the index but either the name that was indexed is not the same as what is currently in the drawer or the drawer is full
-- If the item is in the index but either the name that was indexed is not
-- the same as what is currently in the drawer or the drawer is full
elseif drawers_table_index[src_name] then elseif drawers_table_index[src_name] then
local visualid = drawers_table_index[src_name]["visualid"] local visualid = drawers_table_index[src_name]["visualid"]
local indexed_drawer_meta = core.get_meta({x = drawers_table_index[src_name]["drawer_pos_x"], y = drawers_table_index[src_name]["drawer_pos_y"], z = drawers_table_index[src_name]["drawer_pos_z"]}) local indexed_drawer_meta = core.get_meta({x = drawers_table_index[src_name]["drawer_pos_x"], y = drawers_table_index[src_name]["drawer_pos_y"], z = drawers_table_index[src_name]["drawer_pos_z"]})
@ -279,7 +316,11 @@ local function controller_node_timer(pos, elapsed)
end end
end end
-- This might not be needed, but my concern is if the above indexing takes enough time, there could be a "race condition" where the item in the src inventory is no longer the same item when we checked before or the quantity of the items changed so I'm having it grab the item stack again just in case -- This might not be needed, but my concern is if the above indexing takes
-- enough time, there could be a "race condition" where the item in the src
-- inventory is no longer the same item when we checked before or the
-- quantity of the items changed so I'm having it grab the item stack again
-- just in case.
-- If a race condition does occur, items could be lost or duplicated -- If a race condition does occur, items could be lost or duplicated
src = inv:get_stack("src", 1) src = inv:get_stack("src", 1)
src_name = src:get_name() src_name = src:get_name()
@ -342,68 +383,142 @@ local function controller_node_timer(pos, elapsed)
return true return true
end end
-- Set the controller definition using a table to allow for pipeworks and potentially other mod support local function controller_can_dig(pos, player)
local controller_def = {} local meta = core.get_meta(pos);
-- MCL2 requires a few different groups and parameters that default does not
if core.get_modpath("mcl_core") and mcl_core then
controller_def.groups = {pickaxey = 1, stone = 1, building_block = 1, material_stone = 1}
controller_def._mcl_blast_resistance = 30
controller_def._mcl_hardness = 1.5
else
controller_def.groups = {cracky = 3, level = 2}
end
controller_def.description = S("Drawer Controller")
controller_def.tiles = {"drawer_controller_top_bottom.png", "drawer_controller_top_bottom.png", "drawer_controller_side.png", "drawer_controller_side.png", "drawer_controller_side.png", "drawer_controller_side.png"}
controller_def.can_dig = controller_can_dig
controller_def.on_construct = function(pos)
local meta = core.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size('src', 1) return inv:is_empty("src")
end
local function controller_on_construct(pos)
local meta = core.get_meta(pos)
meta:set_string("current_state", "running") meta:set_string("current_state", "running")
meta:set_float("times_ran_while_jammed", 0) meta:set_float("times_ran_while_jammed", 0)
meta:set_string("jammed_item_name", "") meta:set_string("jammed_item_name", "")
meta:set_string("drawers_table_index", "") meta:set_string("drawers_table_index", "")
meta:set_string("formspec", controller_formspec(pos, S("Running"))) meta:set_string("formspec", controller_formspec(pos, S("Running")))
local timer = core.get_node_timer(pos)
timer:start(controller_interval) meta:get_inventory():set_size("src", 1)
core.get_node_timer(pos):start(controller_interval)
end end
controller_def.on_blast = function(pos)
local function controller_on_blast(pos)
local drops = {} local drops = {}
default.get_inventory_drops(pos, "src", drops) default.get_inventory_drops(pos, "src", drops)
drops[#drops+1] = "drawers:controller" drops[#drops+1] = "drawers:controller"
core.remove_node(pos) core.remove_node(pos)
return drops return drops
end end
controller_def.on_timer = controller_node_timer
controller_def.allow_metadata_inventory_put = controller_allow_metadata_inventory_put
controller_def.allow_metadata_inventory_move = controller_allow_metadata_inventory_move
controller_def.allow_metadata_inventory_take = controller_allow_metadata_inventory_take
-- Mostly copied from the drawers in the drawer mod to add pipeworks support local function controller_allow_metadata_inventory_put(pos, listname, index, stack, player)
if core.get_modpath("pipeworks") and pipeworks then if core.is_protected(pos, player:get_player_name()) then
controller_def.groups.tubedevice = 1 return 0
controller_def.groups.tubedevice_receiver = 1
controller_def.tube = controller_def.tube or {}
controller_def.tube.insert_object = function(pos, node, stack, tubedir)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("src", stack)
end end
controller_def.tube.can_insert = function(pos, node, stack, tubedir) if listname == "src" then
local meta = core.get_meta(pos) return stack:get_count()
local inv = meta:get_inventory()
return inv:room_for_item("src", stack)
end end
controller_def.tube.connect_sides = {left = 1, right = 1, back = 1, front = 1,
top = 1, bottom = 1}
controller_def.after_place_node = pipeworks.after_place
controller_def.after_dig_node = pipeworks.after_dig
end end
core.register_node('drawers:controller', controller_def) local function controller_allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
return controller_allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
-- Because the rest of the drawers mod doesn't have a hard depend on default, I changed the recipe to have an alternative local function controller_allow_metadata_inventory_take(pos, listname, index, stack, player)
if core.get_modpath("default") and default then if core.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
-- Registers the drawer controller
local function register_controller()
-- Set the controller definition using a table to allow for pipeworks and
-- potentially other mod support
local def = {}
def.description = S("Drawer Controller")
def.drawtype = "nodebox"
def.node_box = { type = "fixed", fixed = drawers.node_box_simple }
def.collision_box = { type = "regular" }
def.selection_box = { type = "regular" }
def.paramtype = "light"
def.paramtype2 = "facedir"
def.legacy_facedir_simple = true
-- add pipe connectors, if pipeworks is enabled
if pipeworks_loaded then
def.tiles = {
"drawers_controller_top.png^pipeworks_tube_connection_metallic.png",
"drawers_controller_top.png^pipeworks_tube_connection_metallic.png",
"drawers_controller_side.png^pipeworks_tube_connection_metallic.png",
"drawers_controller_side.png^pipeworks_tube_connection_metallic.png",
"drawers_controller_top.png^pipeworks_tube_connection_metallic.png",
"drawers_controller_front.png"
}
else
def.tiles = {
"drawers_controller_top.png",
"drawers_controller_top.png",
"drawers_controller_side.png",
"drawers_controller_side.png",
"drawers_controller_top.png",
"drawers_controller_front.png"
}
end
-- MCL2 requires a few different groups and parameters that MTG does not
if mcl_loaded then
def.groups = {
pickaxey = 1, stone = 1, building_block = 1, material_stone = 1
}
def._mcl_blast_resistance = 30
def._mcl_hardness = 1.5
else
def.groups = {
cracky = 3, level = 2
}
end
def.can_dig = controller_can_dig
def.on_construct = controller_on_construct
def.on_blast = controller_on_blast
def.on_timer = controller_node_timer
def.allow_metadata_inventory_put = controller_allow_metadata_inventory_put
def.allow_metadata_inventory_move = controller_allow_metadata_inventory_move
def.allow_metadata_inventory_take = controller_allow_metadata_inventory_take
if pipeworks_loaded then
def.groups.tubedevice = 1
def.groups.tubedevice_receiver = 1
def.tube = {}
def.tube.insert_object = function(pos, node, stack, tubedir)
return core.get_meta(pos):get_inventory():add_item("src", stack)
end
def.tube.can_insert = function(pos, node, stack, tubedir)
return core.get_meta(pos):get_inventory():room_for_item("src", stack)
end
def.tube.connect_sides = {
left = 1, right = 1, back = 1, top = 1, bottom = 1
}
def.after_place_node = pipeworks.after_place
def.after_dig_node = pipeworks.after_dig
end
core.register_node("drawers:controller", def)
end
-- register drawer controller
register_controller()
if default_loaded then
core.register_craft({ core.register_craft({
output = 'drawers:controller', output = 'drawers:controller',
recipe = { recipe = {
@ -412,7 +527,7 @@ if core.get_modpath("default") and default then
{'default:steel_ingot', 'default:diamond', 'default:steel_ingot'}, {'default:steel_ingot', 'default:diamond', 'default:steel_ingot'},
} }
}) })
elseif core.get_modpath("mcl_core") and mcl_core then elseif mcl_loaded then
core.register_craft({ core.register_craft({
output = 'drawers:controller', output = 'drawers:controller',
recipe = { recipe = {
@ -422,6 +537,8 @@ elseif core.get_modpath("mcl_core") and mcl_core then
} }
}) })
else else
-- Because the rest of the drawers mod doesn't have a hard depend on
-- default, I changed the recipe to have an alternative
core.register_craft({ core.register_craft({
output = 'drawers:controller', output = 'drawers:controller',
recipe = { recipe = {

@ -1,7 +1,7 @@
--[[ --[[
Minetest Mod Storage Drawers - A Mod adding storage drawers Minetest Mod Storage Drawers - A Mod adding storage drawers
Copyright (C) 2017 LNJ <git@lnj.li> Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
MIT License MIT License

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B