diff --git a/patches/unapplied/server/0994-Add-Alternate-Current-redstone-implementation.patch b/patches/server/1064-Add-Alternate-Current-redstone-implementation.patch similarity index 91% rename from patches/unapplied/server/0994-Add-Alternate-Current-redstone-implementation.patch rename to patches/server/1064-Add-Alternate-Current-redstone-implementation.patch index dc479927b8..afc78251b9 100644 --- a/patches/unapplied/server/0994-Add-Alternate-Current-redstone-implementation.patch +++ b/patches/server/1064-Add-Alternate-Current-redstone-implementation.patch @@ -22,7 +22,7 @@ Alternate Current's wire handler. diff --git a/src/main/java/alternate/current/wire/LevelHelper.java b/src/main/java/alternate/current/wire/LevelHelper.java new file mode 100644 -index 0000000000000000000000000000000000000000..8196460fe91bc4d1b03ca214d4323276d1d19464 +index 0000000000000000000000000000000000000000..eda108e2df9bf7d1ddd89287b8d2c2d7f1637c96 --- /dev/null +++ b/src/main/java/alternate/current/wire/LevelHelper.java @@ -0,0 +1,66 @@ @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..8196460fe91bc4d1b03ca214d4323276 + static boolean setWireState(ServerLevel level, BlockPos pos, BlockState state, boolean updateNeighborShapes) { + int y = pos.getY(); + -+ if (y < level.getMinBuildHeight() || y >= level.getMaxBuildHeight()) { ++ if (y < level.getMinY() || y >= level.getMaxY()) { + return false; + } + @@ -81,7 +81,7 @@ index 0000000000000000000000000000000000000000..8196460fe91bc4d1b03ca214d4323276 + // notify clients of the BlockState change + level.getChunkSource().blockChanged(pos); + // mark the chunk for saving -+ chunk.setUnsaved(true); ++ chunk.markUnsaved(); + + if (updateNeighborShapes) { + prevState.updateIndirectNeighbourShapes(level, pos, Block.UPDATE_CLIENTS); @@ -980,7 +980,7 @@ index 0000000000000000000000000000000000000000..4fd8cb29024330397cfe4cbc1f237d28 +} diff --git a/src/main/java/alternate/current/wire/WireConnectionManager.java b/src/main/java/alternate/current/wire/WireConnectionManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..c69dcf2b418a0a2f373425ea0dd7144fd2f33c87 +index 0000000000000000000000000000000000000000..f03b313e58385d626490a9e64c9616fd08aa951e --- /dev/null +++ b/src/main/java/alternate/current/wire/WireConnectionManager.java @@ -0,0 +1,134 @@ @@ -1111,7 +1111,7 @@ index 0000000000000000000000000000000000000000..c69dcf2b418a0a2f373425ea0dd7144f + * important. + */ + void forEach(Consumer consumer, UpdateOrder updateOrder, int iFlowDir) { -+ for (int iDir : updateOrder.cardinalNeighbors(iFlowDir)) { ++ for (int iDir : updateOrder.cardinalNeighbors(iFlowDir)) { + for (WireConnection c = heads[iDir]; c != null && c.iDir == iDir; c = c.next) { + consumer.accept(c); + } @@ -1120,15 +1120,14 @@ index 0000000000000000000000000000000000000000..c69dcf2b418a0a2f373425ea0dd7144f +} diff --git a/src/main/java/alternate/current/wire/WireHandler.java b/src/main/java/alternate/current/wire/WireHandler.java new file mode 100644 -index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b7922fccd573 +index 0000000000000000000000000000000000000000..259b301b2c8b64cb7974a235afb260e0e991af54 --- /dev/null +++ b/src/main/java/alternate/current/wire/WireHandler.java -@@ -0,0 +1,1053 @@ +@@ -0,0 +1,1073 @@ +package alternate.current.wire; + +import java.util.Iterator; +import java.util.Queue; -+import java.util.function.Consumer; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; @@ -1143,6 +1142,7 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.InstantNeighborUpdater; +import net.minecraft.world.level.redstone.NeighborUpdater; ++import net.minecraft.world.level.redstone.Orientation; +import net.minecraft.world.level.redstone.Redstone; + +/** @@ -1284,24 +1284,15 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + return iDir ^ (0b10 >>> (iDir >>> 2)); + } + -+ // Each array is placed at the index that encodes the direction that is missing -+ // from the array. -+ private static final int[][] I_EXCEPT = { -+ { NORTH, EAST, SOUTH, DOWN, UP }, -+ { WEST, EAST, SOUTH, DOWN, UP }, -+ { WEST, NORTH, SOUTH, DOWN, UP }, -+ { WEST, NORTH, EAST, DOWN, UP }, -+ { WEST, NORTH, EAST, SOUTH, UP }, -+ { WEST, NORTH, EAST, SOUTH, DOWN } -+ }; -+ private static final int[][] I_EXCEPT_CARDINAL = { -+ { NORTH, EAST, SOUTH }, -+ { WEST, EAST, SOUTH }, -+ { WEST, NORTH, SOUTH }, -+ { WEST, NORTH, EAST, }, -+ { WEST, NORTH, EAST, SOUTH }, -+ { WEST, NORTH, EAST, SOUTH } -+ }; ++ public static int index(Direction dir) { ++ for (int i = 0; i < ALL.length; i++) { ++ if (dir == ALL[i]) { ++ return i; ++ } ++ } ++ ++ return -1; ++ } + } + + /** @@ -1402,16 +1393,22 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + this.fillNodeCache(0, 16); + } + ++ private Node getOrAddNode(BlockPos pos) { ++ // just pass in null, then the state will only be retrieved ++ // if there is no node as this position yet ++ return getOrAddNode(pos, null); ++ } ++ + /** -+ * Retrieve the {@link Node Node} that represents the ++ * Retrieve the {@link alternate.current.wire.Node Node} that represents the + * block at the given position in the level. + */ -+ private Node getOrAddNode(BlockPos pos) { ++ private Node getOrAddNode(BlockPos pos, BlockState state) { + return nodes.compute(pos.asLong(), (key, node) -> { + if (node == null) { + // If there is not yet a node at this position, retrieve and + // update one from the cache. -+ return getNextNode(pos); ++ return getNextNode(pos, state != null ? state : level.getBlockState(pos)); + } + if (node.invalid) { + return revalidateNode(node); @@ -1422,7 +1419,7 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + } + + /** -+ * Remove and return the {@link Node Node} at the given ++ * Remove and return the {@link alternate.current.wire.Node Node} at the given + * position. + */ + private Node removeNode(BlockPos pos) { @@ -1430,17 +1427,9 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + } + + /** -+ * Return a {@link Node Node} that represents the block -+ * at the given position. -+ */ -+ private Node getNextNode(BlockPos pos) { -+ return getNextNode(pos, level.getBlockState(pos)); -+ } -+ -+ /** + * Return a node that represents the given position and block state. If it is a -+ * wire, then create a new {@link WireNode WireNode}. -+ * Otherwise, grab the next {@link Node Node} from the ++ * wire, then create a new {@link alternate.current.wire.WireNode WireNode}. ++ * Otherwise, grab the next {@link alternate.current.wire.Node Node} from the + * cache and update it. + */ + private Node getNextNode(BlockPos pos, BlockState state) { @@ -1483,6 +1472,10 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + * Otherwise, the node can be quickly revalidated with the new block state. + */ + private Node revalidateNode(Node node) { ++ if (!node.invalid) { ++ return node; ++ } ++ + BlockPos pos = node.pos; + BlockState state = level.getBlockState(pos); + @@ -1539,17 +1532,28 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + /** + * This method should be called whenever a wire receives a block update. + */ -+ public void onWireUpdated(BlockPos pos) { ++ public boolean onWireUpdated(BlockPos pos, BlockState state, Orientation orientation) { ++ Node node = getOrAddNode(pos, state); ++ ++ if (!node.isWire()) { ++ return false; // we should never get here ++ } ++ ++ WireNode wire = node.asWire(); ++ + invalidate(); -+ findRoots(pos); ++ revalidateNode(wire); ++ findRoots(wire, orientation); + tryUpdate(); ++ ++ return true; + } + + /** + * This method should be called whenever a wire is placed. + */ -+ public void onWireAdded(BlockPos pos) { -+ Node node = getOrAddNode(pos); ++ public void onWireAdded(BlockPos pos, BlockState state) { ++ Node node = getOrAddNode(pos, state); + + if (!node.isWire()) { + return; // we should never get here @@ -1641,15 +1645,19 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + * from multiple points at once, checking for common cases like the one + * described above is relatively straight-forward. + */ -+ private void findRoots(BlockPos pos) { -+ Node node = getOrAddNode(pos); ++ private void findRoots(WireNode wire, Orientation orientation) { ++ // horizontal direction bias for update order purposes ++ int iDirBias = -1; + -+ if (!node.isWire()) { -+ return; // we should never get here ++ if (orientation != null) { ++ Direction dir = orientation.getFront().getAxis().isHorizontal() ++ ? orientation.getFront() ++ : orientation.getUp(); ++ ++ iDirBias = Directions.index(dir); + } + -+ WireNode wire = node.asWire(); -+ findRoot(wire); ++ findRoot(wire, iDirBias); + + // If the wire at the given position is not in an invalid state + // we can exit early. @@ -1657,33 +1665,43 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + return; + } + -+ for (int iDir : updateOrder.directNeighbors(wire.iFlowDir)) { -+ Node neighbor = getNeighbor(wire, iDir); -+ -+ if (neighbor.isConductor() || neighbor.isSignalSource()) { -+ findRootsAround(neighbor, Directions.iOpposite(iDir)); ++ if (orientation == null) { ++ // no neighborChanged orientation present, look around in all sides ++ for (int iDir : updateOrder.directNeighbors(wire.iFlowDir)) { ++ findRootsAround(wire, iDir); + } ++ } else { ++ // use the orientation from the neighborChanged update to look for roots only behind ++ findRootsAround(wire, Directions.index(orientation.getFront().getOpposite())); + } + } + + /** -+ * Look for wires around the given node that require power changes. ++ * Look for wires around a neighbor of the given wire that require power changes. + */ -+ private void findRootsAround(Node node, int except) { -+ for (int iDir : Directions.I_EXCEPT_CARDINAL[except]) { -+ Node neighbor = getNeighbor(node, iDir); ++ private void findRootsAround(WireNode wire, int iDir) { ++ Node node = getNeighbor(wire, iDir); + -+ if (neighbor.isWire()) { -+ findRoot(neighbor.asWire()); ++ if (node.isConductor() || node.isSignalSource()) { ++ for (int iSide : updateOrder.cardinalNeighbors(wire.iFlowDir)) { ++ Node neighbor = getNeighbor(node, iSide); ++ ++ if (neighbor.isWire()) { ++ findRoot(neighbor.asWire(), iSide); ++ } + } + } + } + ++ private void findRoot(WireNode wire) { ++ findRoot(wire, -1); ++ } ++ + /** + * Check if the given wire requires power changes. If it does, queue it for the + * breadth-first search as a root. + */ -+ private void findRoot(WireNode wire) { ++ private void findRoot(WireNode wire, int iDiscoveryDir) { + // Each wire only needs to be checked once. + if (wire.discovered) { + return; @@ -1694,7 +1712,7 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + findPower(wire, false); + + if (needsUpdate(wire)) { -+ searchRoot(wire); ++ searchRoot(wire, iDiscoveryDir); + } + } + @@ -1810,7 +1828,7 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + // Since 1.16 there is a block that is both a conductor and a signal + // source: the target block! + if (neighbor.isConductor()) { -+ power = Math.max(power, getDirectSignalTo(wire, neighbor, Directions.iOpposite(iDir))); ++ power = Math.max(power, getDirectSignalTo(wire, neighbor)); + } + if (neighbor.isSignalSource()) { + power = Math.max(power, neighbor.state.getSignal(level, neighbor.pos, Directions.ALL[iDir])); @@ -1828,10 +1846,10 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + * Determine the direct signal the given wire receives from neighboring blocks + * through the given conductor node. + */ -+ private int getDirectSignalTo(WireNode wire, Node node, int except) { ++ private int getDirectSignalTo(WireNode wire, Node node) { + int power = POWER_MIN; + -+ for (int iDir : Directions.I_EXCEPT[except]) { ++ for (int iDir = 0; iDir < Directions.ALL.length; iDir++) { + Node neighbor = getNeighbor(node, iDir); + + if (neighbor.isSignalSource()) { @@ -1856,13 +1874,13 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + /** + * Queue the given wire for the breadth-first search as a root. + */ -+ private void searchRoot(WireNode wire) { -+ int iBackupFlowDir; -+ -+ if (wire.connections.iFlowDir < 0) { -+ iBackupFlowDir = 0; -+ } else { ++ private void searchRoot(WireNode wire, int iBackupFlowDir) { ++ if (wire.connections.iFlowDir >= 0) { ++ // power flow direction takes precedent + iBackupFlowDir = wire.connections.iFlowDir; ++ } else if (iBackupFlowDir < 0) { ++ // use default value if none is given ++ iBackupFlowDir = 0; + } + + search(wire, true, iBackupFlowDir); @@ -2167,7 +2185,9 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 + * Emit a block update to the given node. + */ + private void updateBlock(Node node, BlockPos neighborPos, Block neighborBlock) { -+ neighborUpdater.neighborChanged(node.pos, neighborBlock, neighborPos); ++ // redstone wire is the only block that uses the neighborChanged orientation ++ // so leaving it as null should not be an issue ++ neighborUpdater.neighborChanged(node.pos, neighborBlock, null); + } + + @FunctionalInterface @@ -2179,7 +2199,7 @@ index 0000000000000000000000000000000000000000..8b7e33ce050ba75139df1c56c007b792 +} diff --git a/src/main/java/alternate/current/wire/WireNode.java b/src/main/java/alternate/current/wire/WireNode.java new file mode 100644 -index 0000000000000000000000000000000000000000..33cd90c30c22200a4e1ae64f40a0bf7864546b33 +index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9f5689bdb --- /dev/null +++ b/src/main/java/alternate/current/wire/WireNode.java @@ -0,0 +1,122 @@ @@ -2299,17 +2319,17 @@ index 0000000000000000000000000000000000000000..33cd90c30c22200a4e1ae64f40a0bf78 + return true; + } + -+ currentPower = LevelHelper.doRedstoneEvent(level, pos, currentPower, Mth.clamp(virtualPower, Redstone.SIGNAL_MIN, Redstone.SIGNAL_MAX)); ++ currentPower = LevelHelper.doRedstoneEvent(level, pos, currentPower, Mth.clamp(virtualPower, Redstone.SIGNAL_MIN, Redstone.SIGNAL_MAX));; + state = state.setValue(RedStoneWireBlock.POWER, currentPower); + + return LevelHelper.setWireState(level, pos, state, added); + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index acc11fc7f30b6d4a3a4445b7db25bf99c93b39f2..6f3eedade396405d67ff56c66755929acda5cff0 100644 +index 3b6b6483bf855493948417f44f06427b625bc910..a0611bf5f88d5b12dc981dda14e355c751ff802e 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -228,6 +228,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. +@@ -230,6 +230,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final UUID uuid; public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent @@ -2317,8 +2337,8 @@ index acc11fc7f30b6d4a3a4445b7db25bf99c93b39f2..6f3eedade396405d67ff56c66755929a public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately -@@ -2427,6 +2428,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. - return crashreportsystemdetails; +@@ -2641,6 +2642,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + return this.chunkSource.getGenerator().getSeaLevel(); } + // Paper start - optimize redstone (Alternate Current) @@ -2332,13 +2352,13 @@ index acc11fc7f30b6d4a3a4445b7db25bf99c93b39f2..6f3eedade396405d67ff56c66755929a EntityCallbacks() {} diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index c4ec80bbab850fe767a345d96f02103ca43eb3cb..ca1dab96b40511d53aedd4f64e6cd0fb03583710 100644 +index 022de445bbbb869c38be4972c98dcf1c665539ec..2cc264f577fdd81d02783e0d6146bea9728789c7 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -2030,4 +2030,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - } - } - // Paper end - notify observers even if grow failed +@@ -2015,6 +2015,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + + public abstract FuelValues fuelValues(); + + // Paper start - optimize redstone (Alternate Current) + public alternate.current.wire.WireHandler getWireHandler() { + // This method is overridden in ServerLevel. @@ -2349,12 +2369,15 @@ index c4ec80bbab850fe767a345d96f02103ca43eb3cb..ca1dab96b40511d53aedd4f64e6cd0fb + return null; + } + // Paper end - optimize redstone (Alternate Current) - } ++ + public static enum ExplosionInteraction implements StringRepresentable { + + NONE("none"), BLOCK("block"), MOB("mob"), TNT("tnt"), TRIGGER("trigger"), STANDARD("standard"); // CraftBukkit - Add STANDARD which will always use Explosion.Effect.DESTROY diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -index 18ed178223cca85dbba65b1e07741622e266d318..c131734cad123a35456d18f8a161f77a4ac9ac99 100644 +index 09b8f5335cb7651d90f4d1ca61b2ec5aa324e443..21f2c61023fadcce30452a02f067cd5d87e5d8dc 100644 --- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -@@ -258,7 +258,7 @@ public class RedStoneWireBlock extends Block { +@@ -290,7 +290,7 @@ public class RedStoneWireBlock extends Block { return floor.isFaceSturdy(world, pos, Direction.UP) || floor.is(Blocks.HOPPER); } @@ -2363,49 +2386,65 @@ index 18ed178223cca85dbba65b1e07741622e266d318..c131734cad123a35456d18f8a161f77a // The bulk of the new functionality is found in RedstoneWireTurbo.java com.destroystokyo.paper.util.RedstoneWireTurbo turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo(this); -@@ -460,7 +460,13 @@ public class RedStoneWireBlock extends Block { +@@ -372,7 +372,13 @@ public class RedStoneWireBlock extends Block { @Override protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { if (!oldState.is(state.getBlock()) && !world.isClientSide) { -- this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone +- this.updateSurroundingRedstone(world, pos, state, null, true); // Paper - Optimize redstone + // Paper start - optimize redstone - replace call to updatePowerStrength + if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { -+ world.getWireHandler().onWireAdded(pos); // Alternate Current ++ world.getWireHandler().onWireAdded(pos, state); // Alternate Current + } else { -+ this.updateSurroundingRedstone(world, pos, state, null); // vanilla/Eigencraft ++ this.updateSurroundingRedstone(world, pos, state, null, true); // Vanilla/Eigencraft + } -+ // Paper end - optimize redstone - Iterator iterator = Direction.Plane.VERTICAL.iterator(); ++ // Paper end - while (iterator.hasNext()) { -@@ -487,7 +493,13 @@ public class RedStoneWireBlock extends Block { - world.updateNeighborsAt(pos.relative(enumdirection), this); + for (Direction direction : Direction.Plane.VERTICAL) { + world.updateNeighborsAt(pos.relative(direction), this); +@@ -391,7 +397,12 @@ public class RedStoneWireBlock extends Block { + world.updateNeighborsAt(pos.relative(direction), this); } -- this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone +- this.updateSurroundingRedstone(world, pos, state, null, false); // Paper - Optimize redstone + // Paper start - optimize redstone - replace call to updatePowerStrength + if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { + world.getWireHandler().onWireRemoved(pos, state); // Alternate Current + } else { -+ this.updateSurroundingRedstone(world, pos, state, null); // vanilla/Eigencraft ++ this.updateSurroundingRedstone(world, pos, state, null, false); // Vanilla/Eigencraft + } -+ // Paper end - optimize redstone this.updateNeighborsOfNeighboringWires(world, pos); } } -@@ -521,8 +533,14 @@ public class RedStoneWireBlock extends Block { +@@ -415,9 +426,15 @@ public class RedStoneWireBlock extends Block { @Override - protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { + protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) { if (!world.isClientSide) { + // Paper start - optimize redstone (Alternate Current) + // Alternate Current handles breaking of redstone wires in the WireHandler. + if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { -+ world.getWireHandler().onWireUpdated(pos); ++ world.getWireHandler().onWireUpdated(pos, state, wireOrientation); + } else + // Paper end - optimize redstone (Alternate Current) - if (state.canSurvive(world, pos)) { -- this.updateSurroundingRedstone(world, pos, state, sourcePos); // Paper - Optimize redstone -+ this.updateSurroundingRedstone(world, pos, state, sourcePos); // Paper - Optimize redstone (Eigencraft) - } else { - dropResources(state, world, pos); - world.removeBlock(pos, false); + if (sourceBlock != this || !useExperimentalEvaluator(world)) { + if (state.canSurvive(world, pos)) { +- this.updateSurroundingRedstone(world, pos, state, wireOrientation, false); // Paper - Optimize redstone ++ this.updateSurroundingRedstone(world, pos, state, wireOrientation, false); // Paper - Optimize redstone (Eigencraft) + } else { + dropResources(state, world, pos); + world.removeBlock(pos, false); +diff --git a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java +index 4a9dc307106687bec084244c0a76e3e30f244fe2..8342dd636531729a187aff1bd69878d7aef9d3eb 100644 +--- a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java ++++ b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java +@@ -17,6 +17,11 @@ public class ExperimentalRedstoneUtils { + if (up != null) { + orientation = orientation.withFront(up); + } ++ // Paper start - Optimize redstone (Alternate Current) - use default front instead of random ++ else if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { ++ orientation = orientation.withFront(Direction.WEST); ++ } ++ // Paper end - Optimize redstone (Alternate Current) + + return orientation; + } else {