This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
the_hyren's profile picture

Thaumcraft Automation Programming

Started by the_hyren, 02 December 2015 - 07:38 PM
the_hyren #1
Posted 02 December 2015 - 08:38 PM
Sorry about the Wall'o text:

So I have a nearly finished autocrafting system for thaumcraft but I need some help programming an advanced computer to run the process, but I've been having trouble getting code to work. There is 5 computers, 1 needs programmed to read the number of cobble in a chest and annouce that number via a peripheral++ chatbox to one of four other computers. I call this one the manager. The first program simply takes the cobble input and annouces it to one of the other 4 computers, based on which are currently not crafting. This should be easy with 4 bool variables and a switch statement. The other 4 computers are mostly identical except for orientation, i call these infuser1 through 4. These contain a table loaded from a file, which has all the recipes, the number of cobble annouced represents on of these recipes. Next I for loop this column in the table into a method that retrieves and crafts items as necessary from my ME system, placing them in a chest that fills the pillars in order clockwise and center last, the rest of the items go into a set of alchemical furnaces that generate the essentia needed. Once this is complete the computer needs to emit a redstone signal to the rear enabling a itemduct retriever that grabs my filler item (wood sword). This item represents all the empty pillar slots that there will be while crafting. 30 seconds later we disable that redstone. Next wait a few minutes for most the essentia items to finish (gonna try sleep(180) to start). Then we emit redstone to the left which makes an autonomous activator wand whack the matrix.

I have my 4 helper functions written and they work fine:
function listen(string myname) waits until a chat event with the infusers name tag. it then returns the message sent
function start() sets left redstone on for 2 seconds, triggering activator
function removeFiller() sets rear redstone on for 30 seconds, removing the filler item (wood swords)
function grabItem(name) tries to grab the item, crafts it on failure, and then trys again

But in the while loop I'm having trouble with my if statements:

while true do
command = listen("infuser1:")
prefix = string.sub(command, 1, 6)
chat.say("Running command: " .. prefix)
if prefix == "infuse" then
txtnum = string.sub(command, 8)
chat.say("Getting recipe " .. txtnum)
num = tonumber(txtnum)

end
end

All I got but so far even if prefix == "infuse" the code in the if doesnt run…
Lyqyd #2
Posted 02 December 2015 - 10:03 PM
Moved to Ask a Pro.
Dragon53535 #3
Posted 02 December 2015 - 10:31 PM
I'm not sure if chatbox chat shows up for other chatbox's. Have you tested that?
the_hyren #4
Posted 03 December 2015 - 05:30 AM
I have not…ill do that now

right, minor issue there haha, doesnt seem to work. So if anyone has other suggestions about communication. if not ill wire all 4 bridges to one computer and integrate both programs. Either way i'd like to get the basic crafting loop done. Then i can make it a function and deal with the multi tasking part
Dragon53535 #5
Posted 03 December 2015 - 02:02 PM
You could just use wireless modems.

Can you show us your entire code please? I'd like to see the rest of it. Because I have a sneaking suspicion that the listen code returns "Infuser" and not "infuser"
Edited on 03 December 2015 - 01:03 PM
the_hyren #6
Posted 03 December 2015 - 07:14 PM
bridge = peripheral.wrap("right")
chat = peripheral.wrap("top")
fillerItem = "minecraft:wooden_sword"
mytag = "infuser1:"
recipefile = "recipes.txt"

function grabItem(name)

num = bridge.retrieve(name, 1, "north")
if num ~= 1 then
bridge.craft(name, 1)
crafting = true
while crafting do
local event, complete, crafted, num, bytes = os.pullEvent("craftingComplete")
crafting = complete
end
bridge.retrieve(name, 1, "north")
end
end

function listen(mytag)
listening = true
while listening do
local event, name, text = os.pullEvent("chat")
start, stop = string.find(text, mytag)
if start ~= nil and start >= 0 then
return string.sub(text, stop + 1)
end
end
end

function startInfusion()
redstone.setOutput("left", true)
sleep(2)
redstone.setOutput("left", false)
end

function removeFiller()
redstone.setOutput("back", true)
sleep(30)
redstone.setOutput("back", false)
end

function loadRecipes(filename)
file = fs.open(file, "r")
data = file.readAll()
file.close()
return textutils.unserialize(data)
end

function saveRecipes(filename, recipes)
file = fs.open(filename, "w")
data = textutils.serialize(recipes)
file.write(data)
file.close()
end

while true do
command = listen(mytag)
prefix = string.sub(command, 1, 6)
chat.say("Running command: " .. prefix)

end
the_hyren #7
Posted 03 December 2015 - 07:17 PM
So as I said, my helper functions all work as intended so far. But I cant seem to make any comparison in an if statement with my prefix var to get any code to work inside said if statement to happen. Brand new to lua language so im sure im just not used to tthe syntax. But I've done lots of php and java so coding algorithm isnt new to me at all
the_hyren #8
Posted 03 December 2015 - 08:03 PM
O and if anyone can shed light on if the serialize and unserialize functions (from textutils) works on matrices of strings. Since I'd prefer to not write a file parsing function of my own for loading the recipe file
the_hyren #9
Posted 03 December 2015 - 08:24 PM
wrote some new code:
a helper function; takes in matrix of strings which are the recipes for all infusions and the recipe row number

function infuse(recipes, recipenum)
length = table.getn(recipes[recipenum])
for i=1,length do
grabItem(recipes[recipenum])
end
removeFiller()
sleep(180)
startInfustion()
end

recipes = loadRecipes(recipefile)
while true do
command = listen(mytag)
prefix = string.sub(command, 1, 6)
info = string.sub(command, 8)

end

and the chat message: the listen function chops the name tag out 'infuser1:' in this case and returns the command so 'reload' or 'infuse someinteger'
prefix is the first 6 so 'reload' or 'infuse' this is what Im having trouble comparing. And info is any excess after a space, so '1' or '22' etc.
Dragon53535 #10
Posted 03 December 2015 - 11:31 PM
Quick couple things:

When typing a message there should be two <> up top, click on those and it will open a "code editor" just paste your code into that and it will allow it to show like this:

--#Heeey
Otherwise, you can use the [.code] tags to do the same thing.

Second: What do you mean by matrices of strings? Do you mean arrays of strings? If so, yeah it works on those.

What is table.getn? Do you mean maxn?
Edited on 03 December 2015 - 10:34 PM
moomoomoo3O9 #11
Posted 04 December 2015 - 12:00 AM
Quick couple things:

When typing a message there should be two <> up top, click on those and it will open a "code editor" just paste your code into that and it will allow it to show like this:

--#Heeey
Otherwise, you can use the [.code] tags to do the same thing.

Second: What do you mean by matrices of strings? Do you mean arrays of strings? If so, yeah it works on those.

What is table.getn? Do you mean maxn?

