From 7de976a0e2ddd1615728a0fd3d40aea5872783d4 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Wed, 1 Jun 2022 04:39:22 +0200 Subject: [PATCH] fix #1454 --- .../carpet/helpers/RedstoneWireTurbo.java | 45 +++++++++++++++++-- .../mixins/RedstoneWireBlock_fastMixin.java | 5 ++- src/main/resources/carpet.accesswidener | 2 + 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main/java/carpet/helpers/RedstoneWireTurbo.java b/src/main/java/carpet/helpers/RedstoneWireTurbo.java index 4a103c95..33512acf 100644 --- a/src/main/java/carpet/helpers/RedstoneWireTurbo.java +++ b/src/main/java/carpet/helpers/RedstoneWireTurbo.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.HashMap; import java.util.concurrent.ThreadLocalRandom; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -662,7 +663,20 @@ public class RedstoneWireTurbo // 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); +// worldIn.neighborChanged(upd.self, wire, upd.parent); + + // [Space Walker] + // The neighbor update system got a significant overhaul in 1.19. + // Shape and block updates are now added to a stack before being + // processed. These changes make it so any neighbor updates emitted + // by this accelerator will not be processed until after the entire + // wire network has updated. This has a significant impact on the + // behavior and introduces Vanilla parity issues. + // To circumvent this issue we bypass the neighbor update stack and + // call BlockStateBase#neighborChanged directly. This change mostly + // restores old behavior, at the cost of bypassing the + // max-chained-neighbor-updates server property. + worldIn.getBlockState(upd.self).neighborChanged(worldIn, upd.self, wire, upd.parent, false); } } @@ -908,12 +922,37 @@ public class RedstoneWireTurbo // [gnembon] added state check cause other things in the tick may have popped it up already // https://github.com/gnembon/fabric-carpet/issues/117 if (worldIn.getBlockState(upd.self).getBlock() == Blocks.REDSTONE_WIRE) - worldIn.setBlock(upd.self, state, 2); + // [Space Walker] suppress shape updates and emit those manually to + // bypass the new neighbor update stack. + if (worldIn.setBlock(upd.self, state, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS)) + updateNeighborShapes(worldIn, upd.self, state); } return state; } - + + /* + * [Space Walker] + * This method emits shape updates around the given block, + * bypassing the new neighbor update stack. Diagonal shape + * updates are omitted, as they are mostly unnecessary. + * Diagonal shape updates are emitted exclusively to other + * redstone wires, in order to update their connection properties. + * Wire connections should never change as a result of power + * changes, so the only behavioral change will be in scenarios + * where earlier shape updates have been suppressed to keep a + * redstone wire in an invalid state. + */ + public void updateNeighborShapes(Level level, BlockPos pos, BlockState state) { + for (Direction dir : Block.UPDATE_SHAPE_ORDER) { + BlockPos neighborPos = pos.relative(dir); + BlockState neighborState = level.getBlockState(neighborPos); + + BlockState newState = neighborState.updateShape(dir.getOpposite(), state, level, neighborPos, pos); + Block.updateOrDestroy(neighborState, newState, level, neighborPos, Block.UPDATE_CLIENTS); + } + } + /* * Optimized function to compute a redstone wire's power level based on cached * state. diff --git a/src/main/java/carpet/mixins/RedstoneWireBlock_fastMixin.java b/src/main/java/carpet/mixins/RedstoneWireBlock_fastMixin.java index fe858c2b..0ac25bd1 100644 --- a/src/main/java/carpet/mixins/RedstoneWireBlock_fastMixin.java +++ b/src/main/java/carpet/mixins/RedstoneWireBlock_fastMixin.java @@ -79,7 +79,10 @@ public abstract class RedstoneWireBlock_fastMixin implements RedstoneWireBlockIn if (blockState_1.getValue(POWER) != i) { blockState_1 = blockState_1.setValue(POWER, i); if (world_1.getBlockState(blockPos_1) == blockState) { - world_1.setBlock(blockPos_1, blockState_1, 2); + // [Space Walker] suppress shape updates and emit those manually to + // bypass the new neighbor update stack. + if (world_1.setBlock(blockPos_1, blockState_1, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS)) + wireTurbo.updateNeighborShapes(world_1, blockPos_1, blockState_1); } if (!CarpetSettings.fastRedstoneDust) { diff --git a/src/main/resources/carpet.accesswidener b/src/main/resources/carpet.accesswidener index e355395a..405db420 100644 --- a/src/main/resources/carpet.accesswidener +++ b/src/main/resources/carpet.accesswidener @@ -5,3 +5,5 @@ accessible class net/minecraft/server/level/ThreadedLevelLightEngine$TaskType accessible class net/minecraft/world/item/crafting/Ingredient$Value accessible class net/minecraft/world/level/lighting/BlockLightSectionStorage$BlockDataLayerStorageMap accessible class net/minecraft/server/MinecraftServer$ReloadableResources + +accessible field net/minecraft/world/level/block/state/BlockBehaviour UPDATE_SHAPE_ORDER [Lnet/minecraft/core/Direction;