Jump to content

[ 1.14+ ] Change blockstate when its Raining and Not Raining.


Kikoz

Recommended Posts

Hello! I'm trying to make my custom campfire to unlit when it is raining and lit automatically when it is not raining.

This is my code, the thing is, it only works when I start the world, not otherwise. I'm still learning coding don't be harsh on me thanks!

 

	public void litWhenRaining(World worldIn, BlockPos pos) {
		      if (worldIn.rand.nextInt(10) == 1 && worldIn.isRaining()) {
		            BlockState blockstate = worldIn.getBlockState(pos);
		            worldIn.setBlockState(pos, blockstate.cycle(LIT), 1);
		         } if (worldIn.rand.nextInt(10) == 1 && !worldIn.isRaining()){
		        	 BlockState blockstate = worldIn.getBlockState(pos);
		               worldIn.setBlockState(pos, blockstate.cycle(LIT), 0);
		            }
		      }

 

Link to comment
Share on other sites

Where are you actually running your code?

If you want it to change instantly you'll have to make a ticking tile entity (see how the daylight sensor works). Since that's not good for performance, you may want to just override the Block#tick method and let it update randomly (like how farmland and leaves works).

I'm eager to learn and am prone to mistakes. Don't hesitate to tell me how I can improve.

Link to comment
Share on other sites

1 hour ago, imacatlolol said:

Where are you actually running your code?

If you want it to change instantly you'll have to make a ticking tile entity (see how the daylight sensor works). Since that's not good for performance, you may want to just override the Block#tick method and let it update randomly (like how farmland and leaves works).

Well I made the part where it changes when raining by looking at the cauldron - fillWithRain. I just need a way to make it change back when it stops raining.

Link to comment
Share on other sites

15 minutes ago, Kikoz said:

Well I made the part where it changes when raining by looking at the cauldron - fillWithRain. I just need a way to make it change back when it stops raining.

Oh! Neat, I didn't recognize that as a vanilla method.

Actually, looking at your code a little closer, you're misusing World#setBlockState and BlockState#cycle entirely. The integer parameter is for flags which are used for updating and syncing. You should use a flag of 11 for both lighting and un-lighting the block.

As for the BlockState, you should use the with method instead of cycle.

Edited by imacatlolol
Typo

I'm eager to learn and am prone to mistakes. Don't hesitate to tell me how I can improve.

Link to comment
Share on other sites

37 minutes ago, imacatlolol said:

Oh! Neat, I didn't recognize that as a vanilla method.

Actually, looking at your code a little closer, you're misusing World#setBlockState and BlockState#cycle entirely. The integer parameter is for flags which are used for updating and syncing. You should use a flag of 11 for both lighting and un-lighting the block.

As for the BlockState, you should use the with method instead of cycle.

Now after looking into Farmland, I've changed it to this:

  public void ChangeWhenClear(BlockState stateIn, World worldIn, BlockPos pos, Random rand) {
     if (!worldIn.isRaining()) {
        if (rand.nextInt(5) == 1) {
           BlockState blockstate = worldIn.getBlockState(pos);
           if (blockstate.get(LIT) == true) {
	    		  worldIn.setBlockState(pos, blockstate.with(LIT, Boolean.valueOf(false)));
	      }
        }
     }
  }

But it still is not working, the fillWithRain works well. 

Link to comment
Share on other sites

   public void ChangeWhenClear(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt(pos.up()) && rand.nextInt(5) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }

Still can't get it to work.. Am I blind?

Link to comment
Share on other sites

8 minutes ago, diesieben07 said:

Could you, idk, show that code so we can debug the problem...?

package com.spcmf.pete11.objects.custommodels;

import java.util.Random;
import java.util.stream.IntStream;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.pathfinding.PathType;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.Half;
import net.minecraft.state.properties.StairsShape;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;


public class CustomCampfire extends Block implements IWaterLoggable {
   public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;
   public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
   public static final EnumProperty<StairsShape> SHAPE = BlockStateProperties.STAIRS_SHAPE;
   public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
   
   public static final BooleanProperty LIT = BlockStateProperties.LIT;
   
   protected static final VoxelShape AABB_SLAB_TOP = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
   protected static final VoxelShape AABB_SLAB_BOTTOM = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
   
   protected static final VoxelShape NWD_CORNER = Block.makeCuboidShape(0.0D, 10.0D, 0.0D, 8.0D, 15.0D, 8.0D);
   protected static final VoxelShape SWD_CORNER = Block.makeCuboidShape(0.0D, 10.0D, 8.0D, 8.0D, 15.0D, 16.0D);
   protected static final VoxelShape NED_CORNER = Block.makeCuboidShape(8.0D, 10.0D, 0.0D, 16.0D, 15.0D, 8.0D);
   protected static final VoxelShape SED_CORNER = Block.makeCuboidShape(8.0D, 10.0D, 8.0D, 16.0D, 15.0D, 16.0D);

   protected static final VoxelShape[] SLAB_TOP_SHAPES = makeShapes(AABB_SLAB_TOP, NWD_CORNER, NED_CORNER, SWD_CORNER, SED_CORNER);
   protected static final VoxelShape[] SLAB_BOTTOM_SHAPES = makeShapes(AABB_SLAB_BOTTOM, NWD_CORNER, NED_CORNER, SWD_CORNER, SED_CORNER);
   private static final int[] field_196522_K = new int[]{12, 5, 3, 10, 14, 13, 7, 11, 13, 7, 11, 14, 8, 4, 1, 2, 4, 1, 2, 8};

   private final Block modelBlock;
   private final BlockState modelState;

   private static VoxelShape[] makeShapes(VoxelShape slabShape, VoxelShape nwCorner, VoxelShape neCorner, VoxelShape swCorner, VoxelShape seCorner) {
      return IntStream.range(0, 16).mapToObj((p_199780_5_) -> {
         return combineShapes(p_199780_5_, slabShape, nwCorner, neCorner, swCorner, seCorner);
      }).toArray((p_199778_0_) -> {
         return new VoxelShape[p_199778_0_];
      });
   }

   /**
    * combines the shapes according to the mode set in the bitfield
    */
   private static VoxelShape combineShapes(int bitfield, VoxelShape slabShape, VoxelShape nwCorner, VoxelShape neCorner, VoxelShape swCorner, VoxelShape seCorner) {
      VoxelShape voxelshape = slabShape;
      if ((bitfield & 1) != 0) {
         voxelshape = VoxelShapes.or(slabShape, nwCorner);
      }

      if ((bitfield & 2) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, neCorner);
      }

      if ((bitfield & 4) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, swCorner);
      }

      if ((bitfield & 8) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, seCorner);
      }

      return voxelshape;
   }

   // Forge: Use the other constructor that takes a Supplier

   public CustomCampfire(BlockState state, Block.Properties properties) {
      super(properties);
      this.setDefaultState(this.stateContainer.getBaseState().with(LIT, Boolean.valueOf(false)).with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM).with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
      this.modelBlock = state.getBlock();
      this.modelState = state;
      this.stateSupplier = () -> state;
   }


   
   
   public CustomCampfire(java.util.function.Supplier<BlockState> state, Block.Properties properties) {
      super(properties);
      this.setDefaultState(this.stateContainer.getBaseState().with(LIT, Boolean.valueOf(false)).with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM).with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
      this.modelBlock = Blocks.AIR; // These are unused, fields are redirected
      this.modelState = Blocks.AIR.getDefaultState();
      this.stateSupplier = state;
   }

   public boolean func_220074_n(BlockState state) {
      return true;
   }
   
   /**
    * Update the provided state given the provided neighbor facing and neighbor state, returning a new state.
    * For example, fences make their connections to the passed in state if possible, and wet concrete powder immediately
    * returns its solidified counterpart.
    * Note that this method should ideally consider only the specific face passed in.
    */
   @SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn, BlockPos currentPos, BlockPos facingPos) {
      if (stateIn.get(WATERLOGGED)) {
         worldIn.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
         worldIn.getPendingBlockTicks().scheduleTick(currentPos, this, 1);
      }

      
      
      return facing.getAxis().isHorizontal() ? stateIn.with(SHAPE, getShapeProperty(stateIn, worldIn, currentPos)) : super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos);
   }
   

   
   public void fillWithRain(World worldIn, BlockPos pos) {
	      if (worldIn.rand.nextInt(5) == 1) {
	         float f = worldIn.getBiome(pos).func_225486_c(pos);
	         if (!(f < 0.15F)) {
	            BlockState blockstate = worldIn.getBlockState(pos);
	            if (blockstate.get(LIT) == false) {
	               worldIn.setBlockState(pos, blockstate.with(LIT, Boolean.valueOf(true)));
	            }

	         }
	      }
	   }
   
  @SuppressWarnings("deprecation")
public void tick(BlockState state, World worldIn, BlockPos pos, Random random) {
	     this.modelBlock.tick(state, worldIn, pos, random);}



  
   public void randomDisplayTick(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt(pos.up()) && rand.nextInt(5) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }
   



public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
      return (state.get(HALF) == Half.TOP ? SLAB_TOP_SHAPES : SLAB_BOTTOM_SHAPES)[field_196522_K[this.func_196511_x(state)]];
   }

   private int func_196511_x(BlockState state) {
      return state.get(SHAPE).ordinal() * 4 + state.get(FACING).getHorizontalIndex();
   }

   /**
    * Called periodically clientside on blocks near the player to show effects (like furnace fire particles). Note that
    * this method is unrelated to {@link randomTick} and {@link #needsRandomTick}, and will always be called regardless
    * of whether the block can receive random update ticks
    */
   @OnlyIn(Dist.CLIENT)
   public void animateTick(BlockState stateIn, World worldIn, BlockPos pos, Random rand) {
      this.modelBlock.animateTick(stateIn, worldIn, pos, rand);
   }

   public void onBlockClicked(BlockState state, World worldIn, BlockPos pos, PlayerEntity player) {
      this.modelState.onBlockClicked(worldIn, pos, player);
   }

   /**
    * Called after a player destroys this Block - the posiiton pos may no longer hold the state indicated.
    */
   public void onPlayerDestroy(IWorld worldIn, BlockPos pos, BlockState state) {
      this.modelBlock.onPlayerDestroy(worldIn, pos, state);
   }

   /**
    * Returns how much this block can resist explosions from the passed in entity.
    */
   public float getExplosionResistance() {
      return this.modelBlock.getExplosionResistance();
   }

   /**
    * Gets the render layer this block will render on. SOLID for solid blocks, CUTOUT or CUTOUT_MIPPED for on-off
    * transparency (glass, reeds), TRANSLUCENT for fully blended transparency (stained glass)
    */
   public BlockRenderLayer getRenderLayer() {
      return this.modelBlock.getRenderLayer();
   }

   /**
    * How many world ticks before ticking
    */
   public int tickRate(IWorldReader worldIn) {
      return this.modelBlock.tickRate(worldIn);
   }

   public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
      if (state.getBlock() != state.getBlock()) {
         this.modelState.neighborChanged(worldIn, pos, Blocks.AIR, pos, false);
         this.modelBlock.onBlockAdded(this.modelState, worldIn, pos, oldState, false);
      }
   }

   public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
      if (state.getBlock() != newState.getBlock()) {
         this.modelState.onReplaced(worldIn, pos, newState, isMoving);
      }
   }

   /**
    * Called when the given entity walks on this Block
    */
   public void onEntityWalk(World worldIn, BlockPos pos, Entity entityIn) {
      this.modelBlock.onEntityWalk(worldIn, pos, entityIn);
   }



   public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
      return this.modelState.onBlockActivated(worldIn, player, handIn, hit);
   }

   /**
    * Called when this Block is destroyed by an Explosion
    */
   public void onExplosionDestroy(World worldIn, BlockPos pos, Explosion explosionIn) {
      this.modelBlock.onExplosionDestroy(worldIn, pos, explosionIn);
   }

   public BlockState getStateForPlacement(BlockItemUseContext context) {
      Direction direction = context.getFace();
      BlockPos blockpos = context.getPos();
      IFluidState ifluidstate = context.getWorld().getFluidState(blockpos);
      BlockState blockstate = this.getDefaultState().with(FACING, context.getPlacementHorizontalFacing()).with(HALF, direction != Direction.DOWN && (direction == Direction.UP || !(context.getHitVec().y - (double)blockpos.getY() > 0.5D)) ? Half.BOTTOM : Half.TOP).with(WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
      return blockstate.with(SHAPE, getShapeProperty(blockstate, context.getWorld(), blockpos));
   }



   /**
    * Returns a stair shape property based on the surrounding stairs from the given blockstate and position
    */
   private static StairsShape getShapeProperty(BlockState state, IBlockReader worldIn, BlockPos pos) {
      Direction direction = state.get(FACING);
      BlockState blockstate = worldIn.getBlockState(pos.offset(direction));
      if (isBlockStairs(blockstate) && state.get(HALF) == blockstate.get(HALF)) {
         Direction direction1 = blockstate.get(FACING);
         if (direction1.getAxis() != state.get(FACING).getAxis() && isDifferentStairs(state, worldIn, pos, direction1.getOpposite())) {
            if (direction1 == direction.rotateYCCW()) {
               return StairsShape.OUTER_LEFT;
            }

            return StairsShape.OUTER_RIGHT;
         }
      }

      BlockState blockstate1 = worldIn.getBlockState(pos.offset(direction.getOpposite()));
      if (isBlockStairs(blockstate1) && state.get(HALF) == blockstate1.get(HALF)) {
         Direction direction2 = blockstate1.get(FACING);
         if (direction2.getAxis() != state.get(FACING).getAxis() && isDifferentStairs(state, worldIn, pos, direction2)) {
            if (direction2 == direction.rotateYCCW()) {
               return StairsShape.INNER_LEFT;
            }

            return StairsShape.INNER_RIGHT;
         }
      }

      return StairsShape.STRAIGHT;
   }

   private static boolean isDifferentStairs(BlockState state, IBlockReader worldIn, BlockPos pos, Direction face) {
      BlockState blockstate = worldIn.getBlockState(pos.offset(face));
      return !isBlockStairs(blockstate) || blockstate.get(FACING) != state.get(FACING) || blockstate.get(HALF) != state.get(HALF);
   }

   public static boolean isBlockStairs(BlockState state) {
      return state.getBlock() instanceof CustomCampfire;
   }

   /**
    * Returns the blockstate with the given rotation from the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withRotation(Rotation)} whenever possible. Implementing/overriding is
    * fine.
    */
   public BlockState rotate(BlockState state, Rotation rot) {
      return state.with(FACING, rot.rotate(state.get(FACING)));
   }

   /**
    * Returns the blockstate with the given mirror of the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withMirror(Mirror)} whenever possible. Implementing/overriding is fine.
    */
   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);
   }

   protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
      builder.add(LIT, FACING, HALF, SHAPE, WATERLOGGED);
   }

   public IFluidState getFluidState(BlockState state) {
      return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
   }

   public boolean allowsMovement(BlockState state, IBlockReader worldIn, BlockPos pos, PathType type) {
      return false;
   }

   private final java.util.function.Supplier<BlockState> stateSupplier;
   private Block getModelBlock() {
       return getModelState().getBlock();
   }
   private BlockState getModelState() {
       return stateSupplier.get();
   }
}

 

