aboutsummaryrefslogtreecommitdiffhomepage
path: root/removed
diff options
context:
space:
mode:
authorMariell Hoversholm <[email protected]>2020-08-04 12:23:54 +0200
committerMiniDigger <[email protected]>2020-08-28 13:38:55 +0200
commit3efe45f56dadad429b6a9df1fca7cacb187bade8 (patch)
treefe7e6145e199d1990b6ec3c479148f6cead520e7 /removed
parent0bad6958028e84943675f29306a89646673cf8a6 (diff)
downloadPaper-3efe45f56dadad429b6a9df1fca7cacb187bade8.tar.gz
Paper-3efe45f56dadad429b6a9df1fca7cacb187bade8.zip
Port Eigencraft to 1.16
Diffstat (limited to 'removed')
-rw-r--r--removed/1.16/0326-Optimize-redstone-algorithm.patch1148
1 files changed, 0 insertions, 1148 deletions
diff --git a/removed/1.16/0326-Optimize-redstone-algorithm.patch b/removed/1.16/0326-Optimize-redstone-algorithm.patch
deleted file mode 100644
index b43213ff7f..0000000000
--- a/removed/1.16/0326-Optimize-redstone-algorithm.patch
+++ /dev/null
@@ -1,1148 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: theosib <[email protected]>
-Date: Thu, 27 Sep 2018 01:43:35 -0600
-Subject: [PATCH] Optimize redstone algorithm
-
-Author: theosib <[email protected]>
-Co-authored-by: egg82 <[email protected]>
-
-Original license: MIT
-
-This patch implements theosib's redstone algorithms to completely overhaul the way redstone works.
-The new algorithms should be many times faster than current vanilla ones.
-From the original author's comments, it looks like it shouldn't interfere with any redstone save for very extreme edge-cases.
-
-Surprisingly, not a lot was touched aside from a few obfuscation helpers and BlockRedstoneWire.
-A lot of this code is self-contained in a helper class.
-
-Aside from making the obvious class/function renames and obfhelpers I didn't need to modify much.
-Just added Bukkit's event system and took a few liberties with dead code and comment misspellings.
-
-diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index 0862a1d629435dea92178fb5473068f23a15adf2..4ba72275b965693f3650f9b4fb138d3320d1b88b 100644
---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -432,4 +432,14 @@ public class PaperWorldConfig {
- private void preventMovingIntoUnloadedChunks() {
- preventMovingIntoUnloadedChunks = getBoolean("prevent-moving-into-unloaded-chunks", false);
- }
-+
-+ public boolean useEigencraftRedstone = false;
-+ private void useEigencraftRedstone() {
-+ useEigencraftRedstone = this.getBoolean("use-faster-eigencraft-redstone", false);
-+ if (useEigencraftRedstone) {
-+ log("Using Eigencraft redstone algorithm by theosib.");
-+ } else {
-+ log("Using vanilla redstone algorithm.");
-+ }
-+ }
- }
-diff --git a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..b69803cbf2db2781aa050b145bf88468254880ae
---- /dev/null
-+++ b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
-@@ -0,0 +1,915 @@
-+package com.destroystokyo.paper.util;
-+
-+import java.util.List;
-+import java.util.Map;
-+import java.util.concurrent.ThreadLocalRandom;
-+
-+import org.bukkit.event.block.BlockRedstoneEvent;
-+
-+import com.google.common.collect.Lists;
-+import com.google.common.collect.Maps;
-+
-+import net.minecraft.server.Block;
-+import net.minecraft.server.BlockPosition;
-+import net.minecraft.server.BlockRedstoneWire;
-+import net.minecraft.server.IBlockData;
-+import net.minecraft.server.Items;
-+import net.minecraft.server.ItemStack;
-+import net.minecraft.server.World;
-+
-+/**
-+ * Used for the faster redstone algorithm.
-+ * Original author: theosib
-+ * Original license: MIT
-+ *
-+ * Ported to Paper and updated to 1.13 by egg82
-+ */
-+public class RedstoneWireTurbo {
-+ /*
-+ * This is Helper class for BlockRedstoneWire. It implements a minimally-invasive
-+ * bolt-on accelerator that performs a breadth-first search through redstone wire blocks
-+ * in order to more efficiently and deterministically compute new redstone wire power levels
-+ * and determine the order in which other blocks should be updated.
-+ *
-+ * Features:
-+ * - Changes to BlockRedstoneWire are very limited, no other classes are affected, and the
-+ * choice between old and new redstone wire update algorithms is switchable on-line.
-+ * - The vanilla implementation relied on World.notifyNeighborsOfStateChange for redstone
-+ * wire blocks to communicate power level changes to each other, generating 36 block
-+ * updates per call. This improved implementation propagates power level changes directly
-+ * between redstone wire blocks. Redstone wire power levels are therefore computed more quickly,
-+ * and block updates are sent only to non-redstone blocks, many of which may perform an
-+ * action when informed of a change in redstone power level. (Note: Block updates are not
-+ * the same as state changes to redstone wire. Wire block states are updated as soon
-+ * as they are computed.)
-+ * - Of the 36 block updates generated by a call to World.notifyNeighborsOfStateChange,
-+ * 12 of them are obviously redundant (e.g. the west neighbor of the east neighbor).
-+ * These are eliminated.
-+ * - Updates to redstone wire and other connected blocks are propagated in a breath-first
-+ * manner, radiating out from the initial trigger (a block update to a redstone wire
-+ * from something other than redstone wire).
-+ * - Updates are scheduled both deterministically and in an intuitive order, addressing bug
-+ * MC-11193.
-+ * - All redstone behavior that used to be locational now works the same in all locations.
-+ * - All behaviors of redstone wire that used to be orientational now work the same in all
-+ * orientations, as long as orientation can be determined; random otherwise. Some other
-+ * redstone components still update directionally (e.g. switches), and this code can't
-+ * compensate for that.
-+ * - Information that is otherwise computed over and over again or which is expensive to
-+ * to compute is cached for faster lookup. This includes coordinates of block position
-+ * neighbors and block states that won't change behind our backs during the execution of
-+ * this search algorithm.
-+ * - Redundant block updates (both to redstone wire and to other blocks) are heavily
-+ * consolidated. For worst-case scenarios (depowering of redstone wire) this results
-+ * in a reduction of block updates by as much as 95% (factor of 1/21). Due to overheads,
-+ * empirical testing shows a speedup better than 10x. This addresses bug MC-81098.
-+ *
-+ * Extensive testing has been performed to ensure that existing redstone contraptions still
-+ * behave as expected. Results of early testing that identified undesirable behavior changes
-+ * were addressed. Additionally, real-time performance testing revealed compute inefficiencies
-+ * With earlier implementations of this accelerator. Some compatibility adjustments and
-+ * performance optimizations resulted in harmless increases in block updates above the
-+ * theoretical minimum.
-+ *
-+ * Only a single redstone machine was found to break: An instant dropper line hack that
-+ * relies on powered rails and quasi-connectivity but doesn't work in all directions. The
-+ * replacement is to lay redstone wire directly on top of the dropper line, which now works
-+ * reliably in any direction.
-+ *
-+ * There are numerous other optimization that can be made, but those will be provided later in
-+ * separate updates. This version is designed to be minimalistic.
-+ *
-+ * Many thanks to the following individuals for their help in testing this functionality:
-+ * - pokechu22, _MethodZz_, WARBEN, NarcolepticFrog, CommandHelper (nessie), ilmango,
-+ * OreoLamp, Xcom6000, tryashtar, RedCMD, Smokey95Dog, EDDxample, Rays Works,
-+ * Nodnam, BlockyPlays, Grumm, NeunEinser, HelVince.
-+ */
-+
-+ /* Reference to BlockRedstoneWire object, which uses this accelerator */
-+ private final BlockRedstoneWire wire;
-+
-+ /*
-+ * Implementation:
-+ *
-+ * RedstoneWire Blocks are updated in concentric rings or "layers" radiating out from the
-+ * initial block update that came from a call to BlockRedstoneWire.neighborChanged().
-+ * All nodes put in Layer N are those with Manhattan distance N from the trigger
-+ * position, reachable through connected redstone wire blocks.
-+ *
-+ * Layer 0 represents the trigger block position that was input to neighborChanged.
-+ * Layer 1 contains the immediate neighbors of that position.
-+ * Layer N contains the neighbors of blocks in layer N-1, not including
-+ * those in previous layers.
-+ *
-+ * Layers enforce an update order that is a function of Manhattan distance
-+ * from the initial coordinates input to neighborChanged. The same
-+ * coordinates may appear in multiple layers, but redundant updates are minimized.
-+ * Block updates are sent layer-by-layer. If multiple of a block's neighbors experience
-+ * redstone wire changes before its layer is processed, then those updates will be merged.
-+ * If a block's update has been sent, but its neighboring redstone changes
-+ * after that, then another update will be sent. This preserves compatibility with
-+ * machines that rely on zero-tick behavior, except that the new functionality is non-
-+ * locational.
-+ *
-+ * Within each layer, updates are ordered left-to-right relative to the direction of
-+ * information flow. This makes the implementation non-orientational. Only when
-+ * this direction is ambiguous is randomness applied (intentionally).
-+ */
-+ private List<UpdateNode> updateQueue0 = Lists.newArrayList();
-+ private List<UpdateNode> updateQueue1 = Lists.newArrayList();
-+ private List<UpdateNode> updateQueue2 = Lists.newArrayList();
-+
-+ public RedstoneWireTurbo(BlockRedstoneWire wire) {
-+ this.wire = wire;
-+ }
-+
-+ /*
-+ * Compute neighbors of a block. When a redstone wire value changes, previously it called
-+ * World.notifyNeighborsOfStateChange. That lists immediately neighboring blocks in
-+ * west, east, down, up, north, south order. For each of those neighbors, their own
-+ * neighbors are updated in the same order. This generates 36 updates, but 12 of them are
-+ * redundant; for instance the west neighbor of a block's east neighbor.
-+ *
-+ * Note that this ordering is only used to create the initial list of neighbors. Once
-+ * the direction of signal flow is identified, the ordering of updates is completely
-+ * reorganized.
-+ */
-+ public static BlockPosition[] computeAllNeighbors(final BlockPosition pos) {
-+ final int x = pos.getX();
-+ final int y = pos.getY();
-+ final int z = pos.getZ();
-+ final BlockPosition[] n = new BlockPosition[24];
-+
-+ // Immediate neighbors, in the same order as
-+ // World.notifyNeighborsOfStateChange, etc.:
-+ // west, east, down, up, north, south
-+ n[0] = new BlockPosition(x - 1, y, z);
-+ n[1] = new BlockPosition(x + 1, y, z);
-+ n[2] = new BlockPosition(x, y - 1, z);
-+ n[3] = new BlockPosition(x, y + 1, z);
-+ n[4] = new BlockPosition(x, y, z - 1);
-+ n[5] = new BlockPosition(x, y, z + 1);
-+
-+ // Neighbors of neighbors, in the same order,
-+ // except that duplicates are not included
-+ n[6] = new BlockPosition(x - 2, y, z);
-+ n[7] = new BlockPosition(x - 1, y - 1, z);
-+ n[8] = new BlockPosition(x - 1, y + 1, z);
-+ n[9] = new BlockPosition(x - 1, y, z - 1);
-+ n[10] = new BlockPosition(x - 1, y, z + 1);
-+ n[11] = new BlockPosition(x + 2, y, z);
-+ n[12] = new BlockPosition(x + 1, y - 1, z);
-+ n[13] = new BlockPosition(x + 1, y + 1, z);
-+ n[14] = new BlockPosition(x + 1, y, z - 1);
-+ n[15] = new BlockPosition(x + 1, y, z + 1);
-+ n[16] = new BlockPosition(x, y - 2, z);
-+ n[17] = new BlockPosition(x, y - 1, z - 1);
-+ n[18] = new BlockPosition(x, y - 1, z + 1);
-+ n[19] = new BlockPosition(x, y + 2, z);
-+ n[20] = new BlockPosition(x, y + 1, z - 1);
-+ n[21] = new BlockPosition(x, y + 1, z + 1);
-+ n[22] = new BlockPosition(x, y, z - 2);
-+ n[23] = new BlockPosition(x, y, z + 2);
-+ return n;
-+ }
-+
-+ /*
-+ * We only want redstone wires to update redstone wires that are
-+ * immediately adjacent. Some more distant updates can result
-+ * in cross-talk that (a) wastes time and (b) can make the update
-+ * order unintuitive. Therefore (relative to the neighbor order
-+ * computed by computeAllNeighbors), updates are not scheduled
-+ * for redstone wire in those non-connecting positions. On the
-+ * other hand, updates will always be sent to *other* types of blocks
-+ * in any of the 24 neighboring positions.
-+ */
-+ private static final boolean[] update_redstone = {
-+ true, true, false, false, true, true, // 0 to 5
-+ false, true, true, false, false, false, // 6 to 11
-+ true, true, false, false, false, true, // 12 to 17
-+ true, false, true, true, false, false // 18 to 23
-+ };
-+
-+ // Internal numbering for cardinal directions
-+ private static final int North = 0;
-+ private static final int East = 1;
-+ private static final int South = 2;
-+ private static final int West = 3;
-+
-+ /*
-+ * These lookup tables completely remap neighbor positions into a left-to-right
-+ * ordering, based on the cardinal direction that is determined to be forward.
-+ * See below for more explanation.
-+ */
-+ private static final int[] forward_is_north = {2, 3, 16, 19, 0, 4, 1, 5, 7, 8, 17, 20, 12, 13, 18, 21, 6, 9, 22, 14, 11, 10, 23, 15};
-+ private static final int[] forward_is_east = {2, 3, 16, 19, 4, 1, 5, 0, 17, 20, 12, 13, 18, 21, 7, 8, 22, 14, 11, 15, 23, 9, 6, 10};
-+ private static final int[] forward_is_south = {2, 3, 16, 19, 1, 5, 0, 4, 12, 13, 18, 21, 7, 8, 17, 20, 11, 15, 23, 10, 6, 14, 22, 9};
-+ private static final int[] forward_is_west = {2, 3, 16, 19, 5, 0, 4, 1, 18, 21, 7, 8, 17, 20, 12, 13, 23, 10, 6, 9, 22, 15, 11, 14};
-+
-+ /* For any orientation, we end up with the update order defined below. This order is relative to any redstone wire block
-+ * that is itself having an update computed, and this center position is marked with C.
-+ * - The update position marked 0 is computed first, and the one marked 23 is last.
-+ * - Forward is determined by the local direction of information flow into position C from prior updates.
-+ * - The first updates are scheduled for the four positions below and above C.
-+ * - Then updates are scheduled for the four horizontal neighbors of C, followed by the positions below and above those neighbors.
-+ * - Finally, updates are scheduled for the remaining positions with Manhattan distance 2 from C (at the same Y coordinate).
-+ * - For a given horizontal distance from C, updates are scheduled starting from directly left and stepping clockwise to directly
-+ * right. The remaining positions behind C are scheduled counterclockwise so as to maintain the left-to-right ordering.
-+ * - If C is in layer N of the update schedule, then all 24 positions may be scheduled for layer N+1. For redstone wire, no
-+ * updates are scheduled for positions that cannot directly connect. Additionally, the four positions above and below C
-+ * are ALSO scheduled for layer N+2.
-+ * - This update order was selected after experimenting with a number of alternative schedules, based on its compatibility
-+ * with existing redstone designs and behaviors that were considered to be intuitive by various testers. WARBEN in particular
-+ * made some of the most challenging test cases, but the 3-tick clocks (made by RedCMD) were also challenging to fix,
-+ * along with the rail-based instant dropper line built by ilmango. Numerous others made test cases as well, including
-+ * NarcolepticFrog, nessie, and Pokechu22.
-+ *
-+ * - The forward direction is determined locally. So when there are branches in the redstone wire, the left one will get updated
-+ * before the right one. Each branch can have its own relative forward direction, resulting in the left side of a left branch
-+ * having priority over the right branch of a left branch, which has priority over the left branch of a right branch, followed
-+ * by the right branch of a right branch. And so forth. Since redstone power reduces to zero after a path distance of 15,
-+ * that imposes a practical limit on the branching. Note that the branching is not tracked explicitly -- relative forward
-+ * directions dictate relative sort order, which maintains the proper global ordering. This also makes it unnecessary to be
-+ * concerned about branches meeting up with each other.
-+ *
-+ * ^
-+ * |
-+ * Forward
-+ * <-- Left Right -->
-+ *
-+ * 18
-+ * 10 17 5 19 11
-+ * 2 8 0 12 16 4 C 6 20 9 1 13 3
-+ * 14 21 7 23 15
-+ * Further 22 Further
-+ * Down Down Up Up
-+ *
-+ * Backward
-+ * |
-+ * V
-+ */
-+
-+ // This allows the above remapping tables to be looked up by cardial direction index
-+ private static final int[][] reordering = { forward_is_north, forward_is_east, forward_is_south, forward_is_west };
-+
-+ /*
-+ * Input: Array of UpdateNode objects in an order corresponding to the positions
-+ * computed by computeAllNeighbors above.
-+ * Output: Array of UpdateNode objects oriented using the above remapping tables
-+ * corresponding to the identified heading (direction of information flow).
-+ */
-+ private static void orientNeighbors(final UpdateNode[] src, final UpdateNode[] dst, final int heading) {
-+ final int[] re = reordering[heading];
-+ for (int i = 0; i < 24; i++) {
-+ dst[i] = src[re[i]];
-+ }
-+ }
-+
-+ /*
-+ * Structure to keep track of redstone wire blocks and
-+ * neighbors that will receive updates.
-+ */
-+ private static class UpdateNode {
-+ public static enum Type {
-+ UNKNOWN, REDSTONE, OTHER
-+ }
-+
-+ IBlockData currentState; // Keep track of redstone wire value
-+ UpdateNode[] neighbor_nodes; // References to neighbors (directed graph edges)
-+ BlockPosition self; // UpdateNode's own position
-+ BlockPosition parent; // Which block pos spawned/updated this node
-+ Type type = Type.UNKNOWN; // unknown, redstone wire, other type of block
-+ int layer; // Highest layer this node is scheduled in
-+ boolean visited; // To keep track of information flow direction, visited restone wire is marked
-+ int xbias, zbias; // Remembers directionality of ancestor nodes; helps eliminate directional ambiguities.
-+ }
-+
-+ /*
-+ * Keep track of all block positions discovered during search and their current states.
-+ * We want to remember one entry for each position.
-+ */
-+ private final Map<BlockPosition, UpdateNode> nodeCache = Maps.newHashMap();
-+
-+ /*
-+ * For a newly created UpdateNode object, determine what type of block it is.
-+ */
-+ private void identifyNode(final World worldIn, final UpdateNode upd1) {
-+ final BlockPosition pos = upd1.self;
-+ final IBlockData oldState = worldIn.getType(pos);
-+ upd1.currentState = oldState;
-+
-+ // Some neighbors of redstone wire are other kinds of blocks.
-+ // These need to receive block updates to inform them that
-+ // redstone wire values have changed.
-+ final Block block = oldState.getBlock();
-+ if (block != wire) {
-+ // Mark this block as not redstone wire and therefore
-+ // requiring updates
-+ upd1.type = UpdateNode.Type.OTHER;
-+
-+ // Non-redstone blocks may propagate updates, but those updates
-+ // are not handled by this accelerator. Therefore, we do not
-+ // expand this position's neighbors.
-+ return;
-+ }
-+
-+ // One job of BlockRedstoneWire.neighborChanged is to convert
-+ // redstone wires to items if the block beneath was removed.
-+ // With this accelerator, BlockRedstoneWire.neighborChanged
-+ // is only typically called for a single wire block, while
-+ // others are processed internally by the breadth first search
-+ // algorithm. To preserve this game behavior, this check must
-+ // be replicated here.
-+ if (!wire.canPlace(null, worldIn, pos)) {
-+ // Pop off the redstone dust
-+ Block.a(worldIn, pos, new ItemStack(Items.REDSTONE)); // TODO
-+ worldIn.setAir(pos);
-+
-+ // Mark this position as not being redstone wire
-+ upd1.type = UpdateNode.Type.OTHER;
-+
-+ // Note: Sending updates to air blocks leads to an empty method.
-+ // Testing shows this to be faster than explicitly avoiding updates to
-+ // air blocks.
-+ return;
-+ }
-+
-+ // If the above conditions fail, then this is a redstone wire block.
-+ upd1.type = UpdateNode.Type.REDSTONE;
-+ }
-+
-+ /*
-+ * Given which redstone wire blocks have been visited and not visited
-+ * around the position currently being updated, compute the cardinal
-+ * direction that is "forward."
-+ *
-+ * rx is the forward direction along the West/East axis
-+ * rz is the forward direction along the North/South axis
-+ */
-+ static private int computeHeading(final int rx, final int rz) {
-+ // rx and rz can only take on values -1, 0, and 1, so we can
-+ // compute a code number that allows us to use a single switch
-+ // to determine the heading.
-+ final int code = (rx + 1) + 3 * (rz + 1);
-+ switch (code) {
-+ case 0: {
-+ // Both rx and rz are -1 (northwest)
-+ // Randomly choose one to be forward.
-+ final int j = ThreadLocalRandom.current().nextInt(0, 1);
-+ return (j == 0) ? North : West;
-+ }
-+ case 1: {
-+ // rx=0, rz=-1
-+ // Definitively North
-+ return North;
-+ }
-+ case 2: {
-+ // rx=1, rz=-1 (northeast)
-+ // Choose randomly between north and east
-+ final int j = ThreadLocalRandom.current().nextInt(0, 1);
-+ return (j == 0) ? North : East;
-+ }
-+ case 3: {
-+ // rx=-1, rz=0
-+ // Definitively West
-+ return West;
-+ }
-+ case 4: {
-+ // rx=0, rz=0
-+ // Heading is completely ambiguous. Choose
-+ // randomly among the four cardinal directions.
-+ return ThreadLocalRandom.current().nextInt(0, 4);
-+ }
-+ case 5: {
-+ // rx=1, rz=0
-+ // Definitively East
-+ return East;
-+ }
-+ case 6: {
-+ // rx=-1, rz=1 (southwest)
-+ // Choose randomly between south and west
-+ final int j = ThreadLocalRandom.current().nextInt(0, 1);
-+ return (j == 0) ? South : West;
-+ }
-+ case 7: {
-+ // rx=0, rz=1
-+ // Definitively South
-+ return South;
-+ }
-+ case 8: {
-+ // rx=1, rz=1 (southeast)
-+ // Choose randomly between south and east
-+ final int j = ThreadLocalRandom.current().nextInt(0, 1);
-+ return (j == 0) ? South : East;
-+ }
-+ }
-+
-+ // We should never get here
-+ return ThreadLocalRandom.current().nextInt(0, 4);
-+ }
-+
-+ // Select whether to use updateSurroundingRedstone from BlockRedstoneWire (old)
-+ // or this helper class (new)
-+ private static final boolean old_current_change = false;
-+
-+ /*
-+ * Process a node whose neighboring redstone wire has experienced value changes.
-+ */
-+ private void updateNode(final World worldIn, final UpdateNode upd1, final int layer) {
-+ final BlockPosition pos = upd1.self;
-+
-+ // Mark this redstone wire as having been visited so that it can be used
-+ // to calculate direction of information flow.
-+ upd1.visited = true;
-+
-+ // Look up the last known state.
-+ // Due to the way other redstone components are updated, we do not
-+ // have to worry about a state changing behind our backs. The rare
-+ // exception is handled by scheduleReentrantNeighborChanged.
-+ final IBlockData oldState = upd1.currentState;
-+
-+ // Ask the wire block to compute its power level from its neighbors.
-+ // This will also update the wire's power level and return a new
-+ // state if it has changed. When a wire power level is changed,
-+ // calculateCurrentChanges will immediately update the block state in the world
-+ // and return the same value here to be cached in the corresponding
-+ // UpdateNode object.
-+ IBlockData newState;
-+ if (old_current_change) {
-+ newState = wire.calculateCurrentChanges(worldIn, pos, pos, oldState);
-+ } else {
-+ // Looking up block state is slow. This accelerator includes a version of
-+ // calculateCurrentChanges that uses cahed wire values for a
-+ // significant performance boost.
-+ newState = this.calculateCurrentChanges(worldIn, upd1);
-+ }
-+
-+ // Only inform neighbors if the state has changed
-+ if (newState != oldState) {
-+ // Store the new state
-+ upd1.currentState = newState;
-+
-+ // Inform neighbors of the change
-+ propagateChanges(worldIn, upd1, layer);
-+ }
-+ }
-+
-+ /*
-+ * This identifies the neighboring positions of a new UpdateNode object,
-+ * determines their types, and links those to into the graph. Then based on
-+ * what nodes in the redstone wire graph have been visited, the neighbors
-+ * are reordered left-to-right relative to the direction of information flow.
-+ */
-+ private void findNeighbors(final World worldIn, final UpdateNode upd1) {
-+ final BlockPosition pos = upd1.self;
-+
-+ // Get the list of neighbor coordinates
-+ final BlockPosition[] neighbors = computeAllNeighbors(pos);
-+
-+ // Temporary array of neighbors in cardinal ordering
-+ final UpdateNode[] neighbor_nodes = new UpdateNode[24];
-+
-+ // Target array of neighbors sorted left-to-right
-+ upd1.neighbor_nodes = new UpdateNode[24];
-+
-+ for (int i=0; i<24; i++) {
-+ // Look up each neighbor in the node cache
-+ final BlockPosition pos2 = neighbors[i];
-+ UpdateNode upd2 = nodeCache.get(pos2);
-+ if (upd2 == null) {
-+ // If this is a previously unreached position, create
-+ // a new update node, add it to the cache, and identify what it is.
-+ upd2 = new UpdateNode();
-+ upd2.self = pos2;
-+ upd2.parent = pos;
-+ nodeCache.put(pos2, upd2);
-+ identifyNode(worldIn, upd2);
-+ }
-+
-+ // For non-redstone blocks, any of the 24 neighboring positions
-+ // should receive a block update. However, some block coordinates
-+ // may contain a redstone wire that does not directly connect to the
-+ // one being expanded. To avoid redundant calculations and confusing
-+ // cross-talk, those neighboring positions are not included.
-+ if (update_redstone[i] || upd2.type != UpdateNode.Type.REDSTONE) {
-+ neighbor_nodes[i] = upd2;
-+ }
-+ }
-+
-+ // Determine the directions from which the redstone signal may have come from. This
-+ // checks for redstone wire at the same Y level and also Y+1 and Y-1, relative to the
-+ // block being expanded.
-+ final boolean fromWest = (neighbor_nodes[0].visited || neighbor_nodes[7].visited || neighbor_nodes[8].visited);
-+ final boolean fromEast = (neighbor_nodes[1].visited || neighbor_nodes[12].visited || neighbor_nodes[13].visited);
-+ final boolean fromNorth = (neighbor_nodes[4].visited || neighbor_nodes[17].visited || neighbor_nodes[20].visited);
-+ final boolean fromSouth = (neighbor_nodes[5].visited || neighbor_nodes[18].visited || neighbor_nodes[21].visited);
-+
-+ int cx = 0, cz = 0;
-+ if (fromWest) cx += 1;
-+ if (fromEast) cx -= 1;
-+ if (fromNorth) cz += 1;
-+ if (fromSouth) cz -= 1;
-+
-+ int heading;
-+ if (cx==0 && cz==0) {
-+ // If there is no clear direction, try to inherit the heading from ancestor nodes.
-+ heading = computeHeading(upd1.xbias, upd1.zbias);
-+
-+ // Propagate that heading to descendant nodes.
-+ for (int i=0; i<24; i++) {
-+ final UpdateNode nn = neighbor_nodes[i];
-+ if (nn != null) {
-+ nn.xbias = upd1.xbias;
-+ nn.zbias = upd1.zbias;
-+ }
-+ }
-+ } else {
-+ if (cx != 0 && cz != 0) {
-+ // If the heading is somewhat ambiguous, try to disambiguate based on
-+ // ancestor nodes.
-+ if (upd1.xbias != 0) cz = 0;
-+ if (upd1.zbias != 0) cx = 0;
-+ }
-+ heading = computeHeading(cx, cz);
-+
-+ // Propagate that heading to descendant nodes.
-+ for (int i=0; i<24; i++) {
-+ final UpdateNode nn = neighbor_nodes[i];
-+ if (nn != null) {
-+ nn.xbias = cx;
-+ nn.zbias = cz;
-+ }
-+ }
-+ }
-+
-+ // Reorder neighboring UpdateNode objects according to the forward direction
-+ // determined above.
-+ orientNeighbors(neighbor_nodes, upd1.neighbor_nodes, heading);
-+ }
-+
-+ /*
-+ * For any redstone wire block in layer N, inform neighbors to recompute their states
-+ * in layers N+1 and N+2;
-+ */
-+ private void propagateChanges(final World worldIn, final UpdateNode upd1, final int layer) {
-+ if (upd1.neighbor_nodes == null) {
-+ // If this node has not been expanded yet, find its neighbors
-+ findNeighbors(worldIn, upd1);
-+ }
-+
-+ final BlockPosition pos = upd1.self;
-+
-+ // All neighbors may be scheduled for layer N+1
-+ final int layer1 = layer + 1;
-+
-+ // If the node being updated (upd1) has already been expanded, then merely
-+ // schedule updates to its neighbors.
-+ for (int i = 0; i < 24; i++) {
-+ final UpdateNode upd2 = upd1.neighbor_nodes[i];
-+
-+ // This test ensures that an UpdateNode is never scheduled to the same layer
-+ // more than once. Also, skip non-connecting redstone wire blocks
-+ if (upd2 != null && layer1 > upd2.layer) {
-+ upd2.layer = layer1;
-+ updateQueue1.add(upd2);
-+
-+ // Keep track of which block updated this neighbor
-+ upd2.parent = pos;
-+ }
-+ }
-+
-+ // Nodes above and below are scheduled ALSO for layer N+2
-+ final int layer2 = layer + 2;
-+
-+ // Repeat of the loop above, but only for the first four (above and below) neighbors
-+ // and for layer N+2;
-+ for (int i = 0; i < 4; i++) {
-+ final UpdateNode upd2 = upd1.neighbor_nodes[i];
-+ if (upd2 != null && layer2 > upd2.layer) {
-+ upd2.layer = layer2;
-+ updateQueue2.add(upd2);
-+ upd2.parent = pos;
-+ }
-+ }
-+ }
-+
-+ // The breadth-first search below will send block updates to blocks
-+ // that are not redstone wire. If one of those updates results in
-+ // a distant redstone wire getting an update, then this.neighborChanged
-+ // will get called. This would be a reentrant call, and
-+ // it is necessary to properly integrate those updates into the
-+ // on-going search through redstone wire. Thus, we make the layer
-+ // currently being processed visible at the object level.
-+
-+ // The current layer being processed by the breadth-first search
-+ private int currentWalkLayer = 0;
-+
-+ private void shiftQueue() {
-+ final List<UpdateNode> t = updateQueue0;
-+ t.clear();
-+ updateQueue0 = updateQueue1;
-+ updateQueue1 = updateQueue2;
-+ updateQueue2 = t;
-+ }
-+
-+ /*
-+ * Perform a breadth-first (layer by layer) traversal through redstone
-+ * wire blocks, propagating value changes to neighbors in an order
-+ * that is a function of distance from the initial call to
-+ * this.neighborChanged.
-+ */
-+ private void breadthFirstWalk(final World worldIn) {
-+ shiftQueue();
-+ currentWalkLayer = 1;
-+
-+ // Loop over all layers
-+ while (updateQueue0.size()>0 || updateQueue1.size()>0) {
-+ // Get the set of blocks in this layer
-+ final List<UpdateNode> thisLayer = updateQueue0;
-+
-+ // Loop over all blocks in the layer. Recall that
-+ // this is a List, preserving the insertion order of
-+ // left-to-right based on direction of information flow.
-+ for (UpdateNode upd : thisLayer) {
-+ if (upd.type == UpdateNode.Type.REDSTONE) {
-+ // If the node is is redstone wire,
-+ // schedule updates to neighbors if its value
-+ // has changed.
-+ updateNode(worldIn, upd, currentWalkLayer);
-+ } else {
-+ // If this block is not redstone wire, send a block update.
-+ // Redstone wire blocks get state updates, but they don't
-+ // need block updates. Only non-redstone neighbors need updates.
-+
-+ // World.neighborChanged is called from
-+ // World.notifyNeighborsOfStateChange, and
-+ // notifyNeighborsOfStateExcept. We don't use
-+ // World.notifyNeighborsOfStateChange here, since we are
-+ // already keeping track of all of the neighbor positions
-+ // that need to be updated. All on its own, handling neighbors
-+ // this way reduces block updates by 1/3 (24 instead of 36).
-+ worldIn.neighborChanged(upd.self, wire, upd.parent);
-+ }
-+ }
-+
-+ // Move on to the next layer
-+ shiftQueue();
-+ currentWalkLayer++;
-+ }
-+
-+ currentWalkLayer = 0;
-+ }
-+
-+ /*
-+ * Normally, when Minecraft is computing redstone wire power changes, and a wire power level
-+ * change sends a block update to a neighboring functional component (e.g. piston, repeater, etc.),
-+ * those updates are queued. Only once all redstone wire updates are complete will any component
-+ * action generate any further block updates to redstone wire. Instant repeater lines, for instance,
-+ * will process all wire updates for one redstone line, after which the pistons will zero-tick,
-+ * after which the next redstone line performs all of its updates. Thus, each wire is processed in its
-+ * own discrete wave.
-+ *
-+ * However, there are some corner cases where this pattern breaks, with a proof of concept discovered
-+ * by Rays Works, which works the same in vanilla. The scenario is as follows:
-+ * (1) A redstone wire is conducting a signal.
-+ * (2) Part-way through that wave of updates, a neighbor is updated that causes an update to a completely
-+ * separate redstone wire.
-+ * (3) This results in a call to BlockRedstoneWire.neighborChanged for that other wire, in the middle of
-+ * an already on-going propagation through the first wire.
-+ *
-+ * The vanilla code, being depth-first, would end up fully processing the second wire before going back
-+ * to finish processing the first one. (Although technically, vanilla has no special concept of "being
-+ * in the middle" of processing updates to a wire.) For the breadth-first algorithm, we give this
-+ * situation special handling, where the updates for the second wire are incorporated into the schedule
-+ * for the first wire, and then the callstack is allowed to unwind back to the on-going search loop in
-+ * order to continue processing both the first and second wire in the order of distance from the initial
-+ * trigger.
-+ */
-+ private IBlockData scheduleReentrantNeighborChanged(final World worldIn, final BlockPosition pos, final IBlockData newState, final BlockPosition source) {
-+ if (source != null) {
-+ // If the cause of the redstone wire update is known, we can use that to help determine
-+ // direction of information flow.
-+ UpdateNode src = nodeCache.get(source);
-+ if (src == null) {
-+ src = new UpdateNode();
-+ src.self = source;
-+ src.parent = source;
-+ src.visited = true;
-+ identifyNode(worldIn, src);
-+ nodeCache.put(source, src);
-+ }
-+ }
-+
-+ // Find or generate a node for the redstone block position receiving the update
-+ UpdateNode upd = nodeCache.get(pos);
-+ if (upd == null) {
-+ upd = new UpdateNode();
-+ upd.self = pos;
-+ upd.parent = pos;
-+ upd.visited = true;
-+ identifyNode(worldIn, upd);
-+ nodeCache.put(pos, upd);
-+ }
-+ upd.currentState = newState;
-+
-+ // Receiving this block update may mean something in the world changed.
-+ // Therefore we clear the cached block info about all neighbors of
-+ // the position receiving the update and then re-identify what they are.
-+ if (upd.neighbor_nodes != null) {
-+ for (int i=0; i<24; i++) {
-+ final UpdateNode upd2 = upd.neighbor_nodes[i];
-+ if (upd2 == null) continue;
-+ upd2.type = UpdateNode.Type.UNKNOWN;
-+ upd2.currentState = null;
-+ identifyNode(worldIn, upd2);
-+ }
-+ }
-+
-+ // The block at 'pos' is a redstone wire and has been updated already by calling
-+ // wire.calculateCurrentChanges, so we don't schedule that. However, we do need
-+ // to schedule its neighbors. By passing the current value of 'currentWalkLayer' to
-+ // propagateChanges, the neighbors of 'pos' are scheduled for layers currentWalkLayer+1
-+ // and currentWalkLayer+2.
-+ propagateChanges(worldIn, upd, currentWalkLayer);
-+
-+ // Return here. The call stack will unwind back to the first call to
-+ // updateSurroundingRedstone, whereupon the new updates just scheduled will
-+ // be propagated. This also facilitates elimination of superfluous and
-+ // redundant block updates.
-+ return newState;
-+ }
-+
-+ /*
-+ * New version of pre-existing updateSurroundingRedstone, which is called from
-+ * wire.updateSurroundingRedstone, which is called from wire.neighborChanged and a
-+ * few other methods in BlockRedstoneWire. This sets off the breadth-first
-+ * walk through all redstone dust connected to the initial position triggered.
-+ */
-+ public IBlockData updateSurroundingRedstone(final World worldIn, final BlockPosition pos, final IBlockData state, final BlockPosition source) {
-+ // Check this block's neighbors and see if its power level needs to change
-+ // Use the calculateCurrentChanges method in BlockRedstoneWire since we have no
-+ // cached block states at this point.
-+ final IBlockData newState = wire.calculateCurrentChanges(worldIn, pos, pos, state);
-+
-+ // If no change, exit
-+ if (newState == state) {
-+ return state;
-+ }
-+
-+ // Check to see if this update was received during an on-going breadth first search
-+ if (currentWalkLayer > 0 || nodeCache.size() > 0) {
-+ // As breadthFirstWalk progresses, it sends block updates to neighbors. Some of those
-+ // neighbors may affect the world so as to cause yet another redstone wire block to receive
-+ // an update. If that happens, we need to integrate those redstone wire updates into the
-+ // already on-going graph walk being performed by breadthFirstWalk.
-+ return scheduleReentrantNeighborChanged(worldIn, pos, newState, source);
-+ }
-+ // If there are no on-going walks through redstone wire, then start a new walk.
-+
-+ // If the source of the block update to the redstone wire at 'pos' is known, we can use
-+ // that to help determine the direction of information flow.
-+ if (source != null) {
-+ final UpdateNode src = new UpdateNode();
-+ src.self = source;
-+ src.parent = source;
-+ src.visited = true;
-+ nodeCache.put(source, src);
-+ identifyNode(worldIn, src);
-+ }
-+
-+ // Create a node representing the block at 'pos', and then propagate updates
-+ // to its neighbors. As stated above, the call to wire.calculateCurrentChanges
-+ // already performs the update to the block at 'pos', so it is not added to the schedule.
-+ final UpdateNode upd = new UpdateNode();
-+ upd.self = pos;
-+ upd.parent = source!=null ? source : pos;
-+ upd.currentState = newState;
-+ upd.type = UpdateNode.Type.REDSTONE;
-+ upd.visited = true;
-+ nodeCache.put(pos, upd);
-+ propagateChanges(worldIn, upd, 0);
-+
-+ // Perform the walk over all directly reachable redstone wire blocks, propagating wire value
-+ // updates in a breadth first order out from the initial update received for the block at 'pos'.
-+ breadthFirstWalk(worldIn);
-+
-+ // With the whole search completed, clear the list of all known blocks.
-+ // We do not want to keep around state information that may be changed by other code.
-+ // In theory, we could cache the neighbor block positions, but that is a separate
-+ // optimization.
-+ nodeCache.clear();
-+
-+ return newState;
-+ }
-+
-+ // For any array of neighbors in an UpdateNode object, these are always
-+ // the indices of the four immediate neighbors at the same Y coordinate.
-+ private static final int[] rs_neighbors = {4, 5, 6, 7};
-+ private static final int[] rs_neighbors_up = {9, 11, 13, 15};
-+ private static final int[] rs_neighbors_dn = {8, 10, 12, 14};
-+
-+ /*
-+ * Updated calculateCurrentChanges that is optimized for speed and uses
-+ * the UpdateNode's neighbor array to find the redstone states of neighbors
-+ * that might power it.
-+ */
-+ private IBlockData calculateCurrentChanges(final World worldIn, final UpdateNode upd) {
-+ IBlockData state = upd.currentState;
-+ final int i = state.get(BlockRedstoneWire.POWER).intValue();
-+ int j = 0;
-+ j = getMaxCurrentStrength(upd, j);
-+ int l = 0;
-+
-+ wire.setCanProvidePower(false);
-+ // Unfortunately, World.isBlockIndirectlyGettingPowered is complicated,
-+ // and I'm not ready to try to replicate even more functionality from
-+ // elsewhere in Minecraft into this accelerator. So sadly, we must
-+ // suffer the performance hit of this very expensive call. If there
-+ // is consistency to what this call returns, we may be able to cache it.
-+ final int k = worldIn.isBlockIndirectlyGettingPowered(upd.self);
-+ wire.setCanProvidePower(true);
-+
-+ // The variable 'k' holds the maximum redstone power value of any adjacent blocks.
-+ // If 'k' has the highest level of all neighbors, then the power level of this
-+ // redstone wire will be set to 'k'. If 'k' is already 15, then nothing inside the
-+ // following loop can affect the power level of the wire. Therefore, the loop is
-+ // skipped if k is already 15.
-+ if (k < 15) {
-+ if (upd.neighbor_nodes == null) {
-+ // If this node's neighbors are not known, expand the node
-+ findNeighbors(worldIn, upd);
-+ }
-+
-+ // These remain constant, so pull them out of the loop.
-+ // Regardless of which direction is forward, the UpdateNode for the
-+ // position directly above the node being calculated is always
-+ // at index 1.
-+ UpdateNode center_up = upd.neighbor_nodes[1];
-+ boolean center_up_is_cube = center_up.currentState.isOccluding(worldIn, center_up.self); // TODO
-+
-+ for (int m = 0; m < 4; m++) {
-+ // Get the neighbor array index of each of the four cardinal
-+ // neighbors.
-+ int n = rs_neighbors[m];
-+
-+ // Get the max redstone power level of each of the cardinal
-+ // neighbors
-+ UpdateNode neighbor = upd.neighbor_nodes[n];
-+ l = getMaxCurrentStrength(neighbor, l);
-+
-+ // Also check the positions above and below the cardinal
-+ // neighbors
-+ boolean neighbor_is_cube = neighbor.currentState.isOccluding(worldIn, neighbor.self); // TODO
-+ if (!neighbor_is_cube) {
-+ UpdateNode neighbor_down = upd.neighbor_nodes[rs_neighbors_dn[m]];
-+ l = getMaxCurrentStrength(neighbor_down, l);
-+ } else
-+ if (!center_up_is_cube) {
-+ UpdateNode neighbor_up = upd.neighbor_nodes[rs_neighbors_up[m]];
-+ l = getMaxCurrentStrength(neighbor_up, l);
-+ }
-+ }
-+ }
-+
-+ // The new code sets this RedstoneWire block's power level to the highest neighbor
-+ // minus 1. This usually results in wire power levels dropping by 2 at a time.
-+ // This optimization alone has no impact on update order, only the number of updates.
-+ j = l - 1;
-+
-+ // If 'l' turns out to be zero, then j will be set to -1, but then since 'k' will
-+ // always be in the range of 0 to 15, the following if will correct that.
-+ if (k > j) j = k;
-+
-+ // egg82's amendment
-+ // Adding Bukkit's BlockRedstoneEvent - er.. event.
-+ if (i != j) {
-+ BlockRedstoneEvent event = new BlockRedstoneEvent(worldIn.getWorld().getBlockAt(upd.self.getX(), upd.self.getY(), upd.self.getZ()), i, j);
-+ worldIn.getServer().getPluginManager().callEvent(event);
-+ j = event.getNewCurrent();
-+ }
-+
-+ if (i != j) {
-+ // If the power level has changed from its previous value, compute a new state
-+ // and set it in the world.
-+ // Possible optimization: Don't commit state changes to the world until they
-+ // need to be known by some nearby non-redstone-wire block.
-+ BlockPosition pos = new BlockPosition(upd.self.getX(), upd.self.getY(), upd.self.getZ());
-+ if (wire.canPlace(null, worldIn, pos)) {
-+ state = state.set(BlockRedstoneWire.POWER, Integer.valueOf(j));
-+ worldIn.setTypeAndData(upd.self, state, 2);
-+ }
-+ }
-+
-+ return state;
-+ }
-+
-+ /*
-+ * Optimized function to compute a redstone wire's power level based on cached
-+ * state.
-+ */
-+ private static int getMaxCurrentStrength(final UpdateNode upd, final int strength) {
-+ if (upd.type != UpdateNode.Type.REDSTONE) return strength;
-+ final int i = upd.currentState.get(BlockRedstoneWire.POWER).intValue();
-+ return i > strength ? i : strength;
-+ }
-+}
-diff --git a/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/src/main/java/net/minecraft/server/BlockRedstoneWire.java
-index 5bf2fc0b3f0a5209682b6056a6512ba9dbdca6d0..52a4982ecd7e4346e55c6fbab80032ed49490c15 100644
---- a/src/main/java/net/minecraft/server/BlockRedstoneWire.java
-+++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java
-@@ -1,5 +1,7 @@
- package net.minecraft.server;
-
-+import com.destroystokyo.paper.PaperConfig;
-+import com.destroystokyo.paper.util.RedstoneWireTurbo;
- import com.google.common.collect.ImmutableMap;
- import com.google.common.collect.Lists;
- import com.google.common.collect.Maps;
-@@ -22,8 +24,8 @@ public class BlockRedstoneWire extends Block {
- public static final BlockStateInteger POWER = BlockProperties.at;
- public static final Map<EnumDirection, BlockStateEnum<BlockPropertyRedstoneSide>> f = Maps.newEnumMap(ImmutableMap.of(EnumDirection.NORTH, BlockRedstoneWire.NORTH, EnumDirection.EAST, BlockRedstoneWire.EAST, EnumDirection.SOUTH, BlockRedstoneWire.SOUTH, EnumDirection.WEST, BlockRedstoneWire.WEST));
- protected static final VoxelShape[] g = new VoxelShape[]{Block.a(3.0D, 0.0D, 3.0D, 13.0D, 1.0D, 13.0D), Block.a(3.0D, 0.0D, 3.0D, 13.0D, 1.0D, 16.0D), Block.a(0.0D, 0.0D, 3.0D, 13.0D, 1.0D, 13.0D), Block.a(0.0D, 0.0D, 3.0D, 13.0D, 1.0D, 16.0D), Block.a(3.0D, 0.0D, 0.0D, 13.0D, 1.0D, 13.0D), Block.a(3.0D, 0.0D, 0.0D, 13.0D, 1.0D, 16.0D), Block.a(0.0D, 0.0D, 0.0D, 13.0D, 1.0D, 13.0D), Block.a(0.0D, 0.0D, 0.0D, 13.0D, 1.0D, 16.0D), Block.a(3.0D, 0.0D, 3.0D, 16.0D, 1.0D, 13.0D), Block.a(3.0D, 0.0D, 3.0D, 16.0D, 1.0D, 16.0D), Block.a(0.0D, 0.0D, 3.0D, 16.0D, 1.0D, 13.0D), Block.a(0.0D, 0.0D, 3.0D, 16.0D, 1.0D, 16.0D), Block.a(3.0D, 0.0D, 0.0D, 16.0D, 1.0D, 13.0D), Block.a(3.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D), Block.a(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 13.0D), Block.a(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D)};
-- private boolean h = true;
-- private final Set<BlockPosition> i = Sets.newHashSet();
-+ private boolean h = true; public final boolean canProvidePower() { return this.h; } public final void setCanProvidePower(boolean value) { this.h = value; } // Paper - OBFHELPER
-+ private final Set<BlockPosition> i = Sets.newHashSet(); private Set<BlockPosition> getBlocksNeedingUpdate() { return this.i; } // Paper - OBFHELPER
-
- public BlockRedstoneWire(Block.Info block_info) {
- super(block_info);
-@@ -157,6 +159,117 @@ public class BlockRedstoneWire extends Block {
- return iblockdata1.d(iworldreader, blockposition1, EnumDirection.UP) || iblockdata1.getBlock() == Blocks.HOPPER;
- }
-
-+ // Paper start - Optimize redstone
-+ // The bulk of the new functionality is found in RedstoneWireTurbo.java
-+ RedstoneWireTurbo turbo = new RedstoneWireTurbo(this);
-+
-+ /*
-+ * Modified version of pre-existing updateSurroundingRedstone, which is called from
-+ * this.neighborChanged and a few other methods in this class.
-+ * Note: Added 'source' argument so as to help determine direction of information flow
-+ */
-+ private IBlockData updateSurroundingRedstone(World worldIn, BlockPosition pos, IBlockData state, BlockPosition source) {
-+ if (worldIn.paperConfig.useEigencraftRedstone) {
-+ return turbo.updateSurroundingRedstone(worldIn, pos, state, source);
-+ }
-+ return a(worldIn, pos, state);
-+ }
-+
-+ /*
-+ * Slightly modified method to compute redstone wire power levels from neighboring blocks.
-+ * Modifications cut the number of power level changes by about 45% from vanilla, and this
-+ * optimization synergizes well with the breadth-first search implemented in
-+ * RedstoneWireTurbo.
-+ * Note: RedstoneWireTurbo contains a faster version of this code.
-+ * Note: Made this public so that RedstoneWireTurbo can access it.
-+ */
-+ public IBlockData calculateCurrentChanges(World worldIn, BlockPosition pos1, BlockPosition pos2, IBlockData state) {
-+ IBlockData iblockstate = state;
-+ int i = state.get(POWER).intValue();
-+ int j = 0;
-+ j = this.getPower(j, worldIn.getType(pos2));
-+ this.setCanProvidePower(false);
-+ int k = worldIn.isBlockIndirectlyGettingPowered(pos1);
-+ this.setCanProvidePower(true);
-+
-+ if (!worldIn.paperConfig.useEigencraftRedstone) {
-+ // This code is totally redundant to if statements just below the loop.
-+ if (k > 0 && k > j - 1) {
-+ j = k;
-+ }
-+ }
-+
-+ int l = 0;
-+
-+ // The variable 'k' holds the maximum redstone power value of any adjacent blocks.
-+ // If 'k' has the highest level of all neighbors, then the power level of this
-+ // redstone wire will be set to 'k'. If 'k' is already 15, then nothing inside the
-+ // following loop can affect the power level of the wire. Therefore, the loop is
-+ // skipped if k is already 15.
-+ if (!worldIn.paperConfig.useEigencraftRedstone || k < 15) {
-+ for (EnumDirection enumfacing : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
-+ BlockPosition blockpos = pos1.shift(enumfacing);
-+ boolean flag = blockpos.getX() != pos2.getX() || blockpos.getZ() != pos2.getZ();
-+
-+ if (flag) {
-+ l = this.getPower(l, worldIn.getType(blockpos));
-+ }
-+
-+ if (worldIn.getType(blockpos).isOccluding(worldIn, blockpos) && !worldIn.getType(pos1.up()).isOccluding(worldIn, pos1)) {
-+ if (flag && pos1.getY() >= pos2.getY()) {
-+ l = this.getPower(l, worldIn.getType(blockpos.up()));
-+ }
-+ } else if (!worldIn.getType(blockpos).isOccluding(worldIn, blockpos) && flag && pos1.getY() <= pos2.getY()) {
-+ l = this.getPower(l, worldIn.getType(blockpos.down()));
-+ }
-+ }
-+ }
-+
-+ if (!worldIn.paperConfig.useEigencraftRedstone) {
-+ // The old code would decrement the wire value only by 1 at a time.
-+ if (l > j) {
-+ j = l - 1;
-+ } else if (j > 0) {
-+ --j;
-+ } else {
-+ j = 0;
-+ }
-+
-+ if (k > j - 1) {
-+ j = k;
-+ }
-+ } else {
-+ // The new code sets this RedstoneWire block's power level to the highest neighbor
-+ // minus 1. This usually results in wire power levels dropping by 2 at a time.
-+ // This optimization alone has no impact on update order, only the number of updates.
-+ j = l - 1;
-+
-+ // If 'l' turns out to be zero, then j will be set to -1, but then since 'k' will
-+ // always be in the range of 0 to 15, the following if will correct that.
-+ if (k > j) j = k;
-+ }
-+
-+ if (i != j) {
-+ state = state.set(POWER, Integer.valueOf(j));
-+
-+ if (worldIn.getType(pos1) == iblockstate) {
-+ worldIn.setTypeAndData(pos1, state, 2);
-+ }
-+
-+ if (!worldIn.paperConfig.useEigencraftRedstone) {
-+ // The new search algorithm keeps track of blocks needing updates in its own data structures,
-+ // so only add anything to blocksNeedingUpdate if we're using the vanilla update algorithm.
-+ this.getBlocksNeedingUpdate().add(pos1);
-+
-+ for (EnumDirection enumfacing1 : EnumDirection.values()) {
-+ this.getBlocksNeedingUpdate().add(pos1.shift(enumfacing1));
-+ }
-+ }
-+ }
-+
-+ return state;
-+ }
-+ // Paper end
- private IBlockData a(World world, BlockPosition blockposition, IBlockData iblockdata) {
- iblockdata = this.b(world, blockposition, iblockdata);
- List<BlockPosition> list = Lists.newArrayList(this.i);
-@@ -255,7 +368,7 @@ public class BlockRedstoneWire extends Block {
- @Override
- public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) {
- if (iblockdata1.getBlock() != iblockdata.getBlock() && !world.isClientSide) {
-- this.a(world, blockposition, iblockdata);
-+ this.updateSurroundingRedstone(world, blockposition, iblockdata, null); // Paper - Optimize redstone
- Iterator iterator = EnumDirection.EnumDirectionLimit.VERTICAL.iterator();
-
- EnumDirection enumdirection;
-@@ -302,7 +415,7 @@ public class BlockRedstoneWire extends Block {
- world.applyPhysics(blockposition.shift(enumdirection), this);
- }
-
-- this.a(world, blockposition, iblockdata);
-+ this.updateSurroundingRedstone(world, blockposition, iblockdata, null); // Paper - Optimize redstone
- Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
-
- EnumDirection enumdirection1;
-@@ -343,7 +456,7 @@ public class BlockRedstoneWire extends Block {
- public void doPhysics(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1, boolean flag) {
- if (!world.isClientSide) {
- if (iblockdata.canPlace(world, blockposition)) {
-- this.a(world, blockposition, iblockdata);
-+ this.updateSurroundingRedstone(world, blockposition, iblockdata, blockposition1); // Paper - Optimize redstone
- } else {
- c(iblockdata, world, blockposition);
- world.a(blockposition, false);
-diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
-index 2db91e85bd5e95d15b607a96114f33b6e7687b19..29594e5fcddfd47d543813a2bf12234d9cbd29fd 100644
---- a/src/main/java/net/minecraft/server/World.java
-+++ b/src/main/java/net/minecraft/server/World.java
-@@ -523,6 +523,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
-
- }
-
-+ public void neighborChanged(BlockPosition pos, Block blockIn, BlockPosition fromPos) { a(pos, blockIn, fromPos); } // Paper - OBFHELPER
- public void a(BlockPosition blockposition, Block block, BlockPosition blockposition1) {
- if (!this.isClientSide) {
- IBlockData iblockdata = this.getType(blockposition);
-@@ -1278,6 +1279,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
- return this.getBlockFacePower(blockposition.down(), EnumDirection.DOWN) > 0 ? true : (this.getBlockFacePower(blockposition.up(), EnumDirection.UP) > 0 ? true : (this.getBlockFacePower(blockposition.north(), EnumDirection.NORTH) > 0 ? true : (this.getBlockFacePower(blockposition.south(), EnumDirection.SOUTH) > 0 ? true : (this.getBlockFacePower(blockposition.west(), EnumDirection.WEST) > 0 ? true : this.getBlockFacePower(blockposition.east(), EnumDirection.EAST) > 0))));
- }
-
-+ public int isBlockIndirectlyGettingPowered(BlockPosition pos) { return this.q(pos); } // Paper - OBFHELPER
- public int q(BlockPosition blockposition) {
- int i = 0;
- EnumDirection[] aenumdirection = World.a;