PneumaticCraft: Repressurized

PneumaticCraft: Repressurized

50M Downloads

Question: Is it possible to break out of an External Program Progwidget?

MuteTiefling opened this issue ยท 7 comments

commented

Use case: I have a rather large program designed to make Mekanism Alloys. I don't really want to make three copies of it for three different alloys as that's a lot of puzzle pieces (~70 per alloy).

So I thought I'd have one program that assigns the variables, then does the external program. By this point, I'm already multiple levels deep, however.

  1. Drone is programmed to look at box 1 for variables used across all it's programs
  2. The variables program then looks into a second box for all the programs it can run.
  3. One of these programs then sets the variables for one alloy and calls yet another box with that program in it.

The trouble is, at this point it simply stays in that last box, looping the alloy program forever. I'd like to just 'break' out and go back up to the previous loop level at the inventory slot it was at, allowing it to move on to the next program in that box. I'd thought I might just send it back to the box called in step 2, but then it starts over with the first program in that box.

Is this at all possible with current programming options?

commented

I suspect not, though I'll admit I don't have the clearest understanding of just what you're trying to do. Any chance you could boil it down to a really simple example and upload the program(s) ?

commented

Sorry, having a hard time finding the right words here.

I'm basically trying to make a subroutine to get around the lack of arrays.

Example Programs : https://gist.github.com/MuteTiefling/d5e0bd1e05a0ba9247bbeb9480db56d4

Overview of Setup:
2020-08-07_16 36 57

Let's see if I can do a better job explaining this time :)

The Drone consists of a simple program to look in a Variables chest and run the programs there. There's only ever one as all it does is set up local variables that all of the other programs will use.

This Variables program then calls the main API chest. This chest has the majority of our programs. In this example, it has three. Each one responsible for some hypothetical alloy. Each program needs to be aware of the two alloy items, but the process for making these is identical. So to save puzzle pieces, they just store those two items in variables and call a third chest with External Program.

This third chest then has a generic processing program. It's tiny here, but in my play world it's got about 80 pieces in it now and I've had to duplicate it 4-5 times. All this is doing is moving two of the alloy items from one chest to another chest.

What I would hope to achieve is this

Drone > Variables > API - Craft A > Subroutine > API - Craft B > Subroutine > API - Craft C > Subroutine > Drone (repeat).

What happens instead is Drone > Variables > Craft A > Subroutine (Ends looping here with Craft A's variables).

Put another way, once the External Program has iterated over every inventory slot in it's area, I'd like a way to tell it to finish or to only iterate a fixed number of times. This would cause that loop to end and the previous External Program to continue processing at the next slot in its own area. In this example, Craft A would call the subroutine chest, it would loop through all inventory slots there, then pop back into the API chest as if Craft A had come to some conclusion. The next program to run would then be Craft B.

I think the only way I could have this work would be to remove the Craft API as the final step of the subroutine, this would cause that loop to end and it would pick up and carry on with the next Craft API. This has it's own problems, however, since I could only accurately match the desired API by NBT data... which becomes a recursion problem since I'd have to have the item set in a variable on it's own item.

I guess another way would be to deposit the APIs into the chest one at a time by redstone and then have the drone enable the hopper to pull it out at the end. Just kind of loop through them randomly...

commented

I am doing something similar in the technodefirmacraft pack for 1.12. There have obviously been changes since the last 1.12 release, but my solution to this issue was to only include a variable on the drone that points to it's root program - then any time an endpoint is reached, reload that root program.
2020-08-24_14 58 41

So in this image all of the barrels on the left side contain "root" programs. Each drone sets the location of their root program to a global variable, then runs initialize, which sets up all of the global variables for root programs, local variables for all of the subroutines, and a bunch of other miscellaneous variables that all or most drones use.

Once the initialize program is complete, it runs the program stored in the root variable.

That program then runs a variety of tests to determine whether it should run one of it's related subroutines and if not runs the "idle" subroutine (the far right barrels), which in turn runs tests to see what idle task should be run.

Once a subroutine is complete, it runs initialize again.

So, for instance, my Maintain Food Drone follows this process:
Drone:
Set Root variable to "#Maintain Food"
Run #Initialize
#Initialize:
Set various variables and run a few tests to ensure the drone didn't break and/or hasn't been recalled
Run Root (which points to #Maintain Food)
#Maintain Food:
If bread needs to be baked -> Run Bake Bread
Else if ingredients are needed -> Run Fetch Ingredients
Else -> Run Idle
Bake Bread:
Bakes Bread
Run #Initialize
Fetch Ingredients:
Fetches Ingredients
Run #Initialize
Idle:
Tests a variety of conditions, then runs a subroutine with concludes by running #Initialize

commented

Yeah - I didn't see much value in splitting programs into separate chunks within the same inventory since there isn't a way to add a filter to the external program caller. Though I suppose using variables/IDs to determine which program to run next would avoid that.

As for the latter concern - yeah, that could definitely be an issue if a drone runs long enough. You could keep a counter that increments every iteration of the initialize program and once it reaches a certain number have the drone go to a specific location, suicide and then get replaced - either with a block placer or incorporate checking for a drone that needs to be revived into the initialization so that whenever a drone suicides another one will come along to revive it.

commented

Actually, now that I think about it, you could use an ID system (using coordinates) to avoid the nesting issue entirely

At the start of each program would be a coordinate condition that compares the Next ID variable to the programs ID - if it doesn't match, move along to the next program. If it does, run the program and at the end set the Next ID variable to the next in line. The drone would set whatever initial variables are needed and then call the external program wiget centered w/ an area encompassing all of the chests/barrels/w/e that store the programs

This would allow you to put all of your programs into the same chest(s) and eliminate the excess nesting issue. It would also make moving programs around a lot easier since you would need to only change one variable instead of dozens. The program would run a bit slower though

commented

Ah, so you've done what I've been avoiding : one program per inventory.

I also wasn't keen on calling the original initialization api since the drones did seem to keep track of how deep they were. Note how it'll keep nesting 'main' deeper and deeper as you go deeper into subroutines. I've been afraid of that causing some lag at some point.

commented

Hrm... I guess I'll keep poking at this to find an alternative. My primary goal is to do recursive crafting on demand. In order to save on plastic I was going to have 'recipes' of 1 to 9 item variables that go to a default crafting program. It would check for each resource and then craft. If anything was missing it would loop back and craft that first before continuing.

Your ID system was going to be integral to that recursion so I could simply set a variable enabling the sub craft. That was going to use item variables instead of coordinates, however, so I don't have to maintain a list of ids for recipes

I might just have to get really plastic heavy though and duplicate a lot of my programming.