Skip to content

Instantly share code, notes, and snippets.

@mtbarr
Created September 13, 2021 12:52
Show Gist options
  • Save mtbarr/14b6b60df851284e156f55221535fa90 to your computer and use it in GitHub Desktop.
Save mtbarr/14b6b60df851284e156f55221535fa90 to your computer and use it in GitHub Desktop.
package net.draconstudios.plugins.nms.v1_8_R3;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.draconstudios.plugins.nms.RedstoneReflectionUtil;
import net.minecraft.server.v1_8_R3.*;
import org.apache.commons.lang3.ArrayUtils;
import org.bukkit.event.block.BlockRedstoneEvent;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class LegacyOptimizedRedstoneWire extends BlockRedstoneWire {
private static final EnumDirection[] facingsHorizontal = {EnumDirection.WEST, EnumDirection.EAST, EnumDirection.NORTH, EnumDirection.SOUTH};
private static final EnumDirection[] facingsVertical = {EnumDirection.DOWN, EnumDirection.UP};
private static final EnumDirection[] facings = ArrayUtils.addAll(facingsVertical, facingsHorizontal);
private static final BaseBlockPosition[] surroundingBlocksOffset;
static {
Set<BaseBlockPosition> set = Sets.newLinkedHashSet();
for (EnumDirection facing : facings) {
set.add(RedstoneReflectionUtil.getOfT(facing, BaseBlockPosition.class));
}
for (EnumDirection facing1 : facings) {
BaseBlockPosition v1 = RedstoneReflectionUtil.getOfT(facing1, BaseBlockPosition.class);
for (EnumDirection facing2 : facings) {
BaseBlockPosition v2 = RedstoneReflectionUtil.getOfT(facing2, BaseBlockPosition.class);
set.add(new BlockPosition(v1.getX() + v2.getX(), v1.getY() + v2.getY(), v1.getZ() + v2.getZ()));
}
}
set.remove(BlockPosition.ZERO);
surroundingBlocksOffset = set.toArray(new BaseBlockPosition[set.size()]);
}
private Set<BlockPosition> turnOff = Sets.newLinkedHashSet();
private Set<BlockPosition> turnOn = Sets.newLinkedHashSet();
private final Set<BlockPosition> updatedRedstoneWire = Sets.newLinkedHashSet();
private boolean g = true;
public LegacyOptimizedRedstoneWire() {
c(0.0F);
a(Block.e);
c("redstoneDust");
K();
}
@Override
public int a(final IBlockAccess iblockaccess, final BlockPosition blockposition, final IBlockData iblockdata, final EnumDirection enumdirection) {
if (!this.g) {
return 0;
}
int i = iblockdata.get(BlockRedstoneWire.POWER);
if (i == 0) {
return 0;
}
if (enumdirection == EnumDirection.UP) {
return i;
}
if (getSidesToPower((World) iblockaccess, blockposition).contains(enumdirection)) {
return i;
}
return 0;
}
private void addAllSurroundingBlocks(final BlockPosition pos, final Set<BlockPosition> set) {
for (BaseBlockPosition vect : surroundingBlocksOffset) {
set.add(pos.a(vect));
}
}
private void addBlocksNeedingUpdate(final World worldIn, final BlockPosition pos, final Set<BlockPosition> set) {
List<EnumDirection> connectedSides = getSidesToPower(worldIn, pos);
for (EnumDirection facing : facings) {
BlockPosition offsetPos = pos.shift(facing);
if (((connectedSides.contains(facing.opposite())) || (facing == EnumDirection.DOWN) || ((facing.k().c()) && (a(worldIn.getType(offsetPos), facing)))) &&
(canBlockBePoweredFromSide(worldIn.getType(offsetPos), facing, true))) {
set.add(offsetPos);
}
}
for (EnumDirection facing : facings) {
BlockPosition offsetPos = pos.shift(facing);
if (((connectedSides.contains(facing.opposite())) || (facing == EnumDirection.DOWN)) &&
(worldIn.getType(offsetPos).getBlock().isOccluding())) {
for (EnumDirection facing1 : facings) {
if (canBlockBePoweredFromSide(worldIn.getType(offsetPos.shift(facing1)), facing1, false)) {
set.add(offsetPos.shift(facing1));
}
}
}
}
}
private void addWireToList(final World worldIn, final BlockPosition pos, final int otherPower) {
final IBlockData state = worldIn.getType(pos);
if (state.getBlock() == this) {
int power = state.get(POWER);
if ((power < otherPower - 1) && (!this.turnOn.contains(pos))) {
this.turnOn.add(pos);
}
if ((power > otherPower) && (!this.turnOff.contains(pos))) {
this.turnOff.add(pos);
}
}
}
private void calculateCurrentChanges(final World world, final BlockPosition blockposition) {
if (world.getType(blockposition).getBlock() == this) {
this.turnOff.add(blockposition);
} else {
checkSurroundingWires(world, blockposition);
}
while (!this.turnOff.isEmpty()) {
Iterator<BlockPosition> iter = this.turnOff.iterator();
final BlockPosition pos = iter.next();
iter.remove();
IBlockData state = world.getType(pos);
int oldPower = state.get(POWER);
this.g = false;
int blockPower = world.A(pos);
this.g = true;
int wirePower = getSurroundingWirePower(world, pos);
wirePower--;
int newPower = Math.max(blockPower, wirePower);
if (newPower < oldPower) {
if ((blockPower > 0) && (!this.turnOn.contains(pos))) {
this.turnOn.add(pos);
}
state = setWireState(world, pos, state, 0);
} else if (newPower > oldPower) {
state = setWireState(world, pos, state, newPower);
}
checkSurroundingWires(world, pos);
}
while (!this.turnOn.isEmpty()) {
Iterator<BlockPosition> iter = this.turnOn.iterator();
final BlockPosition pos = iter.next();
iter.remove();
IBlockData state = world.getType(pos);
int oldPower = state.get(POWER);
this.g = false;
int blockPower = world.A(pos);
this.g = true;
int wirePower = getSurroundingWirePower(world, pos);
wirePower--;
int newPower = Math.max(blockPower, wirePower);
if (oldPower != newPower) {
BlockRedstoneEvent event = new BlockRedstoneEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), oldPower, newPower);
world.getServer().getPluginManager().callEvent(event);
newPower = event.getNewCurrent();
}
if (newPower > oldPower) {
state = setWireState(world, pos, state, newPower);
}
checkSurroundingWires(world, pos);
}
this.turnOff.clear();
this.turnOn.clear();
}
private boolean canBlockBePoweredFromSide(final IBlockData state, final EnumDirection side, final boolean isWire) {
if (((state.getBlock() instanceof BlockPiston)) && (state.get(BlockPiston.FACING) == side.opposite())) {
return false;
}
if (((state.getBlock() instanceof BlockDiodeAbstract)) && (state.get(BlockDirectional.FACING) != side.opposite())) {
if ((isWire) && ((state.getBlock() instanceof BlockRedstoneComparator)) && (state.get(BlockDirectional.FACING).k() != side.k()) && (side.k().c())) {
return true;
}
return false;
}
if (((state.getBlock() instanceof BlockRedstoneTorch)) && ((isWire) || (state.get(BlockTorch.FACING) != side))) {
return false;
}
return true;
}
private void checkSurroundingWires(final World worldIn, final BlockPosition pos) {
final IBlockData state = worldIn.getType(pos);
int ownPower = 0;
if (state.getBlock() == this) {
ownPower = state.get(POWER);
}
for (EnumDirection facing : facingsHorizontal) {
BlockPosition offsetPos = pos.shift(facing);
if (facing.k().c()) {
addWireToList(worldIn, offsetPos, ownPower);
}
}
for (EnumDirection facingVertical : facingsVertical) {
BlockPosition offsetPos = pos.shift(facingVertical);
boolean solidBlock = worldIn.getType(offsetPos).getBlock().u();
for (EnumDirection facingHorizontal : facingsHorizontal) {
if (((facingVertical == EnumDirection.UP) && (!solidBlock))
|| ((facingVertical == EnumDirection.DOWN) && (solidBlock) && (!worldIn.getType(offsetPos.shift(facingHorizontal)).getBlock().isOccluding()))) {
addWireToList(worldIn, offsetPos.shift(facingHorizontal), ownPower);
}
}
}
}
private boolean d(final IBlockAccess iblockaccess, final BlockPosition blockposition, final EnumDirection enumdirection) {
BlockPosition blockposition1 = blockposition.shift(enumdirection);
IBlockData iblockdata = iblockaccess.getType(blockposition1);
Block block = iblockdata.getBlock();
boolean blockisOccluding = block.isOccluding();
boolean upBlockisOccluding = iblockaccess.getType(blockposition.up()).getBlock().isOccluding();
return (!upBlockisOccluding) && (blockisOccluding) && (e(iblockaccess, blockposition1.up()));
}
@Override
public void doPhysics(final World world, final BlockPosition blockposition, final IBlockData iblockdata, final Block block) {
if (!world.isClientSide) {
if (canPlace(world, blockposition)) {
e(world, blockposition, iblockdata);
} else {
b(world, blockposition, iblockdata, 0);
world.setAir(blockposition);
}
}
}
private void e(final World world, final BlockPosition blockposition, final IBlockData iblockdata) {
calculateCurrentChanges(world, blockposition);
Set<BlockPosition> blocksNeedingUpdate = Sets.newLinkedHashSet();
Iterator<BlockPosition> iterator = this.updatedRedstoneWire.iterator();
while (iterator.hasNext()) {
addBlocksNeedingUpdate(world, iterator.next(), blocksNeedingUpdate);
}
Iterator<BlockPosition> blockPositionIterator = Lists.newLinkedList(this.updatedRedstoneWire).descendingIterator();
while (blockPositionIterator.hasNext()) {
addAllSurroundingBlocks(blockPositionIterator.next(), blocksNeedingUpdate);
}
blocksNeedingUpdate.removeAll(this.updatedRedstoneWire);
this.updatedRedstoneWire.clear();
for (BlockPosition pos : blocksNeedingUpdate) {
world.d(pos, this);
}
}
private List<EnumDirection> getSidesToPower(final World worldIn, final BlockPosition pos) {
List<EnumDirection> retval = Lists.newArrayList();
for (EnumDirection facing : facingsHorizontal) {
if (d(worldIn, pos, facing)) {
retval.add(facing);
}
}
if (retval.isEmpty()) {
return Lists.newArrayList(facingsHorizontal);
}
boolean northsouth = (retval.contains(EnumDirection.NORTH)) || (retval.contains(EnumDirection.SOUTH));
boolean eastwest = (retval.contains(EnumDirection.EAST)) || (retval.contains(EnumDirection.WEST));
if (northsouth) {
retval.remove(EnumDirection.EAST);
retval.remove(EnumDirection.WEST);
}
if (eastwest) {
retval.remove(EnumDirection.NORTH);
retval.remove(EnumDirection.SOUTH);
}
return retval;
}
private int getSurroundingWirePower(final World worldIn, final BlockPosition pos) {
int wirePower = 0;
for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
BlockPosition offsetPos = pos.shift(enumfacing);
wirePower = getPower(worldIn, offsetPos, wirePower);
if ((worldIn.getType(offsetPos).getBlock().isOccluding()) && (!worldIn.getType(pos.up()).getBlock().isOccluding())) {
wirePower = getPower(worldIn, offsetPos.up(), wirePower);
} else if (!worldIn.getType(offsetPos).getBlock().isOccluding()) {
wirePower = getPower(worldIn, offsetPos.down(), wirePower);
}
}
return wirePower;
}
@Override
public void onPlace(final World world, final BlockPosition blockposition, final IBlockData iblockdata) {
if (!world.isClientSide) {
e(world, blockposition, iblockdata);
for (EnumDirection enumDirection : EnumDirection.EnumDirectionLimit.VERTICAL) {
world.applyPhysics(blockposition.shift(enumDirection), this);
}
for (EnumDirection enumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
b(world, blockposition.shift(enumDirection));
}
for (EnumDirection enumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
BlockPosition blockposition1 = blockposition.shift(enumDirection);
if (world.getType(blockposition1).getBlock().isOccluding()) {
b(world, blockposition1.up());
} else {
b(world, blockposition1.down());
}
}
}
}
@Override
public void remove(final World world, final BlockPosition blockposition, final IBlockData iblockdata) {
super.remove(world, blockposition, iblockdata);
if (!world.isClientSide) {
EnumDirection[] aenumdirection = EnumDirection.values();
int i = aenumdirection.length;
for (int j = 0; j < i; j++) {
EnumDirection enumdirection = aenumdirection[j];
world.applyPhysics(blockposition.shift(enumdirection), this);
}
e(world, blockposition, iblockdata);
for (EnumDirection enumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
b(world, blockposition.shift(enumDirection));
}
for (EnumDirection enumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
BlockPosition blockposition1 = blockposition.shift(enumDirection);
if (world.getType(blockposition1).getBlock().isOccluding()) {
b(world, blockposition1.up());
} else {
b(world, blockposition1.down());
}
}
}
}
private IBlockData setWireState(final World worldIn, final BlockPosition pos, IBlockData state, final int power) {
state = state.set(POWER, power);
worldIn.setTypeAndData(pos, state, 2);
this.updatedRedstoneWire.add(pos);
return state;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment