Skip to content

Instantly share code, notes, and snippets.

@Panda4994
Created June 26, 2016 20:31
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Panda4994/70ed6d39c89396570e062e4404a8d518 to your computer and use it in GitHub Desktop.
Save Panda4994/70ed6d39c89396570e062e4404a8d518 to your computer and use it in GitHub Desktop.
package net.minecraft.block;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang3.ArrayUtils;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockRedstoneWire extends Block {
/**
* I considered replacing the lists with LinkedHashSets for faster lookup,
* but an artificial test showed barely any difference in performance
*/
/** Positions that need to be turned off **/
private List<BlockPos> turnOff = Lists.<BlockPos>newArrayList();
/** Positions that need to be checked to be turned on **/
private List<BlockPos> turnOn = Lists.<BlockPos>newArrayList();
/** Positions of wire that was updated already (Ordering determines update order and is therefore required!) **/
private final Set<BlockPos> updatedRedstoneWire = Sets.<BlockPos>newLinkedHashSet();
/** Ordered arrays of the facings; Needed for the update order.
* I went with a vertical-first order here, but vertical last would work to.
* However it should be avoided to update the vertical axis between the horizontal ones as this would cause unneeded directional behavior. **/
private static final EnumFacing[] facingsHorizontal = {EnumFacing.WEST, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.SOUTH};
private static final EnumFacing[] facingsVertical = {EnumFacing.DOWN, EnumFacing.UP};
private static final EnumFacing[] facings = ArrayUtils.addAll(facingsVertical, facingsHorizontal);
/** Offsets for all surrounding blocks that need to receive updates **/
private static final Vec3i[] surroundingBlocksOffset;
static {
Set<Vec3i> set = Sets.<Vec3i> newLinkedHashSet();
for (EnumFacing facing : facings) {
set.add(facing.getDirectionVec());
}
for (EnumFacing facing1 : facings) {
Vec3i v1 = facing1.getDirectionVec();
for (EnumFacing facing2 : facings) {
Vec3i v2 = facing2.getDirectionVec();
// TODO Adding an add-method to Vec3i would be nicer of course
set.add(new Vec3i(v1.getX() + v2.getX(), v1.getY() + v2.getY(), v1.getZ() + v2.getZ()));
}
}
set.remove(new Vec3i(0, 0, 0));
surroundingBlocksOffset = set.toArray(new Vec3i[set.size()]);
}
public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> NORTH = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("north", BlockRedstoneWire.EnumAttachPosition.class);
public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> EAST = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("east", BlockRedstoneWire.EnumAttachPosition.class);
public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> SOUTH = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("south", BlockRedstoneWire.EnumAttachPosition.class);
public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> WEST = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("west", BlockRedstoneWire.EnumAttachPosition.class);
public static final PropertyInteger POWER = PropertyInteger.create("power", 0, 15);
protected static final AxisAlignedBB[] REDSTONE_WIRE_AABB = new AxisAlignedBB[]{new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D)};
private boolean canProvidePower = true;
public BlockRedstoneWire() {
super(Material.CIRCUITS);
this.setDefaultState(this.blockState.getBaseState().withProperty(NORTH, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(EAST, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(SOUTH, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(WEST, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(POWER, Integer.valueOf(0)));
}
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return REDSTONE_WIRE_AABB[getAABBIndex(state.getActualState(source, pos))];
}
private static int getAABBIndex(IBlockState state) {
int i = 0;
boolean flag = state.getValue(NORTH) != BlockRedstoneWire.EnumAttachPosition.NONE;
boolean flag1 = state.getValue(EAST) != BlockRedstoneWire.EnumAttachPosition.NONE;
boolean flag2 = state.getValue(SOUTH) != BlockRedstoneWire.EnumAttachPosition.NONE;
boolean flag3 = state.getValue(WEST) != BlockRedstoneWire.EnumAttachPosition.NONE;
if(flag || flag2 && !flag && !flag1 && !flag3) {
i |= 1 << EnumFacing.NORTH.getHorizontalIndex();
}
if(flag1 || flag3 && !flag && !flag1 && !flag2) {
i |= 1 << EnumFacing.EAST.getHorizontalIndex();
}
if(flag2 || flag && !flag1 && !flag2 && !flag3) {
i |= 1 << EnumFacing.SOUTH.getHorizontalIndex();
}
if(flag3 || flag1 && !flag && !flag2 && !flag3) {
i |= 1 << EnumFacing.WEST.getHorizontalIndex();
}
return i;
}
public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) {
state = state.withProperty(WEST, this.getAttachPosition(worldIn, pos, EnumFacing.WEST));
state = state.withProperty(EAST, this.getAttachPosition(worldIn, pos, EnumFacing.EAST));
state = state.withProperty(NORTH, this.getAttachPosition(worldIn, pos, EnumFacing.NORTH));
state = state.withProperty(SOUTH, this.getAttachPosition(worldIn, pos, EnumFacing.SOUTH));
return state;
}
private BlockRedstoneWire.EnumAttachPosition getAttachPosition(IBlockAccess worldIn, BlockPos pos, EnumFacing direction) {
BlockPos blockpos = pos.offset(direction);
IBlockState iblockstate = worldIn.getBlockState(pos.offset(direction));
if(!canConnectTo(worldIn.getBlockState(blockpos), direction) && (iblockstate.isNormalCube() || !canConnectUpwardsTo(worldIn.getBlockState(blockpos.down())))) {
IBlockState iblockstate1 = worldIn.getBlockState(pos.up());
if(!iblockstate1.isNormalCube()) {
boolean flag = worldIn.getBlockState(blockpos).isFullyOpaque() || worldIn.getBlockState(blockpos).getBlock() == Blocks.GLOWSTONE;
if(flag && canConnectUpwardsTo(worldIn.getBlockState(blockpos.up()))) {
if(iblockstate.isBlockNormalCube()) {
return BlockRedstoneWire.EnumAttachPosition.UP;
}
return BlockRedstoneWire.EnumAttachPosition.SIDE;
}
}
return BlockRedstoneWire.EnumAttachPosition.NONE;
} else {
return BlockRedstoneWire.EnumAttachPosition.SIDE;
}
}
@Nullable
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos) {
return NULL_AABB;
}
public boolean isOpaqueCube(IBlockState state) {
return false;
}
public boolean isFullCube(IBlockState state) {
return false;
}
public boolean canPlaceBlockAt(World worldIn, BlockPos pos) {
return worldIn.getBlockState(pos.down()).isFullyOpaque() || worldIn.getBlockState(pos.down()).getBlock() == Blocks.GLOWSTONE;
}
/**
* Recalculates all surrounding wires and causes all needed updates
*
* @author panda
*
* @param worldIn World
* @param pos Position that needs updating
*/
private void updateSurroundingRedstone(World worldIn, BlockPos pos) {
// Recalculate the connected wires
calculateCurrentChanges(worldIn, pos);
// Set to collect all the updates, to only execute them once. Ordering required.
Set<BlockPos> blocksNeedingUpdate = Sets.newLinkedHashSet();
// Add the needed updates
for (BlockPos posi : updatedRedstoneWire) {
addBlocksNeedingUpdate(worldIn, posi, blocksNeedingUpdate);
}
// Add all other updates to keep known behaviors
// They are added in a backwards order because it preserves a commonly used behavior with the update order
Iterator<BlockPos> it = Lists.<BlockPos>newLinkedList(updatedRedstoneWire).descendingIterator();
while (it.hasNext()) {
addAllSurroundingBlocks(it.next(), blocksNeedingUpdate);
}
// Remove updates on the wires as they just were updated
blocksNeedingUpdate.removeAll(updatedRedstoneWire);
/* Avoid unnecessary updates on the just updated wires
* A huge scale test showed about 40% more ticks per second
* It's probably less in normal usage but likely still worth it
*/
updatedRedstoneWire.clear();
// Execute updates
for (BlockPos posi : blocksNeedingUpdate) {
worldIn.notifyBlockOfStateChange(posi, this);
}
}
/**
* Turns on or off all connected wires
*
* @param worldIn World
* @param position Position of the wire that received the update
*/
private void calculateCurrentChanges(World worldIn, BlockPos position) {
// Turn off all connected wires first if needed
if (worldIn.getBlockState(position).getBlock() == this) {
turnOff.add(position);
} else {
// In case this wire was removed, check the surrounding wires
checkSurroundingWires(worldIn, position);
}
while (!turnOff.isEmpty()) {
BlockPos pos = turnOff.remove(0);
IBlockState state = worldIn.getBlockState(pos);
int oldPower = ((Integer)state.getValue(POWER)).intValue();
this.canProvidePower = false;
int blockPower = worldIn.isBlockIndirectlyGettingPowered(pos);
this.canProvidePower = true;
int wirePower = getSurroundingWirePower(worldIn, pos);
// Lower the strength as it moved a block
wirePower--;
int newPower = Math.max(blockPower, wirePower);
// Power lowered?
if (newPower < oldPower) {
// If it's still powered by a direct source (but weaker) mark for turn on
if (blockPower > 0 && !turnOn.contains(pos)) {
turnOn.add(pos);
}
// Set all the way to off for now, because wires that were powered by this need to update first
setWireState(worldIn, pos, state, 0);
// Power rose?
} else if (newPower > oldPower) {
// Set new Power
setWireState(worldIn, pos, state, newPower);
}
// Check if surrounding wires need to change based on the current/new state and add them to the lists
checkSurroundingWires(worldIn, pos);
}
// Now all needed wires are turned off. Time to turn them on again if there is a power source.
while (!turnOn.isEmpty()) {
BlockPos pos = turnOn.remove(0);
IBlockState state = worldIn.getBlockState(pos);
int oldPower = ((Integer)state.getValue(POWER)).intValue();
this.canProvidePower = false;
int blockPower = worldIn.isBlockIndirectlyGettingPowered(pos);
this.canProvidePower = true;
int wirePower = getSurroundingWirePower(worldIn, pos);
// Lower the strength as it moved a block
wirePower--;
int newPower = Math.max(blockPower, wirePower);
if (newPower > oldPower) {
setWireState(worldIn, pos, state, newPower);
} else if (newPower < oldPower) {
// Add warning
}
// Check if surrounding wires need to change based on the current/new state and add them to the lists
checkSurroundingWires(worldIn, pos);
}
turnOff.clear();
turnOn.clear();
}
/**
* Checks if an wire needs to be marked for update depending on the power next to it
*
* @author panda
*
* @param worldIn World
* @param pos Position of the wire that might need to change
* @param otherPower Power of the wire next to it
*/
private void addWireToList(World worldIn, BlockPos pos, int otherPower) {
IBlockState state = worldIn.getBlockState(pos);
if (state.getBlock() == this) {
int power = ((Integer)state.getValue(POWER)).intValue();
// Could get powered stronger by the neighbor?
if (power < (otherPower-1) && !turnOn.contains(pos)) {
// Mark for turn on check.
turnOn.add(pos);
}
// Should have powered the neighbor? Probably was powered by it and is in turn off phase.
if (power > otherPower && !turnOff.contains(pos)) {
// Mark for turn off check.
turnOff.add(pos);
}
}
}
/**
* Checks if the wires around need to get updated depending on this wires state.
* Checks all wires below before the same layer before on top to keep
* some more rotational symmetry around the y-axis.
*
* @author panda
*
* @param worldIn World
* @param pos Position of the wire
*/
private void checkSurroundingWires(World worldIn, BlockPos pos) {
IBlockState state = worldIn.getBlockState(pos);
int ownPower = 0;
if (state.getBlock() == this) {
ownPower = ((Integer)state.getValue(POWER)).intValue();
}
// Check wires on the same layer first as they appear closer to the wire
for (EnumFacing facing : facingsHorizontal) {
BlockPos offsetPos = pos.offset(facing);
if (facing.getAxis().isHorizontal()) {
addWireToList(worldIn, offsetPos, ownPower);
}
}
for (EnumFacing facingVertical : facingsVertical) {
BlockPos offsetPos = pos.offset(facingVertical);
boolean solidBlock = worldIn.getBlockState(offsetPos).isBlockNormalCube();
for (EnumFacing facingHorizontal : facingsHorizontal) {
// wire can travel upwards if the block on top doesn't cut the wire (is non-solid)
// it can travel down if the block below is solid and the block "diagonal" doesn't cut off the wire (is non-solid)
if ((facingVertical == EnumFacing.UP && !solidBlock) || (facingVertical == EnumFacing.DOWN && solidBlock && !worldIn.getBlockState(offsetPos.offset(facingHorizontal)).isBlockNormalCube())) {
addWireToList(worldIn, offsetPos.offset(facingHorizontal), ownPower);
}
}
}
}
/**
* Gets the maximum power of the surrounding wires
*
* @author panda
*
* @param worldIn World
* @param pos Position of the asking wire
* @return The maximum power of the wires that could power the wire at pos
*/
private int getSurroundingWirePower(World worldIn, BlockPos pos) {
int wirePower = 0;
for(EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) {
BlockPos offsetPos = pos.offset(enumfacing);
// Wires on the same layer
wirePower = this.getMaxCurrentStrength(worldIn, offsetPos, wirePower);
// Block below the wire need to be solid (Upwards diode of slabs/stairs/glowstone) and no block should cut the wire
if(worldIn.getBlockState(offsetPos).isNormalCube() && !worldIn.getBlockState(pos.up()).isNormalCube()) {
wirePower = this.getMaxCurrentStrength(worldIn, offsetPos.up(), wirePower);
// Only get from power below if no block is cutting the wire
} else if(!worldIn.getBlockState(offsetPos).isNormalCube()) {
wirePower = this.getMaxCurrentStrength(worldIn, offsetPos.down(), wirePower);
}
}
return wirePower;
}
/**
* Adds all blocks that need to receive an update from a redstone change in this position.
* This means only blocks that actually could change.
*
* @author panda
*
* @param worldIn World
* @param pos Position of the wire
* @param set Set to add the update positions too
*/
private void addBlocksNeedingUpdate(World worldIn, BlockPos pos, Set<BlockPos> set) {
List<EnumFacing> connectedSides = getSidesToPower(worldIn, pos);
BlockPos offsetPos2;
// Add the blocks next to the wire first (closest first order)
for (EnumFacing facing : facings) {
BlockPos offsetPos = pos.offset(facing);
// canConnectTo() is not the nicest solution here as it returns true for e.g. the front of a repeater
// canBlockBePowereFromSide catches these cases
if (connectedSides.contains(facing.getOpposite()) || facing == EnumFacing.DOWN || (facing.getAxis().isHorizontal() && canConnectTo(worldIn.getBlockState(offsetPos), facing))) {
if (canBlockBePoweredFromSide(worldIn.getBlockState(offsetPos), facing, true)) set.add(offsetPos);
}
}
// Later add blocks around the surrounding blocks that get powered
for (EnumFacing facing : facings) {
BlockPos offsetPos = pos.offset(facing);
if (connectedSides.contains(facing.getOpposite()) || facing == EnumFacing.DOWN) {
if (worldIn.getBlockState(offsetPos).isNormalCube()) {
for (EnumFacing facing1 : facings) {
if (canBlockBePoweredFromSide(worldIn.getBlockState(offsetPos.offset(facing1)), facing1, false)) set.add(offsetPos.offset(facing1));
}
}
}
}
}
/**
* Checks if a block can get powered from a side.
* This behavior would better be implemented per block type as follows:
* - return false as default. (blocks that are not affected by redstone don't need to be updated, it doesn't really hurt if they are either)
* - return true for all blocks that can get powered from all side and change based on it (doors, fence gates, trap doors, note blocks, lamps, dropper, hopper, TNT, rails, possibly more)
* - implement own logic for pistons, repeaters, comparators and redstone torches
* The current implementation was chosen to keep everything in one class.
*
* Why is this extra check needed?
* 1. It makes sure that many old behaviors still work (QC + Pistons).
* 2. It prevents updates from "jumping".
* Or rather it prevents this wire to update a block that would get powered by the next one of the same line.
* This is to prefer as it makes understanding the update order of the wire really easy. The signal "travels" from the power source.
*
* @author panda
*
* @param state State of the block
* @param side Side from which it gets powered
* @param isWire True if it's powered by a wire directly, False if through a block
* @return True if the block can change based on the power level it gets on the given side, false otherwise
*/
private boolean canBlockBePoweredFromSide(IBlockState state, EnumFacing side, boolean isWire) {
if (state.getBlock() instanceof BlockPistonBase && state.getValue(BlockPistonBase.FACING) == side.getOpposite()) return false;
if (state.getBlock() instanceof BlockRedstoneDiode && state.getValue(BlockRedstoneDiode.FACING) != side.getOpposite()) {
if (isWire && state.getBlock() instanceof BlockRedstoneComparator && state.getValue(BlockRedstoneComparator.FACING).getAxis() != side.getAxis() && side.getAxis().isHorizontal()) return true;
return false;
}
if (state.getBlock() instanceof BlockRedstoneTorch) {
if (isWire || state.getValue(BlockRedstoneTorch.FACING) != side) return false;
}
return true;
}
/**
* Creates a list of all horizontal sides that can get powered by a wire.
* The list is ordered the same as the facingsHorizontal.
*
* @param worldIn World
* @param pos Position of the wire
* @return List of all facings that can get powered by this wire
*/
private List<EnumFacing> getSidesToPower(World worldIn, BlockPos pos) {
List retval = Lists.<EnumFacing>newArrayList();
for (EnumFacing facing : facingsHorizontal) {
if (isPowerSourceAt(worldIn, pos, facing)) retval.add(facing);
}
if (retval.isEmpty()) return Lists.<EnumFacing>newArrayList(facingsHorizontal);
boolean northsouth = retval.contains(EnumFacing.NORTH) || retval.contains(EnumFacing.SOUTH);
boolean eastwest = retval.contains(EnumFacing.EAST) || retval.contains(EnumFacing.WEST);
if (northsouth) {
retval.remove(EnumFacing.EAST);
retval.remove(EnumFacing.WEST);
}
if (eastwest) {
retval.remove(EnumFacing.NORTH);
retval.remove(EnumFacing.SOUTH);
}
return retval;
}
/**
* Adds all surrounding positions to a set.
* This is the neighbor blocks, as well as their neighbors
*
* @param pos
* @param set
*/
private void addAllSurroundingBlocks(BlockPos pos, Set<BlockPos> set) {
for (Vec3i vect : surroundingBlocksOffset) {
set.add(pos.add(vect));
}
}
/**
* Sets the block state of a wire with a new power level and marks for updates
*
* @author panda
*
* @param worldIn World
* @param pos Position at which the state needs to be set
* @param state Old state
* @param power Power it should get set to
*/
private void setWireState(World worldIn, BlockPos pos, IBlockState state, int power) {
state = state.withProperty(POWER, Integer.valueOf(power));
worldIn.setBlockState(pos, state, 2);
updatedRedstoneWire.add(pos);
}
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) {
if(!worldIn.isRemote) {
this.updateSurroundingRedstone(worldIn, pos);
for (Vec3i vec : surroundingBlocksOffset) {
worldIn.notifyBlockOfStateChange(pos.add(vec), this);
}
}
}
public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
super.breakBlock(worldIn, pos, state);
if(!worldIn.isRemote) {
this.updateSurroundingRedstone(worldIn, pos);
for (Vec3i vec : surroundingBlocksOffset) {
worldIn.notifyBlockOfStateChange(pos.add(vec), this);
}
}
}
private int getMaxCurrentStrength(World worldIn, BlockPos pos, int strength) {
if(worldIn.getBlockState(pos).getBlock() != this) {
return strength;
} else {
int i = ((Integer)worldIn.getBlockState(pos).getValue(POWER)).intValue();
return i > strength?i:strength;
}
}
public void func_189540_a(IBlockState p_189540_1_, World p_189540_2_, BlockPos p_189540_3_, Block p_189540_4_) {
if(!p_189540_2_.isRemote) {
if(this.canPlaceBlockAt(p_189540_2_, p_189540_3_)) {
this.updateSurroundingRedstone(p_189540_2_, p_189540_3_);
} else {
this.dropBlockAsItem(p_189540_2_, p_189540_3_, p_189540_1_, 0);
p_189540_2_.setBlockToAir(p_189540_3_);
}
}
}
@Nullable
public Item getItemDropped(IBlockState state, Random rand, int fortune) {
return Items.REDSTONE;
}
public int getStrongPower(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) {
return !this.canProvidePower?0:blockState.getWeakPower(blockAccess, pos, side);
}
public int getWeakPower(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) {
if(!this.canProvidePower) {
return 0;
} else {
// Changed implementation to use getSidesToPower() to avoid duplicate implementation
if (side == EnumFacing.UP || getSidesToPower((World)blockAccess, pos).contains(side)) {
return ((Integer)blockState.getValue(POWER)).intValue();
} else {
return 0;
}
}
}
private boolean isPowerSourceAt(IBlockAccess worldIn, BlockPos pos, EnumFacing side) {
BlockPos blockpos = pos.offset(side);
IBlockState iblockstate = worldIn.getBlockState(blockpos);
boolean flag = iblockstate.isNormalCube();
boolean flag1 = worldIn.getBlockState(pos.up()).isNormalCube();
return !flag1 && flag && canConnectUpwardsTo(worldIn, blockpos.up())?true:(canConnectTo(iblockstate, side)?true:(iblockstate.getBlock() == Blocks.POWERED_REPEATER && iblockstate.getValue(BlockRedstoneDiode.FACING) == side?true:!flag && canConnectUpwardsTo(worldIn, blockpos.down())));
}
protected static boolean canConnectUpwardsTo(IBlockAccess worldIn, BlockPos pos) {
return canConnectUpwardsTo(worldIn.getBlockState(pos));
}
protected static boolean canConnectUpwardsTo(IBlockState state) {
return canConnectTo(state, (EnumFacing)null);
}
protected static boolean canConnectTo(IBlockState blockState, @Nullable EnumFacing side) {
Block block = blockState.getBlock();
if(block == Blocks.REDSTONE_WIRE) {
return true;
} else if(Blocks.UNPOWERED_REPEATER.isSameDiode(blockState)) {
EnumFacing enumfacing = (EnumFacing)blockState.getValue(BlockRedstoneRepeater.FACING);
return enumfacing == side || enumfacing.getOpposite() == side;
} else {
return blockState.canProvidePower() && side != null;
}
}
public boolean canProvidePower(IBlockState state) {
return this.canProvidePower;
}
public static int colorMultiplier(int p_176337_0_) {
float f = (float)p_176337_0_ / 15.0F;
float f1 = f * 0.6F + 0.4F;
if(p_176337_0_ == 0) {
f1 = 0.3F;
}
float f2 = f * f * 0.7F - 0.5F;
float f3 = f * f * 0.6F - 0.7F;
if(f2 < 0.0F) {
f2 = 0.0F;
}
if(f3 < 0.0F) {
f3 = 0.0F;
}
int i = MathHelper.clamp_int((int)(f1 * 255.0F), 0, 255);
int j = MathHelper.clamp_int((int)(f2 * 255.0F), 0, 255);
int k = MathHelper.clamp_int((int)(f3 * 255.0F), 0, 255);
return -16777216 | i << 16 | j << 8 | k;
}
public void randomDisplayTick(IBlockState stateIn, World worldIn, BlockPos pos, Random rand) {
int i = ((Integer)stateIn.getValue(POWER)).intValue();
if(i != 0) {
double d0 = (double)pos.getX() + 0.5D + ((double)rand.nextFloat() - 0.5D) * 0.2D;
double d1 = (double)((float)pos.getY() + 0.0625F);
double d2 = (double)pos.getZ() + 0.5D + ((double)rand.nextFloat() - 0.5D) * 0.2D;
float f = (float)i / 15.0F;
float f1 = f * 0.6F + 0.4F;
float f2 = Math.max(0.0F, f * f * 0.7F - 0.5F);
float f3 = Math.max(0.0F, f * f * 0.6F - 0.7F);
worldIn.spawnParticle(EnumParticleTypes.REDSTONE, d0, d1, d2, (double)f1, (double)f2, (double)f3, new int[0]);
}
}
public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) {
return new ItemStack(Items.REDSTONE);
}
public BlockRenderLayer getBlockLayer() {
return BlockRenderLayer.CUTOUT;
}
public IBlockState getStateFromMeta(int meta) {
return this.getDefaultState().withProperty(POWER, Integer.valueOf(meta));
}
public int getMetaFromState(IBlockState state) {
return ((Integer)state.getValue(POWER)).intValue();
}
public IBlockState withRotation(IBlockState state, Rotation rot) {
switch(rot) {
case CLOCKWISE_180:
return state.withProperty(NORTH, state.getValue(SOUTH)).withProperty(EAST, state.getValue(WEST)).withProperty(SOUTH, state.getValue(NORTH)).withProperty(WEST, state.getValue(EAST));
case COUNTERCLOCKWISE_90:
return state.withProperty(NORTH, state.getValue(EAST)).withProperty(EAST, state.getValue(SOUTH)).withProperty(SOUTH, state.getValue(WEST)).withProperty(WEST, state.getValue(NORTH));
case CLOCKWISE_90:
return state.withProperty(NORTH, state.getValue(WEST)).withProperty(EAST, state.getValue(NORTH)).withProperty(SOUTH, state.getValue(EAST)).withProperty(WEST, state.getValue(SOUTH));
default:
return state;
}
}
public IBlockState withMirror(IBlockState state, Mirror mirrorIn) {
switch(mirrorIn) {
case LEFT_RIGHT:
return state.withProperty(NORTH, state.getValue(SOUTH)).withProperty(SOUTH, state.getValue(NORTH));
case FRONT_BACK:
return state.withProperty(EAST, state.getValue(WEST)).withProperty(WEST, state.getValue(EAST));
default:
return super.withMirror(state, mirrorIn);
}
}
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, new IProperty[]{NORTH, EAST, SOUTH, WEST, POWER});
}
static enum EnumAttachPosition implements IStringSerializable {
UP("up"),
SIDE("side"),
NONE("none");
private final String name;
private EnumAttachPosition(String name) {
this.name = name;
}
public String toString() {
return this.getName();
}
public String getName() {
return this.name;
}
}
}
@Lothrazar
Copy link

amazing!

@Dummyc0m
Copy link

Seriously, this seems like a simple logical fix that mojang should implement.

@professorg
Copy link

You should work for Mojang. Or Microsoft I guess...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment