tcr/common/src/main/java/common/block/tech/BlockPistonBase.java
2025-06-27 16:27:16 +02:00

734 lines
24 KiB
Java
Executable file

package common.block.tech;
import java.util.List;
import common.block.Block;
import common.block.Directional;
import common.block.ITileEntityProvider;
import common.block.Material;
import common.block.SoundType;
import common.collect.Lists;
import common.entity.Entity;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.SoundEvent;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemStack;
import common.item.block.ItemPiston;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.Property;
import common.properties.PropertyBool;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityPiston;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.util.Facing;
import common.vars.Vars;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;
public class BlockPistonBase extends Block implements Directional
{
private static class BlockPistonStructureHelper
{
private final World world;
private final BlockPos pistonPos;
private final BlockPos blockToMove;
private final Facing moveDirection;
private final List<BlockPos> toMove = Lists.<BlockPos>newArrayList();
private final List<BlockPos> toDestroy = Lists.<BlockPos>newArrayList();
public BlockPistonStructureHelper(World worldIn, BlockPos posIn, Facing pistonFacing, boolean extending)
{
this.world = worldIn;
this.pistonPos = posIn;
if (extending)
{
this.moveDirection = pistonFacing;
this.blockToMove = posIn.offset(pistonFacing);
}
else
{
this.moveDirection = pistonFacing.getOpposite();
this.blockToMove = posIn.offset(pistonFacing, 2);
}
}
public boolean canMove()
{
this.toMove.clear();
this.toDestroy.clear();
Block block = this.world.getState(this.blockToMove).getBlock();
if (!BlockPistonBase.canPush(block, this.world, this.blockToMove, this.moveDirection, false))
{
if (block.getMobilityFlag() != 1)
{
return false;
}
else
{
this.toDestroy.add(this.blockToMove);
return true;
}
}
else if (!this.canPistonSlide(this.blockToMove))
{
return false;
}
else
{
for (int i = 0; i < this.toMove.size(); ++i)
{
BlockPos blockpos = (BlockPos)this.toMove.get(i);
if (this.world.getState(blockpos).getBlock() == Blocks.slime_block && !this.canSlide(blockpos))
{
return false;
}
}
return true;
}
}
private boolean canPistonSlide(BlockPos origin)
{
Block block = this.world.getState(origin).getBlock();
if (block == Blocks.air)
{
return true;
}
else if (!BlockPistonBase.canPush(block, this.world, origin, this.moveDirection, false))
{
return true;
}
else if (origin.equals(this.pistonPos))
{
return true;
}
else if (this.toMove.contains(origin))
{
return true;
}
else
{
int i = 1;
if (i + this.toMove.size() > Vars.pistonLimit)
{
return false;
}
else
{
while (block == Blocks.slime_block)
{
BlockPos blockpos = origin.offset(this.moveDirection.getOpposite(), i);
block = this.world.getState(blockpos).getBlock();
if (block == Blocks.air || !BlockPistonBase.canPush(block, this.world, blockpos, this.moveDirection, false) || blockpos.equals(this.pistonPos))
{
break;
}
++i;
if (i + this.toMove.size() > Vars.pistonLimit)
{
return false;
}
}
int i1 = 0;
for (int j = i - 1; j >= 0; --j)
{
this.toMove.add(origin.offset(this.moveDirection.getOpposite(), j));
++i1;
}
int j1 = 1;
while (true)
{
BlockPos blockpos1 = origin.offset(this.moveDirection, j1);
int k = this.toMove.indexOf(blockpos1);
if (k > -1)
{
this.reorderMoveList(i1, k);
for (int l = 0; l <= k + i1; ++l)
{
BlockPos blockpos2 = (BlockPos)this.toMove.get(l);
if (this.world.getState(blockpos2).getBlock() == Blocks.slime_block && !this.canSlide(blockpos2))
{
return false;
}
}
return true;
}
block = this.world.getState(blockpos1).getBlock();
if (block == Blocks.air)
{
return true;
}
if (!BlockPistonBase.canPush(block, this.world, blockpos1, this.moveDirection, true) || blockpos1.equals(this.pistonPos))
{
return false;
}
if (block.getMobilityFlag() == 1)
{
this.toDestroy.add(blockpos1);
return true;
}
if (this.toMove.size() >= Vars.pistonLimit)
{
return false;
}
this.toMove.add(blockpos1);
++i1;
++j1;
}
}
}
}
private void reorderMoveList(int splitA, int splitB)
{
List<BlockPos> list = Lists.<BlockPos>newArrayList();
List<BlockPos> list1 = Lists.<BlockPos>newArrayList();
List<BlockPos> list2 = Lists.<BlockPos>newArrayList();
list.addAll(this.toMove.subList(0, splitB));
list1.addAll(this.toMove.subList(this.toMove.size() - splitA, this.toMove.size()));
list2.addAll(this.toMove.subList(splitB, this.toMove.size() - splitA));
this.toMove.clear();
this.toMove.addAll(list);
this.toMove.addAll(list1);
this.toMove.addAll(list2);
}
private boolean canSlide(BlockPos pos)
{
for (Facing enumfacing : Facing.values())
{
if (enumfacing.getAxis() != this.moveDirection.getAxis() && !this.canPistonSlide(pos.offset(enumfacing)))
{
return false;
}
}
return true;
}
public List<BlockPos> getBlocksToMove()
{
return this.toMove;
}
public List<BlockPos> getBlocksToDestroy()
{
return this.toDestroy;
}
}
public static final PropertyBool EXTENDED = PropertyBool.create("extended");
/** This piston is the sticky one? */
private final boolean isSticky;
public BlockPistonBase(boolean isSticky)
{
super(Material.PISTON);
this.setDefaultState(this.getBaseState().withProperty(FACING, Facing.NORTH).withProperty(EXTENDED, Boolean.valueOf(false)));
this.isSticky = isSticky;
this.setStepSound(SoundType.STONE);
this.setHardness(0.5F);
this.setTab(CheatTab.TECHNOLOGY);
}
/**
* Used to determine ambient occlusion and culling when rebuilding chunks for render
*/
public boolean isOpaqueCube()
{
return false;
}
/**
* Called by ItemBlocks after a block is set in the world, to allow post-place logic
*/
public void onBlockPlacedBy(World worldIn, BlockPos pos, State state, EntityLiving placer, ItemStack stack)
{
worldIn.setState(pos, state.withProperty(FACING, getFacingFromEntity(worldIn, pos, placer)), 2);
if (!worldIn.client)
{
this.checkForMove(worldIn, pos, state);
}
}
/**
* Called when a neighboring block changes.
*/
public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock)
{
if (!worldIn.client)
{
this.checkForMove(worldIn, pos, state);
}
}
public void onBlockAdded(AWorldServer worldIn, BlockPos pos, State state)
{
if (!worldIn.client && worldIn.getTileEntity(pos) == null)
{
this.checkForMove(worldIn, pos, state);
}
}
/**
* Called by ItemBlocks just before a block is actually set in the world, to allow for adjustments to the
* IBlockstate
*/
public State onBlockPlaced(World worldIn, BlockPos pos, Facing facing, float hitX, float hitY, float hitZ, EntityLiving placer)
{
return this.getState().withProperty(FACING, getFacingFromEntity(worldIn, pos, placer)).withProperty(EXTENDED, Boolean.valueOf(false));
}
private void checkForMove(World worldIn, BlockPos pos, State state)
{
Facing enumfacing = (Facing)state.getValue(FACING);
boolean flag = this.shouldBeExtended(worldIn, pos, enumfacing);
if (flag && !((Boolean)state.getValue(EXTENDED)).booleanValue())
{
if ((new BlockPistonStructureHelper(worldIn, pos, enumfacing, true)).canMove())
{
worldIn.addBlockEvent(pos, this, 0, enumfacing.getIndex());
}
}
else if (!flag && ((Boolean)state.getValue(EXTENDED)).booleanValue())
{
worldIn.setState(pos, state.withProperty(EXTENDED, Boolean.valueOf(false)), 2);
worldIn.addBlockEvent(pos, this, 1, enumfacing.getIndex());
}
}
private boolean shouldBeExtended(World worldIn, BlockPos pos, Facing facing)
{
for (Facing enumfacing : Facing.values())
{
if (enumfacing != facing && worldIn.isSidePowered(pos.offset(enumfacing), enumfacing))
{
return true;
}
}
if (worldIn.isSidePowered(pos, Facing.DOWN))
{
return true;
}
else
{
BlockPos blockpos = pos.up();
for (Facing enumfacing1 : Facing.values())
{
if (enumfacing1 != Facing.DOWN && worldIn.isSidePowered(blockpos.offset(enumfacing1), enumfacing1))
{
return true;
}
}
return false;
}
}
/**
* Called on both Client and Server when World#addBlockEvent is called
*/
public boolean onBlockEventReceived(World worldIn, BlockPos pos, State state, int eventID, int eventParam)
{
Facing enumfacing = (Facing)state.getValue(FACING);
if (!worldIn.client)
{
boolean flag = this.shouldBeExtended(worldIn, pos, enumfacing);
if (flag && eventID == 1)
{
worldIn.setState(pos, state.withProperty(EXTENDED, Boolean.valueOf(true)), 2);
return false;
}
if (!flag && eventID == 0)
{
return false;
}
}
if (eventID == 0)
{
if (!this.doMove(worldIn, pos, enumfacing, true))
{
return false;
}
worldIn.setState(pos, state.withProperty(EXTENDED, Boolean.valueOf(true)), 2);
worldIn.playSound(SoundEvent.PISTON_OUT, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.5D, (double)pos.getZ() + 0.5D, 0.5F);
}
else if (eventID == 1)
{
TileEntity tileentity1 = worldIn.getTileEntity(pos.offset(enumfacing));
if (tileentity1 instanceof TileEntityPiston)
{
((TileEntityPiston)tileentity1).clearPistonTileEntity();
}
worldIn.setState(pos, Blocks.piston_extension.getState().withProperty(BlockPistonMoving.FACING, enumfacing).withProperty(BlockPistonMoving.TYPE, this.isSticky ? BlockPistonHead.EnumPistonType.STICKY : BlockPistonHead.EnumPistonType.DEFAULT), 3);
worldIn.setTileEntity(pos, BlockPistonMoving.newTileEntity(this.getState().withProperty(FACING, getFacing(eventParam)).withProperty(EXTENDED, (eventParam & 8) > 0), enumfacing, false, true));
if (this.isSticky)
{
BlockPos blockpos = pos.add(enumfacing.getFrontOffsetX() * 2, enumfacing.getFrontOffsetY() * 2, enumfacing.getFrontOffsetZ() * 2);
Block block = worldIn.getState(blockpos).getBlock();
boolean flag1 = false;
if (block == Blocks.piston_extension)
{
TileEntity tileentity = worldIn.getTileEntity(blockpos);
if (tileentity instanceof TileEntityPiston)
{
TileEntityPiston tileentitypiston = (TileEntityPiston)tileentity;
if (tileentitypiston.getFacing() == enumfacing && tileentitypiston.isExtending())
{
tileentitypiston.clearPistonTileEntity();
flag1 = true;
}
}
}
if (!flag1 && block != Blocks.air && canPush(block, worldIn, blockpos, enumfacing.getOpposite(), false) && (block.getMobilityFlag() == 0 || block == Blocks.piston || block == Blocks.sticky_piston))
{
this.doMove(worldIn, pos, enumfacing, false);
}
}
else
{
worldIn.setBlockToAir(pos.offset(enumfacing));
}
worldIn.playSound(SoundEvent.PISTON_IN, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.5D, (double)pos.getZ() + 0.5D, 0.5F);
}
return true;
}
public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
{
State iblockstate = worldIn.getState(pos);
if (iblockstate.getBlock() == this && ((Boolean)iblockstate.getValue(EXTENDED)).booleanValue())
{
float f = 0.25F;
Facing enumfacing = (Facing)iblockstate.getValue(FACING);
if (enumfacing != null)
{
switch (enumfacing)
{
case DOWN:
this.setBlockBounds(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F);
break;
case UP:
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F);
break;
case NORTH:
this.setBlockBounds(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F);
break;
case SOUTH:
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F);
break;
case WEST:
this.setBlockBounds(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
break;
case EAST:
this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F);
}
}
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
}
/**
* Sets the block's bounds for rendering it as an item
*/
public void setBlockBoundsForItemRender()
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
/**
* Add all collision boxes of this Block to the list that intersect with the given mask.
*/
public void addCollisionBoxesToList(World worldIn, BlockPos pos, State state, BoundingBox mask, List<BoundingBox> list, Entity collidingEntity)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
}
public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state)
{
this.setBlockBoundsBasedOnState(worldIn, pos);
return super.getCollisionBoundingBox(worldIn, pos, state);
}
public boolean isFullCube()
{
return false;
}
public static Facing getFacing(int meta)
{
int i = meta & 7;
return i > 5 ? Facing.getFront(0) : Facing.getFront(i);
}
public static Facing getFacingFromEntity(World worldIn, BlockPos clickedBlock, EntityLiving entityIn)
{
if (ExtMath.absf((float)entityIn.posX - (float)clickedBlock.getX()) < 2.0F && ExtMath.absf((float)entityIn.posZ - (float)clickedBlock.getZ()) < 2.0F)
{
double d0 = entityIn.posY + (double)entityIn.getEyeHeight();
if (d0 - (double)clickedBlock.getY() > 2.0D)
{
return Facing.UP;
}
if ((double)clickedBlock.getY() - d0 > 0.0D)
{
return Facing.DOWN;
}
}
return entityIn.getHorizontalFacing().getOpposite();
}
public static boolean canPush(Block blockIn, World worldIn, BlockPos pos, Facing direction, boolean allowDestroy)
{
if (blockIn == Blocks.obsidian)
{
return false;
}
else if (!World.isValidXZ(pos))
{
return false;
}
else if (pos.getY() >= -World.MAX_SIZE_Y && (direction != Facing.DOWN || pos.getY() != -World.MAX_SIZE_Y))
{
if (pos.getY() <= World.MAX_SIZE_Y - 1 && (direction != Facing.UP || pos.getY() != World.MAX_SIZE_Y - 1))
{
if (blockIn != Blocks.piston && blockIn != Blocks.sticky_piston)
{
if (blockIn.getBlockHardness(worldIn, pos) == -1.0F)
{
return false;
}
if (blockIn.getMobilityFlag() == 2)
{
return false;
}
if (blockIn.getMobilityFlag() == 1)
{
if (!allowDestroy)
{
return false;
}
return true;
}
}
else if (((Boolean)worldIn.getState(pos).getValue(EXTENDED)).booleanValue())
{
return false;
}
return !(blockIn instanceof ITileEntityProvider);
}
else
{
return false;
}
}
else
{
return false;
}
}
private boolean doMove(World worldIn, BlockPos pos, Facing direction, boolean extending)
{
if (!extending)
{
worldIn.setBlockToAir(pos.offset(direction));
}
BlockPistonStructureHelper blockpistonstructurehelper = new BlockPistonStructureHelper(worldIn, pos, direction, extending);
List<BlockPos> list = blockpistonstructurehelper.getBlocksToMove();
List<BlockPos> list1 = blockpistonstructurehelper.getBlocksToDestroy();
if (!blockpistonstructurehelper.canMove())
{
return false;
}
else
{
int i = list.size() + list1.size();
Block[] ablock = new Block[i];
Facing enumfacing = extending ? direction : direction.getOpposite();
for (int j = list1.size() - 1; j >= 0; --j)
{
BlockPos blockpos = (BlockPos)list1.get(j);
Block block = worldIn.getState(blockpos).getBlock();
block.dropBlockAsItem(worldIn, blockpos, worldIn.getState(blockpos), 0);
worldIn.setBlockToAir(blockpos);
--i;
ablock[i] = block;
}
for (int k = list.size() - 1; k >= 0; --k)
{
BlockPos blockpos2 = (BlockPos)list.get(k);
State iblockstate = worldIn.getState(blockpos2);
Block block1 = iblockstate.getBlock();
worldIn.setBlockToAir(blockpos2);
blockpos2 = blockpos2.offset(enumfacing);
worldIn.setState(blockpos2, Blocks.piston_extension.getState().withProperty(FACING, direction), 4);
worldIn.setTileEntity(blockpos2, BlockPistonMoving.newTileEntity(iblockstate, direction, extending, false));
--i;
ablock[i] = block1;
}
BlockPos blockpos1 = pos.offset(direction);
if (extending)
{
BlockPistonHead.EnumPistonType blockpistonextension$enumpistontype = this.isSticky ? BlockPistonHead.EnumPistonType.STICKY : BlockPistonHead.EnumPistonType.DEFAULT;
State iblockstate1 = Blocks.piston_head.getState().withProperty(BlockPistonHead.FACING, direction).withProperty(BlockPistonHead.TYPE, blockpistonextension$enumpistontype);
State iblockstate2 = Blocks.piston_extension.getState().withProperty(BlockPistonMoving.FACING, direction).withProperty(BlockPistonMoving.TYPE, this.isSticky ? BlockPistonHead.EnumPistonType.STICKY : BlockPistonHead.EnumPistonType.DEFAULT);
worldIn.setState(blockpos1, iblockstate2, 4);
worldIn.setTileEntity(blockpos1, BlockPistonMoving.newTileEntity(iblockstate1, direction, true, false));
}
for (int l = list1.size() - 1; l >= 0; --l)
{
worldIn.notifyNeighborsOfStateChange((BlockPos)list1.get(l), ablock[i++]);
}
for (int i1 = list.size() - 1; i1 >= 0; --i1)
{
worldIn.notifyNeighborsOfStateChange((BlockPos)list.get(i1), ablock[i++]);
}
if (extending)
{
worldIn.notifyNeighborsOfStateChange(blockpos1, Blocks.piston_head);
worldIn.notifyNeighborsOfStateChange(pos, this);
}
return true;
}
}
/**
* Possibly modify the given BlockState before rendering it on an Entity (Minecarts, Endermen, ...)
*/
public State getStateForEntityRender(State state)
{
return this.getState().withProperty(FACING, Facing.UP);
}
/**
* Convert the given metadata into a BlockState for this Block
*/
public State getStateFromMeta(int meta)
{
return this.getState().withProperty(FACING, getFacing(meta)).withProperty(EXTENDED, Boolean.valueOf((meta & 8) > 0));
}
/**
* Convert the BlockState into the correct metadata value
*/
public int getMetaFromState(State state)
{
int i = 0;
i = i | ((Facing)state.getValue(FACING)).getIndex();
if (((Boolean)state.getValue(EXTENDED)).booleanValue())
{
i |= 8;
}
return i;
}
protected Property[] getProperties()
{
return new Property[] {FACING, EXTENDED};
}
public Model getModel(ModelProvider provider, String name, State state) {
return (state.getValue(EXTENDED) ? provider.getModel("piston_side")
.add(0, 0, 4, 16, 16, 16)
.d().uv(0, 4, 16, 16).rot(180)
.u().uv(0, 4, 16, 16)
.n("piston_inner").uv(0, 0, 16, 16).noCull()
.s("piston_bottom").uv(0, 0, 16, 16)
.w().uv(0, 4, 16, 16).rot(270)
.e().uv(0, 4, 16, 16).rot(90) : provider.getModel("piston_side")
.add(0, 0, 0, 16, 16, 16)
.d().uv(0, 0, 16, 16).rot(180)
.u().uv(0, 0, 16, 16)
.n(this.isSticky ? "piston_top_sticky" : "piston_top").uv(0, 0, 16, 16)
.s("piston_bottom").uv(0, 0, 16, 16)
.w().uv(0, 0, 16, 16).rot(270)
.e().uv(0, 0, 16, 16).rot(90))
.rotate(ModelRotation.getNorthRot(state.getValue(FACING).getAxis() == Facing.Axis.Y
? state.getValue(FACING).getOpposite() : state.getValue(FACING)));
}
protected Item getItemToRegister() {
return new ItemPiston(this);
}
}