Advertisement
asweigart

3dprint (twitch)

Dec 20th, 2016
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.29 KB | None | 0 0
  1. -- 3d printer program by Al Sweigart
  2.  
  3. os.loadAPI('hare')
  4.  
  5.  
  6.  
  7.  
  8.  
  9. -- TODO: I might move this function into the hare library later.
  10. function split(str)
  11. -- splits a string into an array of strings
  12. -- Example: 'a b c' -> {'a', 'b', 'c'}
  13. local result, word
  14.  
  15. result = {}
  16. -- Note: The gmatch() function is
  17. -- beyond the scope of this book.
  18. for word in str:gmatch("%w+") do
  19. table.insert(result, word)
  20. end
  21. return result
  22. end
  23.  
  24.  
  25. function getTurtleInventoryCounts()
  26. local currentInventory = {}
  27. local slot
  28. for slot = 1, 16 do
  29. local itemDetails = turtle.getItemDetail(slot)
  30. if itemDetails ~= nil then
  31. if currentInventory[itemDetails['name']] == nil then
  32. currentInventory[itemDetails['name']] = itemDetails['count']
  33. else
  34. currentInventory[itemDetails['name']] = currentInventory[itemDetails['name']] + itemDetails['count']
  35. end
  36. end
  37. end
  38. return currentInventory
  39. end
  40.  
  41.  
  42. function buildBlockFunction(x, y)
  43. -- currentLayer is a global variable we can use for the layer number
  44. if bp[x .. ',' .. y .. ',' .. currentLayer] == nil then
  45. -- no block at this position, so just return
  46. return
  47. end
  48.  
  49. local blockName = legend[bp[x .. ',' .. y .. ',' .. currentLayer]]
  50. if hare.selectItem(blockName) == false then
  51. error('Could not find a ' .. blockName .. ' block in inventory.')
  52. end
  53.  
  54. turtle.placeDown()
  55. end
  56.  
  57.  
  58.  
  59.  
  60. local SECTION_END_MARK = '~'
  61.  
  62. local cliArgs = {...}
  63. local blueprintFile = cliArgs[1]
  64.  
  65. local i, bpNumLayers, slot
  66.  
  67. if blueprintFile == nil then
  68. print('Usage: 3dprint <blueprintFile>')
  69. return
  70. end
  71.  
  72. -- validate the blueprint file
  73. if not fs.exists(blueprintFile) then
  74. error('Cannot find blueprint file ' .. blueprintFile)
  75. end
  76.  
  77. legend = {} -- contains all the legend information from the blueprint file, NOTE: this is a global variable
  78.  
  79. -- parse the blueprint's key
  80. bpNumLayers = 0
  81. local fp = fs.open(blueprintFile, 'r')
  82. local line = fp.readLine()
  83. while line ~= SECTION_END_MARK do
  84. -- check for early end of file
  85. if line == nil then
  86. error('Unexpected end of file in legend section.')
  87. end
  88.  
  89. -- check that there's an equal sign
  90. if string.sub(line, 2, 2) ~= '=' then
  91. error('No equal sign in legend section line: ' .. line)
  92. end
  93.  
  94. -- make sure a block name is after the equal sign
  95. if string.len(string.sub(line, 3)) == 0 then
  96. error('No block name given for key: ' .. string.sub(line, 1, 1))
  97. end
  98.  
  99. -- Ex. if line is 'C=minecraft:cobblestone', key is 'C' and value is 'minecraft:cobblestone'
  100. legend[string.sub(line, 1, 1)] = string.sub(line, 3)
  101.  
  102. line = fp.readLine()
  103. end
  104.  
  105.  
  106. bp = {} -- NOTE: this is a global variable
  107. local bpLayerSizes = {} -- keys '<layerNum>width' for width and '<layerNum>length' for length of each layer
  108.  
  109. print('Parsing blueprint...')
  110.  
  111. -- parse the layers of the blueprint
  112. local bpchar, x, y, z
  113. z = 0
  114. while true do
  115. --print('layer: ' .. z)
  116. -- read in a single layer section
  117.  
  118. bpLayerSizes[z .. 'maxx'] = 0
  119. bpLayerSizes[z .. 'maxy'] = 0
  120.  
  121. line = fp.readLine()
  122. if line == nil then
  123. --print('end of file')
  124. break
  125. end
  126.  
  127. y = 0
  128. -- read in all the lines for this layer
  129. while line ~= SECTION_END_MARK do
  130. --print('line y: ' .. y)
  131. -- read in each character from the line
  132. for i = 1, string.len(line) do
  133. x = i - 1
  134. --print('char x: ' .. x)
  135. local bpchar = string.sub(line, i, i)
  136. if bpchar ~= '.' then -- ignore periods in the blueprint file
  137. bp[x .. ',' .. y .. ',' .. z] = bpchar
  138. --print(x .. ',' .. y .. ',' .. z .. '=' .. bpchar)
  139.  
  140. -- check to see if we should expand the size in bpLayerSizes
  141. if x > bpLayerSizes[z .. 'maxx'] then
  142. bpLayerSizes[z .. 'maxx'] = x
  143. end
  144. if y > bpLayerSizes[z .. 'maxy'] then
  145. bpLayerSizes[z .. 'maxy'] = y
  146. end
  147.  
  148. end
  149. end
  150.  
  151. line = fp.readLine()
  152. if line == nil then
  153. error('Unexpected end of file in layer ' .. z)
  154. end
  155. y = y + 1
  156. end
  157.  
  158. bpNumLayers = bpNumLayers + 1
  159. z = z + 1
  160. end
  161. fp.close()
  162.  
  163.  
  164. -- start building
  165.  
  166. currentLayer = 0 -- NOTE: this is a global variable
  167. local coordinates, blockChar, itemDetails, blockName, numBlocksNeeded
  168. while currentLayer < bpNumLayers do
  169. print('Building layer ' .. currentLayer .. '...')
  170.  
  171. turtle.up() -- move up first to build this layer
  172.  
  173. -- do an inventory check to see if you can build the current layer
  174.  
  175. -- count up the kinds of blocks and amount needed of each kind for the current layer
  176. currentLayerBlockNeeds = {}
  177. for coordinates, blockChar in pairs(bp) do
  178. -- coordinates is going to be an xyz coordinate string, ex. '2,60,0'
  179. coordinates = split(coordinates)
  180. if tonumber(coordinates[3]) == currentLayer then
  181. -- these coordinates are for the current layer
  182. if currentLayerBlockNeeds[legend[blockChar]] == nil then
  183. currentLayerBlockNeeds[legend[blockChar]] = 1
  184. else
  185. currentLayerBlockNeeds[legend[blockChar]] = currentLayerBlockNeeds[legend[blockChar]] + 1
  186. end
  187. end
  188. end
  189.  
  190. -- count up the kinds of blocks and amount of each kind in the turtle's inventory
  191. currentInventory = getTurtleInventoryCounts()
  192.  
  193. -- compare currentLayerBlockNeeds with currentInventory to make sure we have enough blocks of each type
  194. for blockName, numBlocksNeeded in pairs(currentLayerBlockNeeds) do
  195. local numBlocksHave
  196. if currentInventory[blockName] == nil then
  197. numBlocksHave = 0
  198. else
  199. numBlocksHave = currentInventory[blockName]
  200. end
  201.  
  202. if numBlocksHave < numBlocksNeeded then
  203. -- we don't have enough blocks, calculate how many more we need
  204. print('Need ' .. (numBlocksNeeded - numBlocksHave) .. ' more ' .. blockName)
  205.  
  206. while true do
  207. -- keep waiting until the player adds the needed blocks
  208. os.sleep(1)
  209. currentInventory = getTurtleInventoryCounts() -- recheck the inventory numbers
  210. if currentInventory[blockName] ~= nil and currentInventory[blockName] >= numBlocksNeeded then
  211. break
  212. end
  213. end
  214. end
  215. end
  216.  
  217.  
  218. -- we have enough blocks to begin building this layer
  219. hare.sweepField(bpLayerSizes[currentLayer .. 'maxy'] + 1, bpLayerSizes[currentLayer .. 'maxx'] + 1, buildBlockFunction)
  220.  
  221. currentLayer = currentLayer + 1
  222. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement