Notice to YSPilots/YSFLIGHT

Notice to YSPilots/YSFLIGHT
Legacy Pack available under the YSFLIGHT category.
Any individual requests for a model must be made to my email address, see bottom of the page..

Sunday, 7 January 2018

Computer Craft, Tinkers Construct revisited

So I left my little contraption running over night, with the hope that it'd finish emptying out my ores. Well, it was half right. I came down to a casting basin half full... This wasn't meant to happen! It was only supposed to cast when there was enough in the smeltery to fill a basin. I looked at my code again:

if quantity > 1296 then

Nope, that clearly says if the quantity is greater than 1294 (9 ingots, or enough for a block of that material), then it should open the valve, so why is it still opening when there is less than 9 ingots available?
Because the quantity value doesn't update.
If we refer back to our main code:

local tank = peripheral.wrap("left")
local tankTable = tank.getTankInfo()[1]
local contentsTable = tankTable["contents"]
local quantity = contentsTable["amount"]
while true do

if quantity > 1296 then


The first bit, the local variables, are only called at the start of the program - so the value does not change! I should've noticed this when I looked at the printed quantity on the screen, but truth be told, I didn't look.
So, solutions? I could just move the variables into the "while true do" so they're called every cycle - but that's not very elegant. Instead, I went for the complex approach, and made some functions while I was at it...
First off, I timed how long I actually needed for the casting table to fill, cool and empty (15 seconds), and made a function that would just open the faucet for exactly 15 seconds. The faucet is rising edge triggered - so it only goes off when the redstone input goes high, you can drop it straight back down to low again, ready for the next lot - so my function just pulses it on for 1 seconds, then switches it off again for for a set amount of time. I wanted to be able to easily reuse the function, so I didn't hardcode the time into the function.

function on(side,time)

What does it do?! So, the name of the function is "on" - imaginative! and it takes 2 variables to run it - the side your rednet cable is on (or whatever way you're transmitting your redstone signal), and the time you need it on for. In my case, the rednet cable was on the back of the computer, and it was on for 15 seconds, so calling the command was a simple matter of writing - on("back", 15) and it'd
switch the faucet on for exactly the right amount of time to fill, cool and empty.

So the function takes those 2 variables, and first sets the side you gave it to high for 1 second - then it goes back to low. Now it waits for the time you gave it (minus the 1 seconds it spent setting it high). That's it for that bit!
So, next function I made took care of the issue I had with the first one - that the quantity wasn't updating. in this one, I just moved all the tank/table variables into there... So it looks like this:

function getQuantity(drainObject)
local tank = drainObject.getTankInfo()[1]
local contentsTable = tank["contents"]
local quantity = contentsTable["amount"]

return quantity


I made a new variable - drainObject, which passes the wrapped drain block to the function. This way, if I use something like a wired modem to do it more remotely, I can just pass it that, rather than specifically giving it a side, or hardcoding the side.
So next up - it makes a bunch of local variables that are only accessible from within the function, and don't affect anything outside it. (so I could have another quantity variable used in another function or main script, and it wouldn't take the same value)

The key thing here is the return quantity bit. Basically, I can use the function getQuantity(drainObject) as a variable - so my if statement from the previous one (if quantity > 1296 then do stuff) can use the getQuantity instead of having to define another variable.

I did make another variable for the ingot/casting volume, which is 1296mB or 9 ingots. I did this so I can just change that value to 144 if I wanted to cast single ingots or 576 if I wanted to cast gears.

local ingotVol = 1296 -- 1296 is volume of a full block in mB, for ingots use 144, for gears use 576

The -- bit just is a comment, so it doesn't have any effect on the code, and is only there for the user.

Then I have my loop and if statement:

while true do

if getQuantity(drain) > ingotVol then
print("Contents is: "..getQuantity(drain))
print("Contents is now: "..getQuantity(drain))
print("Quantity is less than 1 block")

So I'm using my getQuantity() function instead of making a new quantity variable, and I'm using my ingotVol variable to tell me the size of the ingot/block/gear I'm making. Then I'm just printing off the quantity again before, switching the faucet on (with our on() function), and printing the quantity again after, to verify that it went down by the correct volume (maybe I should've done a difference... nvm, next time).

Another new thing is the else bit. This is my catch for if there isn't enough metal in the smeltery to make another ingot/gear/block. If that is the case, it just writes on the screen that there isn't enough for a block, and waits for 15 seconds before trying again.

So, future plans for it? Multi- faucet maybe... and maybe get it to plan if there is enough material for full blocks, and if not, uses a ingot instead of a block, ensuring a fully empty smeltery...

Modems as well, so I can centralise it.. And maybe a monitor to show how much material there is in the tank, and how many ingots it has made? Or maybe I'll just leave it there.

Link as always:

Friday, 5 January 2018

Computer Craft and Tinkers Construct (Minecraft)

I've been experimenting a bit with Tinkers Construct and ComputerCraft in Minecraft.
If you don't know what any of those 3 things are, this post is not for you!

The problem I've been trying to solve is this: I've got masses of molten metal in the smeltery, and I want to automatically drain it into a casting basin. I could do this manually, but I've got a lot of metal!
I should also preface this by saying I know very little about Lua, the programing language of ComputerCraft, possibly hence my difficulty solving the issue.

Now, computercraft interfaces with tinkers by way of the OpenPeripherals mod - which gives access to commands such as getTankInfo().

Through OpenPeripherals, it is possible to talk to the Tinkers Smeltery - by way of the drain port for some reason.

So, this is the setup - I've got a computer next to the drain port
I've not yet implemented the actual triggering of the faucet, for now I'm just trying to read the contents of the tanks!

Now, there were a few examples online where people had done apparently similar things, but I couldn't make them work! So I started from scratch.. more or less.

In the lua commandline I could get"left","getTankInfo")to give me a huge long list of all the tasty goodness I wanted to know from the smeltery, but dropping this into an actual application, along the lines of:

tank = peripheral.wrap("left")

gave me nothing, well, it gave me this: table:4d09e6ec...

So, it must be a table then!

To iterate through a table in lua is 

for key, value in pairs(yourTable) do
   print("here is your key: "..key.." and here is your value          "..value)

So adapting it for my use:

for key, value in pairs(tank.getTankInfo()) do
   print("here is your key: "..key.." and here is your value          "..value)

No. No such luck. Attempt to concatenate string and table... Its got a table, within a table?! What fresh madness is this?! Okay, lets take table 1 from that then! I read that there are 2 tables for each tank, the main tank with all the smeltery contents, and the fuel tank (lava), and the first one is the smeltery contents. So, table 1 it is!

for key, value in pairs(tank.getTankInfo()[1]) do
   print("here is your key: "..key.." and here is your value          "..value)
The [1] bit just lets us take the first key in the table, so the first table of tables, and then iterate through that table.

What did this give us?

here is your key: capacity and here is your value 11792
smeltery:4 attempt to concatenate string and table

WHAT?! again?! A table in a table in a table?! 
So first off, I want an actual object for the table, not tank.getTankInfo()... so I'm just going to have 
tankTable = tank.getTankInfo()[1]

So, this should give us the table for the smeltery contents, and it goes something like:
capacity: 11792
>another table containing who knows what!

Lets go back to the lua commandline again, and do our"left","getTankInfo")again and have a closer look:

The bit at the bottom that I can see reads:

  capacity = 1728,
  contents = {
    rawName = "Molten Lead",
    amount = 1728,
    name = "lead.molten",
    id = 187,
Very annoying that blogger doesn't let me do tabs.. but never mind!
So, this is mirroring what we had been seeing, the first key is "capacity", with its value being whatever the capacity in the smeltery is, then is a table, and thats as far as it let me get before. But now we can see the contents of the table! (appropriately called, contents)

So within the contents table is the name of the material, its capacity (again, mirroring the "capacity key") , another name (lead.molten), and the ID, which I'm assuming is the minecraft item ID (nope, 187 is IC2.blockWall... no idea then!)

Anyway! We know the name of the table in the table now! So I'm going to try and get the contents table out as a separate object again, so I'm just going to go:

tankTable = tank.getTankInfo()[1]
contentsTable = tankTable["contents"]

And now, we iterate through the contents table:

for key, value in pairs(contentsTable) do
   print("here is your key: "..key.." and here is your value          "..value)

What do we get:

here is your key: rawName and here is your value Molten Iron
here is your key: amount and here is your value 1680
here is your key: name and here is your value iron.molten
here is your key: id and here is your value 170

It works!
Interestingly, this is the material at the bottom of the smeltery contents, if I change the material at the bottom to bronze:
raw name becomes "Molten Bronze" - so the first table tank.getTankInfo()[1] is the "active" or bottom material in the smeltery - and if I do tank.getTankInfo()[2] I get the 2nd material! Nothing to do with the fuel tanks!

So, now I've figured out how to get the table in a table in a table, I'm going to use my contentsTable object for now:


What do we get?


Woop woop! it works! I can have that as a variable now, and use that in an if statement to open and close the faucet when there is enough metal to fill a casting basin!
For that I'm going to use a rednet cable just to pass the redstone signal through to the faucet.

  1. local tank = peripheral.wrap("left")
  2. local tankTable = tank.getTankInfo()[1]
  3. local contentsTable = tankTable["contents"]
  4. local quantity = contentsTable["amount"]
  5. while true do
  6.   if quantity > 1296 then
  7.     print(quantity)
  8.     redstone.setOutput("front",true)
  9.     sleep(5)
  10.     redstone.setOutput("front",false)
  11.     print(quantity)
  12.     sleep(5)
  13.   end
  14. end

Ooo, nice code formatting! So this is copied from the pastebin I put up:
The first bit I've explained....
From line 5. I've not explained yet.... while true do just repeats the rest infinitely.

if quantity > 1296 then

What this bit does is:
First: if the quantity value from our table is greater than 1296mB (which is 9 ingots), then it is going to do the rest:
print(quantity) is just going to write the quantity on the screen for me
redstone.setOutput("front",true) - this is where my computer placement kind of screwed up... The rednet cable came out the front... Not so pretty, but it works! So, this basically just outputs a redstone signal fron the front of the computer, if you put redstone dust on the ground, it'll light up. The signal is going through the rednet cable to the faucet, so at this point, it opens the faucet.
sleep(5) - just hang about for a bit while the faucet is doing its thing
redstone.setOutput("front", false) - switch the faucet off again, resetting it for the next load, then it prints the quantity again to the screen (was more for debugging than anything...), hang about for a bit with another sleep(5), and then do it all again!

So yea! It works nicely! Another little thing though - the casting basin normally needs emptying by hand when it's finished casting - but if you put a hopper underneath, it empties itself - put an itemduct under that going into your chest/storage, and