Link to comment
Share on other sites

3 minutes ago, diesieben07 said:

The code you posted does not contain the phrase "ChangeWhenClear".

Therefor this statement is incorrect:

 

Please show the place where you are actually calling this method.

I've just tried to rename it to 

   public void randomDisplayTick(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt(pos.up()) && rand.nextInt(5) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }
   

 

Link to comment
Share on other sites

2 minutes ago, diesieben07 said:

Great.

It's really helpful when you change the name of the method we are talking about from one post to the next, that really helps with following the conversation. Especially when you don't tell anyone that you have done this.

 

Again though, the code you posted contains exactly zero calls to the randomDisplayTick method (it only contains the method itself).

So again, this statement is false:

 

I'm sorry, how do I call the randomDisplayTick method?

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

You must be calling it somewhere.

At least you were at some point, because otherwise it's code would never run...

Which it did though, because:

 

That means it ran at least once...

So, please use your IDE to find where you call this method.

That was meant for the fillWithRain method which works. Not for the one that should change the LIT to false.

Link to comment
Share on other sites

8 minutes ago, diesieben07 said:

Okay... well, there is no event for weather change. So you probably need a tile entity which checks every tick.

So this is not working ?   !worldIn.isRainingAt(pos.up())

Link to comment
Share on other sites

Just now, Kikoz said:

So this is not working ?   !worldIn.isRainingAt(pos.up())

Where are you calling that from?

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

Just now, Draco18s said:

Where are you calling that from?

 

26 minutes ago, Kikoz said:

I've just tried to rename it to 


   public void randomDisplayTick(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt(pos.up()) && rand.nextInt(5) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }
   

 

 

1 hour ago, Kikoz said:

package com.spcmf.pete11.objects.custommodels;

import java.util.Random;
import java.util.stream.IntStream;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.pathfinding.PathType;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.Half;
import net.minecraft.state.properties.StairsShape;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;


public class CustomCampfire extends Block implements IWaterLoggable {
   public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;
   public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
   public static final EnumProperty<StairsShape> SHAPE = BlockStateProperties.STAIRS_SHAPE;
   public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
   
   public static final BooleanProperty LIT = BlockStateProperties.LIT;
   
   protected static final VoxelShape AABB_SLAB_TOP = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
   protected static final VoxelShape AABB_SLAB_BOTTOM = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
   
   protected static final VoxelShape NWD_CORNER = Block.makeCuboidShape(0.0D, 10.0D, 0.0D, 8.0D, 15.0D, 8.0D);
   protected static final VoxelShape SWD_CORNER = Block.makeCuboidShape(0.0D, 10.0D, 8.0D, 8.0D, 15.0D, 16.0D);
   protected static final VoxelShape NED_CORNER = Block.makeCuboidShape(8.0D, 10.0D, 0.0D, 16.0D, 15.0D, 8.0D);
   protected static final VoxelShape SED_CORNER = Block.makeCuboidShape(8.0D, 10.0D, 8.0D, 16.0D, 15.0D, 16.0D);

   protected static final VoxelShape[] SLAB_TOP_SHAPES = makeShapes(AABB_SLAB_TOP, NWD_CORNER, NED_CORNER, SWD_CORNER, SED_CORNER);
   protected static final VoxelShape[] SLAB_BOTTOM_SHAPES = makeShapes(AABB_SLAB_BOTTOM, NWD_CORNER, NED_CORNER, SWD_CORNER, SED_CORNER);
   private static final int[] field_196522_K = new int[]{12, 5, 3, 10, 14, 13, 7, 11, 13, 7, 11, 14, 8, 4, 1, 2, 4, 1, 2, 8};

   private final Block modelBlock;
   private final BlockState modelState;

   private static VoxelShape[] makeShapes(VoxelShape slabShape, VoxelShape nwCorner, VoxelShape neCorner, VoxelShape swCorner, VoxelShape seCorner) {
      return IntStream.range(0, 16).mapToObj((p_199780_5_) -> {
         return combineShapes(p_199780_5_, slabShape, nwCorner, neCorner, swCorner, seCorner);
      }).toArray((p_199778_0_) -> {
         return new VoxelShape[p_199778_0_];
      });
   }

   /**
    * combines the shapes according to the mode set in the bitfield
    */
   private static VoxelShape combineShapes(int bitfield, VoxelShape slabShape, VoxelShape nwCorner, VoxelShape neCorner, VoxelShape swCorner, VoxelShape seCorner) {
      VoxelShape voxelshape = slabShape;
      if ((bitfield & 1) != 0) {
         voxelshape = VoxelShapes.or(slabShape, nwCorner);
      }

      if ((bitfield & 2) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, neCorner);
      }

      if ((bitfield & 4) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, swCorner);
      }

      if ((bitfield & 8) != 0) {
         voxelshape = VoxelShapes.or(voxelshape, seCorner);
      }

      return voxelshape;
   }

   // Forge: Use the other constructor that takes a Supplier

   public CustomCampfire(BlockState state, Block.Properties properties) {
      super(properties);
      this.setDefaultState(this.stateContainer.getBaseState().with(LIT, Boolean.valueOf(false)).with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM).with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
      this.modelBlock = state.getBlock();
      this.modelState = state;
      this.stateSupplier = () -> state;
   }


   
   
   public CustomCampfire(java.util.function.Supplier<BlockState> state, Block.Properties properties) {
      super(properties);
      this.setDefaultState(this.stateContainer.getBaseState().with(LIT, Boolean.valueOf(false)).with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM).with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
      this.modelBlock = Blocks.AIR; // These are unused, fields are redirected
      this.modelState = Blocks.AIR.getDefaultState();
      this.stateSupplier = state;
   }

   public boolean func_220074_n(BlockState state) {
      return true;
   }
   
   /**
    * Update the provided state given the provided neighbor facing and neighbor state, returning a new state.
    * For example, fences make their connections to the passed in state if possible, and wet concrete powder immediately
    * returns its solidified counterpart.
    * Note that this method should ideally consider only the specific face passed in.
    */
   @SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn, BlockPos currentPos, BlockPos facingPos) {
      if (stateIn.get(WATERLOGGED)) {
         worldIn.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
         worldIn.getPendingBlockTicks().scheduleTick(currentPos, this, 1);
      }

      
      
      return facing.getAxis().isHorizontal() ? stateIn.with(SHAPE, getShapeProperty(stateIn, worldIn, currentPos)) : super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos);
   }
   

   
   public void fillWithRain(World worldIn, BlockPos pos) {
	      if (worldIn.rand.nextInt(5) == 1) {
	         float f = worldIn.getBiome(pos).func_225486_c(pos);
	         if (!(f < 0.15F)) {
	            BlockState blockstate = worldIn.getBlockState(pos);
	            if (blockstate.get(LIT) == false) {
	               worldIn.setBlockState(pos, blockstate.with(LIT, Boolean.valueOf(true)));
	            }

	         }
	      }
	   }
   
  @SuppressWarnings("deprecation")
public void tick(BlockState state, World worldIn, BlockPos pos, Random random) {
	     this.modelBlock.tick(state, worldIn, pos, random);}



  
   public void randomDisplayTick(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt(pos.up()) && rand.nextInt(5) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }
   



public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
      return (state.get(HALF) == Half.TOP ? SLAB_TOP_SHAPES : SLAB_BOTTOM_SHAPES)[field_196522_K[this.func_196511_x(state)]];
   }

   private int func_196511_x(BlockState state) {
      return state.get(SHAPE).ordinal() * 4 + state.get(FACING).getHorizontalIndex();
   }

   /**
    * Called periodically clientside on blocks near the player to show effects (like furnace fire particles). Note that
    * this method is unrelated to {@link randomTick} and {@link #needsRandomTick}, and will always be called regardless
    * of whether the block can receive random update ticks
    */
   @OnlyIn(Dist.CLIENT)
   public void animateTick(BlockState stateIn, World worldIn, BlockPos pos, Random rand) {
      this.modelBlock.animateTick(stateIn, worldIn, pos, rand);
   }

   public void onBlockClicked(BlockState state, World worldIn, BlockPos pos, PlayerEntity player) {
      this.modelState.onBlockClicked(worldIn, pos, player);
   }

   /**
    * Called after a player destroys this Block - the posiiton pos may no longer hold the state indicated.
    */
   public void onPlayerDestroy(IWorld worldIn, BlockPos pos, BlockState state) {
      this.modelBlock.onPlayerDestroy(worldIn, pos, state);
   }

   /**
    * Returns how much this block can resist explosions from the passed in entity.
    */
   public float getExplosionResistance() {
      return this.modelBlock.getExplosionResistance();
   }

   /**
    * Gets the render layer this block will render on. SOLID for solid blocks, CUTOUT or CUTOUT_MIPPED for on-off
    * transparency (glass, reeds), TRANSLUCENT for fully blended transparency (stained glass)
    */
   public BlockRenderLayer getRenderLayer() {
      return this.modelBlock.getRenderLayer();
   }

   /**
    * How many world ticks before ticking
    */
   public int tickRate(IWorldReader worldIn) {
      return this.modelBlock.tickRate(worldIn);
   }

   public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
      if (state.getBlock() != state.getBlock()) {
         this.modelState.neighborChanged(worldIn, pos, Blocks.AIR, pos, false);
         this.modelBlock.onBlockAdded(this.modelState, worldIn, pos, oldState, false);
      }
   }

   public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
      if (state.getBlock() != newState.getBlock()) {
         this.modelState.onReplaced(worldIn, pos, newState, isMoving);
      }
   }

   /**
    * Called when the given entity walks on this Block
    */
   public void onEntityWalk(World worldIn, BlockPos pos, Entity entityIn) {
      this.modelBlock.onEntityWalk(worldIn, pos, entityIn);
   }



   public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
      return this.modelState.onBlockActivated(worldIn, player, handIn, hit);
   }

   /**
    * Called when this Block is destroyed by an Explosion
    */
   public void onExplosionDestroy(World worldIn, BlockPos pos, Explosion explosionIn) {
      this.modelBlock.onExplosionDestroy(worldIn, pos, explosionIn);
   }

   public BlockState getStateForPlacement(BlockItemUseContext context) {
      Direction direction = context.getFace();
      BlockPos blockpos = context.getPos();
      IFluidState ifluidstate = context.getWorld().getFluidState(blockpos);
      BlockState blockstate = this.getDefaultState().with(FACING, context.getPlacementHorizontalFacing()).with(HALF, direction != Direction.DOWN && (direction == Direction.UP || !(context.getHitVec().y - (double)blockpos.getY() > 0.5D)) ? Half.BOTTOM : Half.TOP).with(WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
      return blockstate.with(SHAPE, getShapeProperty(blockstate, context.getWorld(), blockpos));
   }



   /**
    * Returns a stair shape property based on the surrounding stairs from the given blockstate and position
    */
   private static StairsShape getShapeProperty(BlockState state, IBlockReader worldIn, BlockPos pos) {
      Direction direction = state.get(FACING);
      BlockState blockstate = worldIn.getBlockState(pos.offset(direction));
      if (isBlockStairs(blockstate) && state.get(HALF) == blockstate.get(HALF)) {
         Direction direction1 = blockstate.get(FACING);
         if (direction1.getAxis() != state.get(FACING).getAxis() && isDifferentStairs(state, worldIn, pos, direction1.getOpposite())) {
            if (direction1 == direction.rotateYCCW()) {
               return StairsShape.OUTER_LEFT;
            }

            return StairsShape.OUTER_RIGHT;
         }
      }

      BlockState blockstate1 = worldIn.getBlockState(pos.offset(direction.getOpposite()));
      if (isBlockStairs(blockstate1) && state.get(HALF) == blockstate1.get(HALF)) {
         Direction direction2 = blockstate1.get(FACING);
         if (direction2.getAxis() != state.get(FACING).getAxis() && isDifferentStairs(state, worldIn, pos, direction2)) {
            if (direction2 == direction.rotateYCCW()) {
               return StairsShape.INNER_LEFT;
            }

            return StairsShape.INNER_RIGHT;
         }
      }

      return StairsShape.STRAIGHT;
   }

   private static boolean isDifferentStairs(BlockState state, IBlockReader worldIn, BlockPos pos, Direction face) {
      BlockState blockstate = worldIn.getBlockState(pos.offset(face));
      return !isBlockStairs(blockstate) || blockstate.get(FACING) != state.get(FACING) || blockstate.get(HALF) != state.get(HALF);
   }

   public static boolean isBlockStairs(BlockState state) {
      return state.getBlock() instanceof CustomCampfire;
   }

   /**
    * Returns the blockstate with the given rotation from the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withRotation(Rotation)} whenever possible. Implementing/overriding is
    * fine.
    */
   public BlockState rotate(BlockState state, Rotation rot) {
      return state.with(FACING, rot.rotate(state.get(FACING)));
   }

   /**
    * Returns the blockstate with the given mirror of the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withMirror(Mirror)} whenever possible. Implementing/overriding is fine.
    */
   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);
   }

   protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
      builder.add(LIT, FACING, HALF, SHAPE, WATERLOGGED);
   }

   public IFluidState getFluidState(BlockState state) {
      return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
   }

   public boolean allowsMovement(BlockState state, IBlockReader worldIn, BlockPos pos, PathType type) {
      return false;
   }

   private final java.util.function.Supplier<BlockState> stateSupplier;
   private Block getModelBlock() {
       return getModelState().getBlock();
   }
   private BlockState getModelState() {
       return stateSupplier.get();
   }
}

 

 

