210 lines
7.9 KiB
Java
210 lines
7.9 KiB
Java
package net.minecraft.world.level.redstone;
|
|
|
|
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
|
|
import java.util.ArrayDeque;
|
|
import java.util.Deque;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.RedStoneWireBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
|
import net.minecraft.world.level.block.state.properties.RedstoneSide;
|
|
import net.minecraft.world.level.redstone.Orientation.SideBias;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class ExperimentalRedstoneWireEvaluator extends RedstoneWireEvaluator {
|
|
private final Deque<BlockPos> wiresToTurnOff = new ArrayDeque();
|
|
private final Deque<BlockPos> wiresToTurnOn = new ArrayDeque();
|
|
private final Object2IntMap<BlockPos> updatedWires = new Object2IntLinkedOpenHashMap<>();
|
|
|
|
public ExperimentalRedstoneWireEvaluator(RedStoneWireBlock redStoneWireBlock) {
|
|
super(redStoneWireBlock);
|
|
}
|
|
|
|
@Override
|
|
public void updatePowerStrength(Level level, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean updateShape) {
|
|
Orientation orientation2 = getInitialOrientation(level, orientation);
|
|
this.calculateCurrentChanges(level, pos, orientation2);
|
|
ObjectIterator<Entry<BlockPos>> objectIterator = this.updatedWires.object2IntEntrySet().iterator();
|
|
|
|
for (boolean bl = true; objectIterator.hasNext(); bl = false) {
|
|
Entry<BlockPos> entry = (Entry<BlockPos>)objectIterator.next();
|
|
BlockPos blockPos = (BlockPos)entry.getKey();
|
|
int i = entry.getIntValue();
|
|
int j = unpackPower(i);
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
if (blockState.is(this.wireBlock) && !((Integer)blockState.getValue(RedStoneWireBlock.POWER)).equals(j)) {
|
|
int k = 2;
|
|
if (!updateShape || !bl) {
|
|
k |= 128;
|
|
}
|
|
|
|
level.setBlock(blockPos, blockState.setValue(RedStoneWireBlock.POWER, j), k);
|
|
} else {
|
|
objectIterator.remove();
|
|
}
|
|
}
|
|
|
|
this.causeNeighborUpdates(level);
|
|
}
|
|
|
|
private void causeNeighborUpdates(Level level) {
|
|
this.updatedWires.forEach((blockPos, integer) -> {
|
|
Orientation orientation = unpackOrientation(integer);
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
|
|
for (Direction direction : orientation.getDirections()) {
|
|
if (isConnected(blockState, direction)) {
|
|
BlockPos blockPos2 = blockPos.relative(direction);
|
|
BlockState blockState2 = level.getBlockState(blockPos2);
|
|
Orientation orientation2 = orientation.withFrontPreserveUp(direction);
|
|
level.neighborChanged(blockState2, blockPos2, this.wireBlock, orientation2, false);
|
|
if (blockState2.isRedstoneConductor(level, blockPos2)) {
|
|
for (Direction direction2 : orientation2.getDirections()) {
|
|
if (direction2 != direction.getOpposite()) {
|
|
level.neighborChanged(blockPos2.relative(direction2), this.wireBlock, orientation2.withFrontPreserveUp(direction2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static boolean isConnected(BlockState state, Direction direction) {
|
|
EnumProperty<RedstoneSide> enumProperty = (EnumProperty<RedstoneSide>)RedStoneWireBlock.PROPERTY_BY_DIRECTION.get(direction);
|
|
return enumProperty == null ? direction == Direction.DOWN : ((RedstoneSide)state.getValue(enumProperty)).isConnected();
|
|
}
|
|
|
|
private static Orientation getInitialOrientation(Level level, @Nullable Orientation orientation) {
|
|
Orientation orientation2;
|
|
if (orientation != null) {
|
|
orientation2 = orientation;
|
|
} else {
|
|
orientation2 = Orientation.random(level.random);
|
|
}
|
|
|
|
return orientation2.withUp(Direction.UP).withSideBias(SideBias.LEFT);
|
|
}
|
|
|
|
private void calculateCurrentChanges(Level level, BlockPos pos, Orientation orientation) {
|
|
BlockState blockState = level.getBlockState(pos);
|
|
if (blockState.is(this.wireBlock)) {
|
|
this.setPower(pos, (Integer)blockState.getValue(RedStoneWireBlock.POWER), orientation);
|
|
this.wiresToTurnOff.add(pos);
|
|
} else {
|
|
this.propagateChangeToNeighbors(level, pos, 0, orientation, true);
|
|
}
|
|
|
|
while (!this.wiresToTurnOff.isEmpty()) {
|
|
BlockPos blockPos = (BlockPos)this.wiresToTurnOff.removeFirst();
|
|
int i = this.updatedWires.getInt(blockPos);
|
|
Orientation orientation2 = unpackOrientation(i);
|
|
int j = unpackPower(i);
|
|
int k = this.getBlockSignal(level, blockPos);
|
|
int l = this.getIncomingWireSignal(level, blockPos);
|
|
int m = Math.max(k, l);
|
|
int n;
|
|
if (m < j) {
|
|
if (k > 0 && !this.wiresToTurnOn.contains(blockPos)) {
|
|
this.wiresToTurnOn.add(blockPos);
|
|
}
|
|
|
|
n = 0;
|
|
} else {
|
|
n = m;
|
|
}
|
|
|
|
if (n != j) {
|
|
this.setPower(blockPos, n, orientation2);
|
|
}
|
|
|
|
this.propagateChangeToNeighbors(level, blockPos, n, orientation2, j > m);
|
|
}
|
|
|
|
while (!this.wiresToTurnOn.isEmpty()) {
|
|
BlockPos blockPosx = (BlockPos)this.wiresToTurnOn.removeFirst();
|
|
int ix = this.updatedWires.getInt(blockPosx);
|
|
int o = unpackPower(ix);
|
|
int jx = this.getBlockSignal(level, blockPosx);
|
|
int kx = this.getIncomingWireSignal(level, blockPosx);
|
|
int lx = Math.max(jx, kx);
|
|
Orientation orientation3 = unpackOrientation(ix);
|
|
if (lx > o) {
|
|
this.setPower(blockPosx, lx, orientation3);
|
|
} else if (lx < o) {
|
|
throw new IllegalStateException("Turning off wire while trying to turn it on. Should not happen.");
|
|
}
|
|
|
|
this.propagateChangeToNeighbors(level, blockPosx, lx, orientation3, false);
|
|
}
|
|
}
|
|
|
|
private static int packOrientationAndPower(Orientation orientation, int power) {
|
|
return orientation.getIndex() << 4 | power;
|
|
}
|
|
|
|
private static Orientation unpackOrientation(int data) {
|
|
return Orientation.fromIndex(data >> 4);
|
|
}
|
|
|
|
private static int unpackPower(int data) {
|
|
return data & 15;
|
|
}
|
|
|
|
private void setPower(BlockPos pos, int power, Orientation orientation) {
|
|
this.updatedWires
|
|
.compute(
|
|
pos, (blockPos, integer) -> integer == null ? packOrientationAndPower(orientation, power) : packOrientationAndPower(unpackOrientation(integer), power)
|
|
);
|
|
}
|
|
|
|
private void propagateChangeToNeighbors(Level level, BlockPos pos, int power, Orientation orientation, boolean canTurnOff) {
|
|
for (Direction direction : orientation.getHorizontalDirections()) {
|
|
BlockPos blockPos = pos.relative(direction);
|
|
this.enqueueNeighborWire(level, blockPos, power, orientation.withFront(direction), canTurnOff);
|
|
}
|
|
|
|
for (Direction direction : orientation.getVerticalDirections()) {
|
|
BlockPos blockPos = pos.relative(direction);
|
|
boolean bl = level.getBlockState(blockPos).isRedstoneConductor(level, blockPos);
|
|
|
|
for (Direction direction2 : orientation.getHorizontalDirections()) {
|
|
BlockPos blockPos2 = pos.relative(direction2);
|
|
if (direction == Direction.UP && !bl) {
|
|
BlockPos blockPos3 = blockPos.relative(direction2);
|
|
this.enqueueNeighborWire(level, blockPos3, power, orientation.withFront(direction2), canTurnOff);
|
|
} else if (direction == Direction.DOWN && !level.getBlockState(blockPos2).isRedstoneConductor(level, blockPos2)) {
|
|
BlockPos blockPos3 = blockPos.relative(direction2);
|
|
this.enqueueNeighborWire(level, blockPos3, power, orientation.withFront(direction2), canTurnOff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void enqueueNeighborWire(Level level, BlockPos pos, int power, Orientation orientation, boolean canTurnOff) {
|
|
BlockState blockState = level.getBlockState(pos);
|
|
if (blockState.is(this.wireBlock)) {
|
|
int i = this.getWireSignal(pos, blockState);
|
|
if (i < power - 1 && !this.wiresToTurnOn.contains(pos)) {
|
|
this.wiresToTurnOn.add(pos);
|
|
this.setPower(pos, i, orientation);
|
|
}
|
|
|
|
if (canTurnOff && i > power && !this.wiresToTurnOff.contains(pos)) {
|
|
this.wiresToTurnOff.add(pos);
|
|
this.setPower(pos, i, orientation);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected int getWireSignal(BlockPos pos, BlockState state) {
|
|
int i = this.updatedWires.getOrDefault(pos, -1);
|
|
return i != -1 ? unpackPower(i) : super.getWireSignal(pos, state);
|
|
}
|
|
}
|