This commit is contained in:
kepler155c
2017-09-18 14:46:21 -04:00
parent b4d3160cd8
commit 4116e046d1
14 changed files with 2491 additions and 2211 deletions

View File

@@ -42,7 +42,7 @@ local blockDB = TableDB()
function blockDB:load() function blockDB:load()
local blocks = JSON.decodeFromFile('usr/etc/blocks.json')) local blocks = JSON.decodeFromFile('usr/etc/blocks.json')
if not blocks then if not blocks then
error('Unable to read blocks.json') error('Unable to read blocks.json')

View File

@@ -3,6 +3,20 @@ local TableDB = require('tableDB')
local itemDB = TableDB({ fileName = 'usr/config/items.db' }) local itemDB = TableDB({ fileName = 'usr/config/items.db' })
local function splitKey(key, item)
item = item or { }
local t = Util.split(key, '(.-):')
if #t[#t] > 8 then
item.nbtHash = table.remove(t)
end
item.damage = tonumber(table.remove(t))
item.name = table.concat(t, ':')
return item
end
function itemDB:get(key) function itemDB:get(key)
local item = TableDB.get(self, key) local item = TableDB.get(self, key)
@@ -34,6 +48,54 @@ function itemDB:makeKey(item)
return { item.name, item.damage, item.nbtHash } return { item.name, item.damage, item.nbtHash }
end end
-- Accepts: "minecraft:stick:0" or { name = 'minecraft:stick', damage = 0 }
function itemDB:getName(item)
if type(item) == 'string' then
item = splitKey(item)
end
local detail = self:get(self:makeKey(item))
if detail then
return detail.displayName
end
return item.name .. ':' .. item.damage
end
function itemDB:load()
TableDB.load(self)
for key,item in pairs(self.data) do
splitKey(key, item)
item.maxDamage = item.maxDamage or 0
item.maxCount = item.maxCount or 64
end
end
function itemDB:flush()
if self.dirty then
local t = { }
for k,v in pairs(self.data) do
v = Util.shallowCopy(v)
v.name = nil
v.damage = nil
v.nbtHash = nil
if v.maxDamage == 0 then
v.maxDamage = nil
end
if v.maxCount == 64 then
v.maxCount = nil
end
t[k] = v
end
Util.writeTable(self.fileName, t)
self.dirty = false
end
end
itemDB:load() itemDB:load()
return itemDB return itemDB

View File

@@ -27,7 +27,7 @@ function RefinedAdapter:init(args)
Util.merge(self, controller) Util.merge(self, controller)
end end
end end
function RefinedAdapter:isValid() function RefinedAdapter:isValid()
return not not self.listAvailableItems return not not self.listAvailableItems
end end

View File

@@ -7,17 +7,15 @@ function TableDB:init(args)
fileName = '', fileName = '',
dirty = false, dirty = false,
data = { }, data = { },
tabledef = { },
} }
Util.merge(defaults, args) Util.merge(defaults, args)
Util.merge(self, defaults) Util.merge(self, defaults)
end end
function TableDB:load() function TableDB:load()
local table = Util.readTable(self.fileName) local t = Util.readTable(self.fileName)
if table then if t then
self.data = table.data self.data = t.data or t
self.tabledef = table.tabledef
end end
end end
@@ -43,10 +41,7 @@ end
function TableDB:flush() function TableDB:flush()
if self.dirty then if self.dirty then
Util.writeTable(self.fileName, { Util.writeTable(self.fileName, self.data)
-- tabledef = self.tabledef,
data = self.data,
})
self.dirty = false self.dirty = false
end end
end end

View File

@@ -3,11 +3,11 @@ local Util = require('util')
local Craft = { } local Craft = { }
local function clearGrid(chestAdapter) local function clearGrid(inventoryAdapter)
for i = 1, 16 do for i = 1, 16 do
local count = turtle.getItemCount(i) local count = turtle.getItemCount(i)
if count > 0 then if count > 0 then
chestAdapter:insert(i, count) inventoryAdapter:insert(i, count)
if turtle.getItemCount(i) ~= 0 then if turtle.getItemCount(i) ~= 0 then
return false return false
end end
@@ -19,7 +19,7 @@ end
local function splitKey(key) local function splitKey(key)
local t = Util.split(key, '(.-):') local t = Util.split(key, '(.-):')
local item = { } local item = { }
if #t[#t] > 2 then if #t[#t] > 8 then
item.nbtHash = table.remove(t) item.nbtHash = table.remove(t)
end end
item.damage = tonumber(table.remove(t)) item.damage = tonumber(table.remove(t))
@@ -39,13 +39,13 @@ local function getItemCount(items, key)
return 0 return 0
end end
local function turtleCraft(recipe, qty, chestAdapter) local function turtleCraft(recipe, qty, inventoryAdapter)
clearGrid(chestAdapter) clearGrid(inventoryAdapter)
for k,v in pairs(recipe.ingredients) do for k,v in pairs(recipe.ingredients) do
local item = splitKey(v) local item = splitKey(v)
chestAdapter:provide(item, qty, k) inventoryAdapter:provide(item, qty, k)
if turtle.getItemCount(k) == 0 then -- ~= qty then if turtle.getItemCount(k) == 0 then -- ~= qty then
-- FIX: ingredients cannot be stacked -- FIX: ingredients cannot be stacked
return false return false
@@ -55,9 +55,9 @@ local function turtleCraft(recipe, qty, chestAdapter)
return turtle.craft() return turtle.craft()
end end
function Craft.craftRecipe(recipe, count, chestAdapter) function Craft.craftRecipe(recipe, count, inventoryAdapter)
local items = chestAdapter:listItems() local items = inventoryAdapter:listItems()
local function sumItems(items) local function sumItems(items)
-- produces { ['minecraft:planks:0'] = 8 } -- produces { ['minecraft:planks:0'] = 8 }
@@ -78,10 +78,10 @@ function Craft.craftRecipe(recipe, count, chestAdapter)
if itemCount < icount * count then if itemCount < icount * count then
local irecipe = Craft.recipes[key] local irecipe = Craft.recipes[key]
if irecipe then if irecipe then
Util.print('Crafting %d %s', icount * count - itemCount, key) --Util.print('Crafting %d %s', icount * count - itemCount, key)
if not Craft.craftRecipe(irecipe, if not Craft.craftRecipe(irecipe,
icount * count - itemCount, icount * count - itemCount,
chestAdapter) then inventoryAdapter) then
turtle.select(1) turtle.select(1)
return return
end end
@@ -89,7 +89,7 @@ Util.print('Crafting %d %s', icount * count - itemCount, key)
end end
end end
repeat repeat
if not turtleCraft(recipe, math.min(count, maxCount), chestAdapter) then if not turtleCraft(recipe, math.min(count, maxCount), inventoryAdapter) then
turtle.select(1) turtle.select(1)
return false return false
end end
@@ -101,7 +101,7 @@ Util.print('Crafting %d %s', icount * count - itemCount, key)
end end
-- given a certain quantity, return how many of those can be crafted -- given a certain quantity, return how many of those can be crafted
function Craft.getCraftableAmount(recipe, count, items) function Craft.getCraftableAmount(recipe, count, items, missing)
local function sumItems(recipe, items, summedItems, count) local function sumItems(recipe, items, summedItems, count)
@@ -116,6 +116,9 @@ function Craft.getCraftableAmount(recipe, count, items)
summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) summedItem = summedItem + sumItems(irecipe, items, summedItems, 1)
end end
if summedItem <= 0 then if summedItem <= 0 then
if missing then
missing.name = item
end
return canCraft return canCraft
end end
summedItems[item] = summedItem - 1 summedItems[item] = summedItem - 1
@@ -126,7 +129,7 @@ function Craft.getCraftableAmount(recipe, count, items)
return canCraft return canCraft
end end
return sumItems(recipe, items, { }, math.ceil(count / recipe.count)) return sumItems(recipe, items, { }, math.ceil(count / recipe.count), missing)
end end
function Craft.canCraft(item, count, items) function Craft.canCraft(item, count, items)

View File

@@ -2,8 +2,8 @@ local Point = require('point')
local Util = require('util') local Util = require('util')
local checkedNodes = { } local checkedNodes = { }
local nodes = { } local nodes = { }
local box = { } local box = { }
local oldCallback local oldCallback
local function toKey(pt) local function toKey(pt)
@@ -149,7 +149,7 @@ return function(startPt, endPt, firstPt, verbose)
print(string.format('%d nodes remaining', Util.size(nodes))) print(string.format('%d nodes remaining', Util.size(nodes)))
end end
if Util.size(nodes) == 0 then if not next(nodes) then
break break
end end

View File

@@ -140,18 +140,22 @@ function page:enable(turtle)
end end
function page:runFunction(script, nowrap) function page:runFunction(script, nowrap)
if not socket then for i = 1, 2 do
socket = Socket.connect(self.turtle.id, 161)
if not socket then if not socket then
self.notification:error('Unable to connect') socket = Socket.connect(self.turtle.id, 161)
return
end end
end
if not nowrap then if socket then
script = 'turtle.run(' .. script .. ')' if not nowrap then
script = 'turtle.run(' .. script .. ')'
end
if socket:write({ type = 'script', args = script }) then
return true
end
end
socket = nil
end end
socket:write({ type = 'script', args = script }) self.notification:error('Unable to connect')
end end
function page:runScript(scriptName) function page:runScript(scriptName)
@@ -270,6 +274,7 @@ end
function page.tabs.turtles:eventHandler(event) function page.tabs.turtles:eventHandler(event)
if event.type == 'grid_select' then if event.type == 'grid_select' then
page.turtle = event.selected page.turtle = event.selected
multishell.setTitle(multishell.getCurrent(), page.turtle.label)
if socket then if socket then
socket:close() socket:close()
socket = nil socket = nil

View File

@@ -1447,7 +1447,7 @@ substitutionPage = UI.Page {
{ heading = 'Name', key = 'display_name', width = UI.term.width-9 }, { heading = 'Name', key = 'display_name', width = UI.term.width-9 },
{ heading = 'Qty', key = 'fQty', width = 5 }, { heading = 'Qty', key = 'fQty', width = 5 },
}, },
sortColumn = 'name', sortColumn = 'display_name',
height = UI.term.height-7, height = UI.term.height-7,
y = 7, y = 7,
}, },

View File