table.getn() can be used to get the length, but if you're just using numerical indices (1-whatever) and don't plan on removing any values from the table, I recommend using #tbl (where tbl is the table you want the length of) instead of table.getn(tbl).
Dragon53535 #12
Posted 04 December 2015 - 12:37 AM
table.getn() can be used to get the length, but if you're just using numerical indices (1-whatever) and don't plan on removing any values from the table, I recommend using #tbl (where tbl is the table you want the length of) instead of table.getn(tbl).
Huh, learn new things every day, never used it, always either used ipairs/pairs or #tbl
Bomb Bloke #13
Posted 04 December 2015 - 02:24 AM
Truth be told, table.getn() isn't 100% reliable - it goes off and gets a cached value stored alongside the table which tracks its length, but it's possible to "confuse" that value (albeit via rather obscure methods) and the call doesn't check to see if it's accurate. table.maxn() does check, so naturally it was removed for Lua 5.2.

So long as there are no "gaps" in a table, # will work just fine (and seems to be the fastest choice execution-wise).

http://www.computercraft.info/forums2/index.php?/topic/15987-table-manipulation/

O and if anyone can shed light on if the serialize and unserialize functions (from textutils) works on matrices of strings.

Assuming by "matrix" you mean "table" (Lua's only container type), so long as they hold no functions or coroutines, and also use no recursion, serialise / unserialise should work just fine.

So as I said, my helper functions all work as intended so far. But I cant seem to make any comparison in an if statement with my prefix var to get any code to work inside said if statement to happen. Brand new to lua language so im sure im just not used to tthe syntax. But I've done lots of php and java so coding algorithm isnt new to me at all

You're still referring to this chunk?:

while true do
	command = listen("infuser1:")
	prefix = string.sub(command, 1, 6)
	chat.say("Running command: " .. prefix)
	
	if prefix == "infuse" then
		txtnum = string.sub(command, 8)
		chat.say("Getting recipe " .. txtnum)
		num = tonumber(txtnum)
	end
end

The logic there appears fine to me. It sounds like you're saying that it does chat "Running command: infuse", but does not chat anything further? I can't see how that would be the case. Could you elaborate on the exact behaviour you're seeing?
the_hyren #14
Posted 04 December 2015 - 03:20 AM
Thanks for the html tags for stuff, im not familiar with forums and posts, I usually figure it out on my own by now but I've gotten frustrated.
And thanks for the #tbl part. I have been learning lua syntax from the computercraft wiki and google so any help with easier ways is much appreciated.
And by matrix i do mean table, its just what the computercraft wiki calls 2d arrays, and a quick question, can lua tables be ragged, which is a java term for when arrays of arrays have different dimensions; as in table[1].length doesnt have to equal table[2].length

And finally, the exact problem I'm having is this: I tell it 'infuser1: infuse X' it replies 'Running command: infuse' then nothing else happens and the program stops running. No errors have been logged or crashes happened. Don't know what's up.

I'm using an advanced computer, and I was wondering what the difference between it and normal ones is
the_hyren #15
Posted 04 December 2015 - 03:33 AM
Ok an update of code using new function and #


bridge = peripheral.wrap("right")
chat = peripheral.wrap("top")
fillerItem = "minecraft:wooden_sword"
mytag = "infuser1:"
recipefile = "recipes.txt"
function grabItem(name)
  num = bridge.retrieve(name, 1, "north")
  if num ~= 1 then
    bridge.craft(name, 1)
    crafting = true
    while crafting do
	  local event, complete, crafted, num, bytes = os.pullEvent("craftingComplete")
	  crafting = complete
    end
    bridge.retrieve(name, 1, "north")
  end
end
function listen(mytag)
  listening = true
  while listening do
    local event, name, text = os.pullEvent("chat")
    start, stop = string.find(text, mytag)
    if start ~= nil and start >= 0 then
	  return string.sub(text, stop + 1)
    end
  end
end
function startInfusion()
  redstone.setOutput("left", true)
  sleep(2)
  redstone.setOutput("left", false)
end
function removeFiller()
  redstone.setOutput("back", true)
  sleep(30)
  redstone.setOutput("back", false)
end
function loadRecipes(filename)
  file = fs.open(file, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function saveRecipes(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end
function infuse(recipes, recipenum)
  length = #recipes[recipenum]
  for i=1,length do
    grabItem(recipes[recipenum][i])
  end
  removeFiller()
  sleep(180)
  startInfustion()
end
recipes = loadRecipes(recipefile)
while true do
  command = listen(mytag)
  prefix = string.sub(command, 1, 6)
  info = string.sub(command, 8)
  chat.say("Running command: " .. prefix, 30)
  if prefix == "reload" then
    recipes = loadRecipes(recipefile)
    chat.say("Recipes reloaded.", 30)
  elseif prefix == "save  " then
    saveRecipes(recipefile, recipes)
    chat.say("Recipes saved.", 30)
  elseif prefix == "addnew" then
   
  elseif prefix == "infuse" then
    recipenum = tonumber(info)
    chat.say("Running infuse recipe: " .. info, 30)
    infuse(recipes, recipenum)
    chat.say("Infusion complete.", 30)
  end
end

Quick other question: does lua have a string function that trims white space from strings, as in removes tabs, newlines, and spaces from the front and back of the string? I would like to see if perhaps I have phantom spaces causing trouble
Bomb Bloke #16
Posted 04 December 2015 - 03:50 AM
quick question, can lua tables be ragged, which is a java term for when arrays of arrays have different dimensions; as in table[1].length doesnt have to equal table[2].length

Yes, they can, and the language doesn't ever make assumptions that they might not be. You can also stick any data type in any table, at any index - table[1] can be a string, table[2] might point to another table (or even the same table, if you wanted!), table[3] might contain a function pointer leading to executable code, table[4] might be nil, table[5] might have a number… they're incredibly dynamic.

Arrays are relatively limited. You can treat a Lua table as an array, and you can also treat a table as a hashmap… or even have it act as both, at the same time.

And finally, the exact problem I'm having is this: I tell it 'infuser1: infuse X' it replies 'Running command: infuse' then nothing else happens and the program stops running. No errors have been logged or crashes happened. Don't know what's up.

When you say "the script stops running", you mean pauses (until you manually terminate it, via eg Ctrl + T), or you mean you're returned to the CraftOS command prompt?

I'm guessing you mean the latter case, which would mean that an error is occurring but for some reason the resulting message isn't making it to the screen. Throw in some more print statements - in particular, immediately before and after each line which calls chat.say() - in an attempt to narrow down exactly which one is crashing you out.

I'm using an advanced computer, and I was wondering what the difference between it and normal ones is

The most obvious difference is that normal computers are only able to output shades of grey to their screens, whereas advanced ones have a 16 colour palette.

But in addition, advanced computers boot up using multishell, which allows them to easily run multiple scripts at once.

In terms of turtles, the above is also true but advanced models furthermore have a higher maximum fuel capacity.

In terms of processing power all systems are the same.

Quick other question: does lua have a string function that trims white space from strings, as in removes tabs, newlines, and spaces from the front and back of the string? I would like to see if perhaps I have phantom spaces causing trouble

Not built in, but you could create one. I don't think that's your problem, however.
Lupus590 #17
Posted 04 December 2015 - 11:11 AM
I'm using an advanced computer, and I was wondering what the difference between it and normal ones is

The most obvious difference is that normal computers are only able to output shades of grey to their screens, whereas advanced ones have a 16 colour palette.

But in addition, advanced computers boot up using multishell, which allows them to easily run multiple scripts at once.

In terms of turtles, the above is also true but advanced models furthermore have a higher maximum fuel capacity.

In terms of processing power all systems are the same.

advanced computers also allow for mouse input, which normal computers don't.
the_hyren #18
Posted 04 December 2015 - 01:50 PM
I'm guessing you mean the latter case, which would mean that an error is occurring but for some reason the resulting message isn't making it to the screen. Throw in some more print statements - in particular, immediately before and after each line which calls chat.say() - in an attempt to narrow down exactly which one is crashing you out.

Indeed it is the later. It exits to command prompt, which I assumed meant an error but I've checked all my logs, java error and minecraft both. Havent seen anything except for a gui error related to /help 6 command, which has been in my mod pack for all of 1.7. I put a chat before my if/elseif block, it runs, anything in or after does not…really frustrating
the_hyren #19
Posted 04 December 2015 - 08:01 PM
Another update: found a trim function online and implemented it


bridge = peripheral.wrap("right")
chat = peripheral.wrap("top")
fillerItem = "minecraft:wooden_sword"
mytag = "infuser1:"
recipefile = "recipes.txt"
function grabItem(name)
  if name == nil or name == "" then
    name = fillerItem
  end
  num = bridge.retrieve(name, 1, "north")
  if num ~= 1 then
    bridge.craft(name, 1)
    crafting = true
    while crafting do
	  local event, complete, crafted, num, bytes = os.pullEvent("craftingComplete")
	  crafting = complete
    end
    bridge.retrieve(name, 1, "north")
  end
end
function listen(mytag)
  listening = true
  while listening do
    local event, name, text = os.pullEvent("chat")
    start, stop = string.find(text, mytag)
    if start ~= nil and start >= 0 then
	  return string.sub(text, stop + 1)
    end
  end
end
function startInfusion()
  redstone.setOutput("left", true)
  sleep(2)
  redstone.setOutput("left", false)
end
function removeFiller()
  redstone.setOutput("back", true)
  sleep(30)
  redstone.setOutput("back", false)
end
function loadRecipes(filename)
  file = fs.open(file, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function saveRecipes(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end
function infuse(recipes, recipenum)
  length = #recipes[recipenum]
  for i=1,length do
    grabItem(recipes[recipenum][i])
  end
  removeFiller()
  sleep(180)
  startInfustion()
end
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
--recipes = loadRecipes(recipefile)
recipes = {}
while true do
  command = listen(mytag)
  words = {}
  for word in command:gmatch("%S+") do table.insert(words, trim(word)) end
  prefix = table.remove(words, 1)
  chat.say("Running command: "..prefix, 30)
  if prefix == "reload" then
    recipes = loadRecipes(recipefile)
    chat.say("Recipes reloaded.", 30)
  elseif prefix == "save" then
    saveRecipes(recipefile, recipes)
    chat.say("Recipes saved.", 30)
  elseif prefix == "addnew" then
    recipenum = tonumber(table.remove(words, 1))
    recipes[recipenum] = words
    chat.say("Recipe added.", 30)
  elseif prefix == "infuse" then
    recipenum = tonumber(table.remove(words, 1))
    chat.say("Running infuse recipe:".. info, 30)
    infuse(recipes, recipenum)
    chat.say("Infusion complete.", 30)
  end
end
the_hyren #20
Posted 04 December 2015 - 08:21 PM
Found a few things I forgot to update in my code. but before I continue posting it every time how do I use a spoiler tag? That way every post isn't a mile long.

Anyways, it seems the new trim and split functions are helping. I can run reload and save commands and get the chat from them. But the program still crashes somehow so I have to rerun the program between commands. The infuse and addnew commands do not work yet
KingofGamesYami #21
Posted 04 December 2015 - 08:43 PM
For a basic spoiler,
[spoiler]your stuff here[/spoiler]

Spoileryour stuff here

For a named spoiler,
[namedspoiler="name"]stuff here[/namedspoiler]

namestuff here


Side note: large amounts of code are usually put on pastebin, as it makes debugging easier because line numbers are given.
Bomb Bloke #22
Posted 05 December 2015 - 12:03 AM
But the program still crashes somehow so I have to rerun the program between commands.

Again, you're going to have to figure out exactly which lines are triggering these crashes before you can do much about them. Adding print statements to your script to identify the break points would be an easy way to do this. If you don't get what I mean, here's an example:

while true do
        command = listen("infuser1:")
        prefix = string.sub(command, 1, 6)
        print("1")
        chat.say("Running command: " .. prefix)
        print("2")

        if prefix == "infuse" then
                print("3")
                txtnum = string.sub(command, 8)
                chat.say("Getting recipe " .. txtnum)
                num = tonumber(txtnum)
                print("4")
        end

        print("5")
end

If need be, add more prints until you've isolated the exact line at fault.
the_hyren #23
Posted 07 December 2015 - 04:54 AM
Another update using a sample table with the recipe for ICHOR:

Spoiler

bridge = peripheral.wrap("right")
chat = peripheral.wrap("top")
fillerItem = "minecraft:wooden_sword"
mytag = "infuser1:"
recipefile = "recipes"
quantitysplit = "*"

function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
	  table.insert(result, match);
  end
  return result;
end

function grabItem(name)
  if name == nil or name == "" or name == "x" then
    itemname = fillerItem
    quantity = 1
  else
    table = split(name, quantitysplit)
    if #table == 1 then
	  itemname = trim(table[1])
	  quantity = 1
    elseif #table == 2 then
	  itemname = trim(table[1])
	  quantity = tonumber(trim(table[2]))
    end
  end
  num = bridge.retrieve(itemname, quantity, "north")
  quantity = quantity - num
  while quantity > 0 do
    bridge.craft(itemname, quantity)
    crafting = true
    while crafting do
	  event, complete, crafted, num, bytes = os.pullEvent("craftingComplete")
	  if complete then
	    crafting = false
	  end
    end
    num = bridge.retrieve(itemname, quantity, "north")
    quantity = quantity - num
  end
end

function listen(mytag)
  listening = true
  while listening do
    local event, name, text = os.pullEvent("chat")
    start, stop = string.find(text, mytag)
    if start ~= nil and start >= 0 then
	  return string.sub(text, stop + 1)
    end
  end
end

function startInfusion()
  redstone.setOutput("left", true)
  sleep(2)
  redstone.setOutput("left", false)
end

function removeFiller()
  redstone.setOutput("back", true)
  sleep(30)
  redstone.setOutput("back", false)
end

function loadRecipes(filename)
  file = fs.open(file, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end

function saveRecipes(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end

function infuse(recipes, recipenum)
  for item in recipes[recipenum] do
    grabItem(item)
  end
  removeFiller()
  sleep(180)
  startInfustion()
end

--recipes = loadRecipes(recipefile)
recipes = {{"minecraft:ender_eye", "", "", "minecraft:diamond", "", "", "ThaumicTinkerer:kamiResource:6", "", "", "ThaumicTinkerer:kamiResource:7", "", "", "minecraft:nether_star", "minecraft:glowstone*3", "minecraft:torch*2", "minecraft:rotten_flesh*32", "minecraft:ghast_tear*16"}}
while true do
  command = listen(mytag)
  words = {}
  for word in command:gmatch("%S+") do
    table.insert(words, trim(word))
  end
  prefix = table.remove(words, 1)
  chat.say("Running command: "..prefix)
  if prefix == "reload" then
    chat.say("Re-Loading recipes...")
    recipes = loadRecipes(recipefile)
    chat.say("Recipes reloaded.")
  elseif prefix == "save" then
    chat.say("Saving recipes...")
    saveRecipes(recipefile, recipes)
    chat.say("Recipes saved.")
  elseif prefix == "addnew" then
    chat.say("Adding recipe...")
    table.insert(recipes, words)
    chat.say("Recipe added.")
  elseif prefix == "remove" then
    txtnum = table.remove(words, 1)
    chat.say("Removing recipe "..txtnum.."...")
    num = tonumber(txtnum)
    table.remove(recipes, num)
    chat.say("Recipe "..txtnum.." removed.")
  elseif prefix == "infuse" then
    txtnum = table.remove(words, 1)
    chat.say("Running infusion recipe: "..recipenum.."...")
    recipenum = tonumber(txtnum)
    infuse(recipes, recipenum)
    chat.say("Infusion complete.")
  end
end
chat.say("INFUSER1: Ooops, I died...")

Added a handful of extra says to find out whats up, still failing to compare strings to my prefix var. I get the say 'Running command: …' for everything just fine but the first chat in if/elseif never happens and the while loop never hits the end say. So the crash is something at the if prefix == "reload"
Bomb Bloke #24
Posted 07 December 2015 - 05:52 AM
So the crash is something at the if prefix == "reload"

… unless chat.say() is crashing you out, the possibility of which makes using further chat.say() calls a very poor method of attempting to isolate the fault! Use print statements, an external monitor, or even save data to a log file; but using a potential faulty call to report its own stability is only ever going to give you ambiguous results!

Let's just assume that is the problem and see whether or not you can pcall your way around it. Try replacing all chat calls such that this structure:

chat.say("Running command: "..prefix)

… becomes this:

pcall(chat.say, "Running command: "..prefix)

If that doesn't work, put some code that will execute unconditionally and output something before and after your conditional blocks. Use the example I gave you in my last post if you don't get what I mean.
the_hyren #25
Posted 07 December 2015 - 08:37 PM
Ok gotcha, so my first chat("Running command:") could be at fault. I'll try playing with that
the_hyren #26
Posted 07 December 2015 - 08:48 PM
Seems you are correct sir, running a chat.say kills the program, regardless of if its in pcall. i commented several different ones and everything seems to work until it hits a chat.say
the_hyren #27
Posted 07 December 2015 - 09:24 PM
Ok so here is an update, now having trouble with the for loop in infuse that runs the grabItem command. Is my syntax good?

Spoiler

bridge = peripheral.wrap("right")
chat = peripheral.wrap("top")
fillerItem = "minecraft:wooden_sword"
mytag = "infuser1:"
recipefile = "recipes"
quantitysplit = "*"
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
	  table.insert(result, match);
  end
  return result;
end
function grabItem(name)
  if name == nil or name == "x" then
    itemname = fillerItem
    quantity = 1
  else
    table = split(name, quantitysplit)
    if #table == 1 then
	  itemname = trim(table[1])
	  quantity = 1
    elseif #table > 1 then
	  itemname = trim(table[1])
	  quantity = tonumber(trim(table[2]))
    end
  end
  num = bridge.retrieve(itemname, quantity, "north")
  while (quantity - num) > 0 do
    bridge.craft(itemname, quantity - num)
    crafting = true
    while crafting do
	  event, complete, crafted, numcrafted, bytes = os.pullEvent("craftingComplete")
	  if complete then
	    crafting = false
	  end
    end
    num = num + bridge.retrieve(itemname, quantity - num, "north")
    quantity = quantity - num
  end
end
function listen(mytag)
  listening = true
  while listening do
    local event, name, text = os.pullEvent("chat")
    start, stop = string.find(text, mytag)
    if start ~= nil and start >= 0 then
	  return string.sub(text, stop + 1)
    end
  end
end
function startInfusion()
  redstone.setOutput("left", true)
  sleep(2)
  redstone.setOutput("left", false)
end
function loadRecipes(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function saveRecipes(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end
function infuse(recipes, recipenum)
  redstone.setOutput("back", true)
  for item in recipes[recipenum] do
    grabItem(item)
  end
  sleep(10)
  redstone.setOutput("back", false)
  sleep(180)
  startInfustion()
end
recipes = loadRecipes(recipefile)
redstone.setOutput("back", false)
while true do
  command = listen(mytag)
  words = {}
  for word in command:gmatch("%S+") do
    table.insert(words, trim(word))
  end
  prefix = table.remove(words, 1)
  if prefix == "reload" then
    recipes = loadRecipes(recipefile)
  elseif prefix == "save" then
    saveRecipes(recipefile, recipes)
  elseif prefix == "addnew" then
    table.insert(recipes, words)
  elseif prefix == "remove" then
    txtnum = table.remove(words, 1)
    num = tonumber(txtnum)
    table.remove(recipes, num)
  elseif prefix == "infuse" then
    txtnum = table.remove(words, 1)
    recipenum = tonumber(txtnum)
    infuse(recipes, recipenum)
  end
end
Bomb Bloke #28
Posted 08 December 2015 - 02:10 AM
I guess this is the loop you're talking about:

  for item in recipes[recipenum] do
    grabItem(item)
  end

After the keyword "in" a function is expected, but you're supplying one of the sub-tables in your "recipes" table instead. You're looking for ipairs:

  for _, item in ipairs(recipes[recipenum]) do
    grabItem(item)
  end

You could alternatively do:

  local thisRecipe = recipes[recipenum]  -- Cache the first table lookup so we don't need to repeat it.
  for i = 1, #thisRecipe do              -- Repeats an amount equal to the "length" of the sub-table.
    grabItem(thisRecipe[i])              -- Get the i'th element from the sub-table and pass to grabItem.
  end
Edited on 08 December 2015 - 01:14 AM
the_hyren #29
Posted 08 December 2015 - 02:21 AM
Ah, thanks! Lua is a new language to me so I havent a clue what I'm doing haha
the_hyren #30
Posted 11 December 2015 - 06:51 PM
Ok. I split my chatbox command listening into its own program and it almost works 100%. I added another computer and moved my programs to it. I made and placed some wireless routers on all 5 computers.
So here are my questions:
- I cant seem to get the monitor I'm using for feedback/debugging to work quite right. It wont move to a new line. I tried adding /n to my strings but it just doesn't print at all then…
- Any information on using wireless modems to run commands on other computers is appreciated, since the tutorials aren't helping much.
- And since I want to run two programs at once, how can I get my main one to run the command listening one?
Bomb Bloke #31
Posted 12 December 2015 - 02:14 AM
I cant seem to get the monitor I'm using for feedback/debugging to work quite right. It wont move to a new line. I tried adding /n to my strings but it just doesn't print at all then…

The functions available within monitor peripheral tables are pretty much the same as the ones in the term table. The only function in there for moving the cursor to a different row is term.setCursorPos() (and term.scroll(), sorta; that one moves the rows instead of the cursor!). term.write() lacks that functionality.

If you term.redirect() to your monitor, then write() / print() will output to it (and offer you their line-breaking features, which basically involve checking the length of your text and applying term.scroll()/term.setCursorPos() appropriately).

Alternatively, I like to use functions like this one:

local function writeAt(text, x, y, tCol, bCol)
	if not (x and y) then
		local curX, curY = term.getCursorPos()
		x, y = x or curX, y or curY
	end
	
	term.setCursorPos(x, y)
	if tCol then term.setTextColour(tCol) end
	if bCol then term.setBackgroundColour(bCol) end
	term.write(text)
end

It works much the same as term.write(), while allowing me to optionally pre-set the cursor position and text colourations. But if you're wanting word-wrapping, it's typically easiest to stick to write() / print().

Any information on using wireless modems to run commands on other computers is appreciated, since the tutorials aren't helping much.

You can't do this directly - at best, you can send a list of instructions to another computer, which in turn you can program that to recognise those instructions and run specific bits of code accordingly.

There are various ways this can be done, though which ones are suitable depends on whether you care about things like "security" (people could have a lot of fun with a computer set to perform any actions that're wirelessly suggested to it). For example, these snippets can be used to make one system carry out all terminal actions performed by another.

And since I want to run two programs at once, how can I get my main one to run the command listening one?

Running multiple scripts at once may not be the best way to do things (I feel like I'm missing a lot of context), but multishell makes it pretty easy to do.
the_hyren #32
Posted 12 December 2015 - 07:38 AM
Thanks for the help everyone. I think I'm starting to get a hang of lua syntax. I have one final question about looking at inventories. I need to interface my AE crafting interface with my one computer. I simply plan to use a chest with several ae interfaces attached. These are all in blocking mode, meaning they wait until the chest is empty to put any items in. I simply want to place in the chest a number of cobble stone that corresponds to the recipe index within the table. So is this possible or what else could I do in this situation?

But so far my setup basically is 6 computers. 1 has the following program and is responsible for in game modification of my recipe table.
Spoiler

chat = peripheral.wrap("left")
screen = peripheral.wrap("back")
screen.clear()
recipefile = "recipes"
mytag = "infuser:"
screenlines = 2 * 4

function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

function listen(mytag)
  listening = true
  while listening do
   local event, name, text = os.pullEvent("chat")
   start, stop = string.find(text, mytag)
   if start ~= nil and start >= 0 then
	 return string.sub(text, stop + 1)
   end
  end
end

function load(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end

function save(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end

function write(screen, message)
  screen.write(message)
  x, y = screen.getCursorPos()
  screen.setCursorPos(x + 1, y)
  if (x + 1) >= screenlines
    screen.scroll(1)
end

recipes = load(recipefile)
while true do
  command = listen(mytag)
  write(screen, "Command Heard:" .. command)
  words = {}
  for word in command:gmatch("%S+") do
    table.insert(words, trim(word))
  end
  prefix = table.remove(words, 1)
  if prefix == "save" then
    save(recipefile)
    write(screen, "Recipes saved.")
  elseif prefix == "reload" then
    recipes = load(recipefile)
    write(screen, "Recipes loaded.")
  elseif prefix == "add" then
    newrecipe = {}
    for i=1, #words do
	  table.insert(newrecipe, words[i])
    end
    table.insert(recipes, newrecipe)
    write(screen, "Recipe added.")
  elseif prefix == "remove" then
    num = table.remove(words, 1)
    table.remove(recipes, tonumber(num))
    write(screen, "Recipe removed: " .. tostring(num))
  elseif prefix == "read" then
    num = tonumber(table.remove(words, 1))
    if num > #recipes then
	  write(screen, "No such recipe...")
    else
	  recipetoread = recipes[num]
	  for i = 1, #recipetoread do
	    write(screen, recipetoread[i])
	  end
	  write(screen, "End of recipe.")
    end
  end
end

4 others run this program, which using the recipe table file (i made links for all other computers) runs the actual infusion process. This basically has 4 steps: 1) Turn on a servo and the filler retreiver off 2) grab and/or craft as needed all the items in the recipe via peripheral++ me bridge 3) Turn off servo and the filler retreiver on, this retreiver grabs wooden swords from pedestals that will be empty during infusion 4) turn on autonomous activator with a wand in first slot. It wacks the matrix and starts infusion. The piping attached to the me bridge fills all 12 outside pedestals first, then the center, and then any excess gets sent to alchemical furnaces.
Spoiler

myidnum = 1
fillerItem = "minecraft:wooden_sword"
quantitydelimiter = "*"
bridgechestdirection = {"north", "east", "south", "west"}

function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
    table.insert(result, match);
  end
  return result;
end

function loadRecipes(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end

function grabItem(item)
  local itemname, quantity
  if item == nil or item == "" or item == "x" then
    itemname = fillerItem
    quantity = 1
  else
    table = split(item, quantitydelimiter)
    if #table == 1 then
	  itemname = trim(table[1])
	  quantity = 1
    elseif #table >= 2 then
	  itemname = trim(table[1])
	  quantity = tonumber(trim(table[2]))
    else
	  itemname = fillerItem
	  quantity = 1
    end
  end
  quantity = quantity - bridge.retrieve(itemname, quantity, bridgechestdirection[myidnum])
  while quantity > 0 do
    bridge.craft(itemname, quantity)
    crafting = true
    while crafting do
	  local event, name, amount, bytes = os.pullEvent("craftingComplete")
	  if name == itemname then
	    crafting = false
	  end
    end
    quantity = quantity - bridge.retrieve(itemname, quantity, bridgechestdirection[myidnum])
  end
end

function infuse(modem, channel, recipes, recipenum)
  redstone.setOutput("left", true)
  local thisRecipe = recipes[recipenum]
  for i = 1, #thisRecipe do
    grabItem(thisRecipe[i])
  end
  sleep(20)
  redstone.setOutput("left", false)
  sleep(180)
  redstone.setOutput("front", true)
  sleep(2)
  redstone.setOutput("front", false)
  sleep(300)
  redstone.setOutput("back", true)
  sleep(10)
  redstone.setOutput("back", false)
  modem.transmit(channel, myidnum, "Infuser"..tostring(myidnum)..": Infusion complete.")
end

recipes = loadRecipes(recipefile)
modem = peripheral.wrap("top")
modem.open(myidnum)
bridge = peripheral.wrap("right")
escape = false
while escape == false do
  listening = true
  command = ""
  replychannel
  while listening do
    local event, side, senton, replyon, message, distance = os.pullEvent("modem_message")
    if senton == myidnum and replyon == 5 then
	  listening = false
	  command = message
	  replychannel = replyon
    end
  end
  commandtable = split(trim(command), " ")
  prefix = trim(commandtable[1])
  if prefix == "infuse" then
    recipenum = tonumber(trim(commandtable[2]))
    infuse(modem, replychannel, recipes, recipenum)
  end
end

The last computer will monitor a chest and annouce the number of cobble present to the first open infuser, then empty its chest and repeat, waiting as needed for infusions to be done

code not written yet…
Bomb Bloke #33
Posted 12 December 2015 - 11:37 AM
I need to interface my AE crafting interface with my one computer. I simply plan to use a chest with several ae interfaces attached. These are all in blocking mode, meaning they wait until the chest is empty to put any items in. I simply want to place in the chest a number of cobble stone that corresponds to the recipe index within the table. So is this possible or what else could I do in this situation?

Well, if you can wrap the crafting interface as a peripheral, then yeah, it should be possible? I guess? AE isn't my thing…

Perhaps if you wrote some pseudo-code it'd better explain the bits you're having trouble with….
Edited on 12 December 2015 - 10:38 AM
the_hyren #34
Posted 12 December 2015 - 06:04 PM
Ok here it is:

infusersrunning = {0, 0, 0, 0}
recipefile = "recipes"
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function load(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
screen = peripheral.wrap("back")
modem = peripheral.wrap("top")
modem.open(5)
recipes = loadRecipes(recipefile)
sorter = peripheral.wrap("left")
escape = false
while escape == false do
  while sorter.pull("east") do
    sleep(10)
  end
  item = sorter.analyze()
  if item[stringId] == "minecraft:cobblestone" then
    command = "infuse "..tostring(item[amount])
    searching = true
    channel = 0
    while searching do
	  for i=1, #infusersrunning do
	    if infusersrunning[i] < 1 then
		  channel = i
		  infusersrunning[i] = item[amount]
		  searching = false
	    end
	  end
    end
    modem.transmit(channel, 5, command)
  end
  while sorter.push("south") do
    sleep(5)
  end
 
end

I found that the interactive sorter is what I needed. So a different question now. I will occasionally have modem_message events coming through to reset the infusersrunning array but I dont want to use a method that hangs, how do I get events without hanging?
KingofGamesYami #35
Posted 12 December 2015 - 07:10 PM
You can either restructure your code to use non-blocking commands except for a single os.pullEvent call (this would be called a state machine, I think) or use the parallel API to run multiple functions at once.
the_hyren #36
Posted 13 December 2015 - 06:27 AM
OK, think I figured out and implemented the parallel api stuff, a quick question about the line in my code:

		funct = parallel.waitForAny(channel,searching = waitForOpenInfuser(), infusionCompletionListener())
Is that a valid way to get results from a function run by parallel? If not how can I do that?

Manager Program:
Spoiler

infusersrunning = {0, 0, 0, 0}
recipefile = "recipes"
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function load(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function pullItem(direction)
  while sorter.pull(direction) == false do
	sleep(10)
  end
end
function infusionCompletionListener()
  local event, side, channel, replychannel, message, distance = os.pullEvent("modem_message")
  if trim(message) == "Infuser "..tostring(replychannel)..": Infusion complete." then
	infusersrunning[replychannel] = 0
  end
end
function waitForOpenInfuser()
  while true do
	for i=1, #infusersrunning do
	  if infusersrunning[i] < 1 then
		infusersrunning[i] = item[amount]
		return i, false
	  end
	end
  end
end
function pushItem(direction)
  while sorter.push(direction) == false do
	sleep(5)
  end
end
screen = peripheral.wrap("back")
modem = peripheral.wrap("top")
modem.open(5)
recipes = loadRecipes(recipefile)
sorter = peripheral.wrap("left")
escape = false
while escape == false do
  func = parallel.waitForAny(pullItem("east"), infusionCompletionListener())
  if func == 1 then
	item = sorter.analyze()
	if item[stringId] == "minecraft:cobblestone" then
	  command = "infuse "..tostring(item[amount])
	  searching = true
	  channel = 0
	  while searching do
		funct = parallel.waitForAny(channel,searching = waitForOpenInfuser(), infusionCompletionListener())
		if funct == 1 then
		  modem.transmit(channel, 5, command)
		elseif funct == 2 then
		end
	  end
	end
  elseif func == 2 then
  end
  func = parallel.waitForAny(pushItem("south"), infusionCompletionListener())
  if func == 1 then
  elseif func == 2 then
  end
end

Either way here is the other two, I'll start testing and debugging on monday when I'm off work.

Infuser Program:
Spoiler

myidnum = 1
fillerItem = "minecraft:wooden_sword"
quantitydelimiter = "*"
recipefile = "recipes"
bridgechestdirection = {"north", "east", "south", "west"}
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
	table.insert(result, match);
  end
  return result;
end
function loadRecipes(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function grabItem(item)
  local itemname, quantity
  if item == nil or item == "" or item == "x" then
	itemname = fillerItem
	quantity = 1
  else
	table = split(item, quantitydelimiter)
	if #table == 1 then
	  itemname = trim(table[1])
	  quantity = 1
	elseif #table >= 2 then
	  itemname = trim(table[1])
	  quantity = tonumber(trim(table[2]))
	else
	  itemname = fillerItem
	  quantity = 1
	end
  end
  quantity = quantity - bridge.retrieve(itemname, quantity, bridgechestdirection[myidnum])
  while quantity > 0 do
	bridge.craft(itemname, quantity)
	crafting = true
	while crafting do
	  local event, name, amount, bytes = os.pullEvent("craftingComplete")
	  if name == itemname then
		crafting = false
	  end
	end
	quantity = quantity - bridge.retrieve(itemname, quantity, bridgechestdirection[myidnum])
  end
end
function infuse(modem, channel, recipes, recipenum)
  redstone.setOutput("left", true)
  local thisRecipe = recipes[recipenum]
  for i = 1, #thisRecipe do
	grabItem(thisRecipe[i])
  end
  sleep(20)
  redstone.setOutput("left", false)
  sleep(180)
  redstone.setOutput("front", true)
  sleep(2)
  redstone.setOutput("front", false)
  sleep(300)
  redstone.setOutput("back", true)
  sleep(10)
  redstone.setOutput("back", false)
  modem.transmit(channel, myidnum, "Infuser "..tostring(myidnum)..": Infusion complete.")
end
recipes = loadRecipes(recipefile)
modem = peripheral.wrap("top")
modem.open(myidnum)
bridge = peripheral.wrap("right")
escape = false
while escape == false do
  listening = true
  command = ""
  replychannel
  while listening do
	local event, side, senton, replyon, message, distance = os.pullEvent("modem_message")
	if senton == myidnum and replyon == 5 then
	  listening = false
	  command = message
	  replychannel = replyon
	end
  end
  commandtable = split(trim(command), " ")
  prefix = trim(commandtable[1])
  if prefix == "infuse" then
	recipenum = tonumber(trim(commandtable[2]))
	infuse(modem, replychannel, recipes, recipenum)
  end
end

Listener Program:
Spoiler

chat = peripheral.wrap("left")
screen = peripheral.wrap("back")
screen.clear()
recipefile = "recipes"
mytag = "infuser:"
screenlines = 2 * 4
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function listen(mytag)
  listening = true
  while listening do
   local event, name, text = os.pullEvent("chat")
   start, stop = string.find(text, mytag)
   if start ~= nil and start >= 0 then
	 return string.sub(text, stop + 1)
   end
  end
end
function load(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function save(filename, recipes)
  file = fs.open(filename, "w")
  data = textutils.serialize(recipes)
  file.write(data)
  file.close()
end
function write(screen, message)
  screen.write(message)
  x, y = screen.getCursorPos()
  screen.setCursorPos(x + 1, y)
  if (x + 1) >= screenlines
	screen.scroll(1)
end
recipes = load(recipefile)
escape = false
while escape == false do
  command = listen(mytag)
  write(screen, "Command Heard:" .. command)
  words = {}
  for word in command:gmatch("%S+") do
	table.insert(words, trim(word))
  end
  prefix = table.remove(words, 1)
  if prefix == "save" then
	save(recipefile)
	write(screen, "Recipes saved.")
  elseif prefix == "reload" then
	recipes = load(recipefile)
	write(screen, "Recipes loaded.")
  elseif prefix == "add" then
	newrecipe = {}
	for i=1, #words do
	  table.insert(newrecipe, words[i])
	end
	table.insert(recipes, newrecipe)
	write(screen, "Recipe added.")
  elseif prefix == "remove" then
	num = table.remove(words, 1)
	table.remove(recipes, tonumber(num))
	write(screen, "Recipe removed: " .. tostring(num))
  elseif prefix == "read" then
	num = tonumber(table.remove(words, 1))
	if num > #recipes then
	  write(screen, "No such recipe...")
	else
	  recipetoread = recipes[num]
	  for i = 1, #recipetoread do
		write(screen, recipetoread[i])
	  end
	  write(screen, "End of recipe.")
	end
  end
end

And incase its helpful:
Manager tells each infuser what to make, making 4 things at once gives my system better throughput, might increase to 8 if I run into issues with speed
Infuser looks up recipe and grabs items then whacks runic matrix with a wand
Listener allows me to do ingame modification of my recipes for ease
Edited on 13 December 2015 - 05:24 AM
Bomb Bloke #37
Posted 13 December 2015 - 06:29 AM
OK, think I figured out and implemented the parallel api stuff, a quick question about the line in my code:

	    funct = parallel.waitForAny(channel,searching = waitForOpenInfuser(), infusionCompletionListener())
Is that a valid way to get results from a function run by parallel? If not how can I do that?

No, it's not; the idea is that you pass the function pointers to the parallel API and it executes them for you. If you try to execute them before passing them in as parameters then you'll end up passing whatever the functions return instead of the functions themselves. The parallel API offers no method of getting return values from the functions it executes.

Easiest to define upvalues before you define the functions, have said functions put their data into those, and then check their contents when the functions complete. See the "closures" section of this guide regarding scope - ideally, read the whole page.
the_hyren #38
Posted 13 December 2015 - 03:30 PM
Right, I had kinda figured, o well. Here is the rewrite:
Spoiler

infusersrunning = {0, 0, 0, 0}
recipefile = "recipes"
openchannel = 0
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function load(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function pullItem(direction)
  while sorter.pull(direction) == false do
	sleep(10)
  end
end
function infusionCompletionListener()
  local event, side, channel, replychannel, message, distance = os.pullEvent("modem_message")
  if trim(message) == "Infusion complete." then
	infusersrunning[replychannel] = 0
  end
end
function waitForOpenInfuser()
  while true do
	for i=1, #infusersrunning do
	  if infusersrunning[i] < 1 then
		infusersrunning[i] = item[amount]
		openchannel = i
		return
	  end
	end
  end
end
function pushItem(direction)
  while sorter.push(direction) == false do
	sleep(5)
  end
end
screen = peripheral.wrap("back")
modem = peripheral.wrap("top")
modem.open(5)
recipes = loadRecipes(recipefile)
sorter = peripheral.wrap("left")
escape = false
while escape == false do
  func = parallel.waitForAny(pullItem("east"), infusionCompletionListener())
  if func == 1 then
	item = sorter.analyze()
	if item[stringId] == "minecraft:cobblestone" then
	  command = "infuse "..tostring(item[amount])
	  searching = true
	  channel = 0
	  while searching do
		funct = parallel.waitForAny(waitForOpenInfuser(), infusionCompletionListener())
		if funct == 1 then
		  modem.transmit(openchannel, 5, command)
		  searching = false
		elseif funct == 2 then
		end
	  end
	end
	pushing = true
	while pushing do
	  functi = parallel.waitForAny(pushItem("south"), infusionCompletionListener())
	  if functi == 1 then
		pushing = false
	  elseif functi == 2 then
	  end
	end
  elseif func == 2 then
  end
end

If anyone would just check my syntax for errors that would be awesome. Im gonna start debugging
Edited on 13 December 2015 - 02:30 PM
KingofGamesYami #39
Posted 13 December 2015 - 04:17 PM
You're still using parallel incorrectly, you need to pass it a function. For example, this line:


  func = parallel.waitForAny(pullItem("east"), infusionCompletionListener())

Would be written like this:


  func = parallel.waitForAny( function() pullItem("east") end, infusionCompletionListener )
the_hyren #40
Posted 14 December 2015 - 03:45 PM
Gotcha. I'm having trouble with my if statements in listener, specifically anything that uses '#recipes' which should give me the length right?


if num > #recipes then

NVM. I fixed this, turns out recipes was nil. Simply adding {} to my recipes file was fine. Seems my listener program works perfectly now
Edited on 14 December 2015 - 02:48 PM
the_hyren #41
Posted 14 December 2015 - 05:28 PM
Ok, I'm using the interactive sorter to detect the recipe, this is simply a number of cobblestone, in my test case just 1. using
item = sorter.analyze()
should give my a table with values in it but the keys aren't integers and I dont know how to access them properly I guess. How is that done?

list of keys I need:
amount, stringId
the_hyren #42
Posted 14 December 2015 - 09:28 PM
An awesome update! I figured out that the keys act like functions eg. item.stringId is what I needed.

It seems my manager program is also working as intended.

And I'm quite close with the infuser program. I just have to write a method to do a little additional parsing since the me bridge needs a slightly different string
"mod:name meta" instead of "mod:name:meta" should be an easy fix!
the_hyren #43
Posted 14 December 2015 - 09:59 PM
So turns out I'm having trouble splitting my itemname string and reforming it to be compatible with the me bridge. Specifically:

splititem = split(itemname, ":")
  if #splititem == 3 then
	itemname = tostring(splititem[1])..":"..tostring(splititem[2]).." "..tostring(splititem[3])
  end
using this splitting function:

function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
	table.insert(result, match);
  end
  return result;
end

I'm guessing I can't use : as a delimiter, probably because its a standard expression or something.
So could anyone write me a function that takes a string and replaces the second ':' (if it exists) with a space?
Edited on 14 December 2015 - 10:10 PM
KingofGamesYami #44
Posted 15 December 2015 - 12:43 AM

function stripSecondColen( str )
  return table.concat( { str:match( "([^:]+:[^:]+):?(.*)" ) }, " " )
end

Hackies.
the_hyren #45
Posted 15 December 2015 - 06:36 PM
Cool thanks! Just to make sure since I dont understand it much, if there isn't a second : what will this function do?
the_hyren #46
Posted 15 December 2015 - 07:12 PM
Hmmm. So I'm still crashing…

Spoiler

myidnum = 1
fillerItem = "minecraft:wooden_sword"
quantitydelimiter = "*"
recipefile = "recipes"
bridgechestdirection = {"north", "east", "south", "west"}
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function split(s, delimiter)
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
	table.insert(result, match);
  end
  return result;
end
function stripSecondColen(str)
  return table.concat({str:match( "([^:]+:[^:]+):?(.*)" )}, " ")
end
function loadRecipes(filename)
  file = fs.open(filename, "r")
  data = file.readAll()
  file.close()
  return textutils.unserialize(data)
end
function grabItem(modem, channel, item)
  itemname = nil
  quantity = nil
  if item == nil or item == "" or item == "x" then
	itemname = fillerItem
	quantity = 1
  else
	table = split(item, quantitydelimiter)
	if #table == 1 then
	  itemname = trim(table[1])
	  quantity = 1
	elseif #table >= 2 then
	  itemname = trim(table[1])
	  quantity = tonumber(trim(table[2]))
	else
	  itemname = fillerItem
	  quantity = 1
	end
  end
  modem.transmit(channel, myidnum, "Get "..tostring(quantity).." "..itemname)
  transformeditemname = stripSecondColen(itemname)

  modem.transmit(channel, myidnum, "Converting itemname to ME bridge format")
  retrieved = bridge.retrieve(transformeditemname, quantity, bridgechestdirection[myidnum])
  quantity = quantity - retrieved
  while quantity > 0 do
	modem.transmit(channel, myidnum, "Only "..tostring(retrieved).." available...crafting more")
	bridge.craft(transformeditemname, quantity)
	crafting = true
	while crafting do
	  local event, name, amount, bytes = os.pullEvent("craftingComplete")
	  if trim(name) == trim(transformeditemname) then
		crafting = false
	  end
	end
	retrieved = bridge.retrieve(transformeditemname, quantity, bridgechestdirection[myidnum])
	quantity = quantity - retrieved
  end
end
function infuse(modem, channel, recipe)
  redstone.setOutput("left", true)
  modem.transmit(channel, myidnum, "Filler retriever locked.")
  for i = 1, #recipe do
	grabItem(modem, channel, recipe[i])
  end
  sleep(20)
  redstone.setOutput("left", false)
  sleep(180)
  modem.transmit(channel, myidnum, "Whacking matrix...")
  redstone.setOutput("front", true)
  sleep(2)
  redstone.setOutput("front", false)
  modem.transmit(channel, myidnum, "Waiting for completion.")
  sleep(300)
  redstone.setOutput("back", true)
  modem.transmit(channel, myidnum, "Grabbing resultant item.")
  sleep(10)
  redstone.setOutput("back", false)
  modem.transmit(channel, myidnum, "Infusion complete.")
end
recipes = loadRecipes(recipefile)
modem = peripheral.wrap("top")
modem.open(myidnum)
bridge = peripheral.wrap("right")
escape = false
while escape == false do
  listening = true
  command = ""
  replychannel = 0
  while listening do
	local event, side, senton, replyon, message, distance = os.pullEvent("modem_message")
	if senton == myidnum and replyon == 5 then
	  listening = false
	  command = message
	  replychannel = replyon
	end
  end
  commandtable = split(trim(command), " ")
  prefix = trim(commandtable[1])
  if prefix == "infuse" then
	recipenum = tonumber(trim(commandtable[2]))
	infuse(modem, replychannel, recipes[recipenum])
  end
end

So my program does send the
"Get "..tostring(quantity).." "..itemname
But at some point between there and the transmit three lines later there is a crash that exits the infuser program.
This is all in the grabitem function and the item Im getting is Thaumcraft:ItemResource:14 which is Salis Mundis.
Could it be the modem.transmit crashing?
Edited on 15 December 2015 - 06:14 PM
Bomb Bloke #47
Posted 15 December 2015 - 11:52 PM
Could it be the modem.transmit crashing?

Again, if you aren't getting an error message telling you the problematic line, then you can pinpoint it by distributing print statements throughout your script.
the_hyren #48
Posted 16 December 2015 - 12:32 AM
Right I did that. with my modem transmits, I cant really put a moniter on it since it has all its sides used
Dragon53535 #49
Posted 16 December 2015 - 01:21 AM
Then do the smart thing, and print to the screen itself, and not modem.transmit.
the_hyren #50
Posted 16 December 2015 - 03:33 AM
It would not be able to do a full infusion since it has a modem on top, needs to output 3 redstone signals and has the bridge on the other side, its also in a cheat free server. I will try a test setup in a ssp creative world