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 java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.Set; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; import net.minecraft.util.debug.DebugSubscriptions; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; 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.Property; import net.minecraft.world.level.block.state.properties.RedstoneSide; import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.level.redstone.RedstoneWireEvaluator; import org.jspecify.annotations.Nullable; // FIX minecraft-0003: companion HashSets for O(1) membership in wiresToTurnOn/Off queues // Previously: Deque.contains() O(N) → O(N²) BFS for N-wire networks @SuppressWarnings({"unchecked", "rawtypes"}) public class ExperimentalRedstoneWireEvaluator extends RedstoneWireEvaluator { private final Deque wiresToTurnOff = new ArrayDeque(); private final Set wiresToTurnOffSet = new HashSet<>(); // FIX: O(1) contains private final Deque wiresToTurnOn = new ArrayDeque(); private final Set wiresToTurnOnSet = new HashSet<>(); // FIX: O(1) contains private final Object2IntMap updatedWires = new Object2IntLinkedOpenHashMap(); public ExperimentalRedstoneWireEvaluator(RedStoneWireBlock wireBlock) { super(wireBlock); } public void updatePowerStrength(Level level, BlockPos initialPos, BlockState ignored, @Nullable Orientation orientation, boolean shapeUpdateWiresAroundInitialPosition) { Orientation initialOrientation = ExperimentalRedstoneWireEvaluator.getInitialOrientation(level, orientation); this.calculateCurrentChanges(level, initialPos, initialOrientation); ObjectIterator iterator = this.updatedWires.object2IntEntrySet().iterator(); boolean initialWire = true; while (iterator.hasNext()) { Object2IntMap.Entry next = (Object2IntMap.Entry)iterator.next(); BlockPos pos = (BlockPos)next.getKey(); int packed = next.getIntValue(); int newLevel = ExperimentalRedstoneWireEvaluator.unpackPower(packed); BlockState state = level.getBlockState(pos); if (state.is(this.wireBlock) && !((Integer)state.getValue((Property)RedStoneWireBlock.POWER)).equals(newLevel)) { int updateFlags = 2; if (!shapeUpdateWiresAroundInitialPosition || !initialWire) { updateFlags |= 0x80; } level.setBlock(pos, (BlockState)state.setValue((Property)RedStoneWireBlock.POWER, (Comparable)Integer.valueOf(newLevel)), updateFlags); } else { iterator.remove(); } initialWire = false; } this.causeNeighborUpdates(level); } private void causeNeighborUpdates(Level level) { this.updatedWires.forEach((wirePos, packed) -> { Orientation orientation = ExperimentalRedstoneWireEvaluator.unpackOrientation(packed); BlockState state = level.getBlockState(wirePos); for (Direction neighborDirection : orientation.getDirections()) { if (!ExperimentalRedstoneWireEvaluator.isConnected(state, neighborDirection)) continue; BlockPos neighborPos = wirePos.relative(neighborDirection); BlockState neighborState = level.getBlockState(neighborPos); Orientation neighborOrientation = orientation.withFrontPreserveUp(neighborDirection); level.neighborChanged(neighborState, neighborPos, (Block)this.wireBlock, neighborOrientation, false); if (!neighborState.isRedstoneConductor((BlockGetter)level, neighborPos)) continue; for (Direction direction : neighborOrientation.getDirections()) { if (direction == neighborDirection.getOpposite()) continue; level.neighborChanged(neighborPos.relative(direction), (Block)this.wireBlock, neighborOrientation.withFrontPreserveUp(direction)); } } }); if (level instanceof ServerLevel serverLevel) { if (serverLevel.debugSynchronizers().hasAnySubscriberFor(DebugSubscriptions.REDSTONE_WIRE_ORIENTATIONS)) { this.updatedWires.forEach((wirePos, packed) -> serverLevel.debugSynchronizers().sendBlockValue(wirePos, DebugSubscriptions.REDSTONE_WIRE_ORIENTATIONS, ExperimentalRedstoneWireEvaluator.unpackOrientation(packed))); } } } private static boolean isConnected(BlockState state, Direction direction) { EnumProperty property = (EnumProperty)RedStoneWireBlock.PROPERTY_BY_DIRECTION.get(direction); if (property == null) { return direction == Direction.DOWN; } return ((RedstoneSide)state.getValue((Property)property)).isConnected(); } private static Orientation getInitialOrientation(Level level, @Nullable Orientation incomingOrigination) { Orientation orientation = incomingOrigination != null ? incomingOrigination : Orientation.random((RandomSource)level.getRandom()); return orientation.withUp(Direction.UP).withSideBias(Orientation.SideBias.LEFT); } private void calculateCurrentChanges(Level level, BlockPos initialPosition, Orientation initialOrientation) { BlockPos pos; BlockState initialState = level.getBlockState(initialPosition); if (initialState.is(this.wireBlock)) { this.setPower(initialPosition, (Integer)initialState.getValue((Property)RedStoneWireBlock.POWER), initialOrientation); this.wiresToTurnOff.add(initialPosition); this.wiresToTurnOffSet.add(initialPosition); // FIX } else { this.propagateChangeToNeighbors(level, initialPosition, 0, initialOrientation, true); } while (!this.wiresToTurnOff.isEmpty()) { int powerToSet; int wirePower; pos = this.wiresToTurnOff.removeFirst(); this.wiresToTurnOffSet.remove(pos); // FIX: keep set in sync int packed = this.updatedWires.getInt(pos); Orientation orientation = ExperimentalRedstoneWireEvaluator.unpackOrientation(packed); int oldPower = ExperimentalRedstoneWireEvaluator.unpackPower(packed); int blockPower = this.getBlockSignal(level, pos); int newPower = Math.max(blockPower, wirePower = this.getIncomingWireSignal(level, pos)); if (newPower < oldPower) { if (blockPower > 0 && !this.wiresToTurnOnSet.contains(pos)) { // FIX: O(1) this.wiresToTurnOn.add(pos); this.wiresToTurnOnSet.add(pos); // FIX } powerToSet = 0; } else { powerToSet = newPower; } if (powerToSet != oldPower) { this.setPower(pos, powerToSet, orientation); } this.propagateChangeToNeighbors(level, pos, powerToSet, orientation, oldPower > newPower); } while (!this.wiresToTurnOn.isEmpty()) { pos = this.wiresToTurnOn.removeFirst(); this.wiresToTurnOnSet.remove(pos); // FIX: keep set in sync int packed = this.updatedWires.getInt(pos); int oldPower = ExperimentalRedstoneWireEvaluator.unpackPower(packed); int blockPower = this.getBlockSignal(level, pos); int wirePower = this.getIncomingWireSignal(level, pos); int newPower = Math.max(blockPower, wirePower); Orientation orientation = ExperimentalRedstoneWireEvaluator.unpackOrientation(packed); if (newPower > oldPower) { this.setPower(pos, newPower, orientation); } else if (newPower < oldPower) { throw new IllegalStateException("Turning off wire while trying to turn it on. Should not happen."); } this.propagateChangeToNeighbors(level, pos, newPower, orientation, false); } } private static int packOrientationAndPower(Orientation orientation, int power) { return orientation.getIndex() << 4 | power; } private static Orientation unpackOrientation(int packed) { return Orientation.fromIndex((int)(packed >> 4)); } private static int unpackPower(int packed) { return packed & 0xF; } // FIX: replaced compute() lambda (raw-type incompatible) with explicit get+put private void setPower(BlockPos pos, int newPower, Orientation orientation) { int existing = this.updatedWires.getOrDefault(pos, -1); if (existing == -1) { this.updatedWires.put(pos, ExperimentalRedstoneWireEvaluator.packOrientationAndPower(orientation, newPower)); } else { this.updatedWires.put(pos, ExperimentalRedstoneWireEvaluator.packOrientationAndPower( ExperimentalRedstoneWireEvaluator.unpackOrientation(existing), newPower)); } } private void propagateChangeToNeighbors(Level level, BlockPos pos, int newPower, Orientation orientation, boolean allowTurningOff) { BlockPos offsetPos; for (Direction directionHorizontal : orientation.getHorizontalDirections()) { offsetPos = pos.relative(directionHorizontal); this.enqueueNeighborWire(level, offsetPos, newPower, orientation.withFront(directionHorizontal), allowTurningOff); } for (Direction directionVertical : orientation.getVerticalDirections()) { offsetPos = pos.relative(directionVertical); boolean solidBlock = level.getBlockState(offsetPos).isRedstoneConductor((BlockGetter)level, offsetPos); for (Direction directionHorizontal : orientation.getHorizontalDirections()) { BlockPos neighborWire; BlockPos neighbor = pos.relative(directionHorizontal); if (directionVertical == Direction.UP && !solidBlock) { neighborWire = offsetPos.relative(directionHorizontal); this.enqueueNeighborWire(level, neighborWire, newPower, orientation.withFront(directionHorizontal), allowTurningOff); continue; } if (directionVertical != Direction.DOWN || level.getBlockState(neighbor).isRedstoneConductor((BlockGetter)level, neighbor)) continue; neighborWire = offsetPos.relative(directionHorizontal); this.enqueueNeighborWire(level, neighborWire, newPower, orientation.withFront(directionHorizontal), allowTurningOff); } } } private void enqueueNeighborWire(Level level, BlockPos pos, int newFromPower, Orientation orientation, boolean allowTurningOff) { BlockState state = level.getBlockState(pos); if (state.is(this.wireBlock)) { int toPower = this.getWireSignal(pos, state); if (toPower < newFromPower - 1 && !this.wiresToTurnOnSet.contains(pos)) { // FIX: O(1) this.wiresToTurnOn.add(pos); this.wiresToTurnOnSet.add(pos); // FIX this.setPower(pos, toPower, orientation); } if (allowTurningOff && toPower > newFromPower && !this.wiresToTurnOffSet.contains(pos)) { // FIX: O(1) this.wiresToTurnOff.add(pos); this.wiresToTurnOffSet.add(pos); // FIX this.setPower(pos, toPower, orientation); } } } protected int getWireSignal(BlockPos pos, BlockState state) { int packed = this.updatedWires.getOrDefault(pos, -1); if (packed != -1) { return ExperimentalRedstoneWireEvaluator.unpackPower(packed); } return super.getWireSignal(pos, state); } }