Smart Storage v0.6

Now support robot crafting.
This commit is contained in:
Kirigaya Kazuto 2018-11-20 17:44:32 +08:00
parent 15ee96e87e
commit 4b684885d4
2 changed files with 277 additions and 50 deletions

View File

@ -9,7 +9,7 @@ local serialization=require('serialization')
require('libevent')
local version_tag="Smart Storage v0.5.9"
local version_tag="Smart Storage v0.6.1-dbg"
print(version_tag)
print("Checking hardware...")
@ -181,7 +181,7 @@ local function display(tb_data,tb_display,tb_craft,begin_at,filter)
gpu.set(1,1,version_tag)
gpu.fill(1,2,w,1,'-')
gpu.fill(1,h-2,w,1,'-')
gpu.set(1,h-1,"<Refresh> <Reform> <Set Filter> <Clear Filter> <Read recipe>")
gpu.set(1,h-1,"<Refresh> <Reform> <Set Filter> <Clear Filter> <Read recipe> <Debug>")
local count_shown=0
for i=begin_at,#tb_display,1 do
@ -214,14 +214,58 @@ local function display(tb_data,tb_display,tb_craft,begin_at,filter)
gpu.set(4,h-2," Space used: " .. math.floor(tb_data.slot_used/tb_data.slot_total*1000)/10 .. "% (" .. tb_data.slot_used .. "/" .. tb_data.slot_total ..") ")
end
local function SystemGetItem(tb_data,request_key,request_amount)
local fetched=0
local this_table=tb_data[request_key]
for idx,this_info in ipairs(this_table.position) do
local this_trans=component.proxy(this_info.addr)
local need=0
if(this_info.size>request_amount-fetched) then
need=request_amount-fetched
else
need=this_info.size
end
local done=this_trans.transferItem(this_info.side,sides.down,need,this_info.slot)
fetched=fetched+done
this_info.size=this_info.size-done
this_table.total=this_table.total-done
if(fetched>=request_amount) then break end
status("[Working] " .. fetched .. " of " .. request_amount .. " items transferred.")
end
-- Update storage info
local idx=1
while(idx<=#this_table.position) do
if(this_table.position[idx].size<=0) then
table.remove(this_table.position,idx)
result.slot_used=result.slot_used-1
else
idx=idx+1
end
end
if(this_table.total<1) then
result[tb_display[begin_at+e.y-3]]=nil -- Remove this type
table.remove(tb_display,begin_at+e.y-3)
if(begin_at>1) then
begin_at=begin_at-1
end
end
status("[Done] " .. fetched .. " of " .. request_amount .. " items transferred") -- Sometimes (ex: output box is full) not all items can be transferred.
return fetched
end
term.clear()
print("Smart Storage System Starting...")
status("Scanning...")
local craft_table={}
local result=full_scan()
local tb_display=GetDisplayTable(result)
local begin_at=1
local item_filter=''
-- These variable should be local. Here is just for debug purpose.
craft_table={}
result=full_scan()
tb_display=GetDisplayTable(result)
begin_at=1
item_filter=''
local need_refresh=true
@ -343,18 +387,37 @@ while true do
temp=io_trans.getStackInSlot(io_trans_buffer_side,from_slot)
if(temp~=nil or temp.size~=nil) then
newRecipe.from[idx]={
id=getItemXID(temp.name,temp.label)
id=getItemXID(temp.name,temp.label),
size=temp.size
}
end
end
end
if(not craft_table[newRecipe.to.id]) then
craft_table[newRecipe.to.id]={}
end
table.insert(craft_table[newRecipe.to.id],{size=newRecipe.to.size,from=newRecipe.from})
status("New recipe added")
need_refresh=true
end
elseif(e.x<=string.len("<Refresh> <Reform> <Set Filter> <Clear Filter> <Read recipe> <Debug>")) then
term.setCursor(1,h-1)
term.clearLine()
io.write("Lua: ")
local str=io.read()
if(str) then
local f,err=load(str,"UserChunk","t",_ENV)
if(f==nil) then
status("Invalid Debug: " .. err)
else
local ok,err=pcall(f)
if(not ok) then
status("Debug Failed: " .. err)
end
end
need_refresh=true
end
end
elseif(e.y>=3 and e.y<=h-3) then
if(begin_at+e.y-3<=#tb_display) then
@ -370,46 +433,134 @@ while true do
status("Invalid input.")
else
status("Transfer begins.")
local fetched=0
for idx,this_info in ipairs(this_table.position) do
local this_trans=component.proxy(this_info.addr)
local need=0
if(this_info.size>n-fetched) then
need=n-fetched
else
need=this_info.size
end
local done=this_trans.transferItem(this_info.side,sides.down,need,this_info.slot)
fetched=fetched+done
this_info.size=this_info.size-done
this_table.total=this_table.total-done
if(fetched>=n) then break end
status("[Working] " .. fetched .. " of " .. n .. " items transferred.")
end
-- Update storage info
local idx=1
while(idx<=#this_table.position) do
if(this_table.position[idx].size<=0) then
table.remove(this_table.position,idx)
result.slot_used=result.slot_used-1
else
idx=idx+1
end
end
if(this_table.total<1) then
result[tb_display[begin_at+e.y-3]]=nil -- Remove this type
table.remove(tb_display,begin_at+e.y-3)
if(begin_at>1) then
begin_at=begin_at-1
end
end
status("[Done] " .. fetched .. " of " .. n .. " items transferred") -- Sometimes (ex: output box is full) not all items can be transferred.
SystemGetItem(result,tb_display[begin_at+e.y-3],n)
end
elseif(e.button==1) then -- Right click
if(craft_table[tb_display[begin_at+e.y-3]]==nil) then
status("This item can't be crafted.")
else
need_refresh=true
local this_table=result[tb_display[begin_at+e.y-3]]
local this_recipe_list=craft_table[tb_display[begin_at+e.y-3]]
local resolved_recipe_id=nil
status("Calculating crafting need...")
for idx,this_recipe in ipairs(this_recipe_list) do
status("[Working] Checking recipe " .. idx .. "...")
local temp_sum={}
for idx,this_from in pairs(this_recipe.from) do
if(not temp_sum[this_from.id]) then
temp_sum[this_from.id]=0
end
temp_sum[this_from.id]=temp_sum[this_from.id]+this_from.size
end
local available=true
for this_id,this_amount in pairs(temp_sum) do
status("[Checking] ID=" .. this_id)
if(result[this_id].total<this_amount) then
available=false
break
end
end
if(available) then
resolved_recipe_id=idx
break
end
end
if(not resolved_recipe_id) then
status("Unable to craft. Not enough ingredients.")
else
status("[Checked] Following recipe " .. resolved_recipe_id)
local follow_recipe=this_recipe_list[resolved_recipe_id]
local target_slot={1,2,3,10,11,12,19,20,21}
local flag_done=true
local io_trans=component.proxy(io_trans_addr)
for idx,this_slot in pairs(follow_recipe.from) do
local ans=SystemGetItem(result,this_slot.id,this_slot.size)
if(ans~=this_slot.size) then
flag_done=false
break
end
end
if(not flag_done) then
status("Unable to craft. Failed to fetch enough item.")
else
status("[Working] Clearing buffer chest...")
while io_trans.transferItem(io_trans_buffer_side,io_trans_output_side)>0 do end
status("[Working] Moving resource to buffer chest...")
for i=1,9,1 do
if(follow_recipe.from[i]) then
status("[Working] Gathering item for slot " .. i .. "...")
local which_slot=0
while which_slot<1 do
for j=1,io_trans.getInventorySize(io_trans_output_side),1 do
local this_info=io_trans.getStackInSlot(io_trans_output_side,j)
if(this_info~=nil and this_info.size~=nil and
(getItemXID(this_info.name,this_info.label)==follow_recipe.from[i].id) and
(this_info.size>=follow_recipe.from[i].size)
) then
which_slot=j
break
end
end
status("[Working] Waiting item for slot " .. i .. "...")
end
io_trans.transferItem(io_trans_output_side,io_trans_buffer_side,follow_recipe.from[i].size,which_slot,target_slot[i])
end
end
status("[Pending] Waiting for robot response...")
modem.send(robotAddr,1000,"do_craft")
local robot_ok=true
while true do
local e=WaitEvent(5,"modem_message")
if(e==nil) then
status("Unable to craft. Robot no response.")
robot_ok=false
break
elseif(e.event=="modem_message" and e.port==1001 and e.data[1]=="craft_started") then
break
end
end
if(robot_ok) then
status("[Pending] Robot is crafting... (Ctrl+C to stop)")
local craft_done=false
local craft_ok=false
while true do
local e=WaitMultipleEvent("modem_message","interrupted")
if(e.event=="interrupted") then
status("Craft process is cancelled by user.")
break
elseif(e.event=="modem_message" and e.port==1001 and e.data[1]=="craft_done") then
status("[Working] Robot crafting finished.")
craft_ok=e.data[2]
craft_done=true
break
end
end
if(craft_done) then
status("[Working] Moving items to output chest...")
while io_trans.transferItem(io_trans_buffer_side,io_trans_output_side)>0 do end
if(craft_ok) then
status("[Done] Item crafted successfully.")
else
status("[Done] Item failed to craft.")
end
end
end
end
end
end
end
end
end

76
SmartStorageRobot.lua Normal file
View File

@ -0,0 +1,76 @@
-- Smart Storage Robot
-- Author: Kiritow
local component=require('component')
local sides=require('sides')
local serialization=require('serialization')
local robot=require('robot')
require('libevent')
local version_tag="Smart Storage Robot v0.1"
print(version_tag)
print("Checking hardware...")
local modem=component.modem
local crafting=component.crafting
local controller=component.inventory_controller
if(not modem or not crafting or not controller or robot.inventorySize()<16) then
print("This program requires Modem, Crafting upgrade, Inventory Controller upgrade and at least a 16-slot inventory to run.")
return
end
print("Reading config...")
print("Waiting for Smart Storage System... (Ctrl+C to stop)")
local sysAddr=''
modem.open(1000)
while true do
local e=WaitMultipleEvent("modem_message","interrupted")
if(e.event=="interrupted") then
print("Cancelled by user.")
modem.close(1000)
return
elseif(e.event=="modem_message" and e.port==1000 and e.data[1]=="find_crafting_robot") then
print("System request received.")
sysAddr=e.senderAddress
modem.send(sysAddr,1001,"crafting_robot_response")
print("Response sent.")
break
end
end
print("Smart Storage System set to " .. sysAddr)
while true do
print("Waiting for requests... (Ctrl+C to stop)")
local e=WaitMultipleEvent("modem_message","interrupted")
if(e.event=="interrupted") then
print("Receive stop signal")
break
elseif(e.event=="modem_message" and e.port==1000) then
if(e.data[1]=="do_craft") then
print("[Pending] Sending response...")
modem.send(sysAddr,1001,"craft_started")
print("[Working] Start craft task...")
local from_slot={1,2,3,10,11,12,19,20,21}
local to_slot={1,2,3,5,6,7,9,10,11}
print("[Working] Moving resource...")
for i=1,9,1 do
robot.select(to_slot[i])
controller.suckFromSlot(sides.front,from_slot[i])
end
print("[Working] Crafting...")
robot.select(4)
local result=crafting.craft()
print("[Working] Craft result: ",result)
print("[Working] Cleaning inventory...")
for i=1,16,1 do
robot.select(i)
robot.drop()
end
modem.send(sysAddr,1001,"craft_done",result)
print("[Done] Task craft finished.")
end
end
end
print("Closing ports...")
modem.close(1000)