Jump to content

Recommended Posts

Posted

I'm trying to make a structure (nbt file) randomly gererate in the Netherwastes. Unfortunately the newest tutorial that i found on this topic was for 1.15, and it didn't work for me.

Also im quite new to Minecraft modding in general.

Thanks for the help

Posted

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

Posted

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.

 

 

Posted

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

Posted (edited)

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
Posted (edited)

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
Posted (edited)

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
Posted

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
Posted (edited)

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
Posted (edited)

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
Posted

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?

Posted (edited)

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
Posted

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

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

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