Jump to content

[1.12.2] MultiBlock Structure Pattern Recognition Best Practices


TH3Doctor_11th
 Share

Recommended Posts

Hi all. I have some TEs ready, with blocks and everything set, and I would like to figure out how to efficiently recognize a multiblock structure with those TEs. As regards mechanics, Master-Slave is just right. But are there any best practices about finding out if a multiblock structure is valid or not? I am currently trying with the for loops for each axis, since I don't think recursion would be much better (It's not a Fluid Tank, so the TEs composing the structure could be different. I could implement recursion, but at the moment I am focusing on solving the structure recognition first). The problem is, the structure controller is not at the perfect center of the Multiblock, and as a result I have to check where the TE block is facing. I don't think this is an efficient solution, and I was hoping someone could lead me in the right direction to figure out a good way to solve this. Thanks in advance!

Link to comment
Share on other sites

If you efficiently get all the positions to check and then fail fast if one of the positions is wrong (and also don’t run the code more than is necessary), there shouldn’t be any problems at all

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

The key is to use loops with escapes (break and continue keywords in Java)-- your loops should give up as soon as they "know" there isn't a match. Secondly it is good to find the lack of match as early in the loop as possible, so if you can find unique parts (least likely to spawn naturally and/or uncommon to build) of the structure to check first that is helpful. 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Thanks for the answers @Cadiboo @jabelar :D So, since I wanted to use an energy containment / transfer block (I am working on a Technical Mod) in conjuction with the controller, I could start by checking if and where it is located relative to the controller itself. So, I have to do 4 conditional checks for the x and z axis, both negative and positive, and if I am planning on adding a transfer and a battery with different costs in crafting terms, i need to check separately for both. Is it correct? (I am using Structure classes, Singletons, to hold off 3D Matrixes that contain the correct order of blocks). Just another thing, would it be better to have the structure made of TEs so wherever I click I can open the future GUI of the controller following the Master-Slave principle, or should I make players click just on the controller (which will have a different texture of course) keeping the other blocks of the structure without TEs? (except the transferer / battery, which will have their own GUIs). Thanks again for both your answers!

Link to comment
Share on other sites

After some trials, I found out a possible solution that I would like to share and get some feedback from both :D As you said, I have to recognize the unique pieces of the multiblock first. If any of them is missing, I just say "nope, no correct structure". Then, through BlockPos.getAllInBox() or something like that, I get the positions in the N x N x N, and I iterate through them (ignoring the positions of the special ones, that I asserted to be there at this stage) and check if the blocks at the corresponding locations are, for example, casings. Again, if anything is not at its place, then it's not a valid structure. Else, everything is in its place, and the structure is ready :D let me know

Link to comment
Share on other sites

4 hours ago, TH3Doctor_11th said:

After some trials, I found out a possible solution that I would like to share and get some feedback from both :D As you said, I have to recognize the unique pieces of the multiblock first. If any of them is missing, I just say "nope, no correct structure". Then, through BlockPos.getAllInBox() or something like that, I get the positions in the N x N x N, and I iterate through them (ignoring the positions of the special ones, that I asserted to be there at this stage) and check if the blocks at the corresponding locations are, for example, casings. Again, if anything is not at its place, then it's not a valid structure. Else, everything is in its place, and the structure is ready :D let me know

That sounds perfect. Then you just have to store a reference (BlockPos?) to the Master somewhere & when the blocks are right clicked return master.rightClicked.

You will also want to return the capabilities of the master when your outside blocks are queried too.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

Yep, that is how its done.

 

One other point, depending on the symmetry of your structure you might want to take different approaches regarding whether the rotations are handled "algorithmically" or "brute force". If you have a structure that is symmetric in both X and Z then obviously you have to only scan once since the shape is same in any rotation. If you have a structure otherwise you need to decide the best way to handle the rotation. The brute force way is to pre-compute the structure in each rotation (really four different structures) and check each with same logic as you outlined above. I generally recommend that way. But if the symmetry is simple you could choose to handle the rotation within the loop -- like when you detect the unique elements they would indicate the rotation and then you apply it.

 

I've seen a lot of people work hard at getting rotation to work, and in the end I recommend just considering each rotation a separate structure and then have very simple checking.

 

Not sure which situation applies to your structure.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

5 hours ago, Cadiboo said:

That sounds perfect. Then you just have to store a reference (BlockPos?) to the Master somewhere & when the blocks are right clicked return master.rightClicked.

You will also want to return the capabilities of the master when your outside blocks are queried too.

Ok! ?

4 hours ago, jabelar said:

Yep, that is how its done.

 

One other point, depending on the symmetry of your structure you might want to take different approaches regarding whether the rotations are handled "algorithmically" or "brute force". If you have a structure that is symmetric in both X and Z then obviously you have to only scan once since the shape is same in any rotation. If you have a structure otherwise you need to decide the best way to handle the rotation. The brute force way is to pre-compute the structure in each rotation (really four different structures) and check each with same logic as you outlined above. I generally recommend that way. But if the symmetry is simple you could choose to handle the rotation within the loop -- like when you detect the unique elements they would indicate the rotation and then you apply it.

 

I've seen a lot of people work hard at getting rotation to work, and in the end I recommend just considering each rotation a separate structure and then have very simple checking.

 

Not sure which situation applies to your structure.

So if I store the correct blocks in a matrix (static and final) for every configuration, would it be ok? Or is it too much? This structure in particular is a 3x3x3 ?

Link to comment
Share on other sites

48 minutes ago, TH3Doctor_11th said:

Ok! ?

So if I store the correct blocks in a matrix (static and final) for every configuration, would it be ok? Or is it too much? This structure in particular is a 3x3x3 ?

I suggest querying your master block for a list of BlockPoss to check for your structure and have your master return an itterable of MutableBlockPos. That’s a horrible explanation, here’s some example code of the concept

for(MutableBlockPos pos getMaster().getAllPositionsInStructure()){

if(!isPositionCorrect(pos)) return FAIL;

}

return SUCCESS;

 

I’ve got a 3x2x3 multiblock structure in my mod that I use this method for, so I’m a bit biased.

Edited by Cadiboo

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

7 hours ago, TH3Doctor_11th said:

Ok! ?

So if I store the correct blocks in a matrix (static and final) for every configuration, would it be ok? Or is it too much? This structure in particular is a 3x3x3 ?

Yeah, I would do it that way. Have a matrix (or whatever format you have for your template) for each possible orientation and just check them all (efficiently like we discussed above). Otherwise you'll do a lot of coding (and probably bang your head over bugs) trying to perform the math to rotate inside the loops.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

2 hours ago, jabelar said:

Otherwise you'll do a lot of coding (and probably bang your head over bugs) trying to perform the math to rotate inside the loops.

Not really. If you do all your offsets based on a Facing (and Facing has a getOffset method) you don't even need to think about it.

 

"This block is 1 forward" -> pos.offsetX(Facing.getX()).offsetZ(Facing.getZ())

"This block should be one to the right" -> pos.offsetZ(Facing.getX()).offsetX(Facing.getZ())

 

Then you just loop over the horizontal facing values.

Edited by Draco18s

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

2 hours ago, Draco18s said:

Not really. If you do all your offsets based on a Facing (and Facing has a getOffset method) you don't even need to think about it.

 

"This block is 1 forward" -> pos.offsetX(Facing.getX()).offsetZ(Facing.getZ())

"This block should be one to the right" -> pos.offsetZ(Facing.getX()).offsetX(Facing.getZ())

 

Then you just loop over the horizontal facing values.

 

The logic for rotation isn't that simple, as the movement needed for each block is dependent on the size of the overall structure and distance of each block from the center. You also have to do different math for structures that have odd number of blocks on each side (in which case there is a center block) versus even number of blocks on each side. And if your structure isn't same size on each side you have to add logic to "pad" out the short side during the rotation.

 

But even if you consider the rotation logic simple (and for you Draco18s I'm certain it is relatively simple), that is already too much thinking. Furthermore it is also a performance hit. Having the structure pre-rotated with simple looping is less lines of code and can be super efficient.

 

The other problem with clever algorithms is that they are much more prone to bugs and harder to debug. It would be pretty hard to screw up looping through a pre-set matrix.

 

 

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

41 minutes ago, jabelar said:

The logic for rotation isn't that simple, as the movement needed for each block is dependent on the size of the overall structure and distance of each block from the center.

No its not. Two blocks to the right? pos.offsetZ(Facing.getX() * 2).offsetX(Facing.getZ() * 2)

Three blocks left and one up? pos.offsetZ(Facing.getX() * -3).offsetX(Facing.getZ() * -3).offset(Facing.UP)

 

There's always a point from which you can perform all of these calculations and there is no rotation that this doesn't support (unless you want your machines to be constructed on their *sides* too, but even THAT functions if you do it right). It doesn't support mirroring very well, but you CAN do it. The whole even/odd things it moot too. If its an even number of blocks your "center" is just offset to the side a bit, one side extends 1 block away from "center" and the other side extends 2.

 

I dare you to construct something that when rotated does not appear identical to a reference frame rotated the by same amount.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

1 hour ago, Draco18s said:

No its not. Two blocks to the right? pos.offsetZ(Facing.getX() * 2).offsetX(Facing.getZ() * 2)

Three blocks left and one up? pos.offsetZ(Facing.getX() * -3).offsetX(Facing.getZ() * -3).offset(Facing.UP)

 

There's always a point from which you can perform all of these calculations and there is no rotation that this doesn't support (unless you want your machines to be constructed on their *sides* too, but even THAT functions if you do it right). It doesn't support mirroring very well, but you CAN do it. The whole even/odd things it moot too. If its an even number of blocks your "center" is just offset to the side a bit, one side extends 1 block away from "center" and the other side extends 2.

 

I dare you to construct something that when rotated does not appear identical to a reference frame rotated the by same amount.

 

The concept is obviously simple, but the implementation really isn't so much. I entirely know how to code it, but why bother?

 

You're glossing over the fact that every block needs to move a different amount. If you have a 4 x 4 structure, each corner has to move 3 blocks in a straight line, but one edge block on each side needs to move 3 blocks plus 1 block over, and one edge block on each side needs to move 3 block plus 2 blocks over. Then the blocks on the inside each just move 1 block. So every block has to move differently. It is conceptually simple, but it is a pain. And because these are blocks which are discrete, the movements are different for odd versus even.

 

And anyway, calculating new positions at all is more processing than needs to be done with a pre-rotated structure -- which needs none. So performance-wise an algorithmic rotation is always going to suffer a relative performance hit.

 

I agree it is totally possible to do it your way, but fail to see any advantage in doing it algorithmically, especially if you want to generalize it for arbitrary size. My way is literally 10 lines of code or less, less likely to have a bug, and performs faster.

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

1 hour ago, jabelar said:

You're glossing over the fact that every block needs to move a different amount.

I swear, you're either misrepresenting the argument on purpose in order to create strawman or you're actually not understanding it.

 

Lets take this layout:

layout1.png

The left side is just a mirror of the right, so I'm not bothering to draw its offsets.

 

If we want to rotate it, we get this:

layout2.png

 

Notice how two of the positions (besides the center) remain filled, even though they are different parts of the whole layout:

layout.gif

 

This is because of how rotations work: they swap the X and Z values (and sometimes flip their sign).

https://math.stackexchange.com/questions/1330161/how-to-rotate-points-through-90-degree

 

In order to make what we want to happen, we treat things as relative. Instead of +2X we call it +2R.


if Facing.Forward.Z is our Forward offset (moves up under no rotation) and Facing.Forward.X is our Right offset (moves right under no rotation)
 

We'll do this process by focusing only on this blue block:

layout3.png

 

In this orientation it's +1F,+2R. Lets animate that.

layout_move1.gif

 

Now lets rotate it 90 degrees.

layout_move2.gif

 

HOLY SHIT IT WORKS

Edited by Draco18s
  • Like 2

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

I totally understand the mirroring method of Cartesian rotation. And it isn't that hard but the problem with the swapping method is that there are a couple details in calculating the center with potential for causing some confusion. Maybe not confusing for you, or me, but for the average modder probably. 

 

Imagine your matrix is a 5 x 4 matrix:

A B C D E

F G H I J

K L M N O

P Q R S T

 

And you're rotating clockwise by 90 degrees to get:

P K F A

Q L G B

R M H C

S N I D

T O J E 

 

So I believe, correct me if there is simpler way, the steps for your algorithm are:

  1. find center block of the base matrix. Easy right -- just divide the dimensions in half so it must be 2.5, 2. But wait if I look at the array the center is really at the 3rd position across and 2.5 down, so isn't the center then actually 3, 2.5? Okay, but wait in computing we start counting at 0 so the center is really at the array index 2, 1.5. 
  2. Now we can start swapping. We'll create an empty new array and populate it. The dimensions should be a 4 x 5 array now.
  3. For rotation we want to implement it by transforming (x, z) to (-z, x). The first element in the base is at index 0, 0 but we need to convert that to a relative coordinates from the center so let's say the first element is at relative position -2, -1.5. We swap that so it is now 1.5, -2. Also the swap results are now relative to the new array center at index 1.5, 2 so we add them and get index of 3, 0. Yay, it worked!

Now I admit that isn't that hard, but you have to imagine the "average" modder on this forum implementing this without the hints I gave above. Wouldn't you bet that we'd be getting questions where it wasn't working because people screwed up by not figuring out the center properly?

 

By the way, the point of my recommendation was to "pre-rotate" the structures. I'm not at all against using this algorithm for doing it in advance. I just think people will muck it up combining the rotation into the loop that does the actual checking.

 

P.S. Thanks for taking the time to make the animated pictures!

Edited by jabelar
  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

You missed the fact that my example layout was 6x5 didn't you?

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • I made a huge forge 1.7.10 mod pack but whenever I try to create a singleplayer world I get the error saying "A fatal error has occurred, this connection is terminated." Does anyone know what the issue could be?  Here is my fml-client-latest.log from when it crashes: https://paste.ubuntu.com/p/3rKSJSqnrX/ and here is the list of mods: https://imgur.com/a/AZifMbg    
    • Im trying to host a minecraft server using the curseforge serverpack from FTB Direwolf20 and when I try to start the server I run into an error The Error: Starting server A problem occurred running the Server launcher.java.lang.reflect.InvocationTargetException         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)         at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)         at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)         at java.lang.reflect.Method.invoke(Unknown Source)         at cpw.mods.fml.relauncher.ServerLaunchWrapper.run(ServerLaunchWrapper.java:43)         at cpw.mods.fml.relauncher.ServerLaunchWrapper.main(ServerLaunchWrapper.java:12) Caused by: java.lang.NoClassDefFoundError: org/apache/logging/log4j/Level         at net.minecraft.launchwrapper.Launch.launch(Launch.java:94)         at net.minecraft.launchwrapper.Launch.main(Launch.java:28)         ... 6 more Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.Level         at java.net.URLClassLoader$1.run(Unknown Source)         at java.net.URLClassLoader$1.run(Unknown Source)         at java.security.AccessController.doPrivileged(Native Method)         at java.net.URLClassLoader.findClass(Unknown Source)         at java.lang.ClassLoader.loadClass(Unknown Source)         at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)         at java.lang.ClassLoader.loadClass(Unknown Source)         ... 8 more   I'have tried deleting and downloading the newset version of java wich didnt work and now im using an older version which is the 1.7.0_80 Here is what my Server folder looks like: https://ibb.co/jkbfRY7 Here is what the ServerStart.bat file looks like: @if NOT "%FTB_VERBOSE%"=="yes" ( @echo off ) call settings.bat if NOT EXIST minecraft_server.1.7.10.jar ( goto install ) if NOT EXIST libraries\%LAUNCHWRAPPER% ( goto install ) goto skipinstall :install echo running install script! call FTBInstall.bat :skipinstall REM Check if java in path REM TODO: use %JAVACMD% where java > NUL 2>&1 if %ERRORLEVEL% NEQ 0 ( echo No java binary in path. Can't run server, exiting... pause exit /B ) REM Test JVM REM e.g. 32-bit JVM does not have server\jvm.dll library java -server -version > java-test.log 2>&1 if %ERRORLEVEL% NEQ 0 ( echo Detected following JVM error: echo ======================================= more java-test.log echo ======================================= echo JVM test failed. Can't run server, Exiting... pause exit /B ) if not exist eula.txt ( echo Missing eula.txt. Startup will fail and eula.txt will be created echo Make sure to read eula.txt before playing! goto startserver ) find "eula=false" eula.txt 1 > NUL 2>&1 if %ERRORLEVEL% EQU 0 ( echo Make sure to read eula.txt before playing! Exiting. pause exit /B ) del /f /q autostart.stamp > nul 2>1 :startserver echo Starting server java -server -Xms512M -Xmx2048M -XX:PermSize=256M -XX:+UseParNewGC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar FTBServer-1.7.10-1558.jar nogui :server_loop if exist autostart.stamp ( del /f /q autostart.stamp > nul 2>1 echo If you want to completely stop the server process now, press Ctrl+C before the time is up! for /l %%i in (5,-1,1) do ( echo Restarting server in %%i choice /t 1 /d y > nul ) echo Starting server now java -server -Xms512M -Xmx2048M -XX:PermSize=256M -XX:+UseParNewGC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar FTBServer-1.7.10-1558.jar nogui echo Server process finished goto :server_loop ) echo Exiting... pause  
    • Made a modpack (Well Rounded Blockheads, in case the modlist on curseforge helps) and server to host it, worked fine until last night. The issue that pops up after some days being up/working is when you leave a world (singleplayer) or shutdown a server, the process hangs and jumps to 8.5gb ram used, eats up CPU usage (50-60% in taskman on a 3800x) and just sits there. If done on a single player world, the game doesnt fully crash, (e.g. if you alt+f4 buttons like save and quit, options stay in the window, are still clickable but they do nothing) Saving seems to still happen, as location/inventory updates if I restart server or client and play the world again.   If I start the currently afflicted server but dont login the server closes properly, its only once I log back in the problem occurs. Its a priv server and I dont have anyone else to test atm so Idk if its a prob with my player or players/area in general. Only recent changes in game are the additions of a pnuematicraft pressure chamber, an enchanting table, and bookshelves from builders crafts and additions.... I've been trying to get help on this all day, so ANY assistance goes a long way, even if its a way to debug this myself >~< Debug/Latest logs
    • Thanks warjort. I was afraid, that this is because they are entities. Now I know where to dig. But what about water, for example? I have checked via debug code, that there is no entity there (appropriate method return null). What is wrong with liquids?
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.