Jump to content




Thaumcraft Automation Programming

help lua peripheral

49 replies to this topic

#21 KingofGamesYami

  • Members
  • 3,002 posts
  • LocationUnited States of America

Posted 04 December 2015 - 08:43 PM

For a basic spoiler,
[spoiler]your stuff here[/spoiler]

Spoiler

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

name
[/code]

Side note: large amounts of code are usually put on pastebin, as it makes debugging easier because line numbers are given.

#22 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 05 December 2015 - 12:03 AM

View Postthe_hyren, on 04 December 2015 - 08:21 PM, said:

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.

#23 the_hyren

  • Members
  • 29 posts

Posted 07 December 2015 - 04:54 AM

Another update using a sample table with the recipe for ICHOR:

Spoiler

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"

#24 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 07 December 2015 - 05:52 AM

View Postthe_hyren, on 07 December 2015 - 04:54 AM, said:

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.

#25 the_hyren

  • Members
  • 29 posts

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

#26 the_hyren

  • Members
  • 29 posts

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

#27 the_hyren

  • Members
  • 29 posts

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


#28 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

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 by Bomb Bloke, 08 December 2015 - 02:14 AM.


#29 the_hyren

  • Members
  • 29 posts

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

#30 the_hyren

  • Members
  • 29 posts

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?

#31 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 12 December 2015 - 02:14 AM

View Postthe_hyren, on 11 December 2015 - 06:51 PM, said:

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().

View Postthe_hyren, on 11 December 2015 - 06:51 PM, said:

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.

View Postthe_hyren, on 11 December 2015 - 06:51 PM, said:

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.

#32 the_hyren

  • Members
  • 29 posts

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

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

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...

#33 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 12 December 2015 - 11:37 AM

View Postthe_hyren, on 12 December 2015 - 07:38 AM, said:

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 by Bomb Bloke, 12 December 2015 - 11:38 AM.


#34 the_hyren

  • Members
  • 29 posts

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?

#35 KingofGamesYami

  • Members
  • 3,002 posts
  • LocationUnited States of America

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.

#36 the_hyren

  • Members
  • 29 posts

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

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

Infuser Program:
Spoiler

Listener Program:
Spoiler

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 by the_hyren, 13 December 2015 - 06:24 AM.


#37 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 13 December 2015 - 06:29 AM

View Postthe_hyren, on 13 December 2015 - 06:22 AM, said:

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.

#38 the_hyren

  • Members
  • 29 posts

Posted 13 December 2015 - 03:30 PM

Right, I had kinda figured, o well. Here is the rewrite:
Spoiler

If anyone would just check my syntax for errors that would be awesome. Im gonna start debugging

Edited by the_hyren, 13 December 2015 - 03:30 PM.


#39 KingofGamesYami

  • Members
  • 3,002 posts
  • LocationUnited States of America

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 )


#40 the_hyren

  • Members
  • 29 posts

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 by the_hyren, 14 December 2015 - 03:48 PM.






1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users