diff --git a/sl_robot/commands.lua b/sl_robot/commands.lua index 1f12c02..78dc94b 100644 --- a/sl_robot/commands.lua +++ b/sl_robot/commands.lua @@ -14,6 +14,15 @@ ]]-- +-- constrict value to the given range +local function range(val, min, max) + val = tonumber(val) + if val < min then return min end + if val > max then return max end + return val +end + + sl_robot.register_action("get_ms_time", { cmnd = function(self) @@ -25,7 +34,7 @@ sl_robot.register_action("get_ms_time", { sl_robot.register_action("forward", { cmnd = function(self, steps) - steps = math.min(tonumber(steps or 1), 100) + steps = range(steps, 1, 100) local idx = 1 while idx <= steps do local meta = minetest.get_meta(self.meta.pos) @@ -49,7 +58,7 @@ sl_robot.register_action("forward", { sl_robot.register_action("backward", { cmnd = function(self, steps) - steps = math.min(tonumber(steps or 1), 100) + steps = range(steps, 1, 100) local idx = 1 while idx <= steps do local meta = minetest.get_meta(self.meta.pos) @@ -140,8 +149,8 @@ sl_robot.register_action("down", { sl_robot.register_action("take", { cmnd = function(self, num, slot) - num = math.min(tonumber(num or 1), 99) - slot = math.min(tonumber(slot or 1), 8) + num = range(num, 1, 99) + slot = range(slot, 1, 8) local meta = minetest.get_meta(self.meta.pos) local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos")) local robot_param2 = meta:get_int("robot_param2") @@ -159,8 +168,8 @@ sl_robot.register_action("take", { sl_robot.register_action("add", { cmnd = function(self, num, slot) - num = math.min(tonumber(num or 1), 99) - slot = math.min(tonumber(slot or 1), 8) + num = range(num, 1, 99) + slot = range(slot, 1, 8) local meta = minetest.get_meta(self.meta.pos) local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos")) local robot_param2 = meta:get_int("robot_param2") @@ -177,7 +186,7 @@ sl_robot.register_action("add", { sl_robot.register_action("place", { cmnd = function(self, slot, dir) - slot = math.min(tonumber(slot or 1), 8) + slot = range(slot, 1, 8) local meta = minetest.get_meta(self.meta.pos) local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos")) local robot_param2 = meta:get_int("robot_param2") @@ -193,7 +202,7 @@ sl_robot.register_action("place", { sl_robot.register_action("dig", { cmnd = function(self, slot, dir) - slot = math.min(tonumber(slot or 1), 8) + slot = range(slot, 1, 8) local meta = minetest.get_meta(self.meta.pos) local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos")) local robot_param2 = meta:get_int("robot_param2") @@ -215,17 +224,3 @@ sl_robot.register_action("stop", { end, help = "tbd" }) - ---sl_robot.register_action("run", { --- cmnd = function(self, sCmd, reverse) --- slot = math.min(tonumber(slot or 1), 8) --- local meta = minetest.get_meta(self.meta.pos) --- local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos")) --- local robot_param2 = meta:get_int("robot_param2") - --- for cmnd in sCmd:gmatch("%w+") do --- if cmnd:byte() --- end --- end, --- help = " " ---}) diff --git a/sl_robot/init.lua b/sl_robot/init.lua index 2dd146b..ecfe824 100644 --- a/sl_robot/init.lua +++ b/sl_robot/init.lua @@ -16,3 +16,4 @@ sl_robot = {} dofile(minetest.get_modpath("sl_robot") .. "/robot.lua") dofile(minetest.get_modpath("sl_robot") .. "/base.lua") dofile(minetest.get_modpath("sl_robot") .. "/commands.lua") +dofile(minetest.get_modpath("sl_robot") .. "/run_cmnd.lua") diff --git a/sl_robot/robot.lua b/sl_robot/robot.lua index 40ced31..d8b4548 100644 --- a/sl_robot/robot.lua +++ b/sl_robot/robot.lua @@ -23,40 +23,38 @@ local Face2Dir = {[0]= local Inventories = { - ["default:chest"] = {take = "main", add = "main", fuel = "main"}, - ["default:chest_locked"] = {take = "main", add = "main", fuel = "main"}, - ["default:chest_locked"] = {take = "main", add = "main", fuel = "main"}, - ["default:furnace"] = {take = "dst", add = "src", fuel = "fuel"}, - ["default:furnace_active"] = {take = "dst", add = "src", fuel = "fuel"}, - ["tubelib:distributor"] = {take = "src", add = "src", fuel = "src"}, - ["gravelsieve:sieve"] = {take = "dst", add = "src", fuel = "src"}, - ["gravelsieve:auto_sieve0"] = {take = "dst", add = "src", fuel = "src"}, - ["gravelsieve:auto_sieve1"] = {take = "dst", add = "src", fuel = "src"}, - ["gravelsieve:auto_sieve2"] = {take = "dst", add = "src", fuel = "src"}, - ["gravelsieve:auto_sieve3"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:autocrafter"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:autocrafter_active"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:chest"] = {take = "main", add = "main", fuel = "main"}, - ["tubelib_addons1:fermenter"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:reformer"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:funnel"] = {take = "main", add = "main", fuel = "main"}, - ["tubelib_addons1:grinder"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:grinder_active"] = {take = "dst", add = "src", fuel = "src"}, - ["tubelib_addons1:harvester_base"] = {take = "main", add = "main", fuel = "fuel"}, - ["tubelib_addons1:quarry"] = {take = "main", add = "main", fuel = "fuel"}, - ["tubelib_addons1:quarry_active"] = {take = "main", add = "main", fuel = "fuel"}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, --- [""] = {take = "", add = "", fuel = ""}, + ["tubelib:distributor"] = {take = "src", add = "src"}, + ["tubelib_addons1:harvester_base"] = {take = "main", add = "fuel"}, + ["tubelib_addons1:quarry"] = {take = "main", add = "fuel"}, + ["tubelib_addons1:quarry_active"] = {take = "main", add = "fuel"}, +-- [""] = {take = "", add = ""}, +-- [""] = {take = "", add = ""}, +-- [""] = {take = "", add = ""}, } +local function inv_list_add(inv, name) + if Inventories[name] then + return inv:get_list(Inventories[name].add) + elseif inv:get_list("src") then + return inv:get_list("src") + elseif inv:get_list("main") then + return inv:get_list("main") + end + return nil +end + +local function inv_list_take(inv, name) + if Inventories[name] then + return inv:get_list(Inventories[name].take) + elseif inv:get_list("dst") then + return inv:get_list("dst") + elseif inv:get_list("main") then + return inv:get_list("main") + end + return nil +end + + -- return the largest stack local function peek(src_list) local max_val = 0 @@ -264,19 +262,13 @@ function sl_robot.robot_take(base_pos, robot_pos, param2, owner, num, slot) return end local node = minetest.get_node_or_nil(pos1) or read_node_with_vm(pos1) - if Inventories[node.name] then - local listname = Inventories[node.name].take - local src_inv = minetest.get_inventory({type="node", pos=pos1}) - if src_inv:is_empty(listname) then - return - end - local src_list = src_inv:get_list(listname) - local dst_inv = minetest.get_inventory({type="node", pos=base_pos}) - local dst_list = dst_inv:get_list("main") - if take_num_items(src_list, num, dst_list[slot]) then - src_inv:set_list(listname, src_list) - dst_inv:set_list("main", dst_list) - end + local src_inv = minetest.get_inventory({type="node", pos=pos1}) + local src_list = inv_list_take(src_inv, node.name) + local dst_inv = minetest.get_inventory({type="node", pos=base_pos}) + local dst_list = dst_inv:get_list("main") + if src_list and take_num_items(src_list, num, dst_list[slot]) then + src_inv:set_list(listname, src_list) + dst_inv:set_list("main", dst_list) end end @@ -286,12 +278,11 @@ function sl_robot.robot_add(base_pos, robot_pos, param2, owner, num, slot) return end local node = minetest.get_node_or_nil(pos1) or read_node_with_vm(pos1) - if Inventories[node.name] then - local listname = Inventories[node.name].take - local dst_inv = minetest.get_inventory({type="node", pos=pos1}) - local dst_list = dst_inv:get_list(listname) - local src_inv = minetest.get_inventory({type="node", pos=base_pos}) - local src_list = src_inv:get_list("main") + local dst_inv = minetest.get_inventory({type="node", pos=pos1}) + local dst_list = inv_list_add(dst_inv, node.name) + local src_inv = minetest.get_inventory({type="node", pos=base_pos}) + local src_list = src_inv:get_list("main") + if dst_list then local taken = src_list[slot]:take_item(num) if dst_inv:room_for_item(listname, taken) then dst_inv:add_item(listname, taken) diff --git a/sl_robot/run_cmnd.lua b/sl_robot/run_cmnd.lua new file mode 100644 index 0000000..a879cc0 --- /dev/null +++ b/sl_robot/run_cmnd.lua @@ -0,0 +1,122 @@ +--[[ + + sl_robot + ======== + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + run_cmnd.lua: + + Register the run command + +]]-- + +local function Reverse(arr) + local i, j = 1, #arr + + while i < j do + arr[i], arr[j] = arr[j], arr[i] + + i = i + 1 + j = j - 1 + end +end + +local switch = { + f = function(cmnd) + local num = (cmnd:byte(2) or 0x31) - 0x30 + print("forward("..num..")") + end, + b = function(cmnd) + local num = (cmnd:byte(2) or 0x31) - 0x30 + print("backward("..num..")") + end, + l = function(cmnd, reverse) + if reverse then + print("right()") + else + print("left()") + end + end, + r = function(cmnd, reverse) + if reverse then + print("left()") + else + print("right()") + end + end, + u = function(cmnd) + print("up()") + end, + d = function(cmnd) + print("down()") + end, + t = function(cmnd) + local num, slot + if cmnd:sub(2,2) == "s" then + num = 99 + slot = (cmnd:byte(3) or 0x31) - 0x30 + else + num = 1 + slot = (cmnd:byte(2) or 0x31) - 0x30 + end + print("take("..num..","..slot..")") + end, + a = function(cmnd) + local num, slot + if cmnd:sub(2,2) == "s" then + num = 99 + slot = (cmnd:byte(3) or 0x31) - 0x30 + else + num = 1 + slot = (cmnd:byte(2) or 0x31) - 0x30 + end + print("add("..num..","..slot..")") + end, + p = function(cmnd) + local num, slot + if cmnd:sub(2,2) == "u" then + slot = (cmnd:byte(3) or 0x31) - 0x30 + print("place("..slot..",U)") + elseif cmnd:sub(2,2) == "d" then + slot = (cmnd:byte(3) or 0x31) - 0x30 + print("place("..slot..",D)") + else + slot = (cmnd:byte(2) or 0x31) - 0x30 + print("place("..slot..")") + end + end, + e = function(cmnd) + print(cmnd.." is a invalid command") + end, +} + +local function run(task, reverse) + task = task:gsub("\n", " ") + task = task:gsub("\t", " ") + local cmnds = task:split(" ") + if reverse then + Reverse(cmnds) + end + for i,cmnd in ipairs(cmnds) do + (switch[cmnd:sub(1,1)] or switch["e"])(cmnd, reverse) + end +end + +sl_robot.register_action("run", { + cmnd = function(self, sCmndList, reverse) + sCmndList = sCmndList:gsub("\n", " ") + sCmndList = sCmndList:gsub("\t", " ") + local cmnds = sCmndList:split(" ") + if reverse then + Reverse(cmnds) + end + for i,cmnd in ipairs(cmnds) do + (switch[cmnd:sub(1,1)] or switch["e"])(cmnd, reverse) + end + end, + help = " " +}) diff --git a/tubelib_addons1/init.lua b/tubelib_addons1/init.lua index 48cd012..6ef127f 100644 --- a/tubelib_addons1/init.lua +++ b/tubelib_addons1/init.lua @@ -19,4 +19,4 @@ dofile(minetest.get_modpath("tubelib_addons1") .. '/fermenter.lua') dofile(minetest.get_modpath("tubelib_addons1") .. '/reformer.lua') dofile(minetest.get_modpath("tubelib_addons1") .. '/funnel.lua') dofile(minetest.get_modpath("tubelib_addons1") .. "/pusher_fast.lua") -dofile(minetest.get_modpath("tubelib_addons1") .. '/chest.lua') +dofile(minetest.get_modpath("tubelib_addons1") .. '/chest.lua') \ No newline at end of file diff --git a/tubelib_addons1/textures/tubelib_addons1_autocrafter.png b/tubelib_addons1/textures/tubelib_addons1_autocrafter.png index fbc1d2c..c831b2b 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_autocrafter.png and b/tubelib_addons1/textures/tubelib_addons1_autocrafter.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_autocrafter_active.png b/tubelib_addons1/textures/tubelib_addons1_autocrafter_active.png index 6f3f59b..3e35ef1 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_autocrafter_active.png and b/tubelib_addons1/textures/tubelib_addons1_autocrafter_active.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_biofuel.png b/tubelib_addons1/textures/tubelib_addons1_biofuel.png index 047391a..d91aaac 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_biofuel.png and b/tubelib_addons1/textures/tubelib_addons1_biofuel.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_biogas.png b/tubelib_addons1/textures/tubelib_addons1_biogas.png index 5562895..9d56049 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_biogas.png and b/tubelib_addons1/textures/tubelib_addons1_biogas.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_fermenter_bottom.png b/tubelib_addons1/textures/tubelib_addons1_fermenter_bottom.png index 62c084e..d9d1ac8 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_fermenter_bottom.png and b/tubelib_addons1/textures/tubelib_addons1_fermenter_bottom.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_fermenter_inventory.png b/tubelib_addons1/textures/tubelib_addons1_fermenter_inventory.png index 324fd28..a4795a5 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_fermenter_inventory.png and b/tubelib_addons1/textures/tubelib_addons1_fermenter_inventory.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_fermenter_top.png b/tubelib_addons1/textures/tubelib_addons1_fermenter_top.png index 52efab6..d361b5f 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_fermenter_top.png and b/tubelib_addons1/textures/tubelib_addons1_fermenter_top.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_funnel.png b/tubelib_addons1/textures/tubelib_addons1_funnel.png index 3f89c0f..467342e 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_funnel.png and b/tubelib_addons1/textures/tubelib_addons1_funnel.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_funnel_top.png b/tubelib_addons1/textures/tubelib_addons1_funnel_top.png index fccbbb9..f18d0b6 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_funnel_top.png and b/tubelib_addons1/textures/tubelib_addons1_funnel_top.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_grinder.png b/tubelib_addons1/textures/tubelib_addons1_grinder.png index 88855b7..87e5c58 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_grinder.png and b/tubelib_addons1/textures/tubelib_addons1_grinder.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_grinder_active.png b/tubelib_addons1/textures/tubelib_addons1_grinder_active.png index 704b17b..1707d23 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_grinder_active.png and b/tubelib_addons1/textures/tubelib_addons1_grinder_active.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_harvester.png b/tubelib_addons1/textures/tubelib_addons1_harvester.png index 22f96f9..412e686 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_harvester.png and b/tubelib_addons1/textures/tubelib_addons1_harvester.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_harvester_top.png b/tubelib_addons1/textures/tubelib_addons1_harvester_top.png index 4c8d5f2..0237ce3 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_harvester_top.png and b/tubelib_addons1/textures/tubelib_addons1_harvester_top.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_pusher.png b/tubelib_addons1/textures/tubelib_addons1_pusher.png index d623a76..96c01e0 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_pusher.png and b/tubelib_addons1/textures/tubelib_addons1_pusher.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_quarry.png b/tubelib_addons1/textures/tubelib_addons1_quarry.png index 3d59f1e..dd9bd06 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_quarry.png and b/tubelib_addons1/textures/tubelib_addons1_quarry.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_quarry_active.png b/tubelib_addons1/textures/tubelib_addons1_quarry_active.png index 8561d48..e7b5e81 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_quarry_active.png and b/tubelib_addons1/textures/tubelib_addons1_quarry_active.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_quarry_passive.png b/tubelib_addons1/textures/tubelib_addons1_quarry_passive.png index 86e86eb..a1be3f4 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_quarry_passive.png and b/tubelib_addons1/textures/tubelib_addons1_quarry_passive.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_reformer2_bottom.png b/tubelib_addons1/textures/tubelib_addons1_reformer2_bottom.png index 245b784..994be75 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_reformer2_bottom.png and b/tubelib_addons1/textures/tubelib_addons1_reformer2_bottom.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_reformer2_top.png b/tubelib_addons1/textures/tubelib_addons1_reformer2_top.png index 8f757e4..52ff340 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_reformer2_top.png and b/tubelib_addons1/textures/tubelib_addons1_reformer2_top.png differ diff --git a/tubelib_addons1/textures/tubelib_addons1_reformer_inventory.png b/tubelib_addons1/textures/tubelib_addons1_reformer_inventory.png index fe9d3d6..171ece1 100644 Binary files a/tubelib_addons1/textures/tubelib_addons1_reformer_inventory.png and b/tubelib_addons1/textures/tubelib_addons1_reformer_inventory.png differ diff --git a/tubelib_addons3/chest.lua b/tubelib_addons3/chest.lua new file mode 100644 index 0000000..3a1159e --- /dev/null +++ b/tubelib_addons3/chest.lua @@ -0,0 +1,137 @@ +--[[ + + Tubelib Addons 3 + ================ + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + chest.lua + + A high performance chest + +]]-- + + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + minetest.log("action", player:get_player_name().." moves "..stack:get_name().. + " to chest at "..minetest.pos_to_string(pos)) + return stack:get_count() +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + minetest.log("action", player:get_player_name().." takes "..stack:get_name().. + " from chest at "..minetest.pos_to_string(pos)) + return stack:get_count() +end + +local function get_stack(meta, list) + local inv = meta:get_inventory() + local item = tubelib.get_item(meta, list) + if item and inv:contains_item(list, item) then + -- try to remove a complete stack + item:set_count(98) + local taken = inv:remove_item(list, item) + -- add the already removed + taken:set_count(taken:get_count() + 1) + return taken + end + return item +end + + +local function formspec() + return "size[12,10]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;main;0,0;12,6;]".. + "list[current_player;main;2,6.3;8,4;]".. + "listring[context;main]".. + "listring[current_player;main]" +end + +minetest.register_node("tubelib_addons3:chest", { + description = "HighPerf Chest", + tiles = { + -- up, down, right, left, back, front + 'tubelib_addons3_chest_bottom.png', + 'tubelib_addons3_chest_bottom.png', + "tubelib_addons3_chest_side.png", + "tubelib_addons3_chest_side.png", + "tubelib_addons3_chest_side.png", + "tubelib_addons3_chest_front.png", + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size('main', 72) + end, + + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec()) + meta:set_string("infotext", "HighPerf Chest") + end, + + can_dig = function(pos,player) + if minetest.is_protected(pos, player:get_player_name()) then + return false + end + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("main") + end, + + on_dig = function(pos, node, puncher, pointed_thing) + minetest.node_dig(pos, node, puncher, pointed_thing) + end, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + +minetest.register_craft({ + output = "tubelib_addons3:chest", + recipe = { + {"", "default:steel_ingot", ""}, + {"tubelib_addons1:chest", "default:gold_ingot", "tubelib_addons1:chest"}, + {"", "default:tin_ingot", ""}, + } +}) + +tubelib.register_node("tubelib_addons3:chest", {}, { + on_pull_item = function(pos, side) + local meta = minetest.get_meta(pos) + return get_stack(meta, "main") + end, + on_push_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + tubelib.put_item(meta, "main", item) + end, + on_unpull_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + return tubelib.put_item(meta, "main", item) + end, + + on_recv_message = function(pos, topic, payload) + return "unsupported" + end, +}) diff --git a/tubelib_addons3/depends.txt b/tubelib_addons3/depends.txt new file mode 100644 index 0000000..278e6ab --- /dev/null +++ b/tubelib_addons3/depends.txt @@ -0,0 +1,3 @@ +tubelib +tubelib_addons1 +default diff --git a/tubelib_addons3/description.txt b/tubelib_addons3/description.txt new file mode 100644 index 0000000..317b0eb --- /dev/null +++ b/tubelib_addons3/description.txt @@ -0,0 +1,2 @@ +Tubelib Extension with High Performance nodes + diff --git a/tubelib_addons3/distributor.lua b/tubelib_addons3/distributor.lua new file mode 100644 index 0000000..0357a20 --- /dev/null +++ b/tubelib_addons3/distributor.lua @@ -0,0 +1,491 @@ +--[[ + + Tubelib Addons 3 + ================ + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + distributor.lua: + + A high performance distributor +]]-- + +local NUM_FILTER_ELEM = 6 +local NUM_FILTER_SLOTS = 4 +local TICKS_TO_SLEEP = 5 +local CYCLE_TIME = 2 +local STOP_STATE = 0 +local STANDBY_STATE = -1 + +-- Get one item-stack from the given ItemList, specified by stack number (1..n). +-- Returns nil if ItemList is empty. +local function get_this_stack(meta, listname, number) + if meta == nil or meta.get_inventory == nil then return nil end + local inv = meta:get_inventory() + if inv:is_empty(listname) then + return nil + end + + local items = inv:get_stack(listname, number) + if items:get_count() > 0 then + return inv:remove_item(listname, items) + end + return nil +end + +-- Return a key/value table with all items and the corresponding stack numbers +local function invlist_content_as_kvlist(list) + local res = {} + for idx,items in ipairs(list) do + local name = items:get_name() + if name ~= "" then + res[name] = idx + end + end + return res +end + +-- Return the total number of list entries +local function invlist_num_entries(list) + local res = 0 + for _,items in ipairs(list) do + local name = items:get_name() + if name ~= "" then + res = res + items:get_count() + end + end + return res +end + +-- Return a flat table with all items +local function invlist_entries_as_list(list) + local res = {} + for _,items in ipairs(list) do + local name = items:get_name() + local count = items:get_count() + if name ~= "" then + for i = 1,count do + res[#res+1] = name + end + end + end + return res +end + + +local function AddToTbl(kvTbl, new_items) + for _, l in ipairs(new_items) do + kvTbl[l] = true + end + return kvTbl +end + + +local function distributor_formspec(state, filter) + return "size[10,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;src;0,0;2,4;]".. + "image[2,1.5;1,1;tubelib_gui_arrow.png]".. + "image_button[2,3;1,1;".. tubelib.state_button(state) ..";button;]".. + "checkbox[3,0;filter1;On;"..dump(filter[1]).."]".. + "checkbox[3,1;filter2;On;"..dump(filter[2]).."]".. + "checkbox[3,2;filter3;On;"..dump(filter[3]).."]".. + "checkbox[3,3;filter4;On;"..dump(filter[4]).."]".. + "image[3.6,0;0.3,1;tubelib_red.png]".. + "image[3.6,1;0.3,1;tubelib_green.png]".. + "image[3.6,2;0.3,1;tubelib_blue.png]".. + "image[3.6,3;0.3,1;tubelib_yellow.png]".. + "list[context;red;4,0;6,1;]".. + "list[context;green;4,1;6,1;]".. + "list[context;blue;4,2;6,1;]".. + "list[context;yellow;4,3;6,1;]".. + "list[current_player;main;1,4.5;8,4;]".. + "listring[context;src]".. + "listring[current_player;main]" +end + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local list = inv:get_list(listname) + + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + if listname == "src" then + return stack:get_count() + elseif invlist_num_entries(list) < NUM_FILTER_ELEM then + return 1 + end + return 0 +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + return stack:get_count() +end + +local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack(from_list, from_index) + return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) +end + +local SlotColors = {"red", "green", "blue", "yellow"} +local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation +local FilterCache = {} -- local cache for filter settings + +local function filter_settings(pos) + local hash = minetest.hash_node_position(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} + local kvFilterItemNames = {} -- { = true,...} + local kvSide2ItemNames = {} -- {"F" = {,...},...} + + -- collect all filter settings + for idx,slot in ipairs(SlotColors) do + local side = Num2Ascii[idx] + if filter[idx] == true then + local list = inv:get_list(slot) + local filter = invlist_entries_as_list(list) + AddToTbl(kvFilterItemNames, filter) + kvSide2ItemNames[side] = filter + end + end + + FilterCache[hash] = { + kvFilterItemNames = kvFilterItemNames, + kvSide2ItemNames = kvSide2ItemNames + } +end + +local function start_the_machine(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + meta:set_int("running", TICKS_TO_SLEEP) + node.name = "tubelib_addons3:distributor_active" + minetest.swap_node(pos, node) + meta:set_string("infotext", "HighPerf Distributor "..number..": running") + local filter = minetest.deserialize(meta:get_string("filter")) + meta:set_string("formspec", distributor_formspec(tubelib.RUNNING, filter)) + minetest.get_node_timer(pos):start(CYCLE_TIME) + return false +end + +local function stop_the_machine(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + meta:set_int("running", STOP_STATE) + node.name = "tubelib_addons3:distributor" + minetest.swap_node(pos, node) + meta:set_string("infotext", "HighPerf Distributor "..number..": stopped") + local filter = minetest.deserialize(meta:get_string("filter")) + meta:set_string("formspec", distributor_formspec(tubelib.STOPPED, filter)) + minetest.get_node_timer(pos):stop() + return false +end + +local function goto_sleep(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + meta:set_int("running", STANDBY_STATE) + node.name = "tubelib_addons3:distributor" + minetest.swap_node(pos, node) + meta:set_string("infotext", "HighPerf Distributor "..number..": standby") + local filter = minetest.deserialize(meta:get_string("filter")) + meta:set_string("formspec", distributor_formspec(tubelib.STANDBY, filter)) + minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) + return false +end + +-- move items to the output slots +local function keep_running(pos, elapsed) + local meta = minetest.get_meta(pos) + local running = meta:get_int("running") - 1 + local player_name = meta:get_string("player_name") + --print("running", running) + local slot_idx = meta:get_int("slot_idx") or 1 + meta:set_int("slot_idx", (slot_idx + 1) % NUM_FILTER_SLOTS) + local side = Num2Ascii[slot_idx+1] + local listname = SlotColors[slot_idx+1] + local inv = meta:get_inventory() + local list = inv:get_list("src") + local kvSrc = invlist_content_as_kvlist(list) + local counter = minetest.deserialize(meta:get_string("item_counter")) or + {red=0, green=0, blue=0, yellow=0} + + -- calculate the filter settings only once + local hash = minetest.hash_node_position(pos) + if FilterCache[hash] == nil then + filter_settings(pos) + end + + -- read data from Cache + -- all filter items as key/value { = true,...} + local kvFilterItemNames = FilterCache[hash].kvFilterItemNames + -- filter items of one slot as list {,...} + local names = FilterCache[hash].kvSide2ItemNames[side] + + if names == nil then + -- this slot is empty + return true + end + + local busy = false + -- move items from configured filters to the output + if next(names) then + for _,name in ipairs(names) do + if kvSrc[name] then + local item = get_this_stack(meta, "src", kvSrc[name]) + if item then + if not tubelib.push_items(pos, side, item, player_name) then + tubelib.put_item(meta, "src", item) + else + counter[listname] = counter[listname] + 1 + busy = true + end + end + end + end + end + + -- move additional items from unconfigured filters to the output + if next(names) == nil then + for name,_ in pairs(kvSrc) do + if kvFilterItemNames[name] == nil then -- not in the filter so far? + local item = get_this_stack(meta, "src", kvSrc[name]) + if item then + if not tubelib.push_items(pos, side, item, player_name) then + tubelib.put_item(meta, "src", item) + else + counter[listname] = counter[listname] + 1 + busy = true + end + end + end + end + end + + if busy == true then + if running <= 0 then + return start_the_machine(pos) + else + running = TICKS_TO_SLEEP + end + else + if running <= 0 then + return goto_sleep(pos) + end + end + + meta:set_string("item_counter", minetest.serialize(counter)) + meta:set_int("running", running) + return true +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + local meta = minetest.get_meta(pos) + local running = meta:get_int("running") + local filter = minetest.deserialize(meta:get_string("filter")) + if fields.filter1 ~= nil then + filter[1] = fields.filter1 == "true" + elseif fields.filter2 ~= nil then + filter[2] = fields.filter2 == "true" + elseif fields.filter3 ~= nil then + filter[3] = fields.filter3 == "true" + elseif fields.filter4 ~= nil then + filter[4] = fields.filter4 == "true" + end + meta:set_string("filter", minetest.serialize(filter)) + + filter_settings(pos) + + if fields.button ~= nil then + if running > STOP_STATE then + stop_the_machine(pos) + else + start_the_machine(pos) + end + else + meta:set_string("formspec", distributor_formspec(tubelib.state(running), filter)) + end +end + +-- tubelib command to turn on/off filter channels +local function change_filter_settings(pos, slot, val) + local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4} + local meta = minetest.get_meta(pos) + local filter = minetest.deserialize(meta:get_string("filter")) + local num = slots[slot] or 1 + if num >= 1 and num <= 4 then + filter[num] = val == "on" + end + meta:set_string("filter", minetest.serialize(filter)) + + filter_settings(pos) + + local running = meta:get_int("running") + meta:set_string("formspec", distributor_formspec(tubelib.state(running), filter)) + return true +end + +minetest.register_node("tubelib_addons3:distributor", { + description = "HighPerf Distributor", + tiles = { + -- up, down, right, left, back, front + 'tubelib_distributor.png^tubelib_addons3_node_frame.png', + 'tubelib_distributor.png^tubelib_addons3_node_frame.png', + 'tubelib_distributor_yellow.png^tubelib_addons3_node_frame.png', + 'tubelib_distributor_green.png^tubelib_addons3_node_frame.png', + "tubelib_distributor_red.png^tubelib_addons3_node_frame.png", + "tubelib_distributor_blue.png^tubelib_addons3_node_frame.png", + }, + + after_place_node = function(pos, placer) + local number = tubelib.add_node(pos, "tubelib_addons3:distributor") + local meta = minetest.get_meta(pos) + meta:set_string("player_name", placer:get_player_name()) + + local filter = {false,false,false,false} + meta:set_string("formspec", distributor_formspec(tubelib.STOPPED, filter)) + meta:set_string("filter", minetest.serialize(filter)) + meta:set_string("number", number) + meta:set_string("infotext", "HighPerf Distributor "..number..": stopped") + local inv = meta:get_inventory() + inv:set_size('src', 8) + inv:set_size('yellow', 6) + inv:set_size('green', 6) + inv:set_size('red', 6) + inv:set_size('blue', 6) + meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) + end, + + on_receive_fields = on_receive_fields, + + on_dig = function(pos, node, puncher, pointed_thing) + if minetest.is_protected(pos, puncher:get_player_name()) then + return + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if inv:is_empty("src") then + minetest.node_dig(pos, node, puncher, pointed_thing) + tubelib.remove_node(pos) + end + end, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + allow_metadata_inventory_move = allow_metadata_inventory_move, + + on_timer = keep_running, + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + +minetest.register_node("tubelib_addons3:distributor_active", { + description = "HighPerf Distributor", + tiles = { + -- up, down, right, left, back, front + { + image = "tubelib_addons3_distributor_active.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0, + }, + }, + 'tubelib_distributor.png^tubelib_addons3_node_frame.png', + 'tubelib_distributor_yellow.png^tubelib_addons3_node_frame.png', + 'tubelib_distributor_green.png^tubelib_addons3_node_frame.png', + "tubelib_distributor_red.png^tubelib_addons3_node_frame.png", + "tubelib_distributor_blue.png^tubelib_addons3_node_frame.png", + }, + + on_receive_fields = on_receive_fields, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + allow_metadata_inventory_move = allow_metadata_inventory_move, + + on_timer = keep_running, + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {crumbly=0, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_craft({ + output = "tubelib_addons3:distributor", + recipe = { + {"", "default:steel_ingot", ""}, + {"default:gold_ingot", "tubelib:distributor", "default:tin_ingot"}, + {"", "default:steel_ingot", ""}, + }, +}) + + +tubelib.register_node("tubelib_addons3:distributor", {"tubelib_addons3:distributor_active"}, { + on_pull_item = function(pos, side) + local meta = minetest.get_meta(pos) + return tubelib.get_item(meta, "src") + end, + on_push_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + return tubelib.put_item(meta, "src", item) + end, + on_unpull_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + return tubelib.put_item(meta, "src", item) + end, + on_recv_message = function(pos, topic, payload) + if topic == "on" then + return start_the_machine(pos) + elseif topic == "off" then + return stop_the_machine(pos) + elseif topic == "state" then + local meta = minetest.get_meta(pos) + local running = meta:get_int("running") + return tubelib.statestring(running) + elseif topic == "filter" then + return change_filter_settings(pos, payload.slot, payload.val) + elseif topic == "counter" then + local meta = minetest.get_meta(pos) + return minetest.deserialize(meta:get_string("item_counter")) or + {red=0, green=0, blue=0, yellow=0} + elseif topic == "clear_counter" then + local meta = minetest.get_meta(pos) + meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) + else + return "unsupported" + end + end, +}) diff --git a/tubelib_addons3/init.lua b/tubelib_addons3/init.lua new file mode 100644 index 0000000..be003d1 --- /dev/null +++ b/tubelib_addons3/init.lua @@ -0,0 +1,15 @@ +--[[ + + Tubelib Addons 3 + ================ + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + +]]-- + +dofile(minetest.get_modpath("tubelib_addons3") .. '/pushing_chest.lua') +dofile(minetest.get_modpath("tubelib_addons3") .. '/chest.lua') +dofile(minetest.get_modpath("tubelib_addons3") .. '/distributor.lua') \ No newline at end of file diff --git a/tubelib_addons3/mod.conf b/tubelib_addons3/mod.conf new file mode 100644 index 0000000..c545ead --- /dev/null +++ b/tubelib_addons3/mod.conf @@ -0,0 +1 @@ +name=tubelib_addons3 diff --git a/tubelib_addons3/pushing_chest.lua b/tubelib_addons3/pushing_chest.lua new file mode 100644 index 0000000..07dc1bd --- /dev/null +++ b/tubelib_addons3/pushing_chest.lua @@ -0,0 +1,203 @@ +--[[ + + Tubelib Addons 3 + ================ + + Copyright (C) 2017-2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + pushing_chest.lua + + A high performance pushing chest + +]]-- + + +local Cache = {} + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + Cache[minetest.get_meta(pos):get_string("number")] = nil + minetest.log("action", player:get_player_name().." moves "..stack:get_name().. + " to chest at "..minetest.pos_to_string(pos)) + return stack:get_count() +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + Cache[minetest.get_meta(pos):get_string("number")] = nil + minetest.log("action", player:get_player_name().." takes "..stack:get_name().. + " from chest at "..minetest.pos_to_string(pos)) + return stack:get_count() +end + +local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + Cache[minetest.get_meta(pos):get_string("number")] = nil + return count +end + +local function configured(pos, item) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local number = meta:get_string("number") + if not Cache[number] then + Cache[number] = {} + for _,items in ipairs(inv:get_list("main")) do + Cache[number][items:get_name()] = true + end + end + return Cache[number][item:get_name()] == true +end + +local function shift_items(pos, elapsed) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if not inv:is_empty("shift") then + local number = meta:get_string("number") + local player_name = meta:get_string("player_name") + local offs = meta:get_int("offs") + meta:set_int("offs", offs + 1) + for i = 0,7 do + local idx = ((i + offs) % 8) + 1 + local stack = inv:get_stack("shift", idx) + if stack:get_count() > 0 then + if tubelib.push_items(pos, "R", stack, player_name) then + inv:set_stack("shift", idx, nil) + return true + end + end + end + end + return true +end + +local function formspec() + return "size[9,9.2]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;shift;0.5,0;8,1;]".. + "list[context;main;0.5,1.2;8,4;]".. + "image[0.5,0;1,1;tubelib_gui_arrow.png]".. + "image[7.5,0;1,1;tubelib_gui_arrow.png]".. + "list[current_player;main;0.5,5.5;8,4;]".. + "image[0.5,1.2;1,1;tubelib_gui_arrow.png^[transformR270]".. + "listring[context;main]".. + "listring[current_player;main]" +end + +minetest.register_node("tubelib_addons3:pushing_chest", { + description = "HighPerf Pushing Chest", + tiles = { + -- up, down, right, left, back, front + { + image = "tubelib_addons3_pushing_chest.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0, + }, + }, + 'tubelib_addons3_chest_bottom.png', + "tubelib_addons3_chest_out.png", + "tubelib_addons3_chest_side.png", + "tubelib_addons3_chest_side.png", + "tubelib_addons3_chest_front.png", + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size('main', 32) + inv:set_size('shift', 8) + end, + + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + local number = tubelib.add_node(pos, "tubelib_addons3:pushing_chest") + meta:set_string("player_name", placer:get_player_name()) + meta:set_string("number", number) + meta:set_string("formspec", formspec()) + meta:set_string("infotext", "HighPerf Pushing Chest "..number) + minetest.get_node_timer(pos):start(2) + end, + + can_dig = function(pos,player) + if minetest.is_protected(pos, player:get_player_name()) then + return false + end + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("main") and inv:is_empty("shift") + end, + + on_dig = function(pos, node, puncher, pointed_thing) + minetest.node_dig(pos, node, puncher, pointed_thing) + end, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + allow_metadata_inventory_move = allow_metadata_inventory_move, + + on_timer = shift_items, + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + +minetest.register_craft({ + output = "tubelib_addons3:pushing_chest", + recipe = { + { "", "default:tin_ingot", ""}, + {"default:chest", "default:gold_ingot", "tubelib:distributor"}, + {"", "default:steel_ingot", ""}, + } +}) + +tubelib.register_node("tubelib_addons3:pushing_chest", {}, { + on_pull_item = function(pos, side) + local meta = minetest.get_meta(pos) + local item = tubelib.get_item(meta, "main") + -- check if one remaining item is left + if meta:get_inventory():contains_item("main", item) then + return item + else + -- don't remove the last item (recipe) + tubelib.put_item(meta, "main", item) + return nil + end + end, + on_push_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + if configured(pos, item) then + return tubelib.put_item(meta, "main", item) + else + return tubelib.put_item(meta, "shift", item) + end + end, + on_unpull_item = function(pos, side, item) + local meta = minetest.get_meta(pos) + return tubelib.put_item(meta, "main", item) + end, + + on_recv_message = function(pos, topic, payload) + return "unsupported" + end, +}) diff --git a/tubelib_addons3/textures/tubelib_addons3_chest_bottom.png b/tubelib_addons3/textures/tubelib_addons3_chest_bottom.png new file mode 100644 index 0000000..4369e36 Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_chest_bottom.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_chest_front.png b/tubelib_addons3/textures/tubelib_addons3_chest_front.png new file mode 100644 index 0000000..782d5ef Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_chest_front.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_chest_out.png b/tubelib_addons3/textures/tubelib_addons3_chest_out.png new file mode 100644 index 0000000..e9077ba Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_chest_out.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_chest_side.png b/tubelib_addons3/textures/tubelib_addons3_chest_side.png new file mode 100644 index 0000000..4ff4d6f Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_chest_side.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_distributor_active.png b/tubelib_addons3/textures/tubelib_addons3_distributor_active.png new file mode 100644 index 0000000..3be1edd Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_distributor_active.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_node_frame.png b/tubelib_addons3/textures/tubelib_addons3_node_frame.png new file mode 100644 index 0000000..2aae6d5 Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_node_frame.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_pushing_chest.png b/tubelib_addons3/textures/tubelib_addons3_pushing_chest.png new file mode 100644 index 0000000..b6342a7 Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_pushing_chest.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_stack_chest_front.png b/tubelib_addons3/textures/tubelib_addons3_stack_chest_front.png new file mode 100644 index 0000000..0a943d3 Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_stack_chest_front.png differ diff --git a/tubelib_addons3/textures/tubelib_addons3_stack_chest_side.png b/tubelib_addons3/textures/tubelib_addons3_stack_chest_side.png new file mode 100644 index 0000000..0ad2fc7 Binary files /dev/null and b/tubelib_addons3/textures/tubelib_addons3_stack_chest_side.png differ