Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local serialization = require("serialization")
- local io = require("io")
- local filesystem = require("filesystem")
- local thread = require("thread")
- local computer = require("computer")
- local sides = require("sides")
- local RETURN_CHEST = "minecraft:trapped_chest"
- function find_transposers()
- return component.list("transposer")
- end
- function get_item_table(db, item_handle)
- -- load a table representing the locations of this item in the storage system
- if db["item_files"][item_handle] == nil then
- db["item_files"][item_handle] = __get_file_handle(db, item_handle)
- end
- local file_path = db["item_files"][item_handle]
- if filesystem.exists(file_path) then
- local read_file = io.open(file_path, "r")
- table_out = serialization.unserialize(read_file:read("*a"))
- read_file:close()
- return table_out
- end
- return {locations={}}
- end
- function __get_file_handle(db, item_handle)
- if not filesystem.exists("/home/db_items") then
- filesystem.makeDirectory("/home/db_items")
- end
- local encoded_name = item_handle:gsub("\"", "x_01")
- local encoded_name = encoded_name:gsub("?", "x_02")
- local encoded_name = encoded_name:gsub(":", "x_03")
- return filesystem.concat("/home", "db_items", encoded_name..".idb")
- end
- function write_item_table(db, item_table, item_handle)
- -- write a item storage table to its representative file
- -- TODO
- if db["item_files"][item_handle] == nil then
- db["item_files"][item_handle] = __get_file_handle(db, item_handle)
- end
- local file_path = db["item_files"][item_handle]
- local out_file = io.open(file_path, "w")
- out_file:write(serialization.serialize(item_table, 1e309))
- out_file:flush()
- out_file:close()
- end
- function item_present(db, item_handle)
- local file_path = __get_file_handle(db, item_handle)
- if filesystem.exists(file_path) then
- local item_table = get_item_table(db, item_handle)
- local transposer_entries = 0
- for address, info in pairs(item_table["locations"]) do
- transposer_entries = transposer_entries + 1
- end
- if transposer_entries == 0 then
- return false
- end
- -- assumes I'll remove an entry from the table once the value it represents is no longer referenced
- return true
- else
- return false
- end
- end
- function load_database()
- if filesystem.exists("/home/items.db") then
- local read_file = io.open("/home/items.db", "r")
- db = serialization.unserialize(read_file:read("*a"))
- read_file:close()
- print("deserialize",db)
- else
- db = {item_files={}, transposer_configurations={}, empty_slots = 0, empty_slots_final = 0}
- print("No cached Database found.")
- print("Performing first time read...")
- read_items(db, find_transposers())
- save_database(db)
- print("blank", db)
- end
- print("return", db)
- return db
- end
- function save_database(db)
- local out_file = io.open("/home/items.db", "w")
- out_file:write(serialization.serialize(db, 1e309))
- out_file:flush()
- out_file:close()
- end
- function read_transposer_configurations(db, transposer_addresses)
- db["transposer_configurations"] = {}
- -- Check every transposer given
- for transposer_address in transposer_addresses do
- local transposer = component.proxy(transposer_address)
- for side=0,5 do
- -- a usable inventory is present if the size is not null
- local inventory_present = transposer.getInventorySize(side) ~= nil
- if inventory_present then
- local inventory_name = transposer.getInventoryName(side)
- if inventory_name == RETURN_CHEST then
- db["transposer_configurations"][transposer_address] = {return_side=side}
- break -- remove if we want to support multiple return chests
- end
- end
- end
- end
- end
- function get_item_amount(db, file_handle)
- local item_table = get_item_table(db, file_handle)
- local count = 0
- for transposer, sides in pairs(item_table["locations"]) do
- for side, slots in pairs(sides) do
- for slot, slot_amount in pairs(slots) do
- count = count + slot_amount
- end
- end
- end
- return count
- end
- function read_items(db, transposers)
- db["empty_slots"] = 0
- read_transposer_configurations(db, transposers)
- for transposer_address in transposers do
- local transposer = component.proxy(transposer_address)
- local transposer_configuration = db["transposer_configurations"][transposer_address]
- for side=0,5 do
- local size = transposer.getInventorySize(side)
- if size ~= nil then
- local inventory_name = transposer.getInventoryName(side)
- if side ~= transposer_configuration["return_side"] then
- for slot_index=1,size do
- local stack = transposer.getStackInSlot(side, slot_index)
- if stack ~= nil then
- local stack_item = string.lower(stack.label)
- local item_table = get_item_table(db, stack_item)
- if item_table["locations"][transposer_address] == nil then
- item_table["locations"][transposer_address] = {}
- end
- if item_table["locations"][transposer_address][tostring(side)] == nil then
- item_table["locations"][transposer_address][tostring(side)] = {}
- end
- if item_table["locations"][transposer_address][tostring(side)][tostring(slot_index)] == nil then
- item_table["locations"][transposer_address][tostring(side)][tostring(slot_index)] = 0
- end
- item_table["locations"][transposer_address][tostring(side)][tostring(slot_index)] = stack.size
- write_item_table(db, item_table, stack_item)
- os.sleep(0)
- else
- db["empty_slots"] = db["empty_slots"] + 1
- end
- end
- end
- end
- end
- end
- db["empty_slots_final"] = db["empty_slots"]
- end
- --[[
- -- Unused but present in code?
- function dfs_entry(table_in)
- for k, v in pairs(table_in) do
- print(k, v)
- if type(v) == "table" then
- dfs_entry(v)
- end
- end
- end
- ]]
- function constantly_update_db_in_background(db, transposers)
- while true do
- read_items(db, transposers)
- save_database(db)
- check_memory_load(true)
- computer.beep(1000, 0.1)
- end
- end
- function output_item(db, transposer_address, side, slot, amount)
- local transposer_interface = component.proxy(transposer_address)
- local return_side = db["transposer_configurations"][transposer_address]["return_side"]
- local transferred_item = string.lower(transposer_interface.getStackInSlot(side, slot)["label"])
- print("Transferring " .. amount .. " " .. transferred_item .. " from " .. string.sub(transposer_address, 0, 8) .. " " .. side .. " " .. slot)
- while amount > 0 do
- for insert_slot=1,transposer_interface.getInventorySize(return_side) do
- local in_slot = transposer_interface.getSlotStackSize(return_side, insert_slot)
- local slot_capacity transposer_interface.getSlotMaxStackSize(return_side, insert_slot)
- if slot_capacity == nil then
- slot_capacity = 64
- end
- local item_in_slot = transposer_interface.getStackInSlot(return_side, insert_slot)
- if in_slot < slot_capacity and (item_in_slot == nil or string.lower(item_in_slot["label"]) == transferred_item) then
- local transfer_amount = math.min(slot_capacity - in_slot, amount)
- transposer_interface.transferItem(side, return_side, transfer_amount, slot, insert_slot)
- amount = amount - transfer_amount
- break
- end
- end
- end
- transposer_interface.transferItem(side, return_side, amount, slot, 1)
- end
- function string_distance(string_in, search_term)
- local search_result = string.find(string_in, search_term, nil, true)
- return search_result
- end
- function compare(q1, q2)
- return q1[1] < q2[1]
- end
- function process_query(db, query)
- -- if there isn't a direct match, find the closest match to it
- if db["item_files"][query] == nil then
- local results = {} -- array style table where a value is (distance from query, string)
- local result_count = 0
- for k, v in pairs(db["item_files"]) do
- local distance = string_distance(k, string.lower(query))
- if distance ~= nil then
- results[result_count+1] = {distance, k}
- result_count = result_count + 1
- end
- end
- -- sort the results table (array), comparing elements with compare
- table.sort(results, compare)
- local printed_results = 0
- local print_limit = 5
- print("Could not find",query)
- if result_count == 0 then
- return
- end
- print("did you mean...")
- while true do
- while printed_results < print_limit and results[printed_results+1] ~= nil do
- print(printed_results+1,"/",#results, results[printed_results+1][2])
- printed_results = printed_results + 1
- end
- print("Select result or show more (y/#/n)?")
- local u_in = string.lower(io.read())
- local u_in_num = tonumber(u_in)
- if u_in == "y" then
- print_limit = print_limit + 5
- elseif u_in_num ~= nil and 1 <= u_in_num and u_in_num <= printed_results then
- return results[u_in_num][2]
- else
- break
- end
- end
- else
- return query
- end
- end
- function fulfill_query(db, query)
- local item_table = get_item_table(db, query)
- local item_count = get_item_amount(db, query)
- print("The storage contains",item_count, query)
- print("How many would you like?")
- local u_in = -1
- while u_in<0 or u_in > item_count do
- local input = io.read()
- if input ~= nil then
- u_in = tonumber(input)
- end
- end
- local requested_amount = math.floor(u_in)
- local total_moved = 0
- for transposer_address, sides in pairs(item_table["locations"]) do
- for side, slots in pairs(sides) do
- for slot, amount in pairs(slots) do
- if requested_amount == 0 then
- write_item_table(db, item_table, query)
- return total_moved
- end
- -- if I want to deal with suddenly nil entries it would be here
- -- check if inventory at slot is the item we want
- -- if not, set table entry to nil and continue looping
- local moved = math.min(requested_amount, amount)
- -- print("moved "..moved.." "..query.." from "..side.." "..slot.." of "..string.sub(transposer_address, 0, 8))
- output_item(db, transposer_address, tonumber(side), tonumber(slot), moved)
- item_table["locations"][transposer_address][tostring(side)][tostring(slot)] = item_table["locations"][transposer_address][tostring(side)][tostring(slot)] - moved
- if item_table["locations"][transposer_address][tostring(side)][tostring(slot)] == 0 then
- item_table["locations"][transposer_address][tostring(side)][tostring(slot)] = nil
- end
- requested_amount = requested_amount - moved
- total_moved = total_moved + moved
- end
- end
- end
- write_item_table(db, item_table, query)
- return total_moved
- end
- function check_memory_load(warn)
- local usage_percentage = 1 - (computer.freeMemory() / computer.totalMemory())
- if usage_percentage > 0.9 and warn then
- print("HIGH MEMORY USAGE", computer.freeMemory()/1024, "kB remaining")
- end
- return usage_percentage
- end
- local db = load_database()
- local transposers = find_transposers()
- print("Creating DB process")
- local db_update_thread = thread.create(constantly_update_db_in_background, db, transposers)
- print("Process created")
- print("DB middleware status:", db_update_thread:status())
- while true do
- print("Query database:")
- local query = io.read()
- if query == "UPDATE DATABASE" then
- read_items(db, transposers)
- save_database(db)
- elseif query == "EXIT" then
- save_database(db)
- os.exit()
- elseif query == "CHECK MIDDLEWARE" then
- print("DB middleware status: " .. db_update_thread:status())
- elseif query == "CHECK FREE" then
- print("DB free slots: ".. db["empty_slots_final"])
- elseif query == "CHECK MEMORY" then
- print("DB free memory:",computer.freeMemory()/1024, "kB remaining")
- else
- local search_term = process_query(db, query)
- if search_term ~= nil then
- local moved = fulfill_query(db, search_term)
- print("Transferred ".. moved .. " of " .. search_term)
- local item_table = get_item_table(db, search_term)
- if get_item_amount(db, search_term) == 0 then
- filesystem.remove(__get_file_handle(db, search_term))
- db["item_files"][search_term] = nil
- else
- write_item_table(db, item_table, search_term)
- end
- save_database(db)
- end
- end
- end
Add Comment
Please, Sign In to add comment