Link to comment
Share on other sites

Ok, so:

  1. That method is only called on the client side and can't actually change the block state.
  2. That method is not called every tick. Its called randomly.

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

Just now, Draco18s said:

Ok, so:

  1. That method is only called on the client side and can't actually change the block state.
  2. That method is not called every tick. Its called randomly.

1. FarmlandBlock uses it to change the block state, I just want it to randomly lit to false when it is not raining. Is there no other way to do it without a ticking entity?

 

Link to comment
Share on other sites

...noooo, it uses the tick method (updateTick from previous versions). I'm looking at it right now.

 

Which...is also called randomly or by schedule, depending on the block. Farmland is random.

 

Also also, randomDisplayTick doesn't exist any more either, its now called animateTick. Put @Override on your damn methods.

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

  @Override
   public void tick(BlockState state, World worldIn, BlockPos pos, Random rand) {
    	  
         if (!worldIn.isRainingAt((pos)) && rand.nextInt(1) == 1) { 
                 worldIn.setBlockState(pos, state.with(LIT, Boolean.valueOf(false)));
            }
      }
   

So this should work?

Link to comment
Share on other sites

Well.

Do you call .tickRandomly() on your BlockProperties?

If yes: then it will tick at random

If no: where are you scheduling your next tick?

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
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

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
×
×
  • Create New...

Important Information

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