Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---#############################---
- ---# INVENTORY SORTER PROGRAM #---
- ---# AUTHOR: ZO125 #---
- ---# 30.04.2020 sZo#---
- ---#############################---
- local component = require "component"
- local computer = require "computer"
- local event = require "event"
- local unicode = require "unicode"
- local transposer = component.transposer
- local gpu = component.gpu
- local CONFIG_FILE = "filter_v2.txt"
- local SORT_PERIOD = 20
- local BLINK_PERIOD = 20
- local edit_handle
- local inventories = {}
- local properity_state = 0
- local filters_pos = 0
- local properities_pos = 0
- local filters = {}
- local screen_x, screen_y = gpu.getResolution()
- ------------------------------
- -- UTILITY FUNCTIONS --
- ------------------------------
- local function inLimits(n, min, max)
- if n < min then
- n = max
- elseif n > max then
- n = min
- end
- return n
- end
- local function rightTab(text, length)
- return text .. string.rep(" ", length - unicode.len(text))
- end
- local function leftTab(text, length)
- return string.rep(" ", length - unicode.len(text)) .. text
- end
- local function compareItemWithFilter(filter_name, filter_metadata, item_name, item_metadata)
- if not (filter_name == "" or filter_name == item_name) then
- return false
- end
- if not (filter_metadata == 0 or (filter_metadata - 1) == item_metadata) then
- return false
- end
- return true
- end
- local function compareItemWithItem(name_1, metadata_1, name_2, metadata_2)
- if name_1 == name_2 and metadata_1 == metadata_2 then
- return true
- end
- return false
- end
- ------------------------------
- -- OBJECT DEFENTIONS --
- ------------------------------
- local function Filter(enabled, input_side, output_side, input_slot_start, input_slot_end, output_slot_start, output_slot_end, name, metadata, count)
- local filter = {
- enabled = enabled or false,
- input_side = input_side or 0,
- output_side = output_side or 0,
- input_slot_start = input_slot_start or 0,
- input_slot_end = input_slot_end or 1,
- output_slot_start = output_slot_start or 0,
- output_slot_end = output_slot_end or 1,
- name = name or "",
- metadata = metadata or 0,
- count = count or 64
- }
- return filter
- end
- ------------------------------
- -- ADD/EDIT FUNCTIONS --
- ------------------------------
- local drawFilter, drawInfo
- local function getProperity(pos)
- local pos = pos or pos or properities_pos
- local filter = filters[filters_pos]
- local input_inventory = inventories[filter.input_side]
- local output_inventory = inventories[filter.output_side]
- -- Returns state, name, min_state, max_state, default_state, fieldname; otherwise returns nil
- if pos == 1 then
- return filter["enabled"], "Активен", nil, nil, false, "enabled"
- elseif pos == 2 then -- INPUT
- return filter["input_side"], "Вход", 0, 5, 0, "input_side"
- elseif pos == 3 then
- local max_state = 0
- if input_inventory then
- max_state = input_inventory.size
- end
- return filter["input_slot_start"], "\226\148\156Слот начало", 0, max_state, 1, "input_slot_start"
- elseif pos == 4 then
- local max_state = 0
- if input_inventory then
- max_state = input_inventory.size
- end
- return filter["input_slot_end"], "\226\148\148Слот конец", 1, max_state, max_state, "input_slot_end"
- elseif pos == 5 then -- OUTPUT
- return filter["output_side"], "Выход", 0, 5, 0, "output_side"
- elseif pos == 6 then
- local max_state = 0
- if output_inventory then
- max_state = output_inventory.size
- end
- return filter["output_slot_start"], "\226\148\156Слот начало", 0, max_state, 0, "output_slot_start"
- elseif pos == 7 then
- local max_state = 0
- if output_inventory then
- max_state = output_inventory.size
- end
- return filter["output_slot_end"], "\226\148\148Слот конец", 1, max_state, max_state, "output_slot_end"
- elseif pos == 8 then
- return filter["name"], "Имя предмета", nil, 255, "", "name"
- elseif pos == 9 then
- return filter["metadata"], "Мета (-1)", 0, 16, 0, "metadata"
- elseif pos == 10 then
- local max_state = (math.floor(filter.output_slot_end - filter.output_slot_start) + 1) * 64
- return filter["count"], "Количество", 0, max_state, max_state, "count"
- end
- end
- local function setProperity(state, pos)
- local pos = pos or pos or properities_pos
- local prev_state, name, min_state, max_state, default_state, fieldname = getProperity(pos)
- local filter = filters[filters_pos]
- if type(prev_state) == "number" then
- state = tonumber(state)
- if not state or state < min_state or state > max_state then
- return
- end
- elseif type(prev_state) == "string" then
- state = tostring(state)
- if not state or #state > max_state then
- return
- end
- elseif type(prev_state) == "boolean" then
- if type(state) ~= "boolean" then
- return
- end
- end
- --error(fieldname)
- filter[fieldname] = state
- end
- local function drawAdditional()
- if filters_pos == 0 then
- drawInfo()
- else
- drawFilter()
- end
- end
- local function addFilter()
- local filter = Filter()
- table.insert(filters, filter)
- filters_pos = #filters
- drawAdditional()
- end
- local function delFilter()
- local count = #filters
- filters[filters_pos] = nil
- for i = filters_pos + 1, count, 1 do
- filters[i - 1] = filters[i]
- end
- filters[count] = nil
- if filters_pos >= count then
- filters_pos = #filters
- end
- drawAdditional()
- end
- local function moveUpFilter() -- F4
- end
- local function moveDownFilter() -- F3
- end
- ------------------------------
- -- DRAWING FUNCTIONS --
- ------------------------------
- local function drawBase()
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.fill(1, 1, screen_x, screen_y, " ")
- gpu.set(1, 1, "Перемещение клавишами со стрелками.")
- gpu.set(1, 2, "ENTER редактирует текст.")
- gpu.set(1, 3, "INSERT добавляет фильтр.")
- gpu.set(1, 4, "DELETE удаляет фильтр.")
- end
- local function drawProperity(pos, clc)
- if clc then
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- end
- local state, name = getProperity(pos)
- state = tostring(state)
- gpu.set(2, pos + 6, rightTab(name, 12) .. "\226\148\130" .. state .. string.rep(" ", screen_x - 14 - #state))
- end
- function drawFilter()
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.set(1, 5,
- string.rep("\226\148\129", 13) .. "\226\148\175" ..
- string.rep("\226\148\129", screen_x)
- )
- gpu.fill(1, 6, screen_x, screen_y - 6, " ")
- gpu.set(2, 6, "ID" ..string.rep(" ", 10) .. "\226\148\130" .. tostring(filters_pos))
- for i = 1, 10 do -- #PROPERITIES
- drawProperity(i, false)
- end
- gpu.set(1, properities_pos + 6, ">")
- end
- function drawInfo()
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.fill(1, 5, screen_x, screen_y - 6, " ")
- gpu.set(1, 5, "SPACE сохранит настройки.")
- gpu.set(1, 6, "BACKSPACE закроет программу.")
- gpu.set(1, 7, "Сортировщик предметов от ZO125")
- gpu.set(1, 8, string.rep("\226\148\129", screen_x))
- gpu.set(1, 9, "Транспозер:" .. transposer.address)
- gpu.set(1, 10,
- string.rep("\226\148\128", 7) .. "\226\148\172" ..
- string.rep("\226\148\128", 7) .. "\226\148\172" ..
- string.rep("\226\148\128", screen_x - 16)
- )
- gpu.set(1, 11, "Сторона\226\148\130Размер \226\148\130Инвентарь")
- local c = 11
- for side = 0, 5 do
- local inventory = inventories[side]
- if inventory then
- c = c + 1
- gpu.set(1, c, leftTab(side, 7) .. "\226\148\130" .. leftTab(inventory.size, 7) .. "\226\148\130" .. inventory.name)
- end
- end
- end
- ------------------------------
- -- INTERFACE NAVIGATION --
- ------------------------------
- local function moveFilters(n)
- filters_pos = inLimits(filters_pos + n, 0, #filters)
- properities_pos = 0
- drawAdditional()
- end
- local function editProperity(n)
- local filter = filters[filters_pos]
- local state, _, min_state, max_state = getProperity()
- if type(state) == "boolean" then
- state = not state
- elseif type(state) == "number" then
- state = inLimits(state + n, min_state, max_state)
- end
- setProperity(state)
- drawProperity(properities_pos, true)
- end
- local function startEdit()
- local properity_text = getProperity()
- if type(properity_text) ~= "string" and type(properity_text) ~= "number" then
- return
- end
- local text = tostring(properity_text)
- local x = 15
- local y = properities_pos + 6
- local cursor = unicode.len(text)
- local blink_stage = 0
- local blink_state = false
- gpu.setBackground(0xFFFFFF)
- gpu.setForeground(0x000000)
- gpu.set(x, y, rightTab(text, screen_x - 14))
- -- Text input processing function
- edit_handle = function(mode, key, char)
- if mode then
- local len = unicode.len(text)
- local prev_text = unicode.sub(text, 1, cursor)
- local next_text = unicode.sub(text, cursor + 1, len)
- if key == 28 then -- Enter
- setProperity(text)
- drawProperity(properities_pos, true)
- edit_handle = nil
- return
- elseif key == 14 then -- Backspace
- if cursor >= 1 then
- prev_text = unicode.sub(prev_text, 1, cursor - 1)
- cursor = cursor - 1
- end
- elseif key == 203 then -- Left arrrow
- if cursor > 1 then
- cursor = cursor - 1
- end
- elseif key == 205 then -- Right arrow
- if cursor < len then
- cursor = cursor + 1
- end
- else
- if char >= 32 then
- local chr = unicode.char(char)
- prev_text = prev_text .. chr
- cursor = cursor + 1
- end
- end
- text = prev_text .. next_text
- gpu.setBackground(0xFFFFFF)
- gpu.setForeground(0x000000)
- gpu.set(x, y, rightTab(text, screen_x - 14))
- else
- if blink_stage >= BLINK_PERIOD then
- blink_stage = 0
- local smb = unicode.sub(text, cursor + 1, cursor + 1)
- smb = smb == "" and " " or smb
- blink_state = not blink_state
- if blink_state then
- gpu.setBackground(0xFFFFFF)
- gpu.setForeground(0x000000)
- else
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- end
- gpu.set(x + cursor, y, smb)
- end
- blink_stage = blink_stage + 1
- end
- end
- end
- local function moveRL(n)
- if properities_pos == 0 then
- moveFilters(n)
- else
- if filters_pos ~= 0 then
- editProperity(n)
- end
- end
- end
- local function moveUD(n)
- if filters_pos ~= 0 then
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.set(1, properities_pos + 6, " ")
- properities_pos = inLimits(properities_pos + n, 0, 10) -- #PROPERITIES
- properity_state = 0
- gpu.set(1, properities_pos + 6, ">")
- end
- end
- ------------------------------
- -- SAVING/LOADING BLOCK --
- ------------------------------
- local function saveProperities()
- local bytes = ""
- for i = 1, #filters, 1 do
- local filter = filters[i]
- bytes = bytes .. string.char(
- filter.enabled and 1 or 0,
- filter.input_side,
- filter.output_side,
- filter.input_slot_start,
- filter.input_slot_end,
- filter.output_slot_start,
- filter.output_slot_end,
- #filter.name
- ) .. filter.name .. string.char(
- filter.metadata,
- filter.count
- )
- end
- local file = io.open(CONFIG_FILE, "wb")
- if file then
- file:write(bytes)
- file:close()
- end
- end
- local function loadProperities()
- local file = io.open(CONFIG_FILE, "rb")
- if file then
- local bytes = file:read("*a")
- file:close()
- if #bytes > 0 then
- local pos = 1
- repeat
- local enabled, input_side, output_side, input_slot_start, input_slot_end, output_slot_start, output_slot_end, name_length = bytes:byte(pos, pos + 7)
- pos = pos + 8
- local name = bytes:sub(pos, pos + name_length - 1)
- pos = pos + name_length
- local metadata, count = bytes:byte(pos, pos + 1)
- pos = pos + 2
- table.insert(filters, Filter(enabled == 1, input_side, output_side, input_slot_start, input_slot_end, output_slot_start, output_slot_end, name, metadata, count))
- until pos >= #bytes
- end
- end
- end
- ------------------------------
- -- ITEM TRANSPORT BLOCK --
- ------------------------------
- local function initInventories()
- for side = 0, 5 do
- local name = transposer.getInventoryName(side)
- if name then
- local size = transposer.getInventorySize(side)
- inventories[side] = {
- name = name,
- size = size,
- stacks = {}
- }
- end
- end
- end
- local function getStacks()
- for side = 0, 5 do
- local inventory = inventories[side]
- if inventory then
- inventory.stacks = transposer.getAllStacks(side)
- end
- end
- end
- local function getSlotItem(inventory, slot)
- local stack = inventory.stacks[slot]
- if stack then
- return stack.name, stack.damage, stack.size, stack.maxSize
- end
- return "", 0, 0, 64
- end
- local function getInputSlot(inventory, input_slot_start, input_slot_end, filter_name, filter_metadata)
- local stacks = inventory.stacks
- if input_slot_start == 0 then
- input_slot_start = 1
- input_slot_end = inventory.size
- end
- for i = input_slot_start, input_slot_end do
- local stack = stacks[i]
- if stack then
- local item_name = stack.name
- local item_metadata = stack.damage
- if compareItemWithFilter(filter_name, filter_metadata, item_name, item_metadata) then
- return i
- end
- end
- end
- return 0
- end
- local function getOutputSlot(inventory, output_slot_start, output_slot_end, item_name, item_metadata)
- local stacks = inventory.stacks
- if output_slot_start == 0 then
- output_slot_start = 1
- output_slot_end = inventory.size
- end
- for i = output_slot_start, output_slot_end do
- local stack = stacks[i]
- if not stack then
- return i
- else
- local stack_item_name = stack.name
- local stack_item_metadata = stack.damage
- if compareItemWithItem(item_name, item_metadata, stack_item_name, stack_item_metadata) and stack.size < stack.maxSize then
- return i
- end
- end
- end
- return 0
- end
- local function separateItems()
- for i = 1, #filters, 1 do
- local filter = filters[i]
- if filter.enabled then
- local input_side = filter.input_side
- local output_side = filter.output_side
- local input_inventory = inventories[input_side]
- local output_inventory = inventories[output_side]
- if input_inventory and output_inventory then
- local filter_name, filter_metadata, filter_count = filter.name, filter.metadata, filter.count
- local input_slot_start = filter.input_slot_start
- local input_slot_end = filter.input_slot_end
- input_slot_start = getInputSlot(input_inventory, input_slot_start, input_slot_end, filter_name, filter_metadata)
- if input_slot_start ~= 0 then
- local item_name, item_metadata, item_count, item_max_count = getSlotItem(input_inventory, input_slot_start)
- if compareItemWithFilter(filter_name, filter_metadata, item_name, item_metadata) then
- local output_slot_start = filter.output_slot_start
- local output_slot_end = filter.output_slot_end
- output_slot_start = getOutputSlot(output_inventory, output_slot_start, output_slot_end, item_name, item_metadata)
- if output_slot_start ~= 0 then
- _, _, out_count, out_max_count = getSlotItem(output_inventory, output_slot_start)
- local transfer_count = math.min(filter_count - out_count, out_max_count, item_count)
- transposer.transferItem(input_side, output_side, transfer_count, input_slot_start, output_slot_start)
- end
- end
- end
- end
- end
- end
- end
- ------------------------------
- -- WORKING PROCESS --
- ------------------------------
- local function init()
- initInventories()
- loadProperities()
- getStacks()
- separateItems()
- drawBase()
- drawInfo()
- local prev_uptime = computer.uptime()
- local counter = 0
- while true do
- local signal = {event.pull(0.05)}
- local current_uptime = computer.uptime()
- local s = signal[1]
- -- Timer
- if current_uptime - prev_uptime > 0.05 then
- if counter % SORT_PERIOD == 0 then
- getStacks()
- separateItems()
- prev_uptime = current_uptime
- end
- if edit_handle then
- edit_handle(false)
- end
- counter = counter + 1
- end
- -- Handler
- if s == "key_down" then
- local key = signal[4]
- local byte = signal[3]
- if edit_handle then
- edit_handle(true, key, byte)
- else
- if key == 203 then -- Left arrow
- moveRL(-1)
- elseif key == 205 then -- Right arrow
- moveRL(1)
- elseif key == 200 then -- Up arrow
- moveUD(-1)
- elseif key == 208 then -- Down arrow
- moveUD(1)
- elseif key == 210 then -- Insert
- addFilter()
- elseif key == 211 then -- Delete
- delFilter()
- elseif key == 28 then -- Enter
- startEdit()
- elseif key == 14 then -- Backspace
- saveProperities()
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.fill(1, 1, screen_x, screen_y, " ")
- return
- elseif key == 57 then -- Space
- if filters_pos == 0 then
- saveProperities()
- end
- end
- end
- end
- end
- end
- --init()
- local ok, msg = pcall(init)
- if not ok then
- print("Error: " .. tostring(msg))
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement