Jump to content

1.16.4 Random Structure generation


Eleocraft

Recommended Posts

So, here is a good (commented) guide on nbt structure generation: https://github.com/TelepathicGrunt/StructureTutorialMod

Here we have some other examples (uncommented) of structures loading from nbt data files: https://github.com/Beethoven92/BetterEndForge/tree/master/src/main/java/mod/beethoven92/betterendforge/common

And last but not least, vanilla has a lot of examples regarding structures that are loaded from nbt and placed into the world. You can try looking at the Igloo, which is one of the simplest. Those are all good places to start learning about nbt structures. Come back if you have questions or if you did not understand something

  • Thanks 1

Check out the port of the BetterEnd fabric mod (WIP): https://www.curseforge.com/minecraft/mc-mods/betterend-forge-port

Link to comment
Share on other sites

Ok, so first of all thx for the quick response. I have tried to understand how it works with the help of the first guide. howewer it seems to be more compicated than I originally thought. So i just tried to copy the components I obviously needed into my own project, but nothing seems to happen, not even a error message or something. My structure just need to have one component, so it would be nice if they were another example without all the extra things that I wont need. Otherwise in the STStructures class line 95 it says me "The final field Structure.field_236384_t_ cannot be assigned". same error in line 109. but if the little i understood is something to go by this part is not strictly needed anyway so I just commented it out. could that be the problem?

 

Also is there a way to better test a structure generator? my testing method is just to fly around in a new world, the structure should spawn all 5-10 chunks so that is not a big problem, but not really a professional way of testing.

 

Also I don't know how to get the Minecraft sourcecode. all the decompilers I found doesn't seem to work for 1.16. I know this is another topic but it would also be interesting to know.

 

 

Link to comment
Share on other sites

So, line 109 here: https://github.com/TelepathicGrunt/StructureTutorialMod/blob/ad5250c0e15eee67b413eebabee238f9b8cd784d/src/main/java/com/telepathicgrunt/structuretutorial/STStructures.java#L109

is actually required. you may not want to comment out that part. Line 95 is needed only if you want your structures to fill with blocks the underneath space if needed, like, for example, village buildings. To easily and quickly locate a structure in your world use the /locate command. Minecraft source code will be already provided in your mod project. You can find it in external libraries inside your IDE.

Check out the port of the BetterEnd fabric mod (WIP): https://www.curseforge.com/minecraft/mc-mods/betterend-forge-port

Link to comment
Share on other sites

I was having the same issue. Make sure that you have set up the accesstransformer.cfg file under resources/META_INF

 

You will also need to uncomment this line in the build.gradle file and reload your gradle project.

accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')

 

That should fix the access issue you are having.

Edited by thelion1997
  • Thanks 1
Link to comment
Share on other sites

Thanks for all the help. it works now! I had already tried the /locate command, turned out it just didn't work because the structure wasn't registered. The problem was indeed that i forgot the accesstransformer file. Now i just have two little problems to fix:

First: the Structure I want to spawn contains a custom Block (with a custom blocks class) that has the attribut "facing" on it. Apparently this is not stored correctly in the nbt file because these blocks always face a different direction.

And second: when i let the structure only spawn in the nether it always generate on top of the bedrock. this problem is described in the Structure tutorial mod:

 

 

             * If you are doing Nether structures, you'll probably want to spawn your structure on top of ledges.
             * Best way to do that is to use getColumnSample to grab a column of blocks at the structure's x/z position.
             * Then loop through it and look for land with air above it and set blockpos's Y value to it.
             * Make sure to set the final boolean in JigsawManager.func_242837_a to false so
             * that the structure spawns at blockpos's y value instead of placing the structure on the Bedrock roof!

 

 

I already set the boolean in the function to false, but i dont understand how to "use getColumnSample to grab a column of blocks at the structure's x/z position. Then loop through it and look for land with air above it and set blockpos's Y value to it."

One more time thanks for the help, I hope you will be able to help me with the last problems.

Edited by Eleocraft
Link to comment
Share on other sites

Since I got no answer on my last questions I tried myself to make a forloop and check for air in a column of blocks. for that I need to get the block by coordinates what also seems to be unnecessarily complicated. After a bit of research I found that "world.getBlockState(new BlockPos(x, i, z)).getBlock()" should work, but for whatever reason I cannot instantiate the type World. is there a way to get this working?

Edited by Eleocraft
Link to comment
Share on other sites

Have a look in Minecraft's NetherFossilStructure for placement in the nether, this will give you an idea of how to check for correct positions. I did a similar thing in my mod here for a Nether Well to be generated:

https://github.com/Phrille/Vanilla-Boom/blob/master/src/main/java/phrille/vanillaboom/world/structures/NetherWellStructure.java

 

Now keep in mind that my code does not do any placement checks other than the first check to see if I start the gen on a block. For instance no checks are done to check if the is enough air to fit the structure in and so on.

  • Thanks 1
Link to comment
Share on other sites

Thanks, that answered my questions. The random generation works fine now. But I still can't find a solution to the other problem, that the facing of my custom Block is not stored correctly. I am sure that it just needs a funktion in my custom block class, but i can't figure out what is missing.

 

EDIT: I think, that the problem isn't that the facing isn't correctly stored, but rather that it's not ajusted if the structure is turned. If no one knows how to solve this probleme i could bypass it by simply not letting the structure rotate. Is this possible?

Edited by Eleocraft
  • Like 1
Link to comment
Share on other sites

Is there really no one who knows how to prevent a randomly generated structure from rotating? this can't be that difficult... Is there maybe a way to generate structures without using .nbt files? that would also help me out...

Edited by Eleocraft
  • Like 1
Link to comment
Share on other sites

Is there any more info you can give on what you are trying to do? Also, do you have a repo? Being able to see your code would be helpful. At a minimum can you post your custom block code?

 

Someone can correct me if I am wrong but I don't believe there is any way to generate structures without *.nbt data. Why are the *.nbt files an issue?

Link to comment
Share on other sites

For whatever reason I can't upload screenshots here, so I need to do it that way:

How it should be:

https://drive.google.com/file/d/1wPQU_a01nhobDIST5MNJ5R1lEHNdQc1A/view?usp=sharing

How it is:

https://drive.google.com/file/d/1prVopizhk0_R4QDMr45gnMwJHB4VPUii/view?usp=sharing

https://drive.google.com/file/d/1-vEV8M7qsHBr7wBq1NTtzsHJWKBWrWzu/view?usp=sharing

 

I just want to get the orientation right.

 

Custom Block Code:

package eleocraft.ancientguardian.objects.blocks;

import java.util.Map;

import javax.annotation.Nullable;

import com.google.common.collect.ImmutableMap;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.IBlockReader;

public class CornerBlock extends Block
{
	 private static final Vector3d BASE_MIN_CORNER_N = new Vector3d(0.0, 8.0, 0.0);
	 private static final Vector3d BASE_MAX_CORNER_N = new Vector3d(16.0, 16.0, 8.0);
	
	 private static final VoxelShape BASE_N = Block.makeCuboidShape(BASE_MIN_CORNER_N.getX(), BASE_MIN_CORNER_N.getY(), BASE_MIN_CORNER_N.getZ(), BASE_MAX_CORNER_N.getX(), BASE_MAX_CORNER_N.getY(), BASE_MAX_CORNER_N.getZ());
	 
	 private static final Vector3d BASE_MIN_CORNER_E = new Vector3d(8.0, 8.0, 0.0);
	 private static final Vector3d BASE_MAX_CORNER_E = new Vector3d(16.0, 16.0, 16.0);
	 
	 private static final VoxelShape BASE_E = Block.makeCuboidShape(BASE_MIN_CORNER_E.getX(), BASE_MIN_CORNER_E.getY(), BASE_MIN_CORNER_E.getZ(), BASE_MAX_CORNER_E.getX(), BASE_MAX_CORNER_E.getY(), BASE_MAX_CORNER_E.getZ());
	 
	 private static final Vector3d BASE_MIN_CORNER_S = new Vector3d(0.0, 8.0, 8.0);
	 private static final Vector3d BASE_MAX_CORNER_S = new Vector3d(16.0, 16.0, 16.0);
	 
	 private static final VoxelShape BASE_S = Block.makeCuboidShape(BASE_MIN_CORNER_S.getX(), BASE_MIN_CORNER_S.getY(), BASE_MIN_CORNER_S.getZ(), BASE_MAX_CORNER_S.getX(), BASE_MAX_CORNER_S.getY(), BASE_MAX_CORNER_S.getZ());
	 
	 private static final Vector3d BASE_MIN_CORNER_W = new Vector3d(0.0, 8.0, 0.0);
	 private static final Vector3d BASE_MAX_CORNER_W = new Vector3d(8.0, 16.0, 16.0);
	 
	 private static final VoxelShape BASE_W = Block.makeCuboidShape(BASE_MIN_CORNER_W.getX(), BASE_MIN_CORNER_W.getY(), BASE_MIN_CORNER_W.getZ(), BASE_MAX_CORNER_W.getX(), BASE_MAX_CORNER_W.getY(), BASE_MAX_CORNER_W.getZ());
	 
	  private static final Map<Direction, VoxelShape> POST_SHAPES =
		        ImmutableMap.of(Direction.NORTH,BASE_N,   Direction.EAST,BASE_E,   Direction.SOUTH,BASE_S,   Direction.WEST,BASE_W);
	  
	 public CornerBlock(Properties properties)
	 {
		super(properties);
	 }
	
	  @Override
	  public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) 
	  {
		    Direction direction = state.get(FACING);
		    VoxelShape voxelShape = POST_SHAPES.get(direction);
	        return voxelShape;
	  }
	  
	  @Nullable
	  @Override
	  public BlockState getStateForPlacement(BlockItemUseContext blockItemUseContext) 
	  {
	    Direction direction = blockItemUseContext.getPlacementHorizontalFacing();  // north, east, south, or west

	    BlockState blockState = getDefaultState().with(FACING, direction);
	    return blockState;
	  }
	  
	  @Override
	  protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) 
	  {
	    builder.add(FACING);
	  }
	  private static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;
}

 

Edited by Eleocraft
Link to comment
Share on other sites

I believe you are missing the rotate/mirror functions. I believe that these are called when the structure is generated and is being rotated. I got these from the StairsBlock.java class.

 

public BlockState rotate(BlockState state, Rotation rot) {
      return state.with(FACING, rot.rotate(state.get(FACING)));
   }

  
   public BlockState mirror(BlockState state, Mirror mirrorIn) {
      Direction direction = state.get(FACING);
      StairsShape stairsshape = state.get(SHAPE);
      switch(mirrorIn) {
      case LEFT_RIGHT:
         if (direction.getAxis() == Direction.Axis.Z) {
            switch(stairsshape) {
            case INNER_LEFT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_RIGHT);
            case INNER_RIGHT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_LEFT);
            case OUTER_LEFT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_RIGHT);
            case OUTER_RIGHT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_LEFT);
            default:
               return state.rotate(Rotation.CLOCKWISE_180);
            }
         }
         break;
      case FRONT_BACK:
         if (direction.getAxis() == Direction.Axis.X) {
            switch(stairsshape) {
            case INNER_LEFT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_LEFT);
            case INNER_RIGHT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_RIGHT);
            case OUTER_LEFT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_RIGHT);
            case OUTER_RIGHT:
               return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_LEFT);
            case STRAIGHT:
               return state.rotate(Rotation.CLOCKWISE_180);
            }
         }
      }

      return super.mirror(state, mirrorIn);
   }

 

You will obviously need to change up the mirror function with the shapes you have defined instead. I believe that the rotate function would probably work as is. 

 

I would recommend looking into the StairsBlock.java class if it is still having issues.

  • Thanks 2
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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

Announcements



×
×
  • Create New...

Important Information

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