From f36b965683adbbe056ec0eca469e68dbc91d9ae1 Mon Sep 17 00:00:00 2001
From: egg82 <eggys82@gmail.com>
Date: Wed, 14 Nov 2018 20:09:37 -0700
Subject: [PATCH] Optimize redstone algorithm (#1494)

---
 .../Optimize-redstone-algorithm.patch         | 1162 +++++++++++++++++
 1 file changed, 1162 insertions(+)
 create mode 100644 Spigot-Server-Patches/Optimize-redstone-algorithm.patch

diff --git a/Spigot-Server-Patches/Optimize-redstone-algorithm.patch b/Spigot-Server-Patches/Optimize-redstone-algorithm.patch
new file mode 100644
index 0000000000..c8db801f20
--- /dev/null
+++ b/Spigot-Server-Patches/Optimize-redstone-algorithm.patch
@@ -0,0 +1,1162 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: theosib <millerti@172.16.221.1>
+Date: Thu, 27 Sep 2018 01:43:35 -0600
+Subject: [PATCH] Optimize redstone algorithm
+
+Author: theosib <millerti@172.16.221.1>
+Co-authored-by: egg82 <eggys82@gmail.com>
+
+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 eabb2c1ba..5fb6e263a 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+@@ -0,0 +0,0 @@ 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 000000000..21d9d6d7e
+--- /dev/null
++++ b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
+@@ -0,0 +0,0 @@
++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.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
++            oldState.dropNaturally(worldIn, pos, 0);
++            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();
++
++            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();
++                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.
++            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 80bad6755..3b45489a4 100644
+--- a/src/main/java/net/minecraft/server/BlockRedstoneWire.java
++++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java
+@@ -0,0 +0,0 @@
+ 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;
+@@ -0,0 +0,0 @@ public class BlockRedstoneWire extends Block {
+     public static final BlockStateInteger POWER = BlockProperties.al;
+     public static final Map<EnumDirection, BlockStateEnum<BlockPropertyRedstoneSide>> q = Maps.newEnumMap(ImmutableMap.of(EnumDirection.NORTH, BlockRedstoneWire.NORTH, EnumDirection.EAST, BlockRedstoneWire.EAST, EnumDirection.SOUTH, BlockRedstoneWire.SOUTH, EnumDirection.WEST, BlockRedstoneWire.WEST));
+     protected static final VoxelShape[] r = 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)};
++    public boolean canProvidePower() { return this.s; } // Paper - OBFHELPER
++    public void setCanProvidePower(boolean value) { this.s = value; } // Paper - OBFHELPER
+     private boolean s = true;
++    private Set<BlockPosition> getBlocksNeedingUpdate() { return this.t; } // Paper - OBFHELPER
+     private final Set<BlockPosition> t = Sets.newHashSet();
+ 
+     public BlockRedstoneWire(Block.Info block_info) {
+@@ -0,0 +0,0 @@ public class BlockRedstoneWire extends Block {
+         return iblockdata1.q() || iblockdata1.getBlock() == Blocks.GLOWSTONE;
+     }
+ 
+-    private IBlockData a(World world, BlockPosition blockposition, IBlockData iblockdata) {
+-        iblockdata = this.b(world, blockposition, iblockdata);
++    // 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.getType(pos1.up()).isOccluding()) {
++                    if (flag && pos1.getY() >= pos2.getY()) {
++                        l = this.getPower(l, worldIn.getType(blockpos.up()));
++                    }
++                } else if (!worldIn.getType(blockpos).isOccluding() && 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 worldIn, BlockPosition pos, IBlockData state) {
++        state = this.b(worldIn, pos, state);
+         ArrayList arraylist = Lists.newArrayList(this.t);
+ 
+         this.t.clear();
+@@ -0,0 +0,0 @@ public class BlockRedstoneWire extends Block {
+         while (iterator.hasNext()) {
+             BlockPosition blockposition1 = (BlockPosition) iterator.next();
+ 
+-            world.applyPhysics(blockposition1, this);
++            worldIn.applyPhysics(blockposition1, this);
+         }
+ 
+-        return iblockdata;
++        return state;
+     }
+ 
+     private IBlockData b(World world, BlockPosition blockposition, IBlockData iblockdata) {
+@@ -0,0 +0,0 @@ public class BlockRedstoneWire extends Block {
+ 
+     public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1) {
+         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;
+@@ -0,0 +0,0 @@ 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;
+@@ -0,0 +0,0 @@ public class BlockRedstoneWire extends Block {
+     public void doPhysics(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
+         if (!world.isClientSide) {
+             if (iblockdata.canPlace(world, blockposition)) {
+-                this.a(world, blockposition, iblockdata);
++                this.updateSurroundingRedstone(world, blockposition, iblockdata, blockposition1); // Paper - Optimize redstone
+             } else {
+                 iblockdata.a(world, blockposition, 0);
+                 world.setAir(blockposition);
+diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
+index 7914f9b60..cdbb247da 100644
+--- a/src/main/java/net/minecraft/server/World.java
++++ b/src/main/java/net/minecraft/server/World.java
+@@ -0,0 +0,0 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
+ 
+     }
+ 
++    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);
+@@ -0,0 +0,0 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
+         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 u(pos); } // Paper - OBFHELPER
+     public int u(BlockPosition blockposition) {
+         int i = 0;
+         EnumDirection[] aenumdirection = World.a;
+--
\ No newline at end of file