@@ -31,8 +31,8 @@ if not controller:isValid() then
controller = nil controller = nil
end end
local chestAdapter = ChestAdapter({ direction = 'west', wrapSide = 'back' }) local chestAdapter = ChestAdapter({ direction = 'north', wrapSide = 'colossalchests:colossalChest_0' })
local turtleChestAdapter = ChestAdapter({ direction = 'up', wrapSide = 'bottom' }) local turtleChestAdapter = ChestAdapter({ direction = 'down', wrapSide = 'top' })
local RESOURCE_FILE = 'usr/config/resources.db' local RESOURCE_FILE = 'usr/config/resources.db'
local RECIPES_FILE = 'usr/etc/recipes.db' local RECIPES_FILE = 'usr/etc/recipes.db'
@@ -40,27 +40,10 @@ local RECIPES_FILE = 'usr/etc/recipes.db'
local jobListGrid local jobListGrid
local craftingPaused = false local craftingPaused = false
local recipes = Util.readTable(RECIPES_FILE) or { } local recipes = Util.readTable(RECIPES_FILE) or { }
local resources = Util.readTable(RESOURCE_FILE) or { } local resources
Craft.setRecipes(recipes) Craft.setRecipes(recipes)
for _,r in pairs(resources) do
r.maxDamage = nil
r.displayName = nil
r.count = nil
r.lname = nil
r.has_recipe = nil
if not r.ignoreDamage then
r.ignoreDamage = nil
end
if not r.auto then
r.auto = nil
end
end
Util.writeTable(RESOURCE_FILE, resources)
local function getItem(items, inItem, ignoreDamage) local function getItem(items, inItem, ignoreDamage)
for _,item in pairs(items) do for _,item in pairs(items) do
if item.name == inItem.name then if item.name == inItem.name then
@@ -76,7 +59,7 @@ end
local function splitKey(key) local function splitKey(key)
local t = Util.split(key, '(.-):') local t = Util.split(key, '(.-):')
local item = { } local item = { }
if #t[#t] > 2 then if #t[#t] > 8 then
item.nbtHash = table.remove(t) item.nbtHash = table.remove(t)
end end
item.damage = tonumber(table.remove(t)) item.damage = tonumber(table.remove(t))
@@ -108,14 +91,6 @@ local function uniqueKey(item)
return table.concat({ item.name, item.damage, item.nbtHash }, ':') return table.concat({ item.name, item.damage, item.nbtHash }, ':')
end end
local function getName(item)
local detail = itemDB:get(itemDB:makeKey(item))
if detail then
return detail.displayName
end
return item.name .. ':' .. item.damage
end
local function mergeResources(t) local function mergeResources(t)
for _,v in pairs(resources) do for _,v in pairs(resources) do
local item = getItem(t, v) local item = getItem(t, v)
@@ -141,7 +116,7 @@ local function mergeResources(t)
for _,v in pairs(t) do for _,v in pairs(t) do
if not v.displayName then if not v.displayName then
v.displayName = getName(v) v.displayName = itemDB:getName(v)
end end
v.lname = v.displayName:lower() v.lname = v.displayName:lower()
end end
@@ -209,7 +184,7 @@ local function addCraftingRequest(item, craftList, count)
local request = craftList[key] local request = craftList[key]
if not craftList[key] then if not craftList[key] then
request = { name = item.name, damage = item.damage, nbtHash = nbtHash, count = 0 } request = { name = item.name, damage = item.damage, nbtHash = nbtHash, count = 0 }
request.displayName = getName(request) request.displayName = itemDB:getName(request)
craftList[key] = request craftList[key] = request
end end
request.count = request.count + count request.count = request.count + count
@@ -221,7 +196,13 @@ local function craftItem(recipe, items, originalItem, craftList, count)
return return
end end
local toCraft = Craft.getCraftableAmount(recipe, count, items) local missing = { }
local toCraft = Craft.getCraftableAmount(recipe, count, items, missing)
if missing.name then
originalItem.status = string.format('%s missing', itemDB:getName(missing.name))
originalItem.statusCode = 'missing'
end
if toCraft > 0 then if toCraft > 0 then
Craft.craftRecipe(recipe, toCraft, chestAdapter) Craft.craftRecipe(recipe, toCraft, chestAdapter)
@@ -265,7 +246,6 @@ local function craftItems(craftList, allItems)
if controller:isCrafting(item) then if controller:isCrafting(item) then
item.status = '(crafting)' item.status = '(crafting)'
else else
local count = item.count local count = item.count
while count >= 1 do -- try to request smaller quantities until successful while count >= 1 do -- try to request smaller quantities until successful
local s, m = pcall(function() local s, m = pcall(function()
@@ -311,6 +291,20 @@ local function jobMonitor(jobList)
{ heading = 'Status', key = 'status', width = mon.width - 10 }, { heading = 'Status', key = 'status', width = mon.width - 10 },
}, },
}) })
function jobListGrid:getRowTextColor(row, selected)
if row.status == '(no recipe)'then
return colors.red
elseif row.statusCode == 'missing' then
return colors.yellow
end
return UI.Grid:getRowTextColor(row, selected)
end
jobListGrid:draw()
jobListGrid:sync()
end end
local function getAutocraftItems() local function getAutocraftItems()
@@ -331,21 +325,17 @@ local function getItemWithQty(items, res, ignoreDamage)
local item = getItem(items, res, ignoreDamage) local item = getItem(items, res, ignoreDamage)
if item then if item and ignoreDamage then
local count = 0
if ignoreDamage then for _,v in pairs(items) do
local count = 0 if item.name == v.name and item.nbtHash == v.nbtHash then
if item.maxDamage > 0 or item.damage == v.damage then
for _,v in pairs(items) do count = count + v.count
if item.name == v.name and item.nbtHash == v.nbtHash then
if item.maxDamage > 0 or item.damage == v.damage then
count = count + v.count
end
end end
end end
item.count = count
end end
item.count = count
end end
return item return item
@@ -362,13 +352,17 @@ local function watchResources(items)
damage = res.damage, damage = res.damage,
nbtHash = res.nbtHash, nbtHash = res.nbtHash,
name = res.name, name = res.name,
displayName = getName(res), displayName = itemDB:getName(res),
count = 0 count = 0
} }
end end
if res.limit and item.count > res.limit then if res.limit and item.count > res.limit then
chestAdapter:provide(res, item.count - res.limit, nil, config.trashDirection) chestAdapter:provide(
{ name = item.name, damage = item.damage },
item.count - res.limit,
nil,
config.trashDirection)
elseif res.low and item.count < res.low then elseif res.low and item.count < res.low then
if res.ignoreDamage then if res.ignoreDamage then
@@ -396,6 +390,27 @@ local function watchResources(items)
return craftList return craftList
end end
local function loadResources()
resources = Util.readTable(RESOURCE_FILE) or { }
for k,v in pairs(resources) do
Util.merge(v, splitKey(k))
end
end
local function saveResources()
local t = { }
for k,v in pairs(resources) do
v = Util.shallowCopy(v)
v.name = nil
v.damage = nil
v.nbtHash = nil
t[k] = v
end
Util.writeTable(RESOURCE_FILE, t)
end
local itemPage = UI.Page { local itemPage = UI.Page {
backgroundColor = colors.lightGray, backgroundColor = colors.lightGray,
titleBar = UI.TitleBar { titleBar = UI.TitleBar {
@@ -404,11 +419,9 @@ local itemPage = UI.Page {
event = 'form_cancel', event = 'form_cancel',
backgroundColor = colors.green backgroundColor = colors.green
}, },
displayName = UI.Window {
x = 2, y = 2, width = UI.term.width - 4, height = 3,
},
form = UI.Form { form = UI.Form {
x = 4, y = 5, height = 8, rex = -4, x = 2, y = 3, height = 8, rex = -4,
margin = 1,
[1] = UI.TextEntry { [1] = UI.TextEntry {
width = 7, width = 7,
backgroundColor = colors.gray, backgroundColor = colors.gray,
@@ -433,7 +446,7 @@ local itemPage = UI.Page {
}, },
[4] = UI.Chooser { [4] = UI.Chooser {
width = 7, width = 7,
formLabel = 'Ignore Dmg', formKey = 'ignore_dmg', formLabel = 'Ignore Dmg', formKey = 'ignoreDamage',
nochoice = 'No', nochoice = 'No',
choices = { choices = {
{ name = 'Yes', value = true }, { name = 'Yes', value = true },
@@ -475,21 +488,11 @@ local itemPage = UI.Page {
statusBar = UI.StatusBar { } statusBar = UI.StatusBar { }
} }
function itemPage.displayName:draw()
local item = self.parent.item
local str = string.format('Name: %s\nDamage: %d', item.displayName, item.damage)
if item.nbtHash then
str = str .. string.format('\n%s', item.nbtHash)
end
self:setCursorPos(1, 1)
self:print(str)
end
function itemPage:enable(item) function itemPage:enable(item)
self.item = item self.item = item
self.form:setValues(item) self.form:setValues(item)
self.titleBar.title = item.name self.titleBar.title = item.displayName or item.name
local devices = self.form[6].choices local devices = self.form[6].choices
Util.clear(devices) Util.clear(devices)
@@ -518,7 +521,7 @@ function itemPage:eventHandler(event)
elseif event.type == 'form_complete' then elseif event.type == 'form_complete' then
local values = self.form.values local values = self.form.values
local keys = { 'name', 'auto', 'low', 'limit', 'damage', local keys = { 'name', 'auto', 'low', 'limit', 'damage',
'nbtHash', 'ignoreDamage', 'nbtHash',
'rsControl', 'rsDevice', 'rsSide', } 'rsControl', 'rsDevice', 'rsSide', }
local filtered = { } local filtered = { }
@@ -544,10 +547,11 @@ function itemPage:eventHandler(event)
if values.ignoreDamage == true then if values.ignoreDamage == true then
filtered.damage = 0 filtered.damage = 0
filtered.ignoreDamage = true
end end
resources[uniqueKey(filtered)] = filtered resources[uniqueKey(filtered)] = filtered
Util.writeTable(RESOURCE_FILE, resources) saveResources()
UI:setPreviousPage() UI:setPreviousPage()
@@ -778,7 +782,7 @@ local function learnRecipe(page)
Util.writeTable(RECIPES_FILE, recipes) Util.writeTable(RECIPES_FILE, recipes)
local displayName = getName(recipe[1]) local displayName = itemDB:getName(recipe[1])
listingPage.statusBar.filter:setValue(displayName) listingPage.statusBar.filter:setValue(displayName)
listingPage.statusBar:timedStatus('Learned: ' .. displayName, 3) listingPage.statusBar:timedStatus('Learned: ' .. displayName, 3)
@@ -896,6 +900,9 @@ function craftPage:eventHandler(event)
return true return true
end end
loadResources()
clearGrid()
UI:setPages({ UI:setPages({
listing = listingPage, listing = listingPage,
item = itemPage, item = itemPage,
@@ -906,10 +913,7 @@ UI:setPages({
UI:setPage(listingPage) UI:setPage(listingPage)
listingPage:setFocus(listingPage.statusBar.filter) listingPage:setFocus(listingPage.statusBar.filter)
clearGrid()
jobMonitor() jobMonitor()
jobListGrid:draw()
jobListGrid:sync()
Event.onInterval(5, function() Event.onInterval(5, function()
@@ -922,10 +926,8 @@ Event.onInterval(5, function()
else else
local craftList = watchResources(items) local craftList = watchResources(items)
jobListGrid:setValues(craftList)
--jobListGrid:draw()
--jobListGrid:sync()
craftItems(craftList, items) craftItems(craftList, items)
jobListGrid:setValues(craftList)
jobListGrid:update() jobListGrid:update()
jobListGrid:draw() jobListGrid:draw()
jobListGrid:sync() jobListGrid:sync()

261
apps/music.lua Normal file
View File

@@ -0,0 +1,261 @@
require = requireInjector(getfenv(1))
local Event = require('event')
local UI = require('ui')
multishell.setTitle(multishell.getCurrent(), 'Music')
local radio = device.drive or error('No drive attached')
if radio.side ~= 'top' and radio.side ~= 'bottom' then
error('Disk drive must be above or below turtle')
end
if not turtle then
error('This program can only be run on a turtle')
end
if not device.monitor then
error('Monitor must be attached (3 wide x 1 tall')
end
local monitor = UI.Device({
deviceType = 'monitor',
textScale = 0.5,
})
UI:setDefaultDevice(monitor)
local page = UI.Page({
volume = 15,
stationName = UI.Text({
y = 2,
x = 2,
width = monitor.width - 14,
height = 3,
backgroundColor = colors.brown,
}),
seek = UI.Button({
y = 7,
x = 13,
height = 3,
event = 'seek',
text = ' >> ',
}),
play = UI.Button({
y = 7,
x = 2,
height = 3,
event = 'play',
text = '> / ll',
}),
louder = UI.Button({
y = 7,
x = monitor.width - 15,
width = 3,
height = 3,
event = 'louder',
text = '+',
}),
quiet = UI.Button({
y = 7,
x = monitor.width - 20,
event = 'quiet',
width = 3,
height = 3,
text = '-',
}),
volumeDisplay = UI.Text({
y = 3,
x = monitor.width - 9,
width = 4,
}),
volume1 = UI.Window({
y = monitor.height - 1,
x = monitor.width - 8,
height = 1,
width = 1,
color = colors.white
}),
volume2 = UI.Window({
y = monitor.height - 2,
x = monitor.width - 7,
height = 2,
width = 1,
color = colors.white
}),
volume3 = UI.Window({
y = monitor.height - 3,
x = monitor.width - 6,
height = 3,
width = 1,
color = colors.yellow
}),
volume4 = UI.Window({
y = monitor.height - 4,
x = monitor.width - 5,
height = 4,
width = 1,
color = colors.yellow,
}),
volume5 = UI.Window({
y = monitor.height - 5,
x = monitor.width - 4,
height = 5,
width = 1,
color = colors.orange,
}),
volume6 = UI.Window({
y = monitor.height - 6,
x = monitor.width - 3,
height = 6,
width = 1,
color = colors.orange,
}),
volume7 = UI.Window({
y = monitor.height - 7,
x = monitor.width - 2,
height = 7,
width = 1,
color = colors.red,
}),
volume8 = UI.Window({
y = monitor.height - 8,
x = monitor.width - 1,
height = 8,
width = 1,
color = colors.red,
})
})
page.volumeControls = {
page.volume1, page.volume2,
page.volume3, page.volume4,
page.volume5, page.volume6,
page.volume7, page.volume8,
}
function page:eventHandler(event)
if event.type == 'play' then
self:play(not self.playing)
elseif event.type == 'seek' then
self:seek()
self:play(true)
elseif event.type == 'louder' then
if self.playing then
self:setVolume(self.volume + 1)
end
elseif event.type == 'quiet' then
if self.playing then
self:setVolume(self.volume - 1)
end
end
end
function page:setVolume(volume, displayOnly)
volume = math.min(volume, 15)
volume = math.max(volume, 1)
self.volume = volume
volume = math.ceil(volume / 2)
for i = 1, volume do
self.volumeControls[i].backgroundColor =
self.volumeControls[i].color
end
for i = volume + 1, #self.volumeControls do
self.volumeControls[i].backgroundColor = colors.black
end
for i = 1, #self.volumeControls do
self.volumeControls[i]:clear()
end
local percent = math.ceil(self.volume / 15 * 100)
self.volumeDisplay.value = percent .. '%'
self.volumeDisplay:draw()
end
function page:seek()
local actions = {
top = {
suck = turtle.suckUp,
drop = turtle.dropUp,
},
bottom = {
suck = turtle.suckDown,
drop = turtle.dropDown,
},
}
local slot = turtle.selectOpenSlot()
actions[radio.side].suck()
repeat
slot = slot + 1
if (slot > 16) then
slot = 1
end
until turtle.getItemCount(slot) >= 1
turtle.select(slot)
actions[radio.side].drop()
self:updateStationName()
end
function page:play(onOff)
self.playing = onOff
if self.playing then
if not radio.hasAudio() then
self:seek()
end
self:updateStationName()
radio.playAudio()
Event.addNamedTimer('songTimer', 180, false, function()
if self.playing then
self:seek()
self:play(true)
self:sync()
end
end)
else
radio.stopAudio()
end
end
function page.stationName:draw()
self:clear()
self:centeredWrite(2, self.value)
end
function page:updateStationName()
local title = radio.getAudioTitle()
if title then
self.stationName.value = title
self.stationName:draw()
end
end
Event.onInterval(1, function()
if not page.playing then
if page.stationName.value == '' then
page:updateStationName()
else
page.stationName.value = ''
page.stationName:draw()
end
page:sync()
end
end)
page:play(true)
page:setVolume(page.volume, true)
UI:setPage(page)
turtle.status = 'Jamming'
UI:pullEvents()
turtle.status = 'idle'
page:play(false)
UI.term:reset()

View File

@@ -1,38 +1,34 @@
requireInjector(getfenv(1)) requireInjector(getfenv(1))
local Event = require('event') local Event = require('event')
local GPS = require('gps') local GPS = require('gps')
local Logger = require('logger') local ChestAdapter = require('chestAdapter18')
local MEProvider = require('meProvider') local Point = require('point')
local Point = require('point') local Socket = require('socket')
local Socket = require('socket') local Util = require('util')
local Util = require('util')
if not device.wireless_modem then if not device.wireless_modem then
error('Modem is required') error('Modem is required')
end end
Logger.setWirelessLogging()
if not turtle then if not turtle then
error('Can only be run on a turtle') error('Can only be run on a turtle')
end end
local blocks = { } local blocks = { }
local meProvider = MEProvider()
local items = { } local items = { }
local pickups = Util.readTable('pickup.tbl') or { } local locations = Util.readTable('/usr/config/pickup') or {
local cells = Util.readTable('cells.tbl') or { } pickups = { },
local refills = Util.readTable('refills.tbl') or { } cells = { },
local fluids = Util.readTable('fluids.tbl') or { } refills = { },
local chestPt = turtle.loadLocation('chest') fluids = { },
local chargePt = turtle.loadLocation('charge') }
local fuel = { local fuel = {
item = { item = {
id = 'minecraft:coal', name = 'minecraft:coal',
dmg = 0, damage = 0,
}, },
qty = 64 qty = 64
} }
@@ -51,14 +47,18 @@ turtle.setMoveCallback(function(action, pt)
end) end)
function refuel() function refuel()
if turtle.getFuelLevel() < 5000 then if turtle.getFuelLevel() < 5000 and locations.dropPt then
print('refueling') print('refueling')
turtle.status = 'refueling' turtle.status = 'refueling'
gotoPoint(chestPt, true) gotoPoint(locations.dropPt, true)
dropOff(chestPt) dropOff(locations.dropPt)
local chestAdapter = ChestAdapter({
wrapSide = 'bottom',
direction = 'up',
})
while turtle.getFuelLevel() < 5000 do while turtle.getFuelLevel() < 5000 do
turtle.select(1) turtle.select(1)
meProvider:provide(fuel.item, fuel.qty, 1) chestAdapter:provide(fuel.item, fuel.qty, 1)
turtle.refuel(64) turtle.refuel(64)
print(turtle.getFuelLevel()) print(turtle.getFuelLevel())
os.sleep(1) os.sleep(1)
@@ -71,7 +71,7 @@ function pickUp(pt)
gotoPoint(pt, true) gotoPoint(pt, true)
while true do while true do
if not turtle.selectOpenSlot() then if not turtle.selectOpenSlot() then
dropOff(chestPt) dropOff(locations.dropPt)
gotoPoint(pt, true) gotoPoint(pt, true)
end end
turtle.select(1) turtle.select(1)
@@ -85,16 +85,17 @@ function dropOff(pt)
if turtle.selectSlotWithItems() then if turtle.selectSlotWithItems() then
gotoPoint(pt, true) gotoPoint(pt, true)
turtle.emptyInventory(turtle.dropDown) turtle.emptyInventory(turtle.dropDown)
if pt == chestPt then if pt == locations.dropPt then
print('refreshing items') print('refreshing items')
items = meProvider:refresh() chestAdapter = ChestAdapter()
items = chestAdapter:refresh()
end end
end end
end end
function gotoPoint(pt, doDetect) function gotoPoint(pt, doDetect)
slots = turtle.getInventory() slots = turtle.getInventory()
while not turtle.pathfind(pt, blocks) do while not turtle.pathfind(pt, { blocks = blocks }) do
if turtle.abort then if turtle.abort then
error('aborted') error('aborted')
end end
@@ -110,7 +111,7 @@ end
function checkCell(pt) function checkCell(pt)
if not turtle.selectOpenSlot() then if not turtle.selectOpenSlot() then
dropOff(chestPt) dropOff(locations.dropPt)
end end
print('checking cell') print('checking cell')
@@ -123,7 +124,7 @@ function checkCell(pt)
print('charging cell') print('charging cell')
turtle.selectOpenSlot() turtle.selectOpenSlot()
turtle.digDown() turtle.digDown()
gotoPoint(chargePt, true) gotoPoint(locations.chargePt, true)
turtle.dropDown() turtle.dropDown()
os.sleep(energy / 20000) os.sleep(energy / 20000)
turtle.suckDown() turtle.suckDown()
@@ -152,12 +153,13 @@ function fluid(points)
end end
function refill(entry) function refill(entry)
dropOff(chestPt) dropOff(locations.dropPt)
turtle.status = 'refilling' turtle.status = 'refilling'
gotoPoint(chestPt) gotoPoint(locations.dropPt)
local chestAdapter = ChestAdapter()
for _,item in pairs(entry.items) do for _,item in pairs(entry.items) do
meProvider:provide(item, tonumber(item.qty), turtle.selectOpenSlot()) chestAdapter:provide(item, tonumber(item.qty), turtle.selectOpenSlot())
end end
if turtle.selectSlotWithItems() then if turtle.selectSlotWithItems() then
@@ -179,7 +181,7 @@ function oldRefill(points)
end end
end end
dropOff(points.source) dropOff(points.source)
dropOff(chestPt) dropOff(locations.dropPt)
end end
local function makeKey(pt) local function makeKey(pt)
@@ -199,8 +201,8 @@ local function pickupHost(socket)
if data.type == 'pickup' then if data.type == 'pickup' then
local key = makeKey(data.point) local key = makeKey(data.point)
pickups[key] = data.point locations.pickups[key] = data.point
Util.writeTable('pickup.tbl', pickups) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' }) socket:write( { type = "response", response = 'added' })
elseif data.type == 'items' then elseif data.type == 'items' then
@@ -208,41 +210,36 @@ local function pickupHost(socket)
elseif data.type == 'refill' then elseif data.type == 'refill' then
local key = makeKey(data.entry.point) local key = makeKey(data.entry.point)
refills[key] = data.entry locations.refills[key] = data.entry
Util.writeTable('refills.tbl', refills) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' }) socket:write( { type = "response", response = 'added' })
elseif data.type == 'setPickup' then elseif data.type == 'setPickup' then
chestPt = data.point locations.dropPt = data.point
-- fix Util.writeTable('/usr/config/pickup', locations)
turtle.storeLocation('chest', chestPt)
socket:write( { type = "response", response = 'Location set' }) socket:write( { type = "response", response = 'Location set' })
elseif data.type == 'setRecharge' then elseif data.type == 'setRecharge' then
chargePt = data.point locations.chargePt = data.point
-- fix Util.writeTable('/usr/config/pickup', locations)
turtle.storeLocation('charge', chargePt)
socket:write( { type = "response", response = 'Location set' }) socket:write( { type = "response", response = 'Location set' })
elseif data.type == 'charge' then elseif data.type == 'charge' then
local key = makeKey(data.point) local key = makeKey(data.point)
cells[key] = data.point locations.cells[key] = data.point
Util.writeTable('cells.tbl', cells) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' }) socket:write( { type = "response", response = 'added' })
elseif data.type == 'fluid' then elseif data.type == 'fluid' then
elseif data.type == 'clear' then elseif data.type == 'clear' then
local key = makeKey(data.point) local key = makeKey(data.point)
refills[key] = nil locations.refills[key] = nil
cells[key] = nil locations.cells[key] = nil
fluids[key] = nil locations.fluids[key] = nil
pickups[key] = nil locations.pickups[key] = nil
Util.writeTable('refills.tbl', refills) Util.writeTable('/usr/config/pickup', locations)
Util.writeTable('cells.tbl', cells)
Util.writeTable('fluids.tbl', fluids)
Util.writeTable('pickup.tbl', pickups)
socket:write( { type = "response", response = 'cleared' }) socket:write( { type = "response", response = 'cleared' })
else else
@@ -303,15 +300,22 @@ end
Event.addRoutine(function() Event.addRoutine(function()
if not turtle.enableGPS() then
error('turtle: No GPS found')
end
refuel()
while true do while true do
if chestPt then if locations.dropPt then
eachClosestEntry(pickups, pickUp) eachClosestEntry(locations.pickups, pickUp)
eachEntry(refills, refill) eachEntry(locations.refills, refill)
refuel() refuel()
end end
eachEntry(fluids, fluid) dropOff(locations.dropPt)
if chargePt then eachEntry(locations.fluids, fluid)
eachEntry(cells, checkCell) if locations.chargePt then
eachEntry(locations.cells, checkCell)
end end
print('sleeping') print('sleeping')
turtle.status = 'sleeping' turtle.status = 'sleeping'
@@ -327,11 +331,6 @@ end)
turtle.run(function() turtle.run(function()
if not turtle.enableGPS() then
error('turtle: No GPS found')
end
refuel()
Event.pullEvents() Event.pullEvents()
end) end)

View File

@@ -18,11 +18,12 @@ local mainPage = UI.Page({
menu = UI.Menu({ menu = UI.Menu({
centered = true, centered = true,
y = 2, y = 2,
height = 8,
menuItems = { menuItems = {
{ prompt = 'Pickup', event = 'pickup', help = 'Pickup items from this location' }, { prompt = 'Pickup', event = 'pickup', help = 'Pickup items from this location' },
{ prompt = 'Charge cell', event = 'charge', help = 'Recharge this cell' }, { prompt = 'Charge cell', event = 'charge', help = 'Recharge this cell' },
{ prompt = 'Refill', event = 'refill', help = 'Recharge this cell' }, { prompt = 'Refill', event = 'refill', help = 'Recharge this cell' },
{ prompt = 'Set pickup location', event = 'setPickup', help = 'Recharge this cell' }, { prompt = 'Set drop off location', event = 'setPickup', help = 'Recharge this cell' },
{ prompt = 'Set recharge location', event = 'setRecharge', help = 'Recharge this cell' }, { prompt = 'Set recharge location', event = 'setRecharge', help = 'Recharge this cell' },
{ prompt = 'Clear', event = 'clear', help = 'Remove this location' }, { prompt = 'Clear', event = 'clear', help = 'Remove this location' },
}, },
@@ -89,7 +90,7 @@ local function sendCommand(cmd)
end end
local function getPoint() local function getPoint()
local gpt = GPS.getPoint() local gpt = GPS.getPoint(2)
if not gpt then if not gpt then
mainPage.statusBar:timedStatus('Unable to get location', 3) mainPage.statusBar:timedStatus('Unable to get location', 3)
end end

View File

@@ -251,143 +251,19 @@ local levelScript = [[
requireInjector(getfenv(1)) requireInjector(getfenv(1))
local Point = require('point') local Level = require('turtle.level')
local Util = require('util') local Util = require('util')
local checkedNodes = { }
local nodes = { }
local box = { }
local function inBox(pt, box)
return pt.x >= box.x and
pt.y >= box.y and
pt.z >= box.z and
pt.x <= box.ex and
pt.y <= box.ey and
pt.z <= box.ez
end
local function toKey(pt)
return table.concat({ pt.x, pt.y, pt.z }, ':')
end
local function addNode(node)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd }
if inBox(testNode, box) then
local key = toKey(testNode)
if not checkedNodes[key] then
nodes[key] = testNode
end
end
end
end
local function dig(action)
local directions = {
top = 'up',
bottom = 'down',
}
-- convert to up, down, north, south, east, west
local direction = directions[action.side] or
turtle.getHeadingInfo(turtle.point.heading).direction
local hi = turtle.getHeadingInfo(direction)
local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd }
if inBox(node, box) then
local key = toKey(node)
checkedNodes[key] = true
nodes[key] = nil
if action.dig() then
addNode(node)
repeat until not action.dig() -- sand, etc
return true
end
end
end
local function move(action)
if action == 'turn' then
dig(turtle.getAction('forward'))
elseif action == 'up' then
dig(turtle.getAction('up'))
elseif action == 'down' then
dig(turtle.getAction('down'))
elseif action == 'back' then
dig(turtle.getAction('up'))
dig(turtle.getAction('down'))
end
end
local function getAdjacentPoint(pt)
local t = { }
table.insert(t, pt)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local heading
if i < 4 then
heading = (hi.heading + 2) % 4
end
table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading })
end
return Point.closest2(turtle.getPoint(), t)
end
local function level()
box.x = math.min(data.startPt.x, data.endPt.x)
box.y = math.min(data.startPt.y, data.endPt.y)
box.z = math.min(data.startPt.z, data.endPt.z)
box.ex = math.max(data.startPt.x, data.endPt.x)
box.ey = math.max(data.startPt.y, data.endPt.y)
box.ez = math.max(data.startPt.z, data.endPt.z)
turtle.pathfind(data.firstPt)
turtle.setPolicy("attack", { dig = dig }, "assuredMove")
turtle.setMoveCallback(move)
repeat
local key = toKey(turtle.point)
checkedNodes[key] = true
nodes[key] = nil
dig(turtle.getAction('down'))
dig(turtle.getAction('up'))
dig(turtle.getAction('forward'))
print(string.format('%d nodes remaining', Util.size(nodes)))
if Util.size(nodes) == 0 then
break
end
local node = Point.closest2(turtle.point, nodes)
node = getAdjacentPoint(node)
if not turtle.gotoPoint(node) then
break
end
until turtle.abort
turtle.resetState()
end
local s, m = turtle.run(function() local s, m = turtle.run(function()
turtle.status = 'Leveling' turtle.status = 'Leveling'
if turtle.enableGPS() then if turtle.enableGPS() then
local pt = Util.shallowCopy(turtle.point) local pt = Util.shallowCopy(turtle.point)
local s, m = pcall(level) local s, m = pcall(function()
Level(data.startPt, data.endPt, data.firstPt)
end)
turtle.pathfind(pt) turtle.pathfind(pt)
if not s and m then if not s and m then
@@ -446,7 +322,7 @@ end
function page:runFunction(id, script) function page:runFunction(id, script)
Util.writeFile('script.tmp', script) --Util.writeFile('script.tmp', script)
self.notification:info('Connecting') self.notification:info('Connecting')
local fn, msg = loadstring(script, 'script') local fn, msg = loadstring(script, 'script')
if not fn then if not fn then

File diff suppressed because it is too large Load Diff