From 363d12194e9f34a630b16c0e2ea8eb053c49294d Mon Sep 17 00:00:00 2001 From: Evert Date: Sat, 7 Apr 2018 18:27:34 +0300 Subject: [PATCH] Add basic nodes, blatantly copy networking from technic --- init.lua | 5 + network.lua | 408 ++++++++++++++++++ nodes.lua | 20 + nodes/cable.lua | 47 ++ nodes/common.lua | 21 + nodes/controller.lua | 47 ++ nodes/crafting_grid.lua | 53 +++ nodes/disk_drive.lua | 47 ++ nodes/grid.lua | 53 +++ textures/storagetest_cable.png | Bin 0 -> 199 bytes textures/storagetest_controller.png | Bin 0 -> 526 bytes textures/storagetest_controller_animated.png | Bin 0 -> 1356 bytes textures/storagetest_crafting_grid.png | Bin 0 -> 488 bytes textures/storagetest_crafting_grid_active.png | Bin 0 -> 451 bytes textures/storagetest_drive.png | Bin 0 -> 393 bytes textures/storagetest_drive_section1.png | Bin 0 -> 179 bytes textures/storagetest_drive_section2.png | Bin 0 -> 180 bytes textures/storagetest_drive_section3.png | Bin 0 -> 188 bytes textures/storagetest_drive_section4.png | Bin 0 -> 181 bytes textures/storagetest_drive_section5.png | Bin 0 -> 188 bytes textures/storagetest_drive_section6.png | Bin 0 -> 182 bytes textures/storagetest_drive_side.png | Bin 0 -> 355 bytes textures/storagetest_grid.png | Bin 0 -> 458 bytes textures/storagetest_grid_active.png | Bin 0 -> 446 bytes textures/storagetest_machine_block.png | Bin 0 -> 647 bytes 25 files changed, 701 insertions(+) create mode 100644 network.lua create mode 100644 nodes/cable.lua create mode 100644 nodes/common.lua create mode 100644 nodes/controller.lua create mode 100644 nodes/crafting_grid.lua create mode 100644 nodes/disk_drive.lua create mode 100644 nodes/grid.lua create mode 100644 textures/storagetest_cable.png create mode 100644 textures/storagetest_controller.png create mode 100644 textures/storagetest_controller_animated.png create mode 100644 textures/storagetest_crafting_grid.png create mode 100644 textures/storagetest_crafting_grid_active.png create mode 100644 textures/storagetest_drive.png create mode 100644 textures/storagetest_drive_section1.png create mode 100644 textures/storagetest_drive_section2.png create mode 100644 textures/storagetest_drive_section3.png create mode 100644 textures/storagetest_drive_section4.png create mode 100644 textures/storagetest_drive_section5.png create mode 100644 textures/storagetest_drive_section6.png create mode 100644 textures/storagetest_drive_side.png create mode 100644 textures/storagetest_grid.png create mode 100644 textures/storagetest_grid_active.png create mode 100644 textures/storagetest_machine_block.png diff --git a/init.lua b/init.lua index bdbdd11..c6e6541 100644 --- a/init.lua +++ b/init.lua @@ -5,5 +5,10 @@ storagetest = rawget(_G, "storagetest") or {} local modpath = minetest.get_modpath(minetest.get_current_modname()) storagetest.modpath = modpath +storagetest.devices = {} + +-- Network +dofile(modpath.."/network.lua") + -- Nodes dofile(modpath.."/nodes.lua") diff --git a/network.lua b/network.lua new file mode 100644 index 0000000..eeadfbe --- /dev/null +++ b/network.lua @@ -0,0 +1,408 @@ +-- Storagetest Network +-- Some code borrowed from Technic (https://github.com/minetest-mods/technic/blob/master/technic/machines/switching_station.lua) + +storagetest.network = {} +storagetest.network.networks = {} +storagetest.network.devices = {} +storagetest.network.redundant_warn = {} + +function storagetest.get_or_load_node(pos) + local node = minetest.get_node_or_nil(pos) + if node then return node end + local vm = VoxelManip() + local MinEdge, MaxEdge = vm:read_from_map(pos, pos) + return nil +end + +local function get_item_group(name, grp) + return minetest.get_item_group(name, grp) > 0 +end + +function storagetest.network.is_network_conductor(name) + return get_item_group(name, "storagetest_distributor") +end + +function storagetest.network.is_network_device(name) + return get_item_group(name, "storagetest_device") +end + +----------------------- +-- Network traversal -- +----------------------- + +local function flatten(map) + local list = {} + for key, value in pairs(map) do + list[#list + 1] = value + end + return list +end + +-- Add a node to the network +local function add_network_node(nodes, pos, network_id) + local node_id = minetest.hash_node_position(pos) + storagetest.network.devices[node_id] = network_id + if nodes[node_id] then + return false + end + nodes[node_id] = pos + return true +end + +local function add_cable_node(nodes, pos, network_id, queue) + if add_network_node(nodes, pos, network_id) then + queue[#queue + 1] = pos + end +end + +local check_node_subp = function(dv_nodes, st_nodes, controllers, all_nodes, pos, devices, c_pos, network_id, queue) + storagetest.get_or_load_node(pos) + local meta = minetest.get_meta(pos) + local name = minetest.get_node(pos).name + + if storagetest.network.is_network_conductor(name) then + add_cable_node(all_nodes, pos, network_id, queue) + end + + if devices[name] then + meta:set_string("st_network", minetest.pos_to_string(c_pos)) + if get_item_group(name, "storagetest_controller") then + -- Another controller, disable it + add_network_node(controllers, pos, network_id) + meta:set_int("active", 0) + elseif get_item_group(name, "storagetest_storage") then + add_network_node(st_nodes, pos, network_id) + elseif storagetest.network.is_network_device(name) then + add_network_node(dv_nodes, pos, network_id) + end + + meta:set_int("nw_timeout", 2) + end +end + +-- Traverse a network given a list of machines and a cable type name +local traverse_network = function(dv_nodes, st_nodes, controllers, all_nodes, pos, devices, c_pos, network_id, queue) + local positions = { + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y+1, z=pos.z}, + {x=pos.x, y=pos.y-1, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+1}, + {x=pos.x, y=pos.y, z=pos.z-1}} + for _, cur_pos in pairs(positions) do + check_node_subp(dv_nodes, st_nodes, controllers, all_nodes, cur_pos, devices, c_pos, network_id, queue) + end +end + +local touch_nodes = function(list) + for _, pos in ipairs(list) do + local meta = minetest.get_meta(pos) + meta:set_int("nw_timeout", 2) -- Touch node + end +end + +local function get_network(c_pos, positions) + local network_id = minetest.hash_node_position(c_pos) + local cached = storagetest.network.networks[network_id] + + if cached then + touch_nodes(cached.dv_nodes) + touch_nodes(cached.st_nodes) + for _, pos in ipairs(cached.controllers) do + local meta = minetest.get_meta(pos) + meta:set_int("active", 0) + meta:set_string("active_pos", minetest.serialize(c_pos)) + end + return cached.dv_nodes, cached.st_nodes + end + + local dv_nodes = {} + local st_nodes = {} + local controllers = {} + local all_nodes = {} + local queue = {} + + for pos in pairs(positions) do + queue = {} + + local node = minetest.get_node(pos) + if node and storagetest.network.is_network_conductor(node.name) and not storagetest.network.is_network_device(node.name) then + add_cable_node(all_nodes, pos, network_id, queue) + elseif node and storagetest.network.is_network_device(node.name) then + queue = {c_pos} + end + + while next(queue) do + local to_visit = {} + for _, posi in ipairs(queue) do + traverse_network(dv_nodes, st_nodes, controllers, all_nodes, + posi, storagetest.devices, c_pos, network_id, to_visit) + end + queue = to_visit + end + end + + dv_nodes = flatten(dv_nodes) + st_nodes = flatten(st_nodes) + controllers = flatten(controllers) + all_nodes = flatten(all_nodes) + + storagetest.network.networks[network_id] = {all_nodes = all_nodes, dv_nodes = dv_nodes, + st_nodes = st_nodes, controllers = controllers} + return dv_nodes, st_nodes +end + +-------------------- +-- Controller ABM -- +-------------------- + +storagetest.network.active_state = true + +minetest.register_chatcommand("storagectl", { + params = "state", + description = "Enables or disables Storagetest's storage controller ABM", + privs = { basic_privs = true }, + func = function(name, state) + if state == "on" then + storagetest.network.active_state = true + else + storagetest.network.active_state = false + end + end +}) + +local function concatinate(t1,t2) + for i=1,#t2 do + t1[#t1+1] = t2[i] + end + return t1 +end + +function storagetest.network.register_abm_controller(name) + minetest.register_abm({ + nodenames = {name}, + label = "Storage Controller", -- allows the mtt profiler to profile this abm individually + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + if not storagetest.network.active_state then return end + local meta = minetest.get_meta(pos) + local meta1 = nil + + local dv_nodes = {} + local st_nodes = {} + local device_name = "Storage Controller" + + local positions = { + {x=pos.x, y=pos.y-1, z=pos.z}, + {x=pos.x, y=pos.y+1, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z-1}, + {x=pos.x, y=pos.y, z=pos.z+1} + } + + local ntwks = {} + local errored = false + local nw_branches = 0 + for _,pos1 in pairs(positions) do + --Disable if necessary + if meta:get_int("active") ~= 1 then + minetest.forceload_free_block(pos) + minetest.forceload_free_block(pos1) + meta:set_string("infotext",("%s Already Present"):format(device_name)) + + local poshash = minetest.hash_node_position(pos) + + if not storagetest.network.redundant_warn[poshash] then + storagetest.network.redundant_warn[poshash] = true + print("[Storagetest] Warning: redundant controller found near "..minetest.pos_to_string(pos)) + end + errored = true + return + end + + local name = minetest.get_node(pos1).name + local networked = storagetest.network.is_network_conductor(name) + if networked then + ntwks[pos1] = true + nw_branches = nw_branches + 1 + end + end + + if errored then + return + end + + if nw_branches == 0 then + minetest.forceload_free_block(pos) + meta:set_string("infotext", ("%s Has No Network"):format(device_name)) + return + else + minetest.forceload_block(pos) + end + + dv_nodes, st_nodes = get_network(pos, ntwks) + local network_id = minetest.hash_node_position(pos) + + -- Run all the nodes + local function run_nodes(list) + for _, pos2 in ipairs(list) do + storagetest.get_or_load_node(pos2) + local node2 = minetest.get_node(pos2) + local nodedef + if node2 and node2.name then + nodedef = minetest.registered_nodes[node2.name] + end + if nodedef and nodedef.storagetest_run then + nodedef.storagetest_run(pos2, node2, network_id) + end + end + end + + run_nodes(dv_nodes) + run_nodes(st_nodes) + + meta:set_string("infotext", ("%s Active"):format(device_name)) + end, + }) +end + +------------------------------------- +-- Update networks on block change -- +------------------------------------- + +local function check_connections(pos) + local machines = {} + for name in pairs(storagetest.devices) do + machines[name] = true + end + local connections = {} + local positions = { + {x=pos.x+1, y=pos.y, z=pos.z}, + {x=pos.x-1, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y+1, z=pos.z}, + {x=pos.x, y=pos.y-1, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+1}, + {x=pos.x, y=pos.y, z=pos.z-1}} + for _,connected_pos in pairs(positions) do + local name = minetest.get_node(connected_pos).name + if machines[name] or storagetest.network.is_network_conductor(name) or get_item_group(name, "storagetest_controller") then + table.insert(connections,connected_pos) + end + end + return connections +end + +function storagetest.network.clear_networks(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + local name = node.name + local placed = name ~= "air" + local positions = check_connections(pos) + if #positions < 1 then return end + local dead_end = #positions == 1 + for _,connected_pos in pairs(positions) do + local net = storagetest.network.devices[minetest.hash_node_position(connected_pos)] or minetest.hash_node_position(connected_pos) + if net and storagetest.network.networks[net] then + if dead_end and placed then + -- Dead end placed, add it to the network + -- Get the network + local node_at = minetest.get_node(positions[1]) + local network_id = storagetest.network.devices[minetest.hash_node_position(positions[1])] or minetest.hash_node_position(positions[1]) + + if not network_id or not storagetest.network.networks[network_id] then + -- We're evidently not on a network, nothing to add ourselves to + return + end + local c_pos = minetest.get_position_from_hash(network_id) + local network = storagetest.network.networks[network_id] + + -- Actually add it to the (cached) network + -- This is similar to check_node_subp + storagetest.network.devices[minetest.hash_node_position(pos)] = network_id + pos.visited = 1 + + if storagetest.network.is_network_conductor(name) then + table.insert(network.all_nodes, pos) + end + + if storagetest.devices[name] then + meta:set_string("st_network", minetest.pos_to_string(c_pos)) + if get_item_group(name, "storagetest_controller") then + table.insert(network.controllers, pos) + elseif storagetest.network.is_network_device(name) then + table.insert(network.dv_nodes, pos) + end + end + elseif dead_end and not placed then + -- Dead end removed, remove it from the network + -- Get the network + local network_id = storagetest.network.devices[minetest.hash_node_position(positions[1])] or minetest.hash_node_position(positions[1]) + if not network_id or not storagetest.network.networks[network_id] then + -- We're evidently not on a network, nothing to remove ourselves from + return + end + local network = storagetest.network.networks[network_id] + + -- Search for and remove device + storagetest.network.devices[minetest.hash_node_position(pos)] = nil + for tblname,table in pairs(network) do + for devicenum,device in pairs(table) do + if device.x == pos.x + and device.y == pos.y + and device.z == pos.z then + table[devicenum] = nil + end + end + end + else + -- Not a dead end, so the whole network needs to be recalculated + for _,v in pairs(storagetest.network.networks[net].all_nodes) do + local pos1 = minetest.hash_node_position(v) + storagetest.network.devices[pos1] = nil + end + storagetest.network.networks[net] = nil + end + end + end +end + +-- Timeout ABM +-- Timeout for a node in case it was disconnected from the network +-- A node must be touched by the station continuously in order to function +local function controller_timeout_count(pos, tier) + local meta = minetest.get_meta(pos) + local timeout = meta:get_int("nw_timeout") + if timeout <= 0 then + return true + else + meta:set_int("nw_timeout", timeout - 1) + return false + end +end + +function storagetest.network.register_abm_nodes() + minetest.register_abm({ + label = "Devices: timeout check", + nodenames = {"group:storagetest_device"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local meta = minetest.get_meta(pos) + if storagetest.devices[node.name] and controller_timeout_count(pos) then + local nodedef = minetest.registered_nodes[node.name] + if nodedef and nodedef.storagetest_disabled_name then + node.name = nodedef.storagetest_disabled_name + minetest.swap_node(pos, node) + elseif nodedef and nodedef.storagetest_on_disable then + nodedef.storagetest_on_disable(pos, node) + end + if nodedef then + local meta = minetest.get_meta(pos) + meta:set_string("infotext", ("%s Has No Network"):format(nodedef.description)) + end + end + end, + }) +end diff --git a/nodes.lua b/nodes.lua index cfa185d..84f68eb 100644 --- a/nodes.lua +++ b/nodes.lua @@ -1 +1,21 @@ -- Storagetest nodes + +-- Common registrations +dofile(storagetest.modpath.."/nodes/common.lua") + +-- Controller +dofile(storagetest.modpath.."/nodes/controller.lua") + +-- Cabling +dofile(storagetest.modpath.."/nodes/cable.lua") + +-- Disk drives +dofile(storagetest.modpath.."/nodes/disk_drive.lua") + +-- Grids +dofile(storagetest.modpath.."/nodes/grid.lua") +dofile(storagetest.modpath.."/nodes/crafting_grid.lua") + +-- Start the network +storagetest.network.register_abm_controller("storagetest:controller_active") +storagetest.network.register_abm_nodes() diff --git a/nodes/cable.lua b/nodes/cable.lua new file mode 100644 index 0000000..9b589b2 --- /dev/null +++ b/nodes/cable.lua @@ -0,0 +1,47 @@ +-- Storagetest cabling + +minetest.register_node("storagetest:cable", { + description = "Storage Cable", + drawtype = "nodebox", + tiles = {"storagetest_cable.png"}, + node_box = { + type = "connected", + fixed = {{-1/8, -1/8, -1/8, 1/8, 1/8, 1/8}}, + connect_front = { + {-1/8, -1/8, -1/2, 1/8, 1/8, -1/8} + }, + connect_back = { + {-1/8, -1/8, 1/8, 1/8, 1/8, 1/2} + }, + connect_top = { + {-1/8, 1/8, -1/8, 1/8, 1/2, 1/8} + }, + connect_bottom = { + {-1/8, -1/2, -1/8, 1/8, -1/8, 1/8} + }, + connect_left = { + {-1/2, -1/8, -1/8, 1/8, 1/8, 1/8} + }, + connect_right = { + {1/8, -1/8, -1/8, 1/2, 1/8, 1/8} + }, + }, + paramtype = "light", + connect_sides = { "top", "bottom", "front", "left", "back", "right" }, + is_ground_content = false, + connects_to = { + "group:storagetest_controller", + "group:storagetest_distributor", + "group:storagetest_cable", + }, + groups = { + storagetest_distributor = 1, + storagetest_cable = 1, + cracky = 2, + oddly_breakable_by_hand = 2 + }, + on_construct = function (pos) + storagetest.network.clear_networks(pos) + end, + on_destruct = storagetest.network.clear_networks, +}) diff --git a/nodes/common.lua b/nodes/common.lua new file mode 100644 index 0000000..d60e352 --- /dev/null +++ b/nodes/common.lua @@ -0,0 +1,21 @@ +-- Storagetest commons + +storagetest.helpers = {} + +function storagetest.helpers.swap_node(pos, noded) + local node = minetest.get_node(pos) + if node.name == noded.name then + return + end + minetest.swap_node(pos, noded) +end + +function storagetest.helpers.grid_refresh(pos, n, network) + local node = minetest.get_node(pos) + local nodedef = minetest.registered_nodes[node.name] + + if nodedef.storagetest_enabled_name then + node.name = nodedef.storagetest_enabled_name + storagetest.helpers.swap_node(pos, node) + end +end diff --git a/nodes/controller.lua b/nodes/controller.lua new file mode 100644 index 0000000..4453016 --- /dev/null +++ b/nodes/controller.lua @@ -0,0 +1,47 @@ +-- Storagetest controller + +minetest.register_node("storagetest:controller", { + description = "Storage Controller", + tiles = {"storagetest_controller.png"}, + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Storage Controller") + meta:set_string("active", 1) + meta:set_string("channel", "controller"..minetest.pos_to_string(pos)) + minetest.swap_node(pos, {name="storagetest:controller_active"}) + local poshash = minetest.hash_node_position(pos) + storagetest.network.redundant_warn[poshash] = nil + end, + after_dig_node = function(pos) + minetest.forceload_free_block(pos) + pos.y = pos.y - 1 + minetest.forceload_free_block(pos) + local poshash = minetest.hash_node_position(pos) + technic.redundant_warn[poshash] = nil + end, + groups = { + cracky = 1, + storagetest_controller = 1 + } +}) + +minetest.register_node("storagetest:controller_active", { + description = "Storage Controller", + tiles = { + { + name = "storagetest_controller_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 5.0, + }, + } + }, + drop = "storagetest:controller", + groups = { + cracky = 1, + not_in_creative_inventory = 1, + storagetest_controller = 1 + } +}) diff --git a/nodes/crafting_grid.lua b/nodes/crafting_grid.lua new file mode 100644 index 0000000..4f8b9c1 --- /dev/null +++ b/nodes/crafting_grid.lua @@ -0,0 +1,53 @@ +-- Crafting Grid + +local function timer(pos, elapsed) + local refresh = false + local meta = minetest.get_meta(pos) + local node = minetest.get_node(pos) + + return refresh +end + +minetest.register_node("storagetest:crafting_grid", { + description = "Crafting Grid", + tiles = { + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_machine_block.png", + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_crafting_grid.png", + }, + paramtype2 = "facedir", + on_timer = timer, + groups = { + cracky = 1, + storagetest_distributor = 1, + storagetest_device = 1, + }, + on_construct = function (pos) + storagetest.network.clear_networks(pos) + end, + on_destruct = storagetest.network.clear_networks, + storagetest_run = storagetest.helpers.grid_refresh, + storagetest_enabled_name = "storagetest:crafting_grid_active", +}) + +minetest.register_node("storagetest:crafting_grid_active", { + description = "Crafting Grid", + tiles = { + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_machine_block.png", + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_crafting_grid_active.png", + }, + drop = "storagetest:crafting_grid", + paramtype2 = "facedir", + on_timer = timer, + groups = { + cracky = 1, + storagetest_distributor = 1, + storagetest_device = 1, + not_in_creative_inventory = 1 + }, + on_destruct = storagetest.network.clear_networks, + storagetest_run = storagetest.helpers.grid_refresh, + storagetest_disabled_name = "storagetest:crafting_grid", +}) + +storagetest.devices["storagetest:crafting_grid"] = true +storagetest.devices["storagetest:crafting_grid_active"] = true diff --git a/nodes/disk_drive.lua b/nodes/disk_drive.lua new file mode 100644 index 0000000..2747c93 --- /dev/null +++ b/nodes/disk_drive.lua @@ -0,0 +1,47 @@ +-- Disk Drive + +local function timer(pos, elapsed) + local refresh = false + local meta = minetest.get_meta(pos) + local node = minetest.get_node(pos) + + return refresh +end + +local function register_disk_drive(index) + local groups = { + cracky = 1, + storagetest_distributor = 1, + storagetest_device = 1, + storagetest_storage = 1, + } + + local driveoverlay = "" + if index ~= 0 then + groups["not_in_creative_inventory"] = 1 + driveoverlay = "^storagetest_drive_section"..index..".png" + end + + minetest.register_node("storagetest:disk_drive"..index, { + description = "Disk Drive", + tiles = { + "storagetest_drive_side.png", "storagetest_drive_side.png", "storagetest_drive_side.png", + "storagetest_drive_side.png", "storagetest_drive_side.png", "storagetest_drive.png"..driveoverlay, + }, + drop = "storagetest:disk_drive0", + paramtype2 = "facedir", + on_timer = timer, + groups = groups, + on_construct = function (pos) + storagetest.network.clear_networks(pos) + end, + on_destruct = storagetest.network.clear_networks, + }) + + storagetest.devices["storagetest:disk_drive"..index] = true +end + +-- Register 6 variants of the disk drive. +for i = 0, 6 do + register_disk_drive(i) +end diff --git a/nodes/grid.lua b/nodes/grid.lua new file mode 100644 index 0000000..cf61008 --- /dev/null +++ b/nodes/grid.lua @@ -0,0 +1,53 @@ +-- Storage Grid + +local function timer(pos, elapsed) + local refresh = false + local meta = minetest.get_meta(pos) + local node = minetest.get_node(pos) + + return refresh +end + +minetest.register_node("storagetest:grid", { + description = "Grid", + tiles = { + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_machine_block.png", + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_grid.png", + }, + paramtype2 = "facedir", + on_timer = timer, + groups = { + cracky = 1, + storagetest_distributor = 1, + storagetest_device = 1, + }, + on_construct = function (pos) + storagetest.network.clear_networks(pos) + end, + on_destruct = storagetest.network.clear_networks, + storagetest_run = storagetest.helpers.grid_refresh, + storagetest_enabled_name = "storagetest:grid_active", +}) + +minetest.register_node("storagetest:grid_active", { + description = "Grid", + tiles = { + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_machine_block.png", + "storagetest_machine_block.png", "storagetest_machine_block.png", "storagetest_grid_active.png", + }, + drop = "storagetest:grid", + paramtype2 = "facedir", + on_timer = timer, + groups = { + cracky = 1, + storagetest_distributor = 1, + storagetest_device = 1, + not_in_creative_inventory = 1 + }, + on_destruct = storagetest.network.clear_networks, + storagetest_run = storagetest.helpers.grid_refresh, + storagetest_disabled_name = "storagetest:grid", +}) + +storagetest.devices["storagetest:grid"] = true +storagetest.devices["storagetest:grid_active"] = true diff --git a/textures/storagetest_cable.png b/textures/storagetest_cable.png new file mode 100644 index 0000000000000000000000000000000000000000..343a837ec0b93f6cc0dd5fa36abe77ad8702b9b4 GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEFdh=h=rX?TVQ7Vvu>b}Y-UJAiF1B#Zfaf$kjuc}T$Gwv zlA5AWo>`Ki;O^-gkfN8$4iwk+ba4!^IGvnufN{;5HUE;67c;A|aUER2$ivg~!)b<+ j!}bgrwm1pXhDJt)>J7Y&vo0Uf1exdQ>gTe~DWM4fvobWN literal 0 HcmV?d00001 diff --git a/textures/storagetest_controller.png b/textures/storagetest_controller.png new file mode 100644 index 0000000000000000000000000000000000000000..7680450b4abeff4dd76648cce6edb9e7fa266c98 GIT binary patch literal 526 zcmV+p0`dKcP)Kq-03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00DAIL_t(I%Z-ysZsafw zMW0l($}ZSmNe8HV1jr2<$PF4fWtKTmt!yW;Jh2zC+%=|~8$kp3{wFE(`}I{b=MWJj z%g|*Z#z>42RB`(~`#i@2^Rl3-Ow+X8%QVltzr9hGB@e?G44`SRO4oHfJwGGX7|OEb zbUM+tEmc+BU9aPKJYoRJoZAldfq<&2?w*SXk{1QQH$`t#B)X=%)s7E=s;&`h?F}V8 zenbW^fZgqo{`2#KlqgNwUy)OU5SZr~iNkQ0*0e444+>P3F-F9kdo>1BzmuubG|ibP zbCJM%&oGXN%kv8b$x2<<{7=Z?Z~$ZeRvR{QqH3zeSslFhIOh;!E#|5QP1F2SfiZ@n zERopvn{);0s@lkH*Ijf%*Y>f_fi4R&3k0wV=v4j`Uw&4D0;-0U{K?2r(h` QJOBUy07*qoM6N<$f?+$_z5oCK literal 0 HcmV?d00001 diff --git a/textures/storagetest_controller_animated.png b/textures/storagetest_controller_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..4a0f713f0aa808e7d723e337bf988d3526a1b595 GIT binary patch literal 1356 zcmV-S1+)5zP)WFU8GbZ8()Nlj2>E@cM*00gi}L_t(&-tF1DZrfHE z2k`%)NSfls>QKZTOYOd7u;Bo*RUkme0(k-1NeAf-`V7t!NL!JoNE{TXEf0aU6oxx= z?C8Q7T!}JCi98*sLs6f2k?Iab%d-$734NDy&JP61PT#!YimF1EWyp#G9)|Ed51!`% zoI~B%z=ozl0uY2DIOmv7r}1@p8U*q}IfUCYAM?N~Rx~tY7F@>x`@Y@gKYjQB%d+ORrfj5z1fo!@f2rQARhei%Pl%J1KkHF_4p(Y zx)09MxwAduL8oS3~{ zc+j!t9&{fZfOE7r_0>HP^@>t@e~xo^rFj&Wf)Fmq#nlTHm<3I+0(QpX1 zyA8V@U9jz_Nwy8#?`C`8dftD^gWqp%5n2YMp|fywMh*<~i5@tkl$qEj9)uYli0IS< zP!FUO52T#k$fyS)@gOMh0Mr8-EwBt!ax&o5gD~NNH1iOryxfvFc}z^Dh|%!5k8gD}SfPCXDymwJ%77N`eb?{0(FqYJQSO|k*}k31-! z56b6*^7){AJ}5mXJt#dWJt*HNmhThG_lf2E#PWM%`Mt6H-uN&5-uM?hSWS%mw2J=# O0000@KhRUhU$dXYl>`byiBZ+uyk69IpvZwST&*>R4!LQg(@@vU$7NZjb9vb9eK}cRvzujqKlABf07J+Xqg2 zOrPfFay#@07Aozq*Z6mPPT!_gA1s%KaxvU8S$%t^Z~Eho{M+BQF^fOi>8iVT|6@j} z(7xl3%NH+wblH8^rr%#?2A%sM!NlL+eFVdQ&MBb@0EDH;UjP6A literal 0 HcmV?d00001 diff --git a/textures/storagetest_crafting_grid_active.png b/textures/storagetest_crafting_grid_active.png new file mode 100644 index 0000000000000000000000000000000000000000..39249f5f79686b4f0d3814078fa1743900d096ee GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)3itC@Qjt9Vo(C;1OBO zz`!jG!i)^F=12eq*-JcqUD+S8uyZMz#BY9e0VpJ!84^+AoS&PUnpXnkGB7w7r6!i7 zrYMwWmSiZnd-?{X=%oS;WK{QbaSX9IJ$LeMKW0M#*Z%a}_jy~McrR$-(&UvD3Od5S z;E%kj1}m#+=4bVrD&O|CDM@>%$eolsdFe*D-0M^2XD;U~J6FACYsB*l>y(dq^azH0 z%=DU-%5kAgc9qv(71wTJF zF|PUi@4=T}TW+6bWw;ila{6=f$9IL>|E;Qy7JqE0q{MTOVUo&?4L4=9^UwdkZku~s zY2zxk$bisS5`u>dR_!|WOGi3~(ZOx8phWRMeTIA0M>-6Sv>CST(b!P39(W{S2uX}tw?r2q0Y44-xwx+zV{iTSf(5zi*EeGy}%}PzF o>?`I|W?FTn)b~c-%3ptKm^!q3W;vWQ2Spcyr>mdKI;Vst0HGhV!vFvP literal 0 HcmV?d00001 diff --git a/textures/storagetest_drive.png b/textures/storagetest_drive.png new file mode 100644 index 0000000000000000000000000000000000000000..af6d55983994ac4375492d67fe751baddf361195 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#5eqw)IbW-K+g6~EY-UJAiF1B#Zfaf$kjuc}T$GwvlA5AWo>`Ki;O^-gkfN8$ z4ix|I>Eak-ae8U6V^@oTz?!_r2`&?B4*swA3=sL-sHFDNmgnS}dWDy^ z-r6SmXR!!_iLbD^3yX`${!R`hrssEFx<8lMmRl_pk!|RE`DKG4TWPHF`Qnn;@`I-~ zu`m?uFb!2=djB__(}gAZ4C|MBk1hICrlsEOcF=5HmieexNoe|axu|Rd;|`89JZXKg zt1rAV;1Qqe8py!#ta4w%LhXNLHT}mQUv*5V)mPf}^>|dZ*~V3?PS0VUcIsp&1H-Yx zJuj|AIlEl=UTdU$vDsjfHK%;Bf|BRlGc~XMC#+ydxc~jd!S|N!B5eHkiYL|h)UPa! hozHT5Q_bHw^$b;Jb*8gt{XE z)7O>#5eqvvpZGhjlRtn$vY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5XHH)5S5w;&gI?M8*M*{XE z)7O>#5eqvvpQ_s385KYw+02lL66gHf+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g z9Vo8l>Eak-aXL9cBI5u@a!G0FU-xMm+S{XE z)7O>#5eqvvpZ+n9!Ze_eY-UJAiF1B#Zfaf$kjuc}T$GwvlA5AWo>`Ki;O^-gkfN8$ z4iq=?ba4!^IGvmzk#T?{xumr8ulqC&ZEa<*KF--IQ{|RgNjLpCBdmPlmNw amVseAJO6@tN8Mh7jP-Q&b6Mw<&;$S*b})wk literal 0 HcmV?d00001 diff --git a/textures/storagetest_drive_section4.png b/textures/storagetest_drive_section4.png new file mode 100644 index 0000000000000000000000000000000000000000..b7cc5710c6ed3ef7deba90082b44dade228e141f GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#5eqvvKik}eH@tyDvY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5XHP)5S5w;&gI?M8*M*bP0l+XkK1;#F^ literal 0 HcmV?d00001 diff --git a/textures/storagetest_drive_section5.png b/textures/storagetest_drive_section5.png new file mode 100644 index 0000000000000000000000000000000000000000..b77d13b66d7284787e2243c365f8664f2ab3ff78 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#5eqvvzxa2-A3K3UvY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5b!n)5S5w;&gI?M8*M*{XE z)7O>#5eqvvzx>Zr1>Ha)+02lL66gHf+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g z9Vo8j>Eak-aXL9cBI5u@a!G0FU-xMm+SZHr UHc_h{o&y=^>FVdQ&MBb@0Cs6GHvj+t literal 0 HcmV?d00001 diff --git a/textures/storagetest_drive_side.png b/textures/storagetest_drive_side.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d329b9b6bac5001eaf9f0b9d8aa380424f1cdc GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#5eqw)vDhc|+s}bQvY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5c*C>@q^go~zx+?SWkc@m ziWORd4>xy&gu0lRDD^!qU^xF-ATcd8G?ZalYG=nYVFQtl2R-xV&Qw~o%Es*2>{YAw zsJ`8ozi8#0nQ3Mm@0^#b2PztePPGx3} u_MN_G|MDD?(crv$IOmPG#re z`SRDi_iv{y(x~7{HfV@Dx9Upi+2dKQ5y=`|O?UH-Ye(paNgS|xzuxhwX$Qxor$6&u zrWV=#-@aniD($sJcE_W#-9yekdB?WFv#I6q!-dWB^yjo)l2$za;=^`Q4 z(51bC*%k7>x0UQp{}anxCA|42kJ}^Pr3?@D9+%3lY;QAc+oLf-;!rWy^pofO?(ATG zVW8l9+2+2(RrdGCcW$_^%upJ-F-Fgy|E}oW-|H8j7fEv2Q(Uv|`VEzZ+0jlMF&RrE r-KIUacy4g5Nh|lZP@ns(&;R}~h(GK7qPABk1Qev6u6{1-oD!M_e)Znn&J)=kxioIxKHHP#=3eZ+*GDaB?qP}MjbbmYg1nYYabO9b zHs#*p#%-?!1ZOR?yyAO#TaDlH7J(nZUJDs+9#_(t?)}bPxhJekfa&vYcfE^WuS;_o zT-&+$&D+YmpCu27-44I{{?Xyj|If;=XJ51Wp}^X$%lbtYbTbKGe|=f{T)^#ZGeWNK z6>w>pBNTNpzVw{L^V)nC24e{xhn1(-Ggv&o;FbL=L1XC(rvpnQsuejDV%t}~{&oDZ zb^Ba%$BxyaYzaFf3XH4o^9fo0^f*5I`+1SzLl)VUQvDZQ9VZ(bx_ygS`u)eMLs8wA kq+Cu|3Y$y6np?k*acXaU4{O@hTcBX{boFyt=akR{0P`2Ez5oCK literal 0 HcmV?d00001 diff --git a/textures/storagetest_machine_block.png b/textures/storagetest_machine_block.png new file mode 100644 index 0000000000000000000000000000000000000000..2436b5d72aba5a8720294191db83db5e26944af4 GIT binary patch literal 647 zcmV;20(kw2P)WFU8GbZ8()Nlj2>E@cM*00HYsL_t(I%ThhbedD2<~5kd&8`_8hi^r@!zj^46gGeUl*fyGz9kN^B!C)wN^Ne_dgLK#)!Q_<3K)7M(;P!=ac>MK!Ec&NY}*} zgM3|txwY-b4=ktjCa)rh8OzN7vMi`7V+?xlcihLoMebydft6BNrix_(q<6}3P|p(q zhC5+~$lc%ZPRD^wqQ# literal 0 HcmV?d00001