diff --git a/src/main/java/carpet/fakes/RedstoneWireBlockInterface.java b/src/main/java/carpet/fakes/RedstoneWireBlockInterface.java new file mode 100644 index 00000000..35889a52 --- /dev/null +++ b/src/main/java/carpet/fakes/RedstoneWireBlockInterface.java @@ -0,0 +1,11 @@ +package carpet.fakes; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface RedstoneWireBlockInterface { + BlockState updateLogicPublic(World world_1, BlockPos blockPos_1, BlockState blockState_1); + void setWiresGivePower(boolean wiresGivePower); + boolean getWiresGivePower(); +} diff --git a/src/main/java/carpet/helpers/RedstoneWireTurbo.javax b/src/main/java/carpet/helpers/RedstoneWireTurbo.java similarity index 96% rename from src/main/java/carpet/helpers/RedstoneWireTurbo.javax rename to src/main/java/carpet/helpers/RedstoneWireTurbo.java index 02b39435..361b43ba 100644 --- a/src/main/java/carpet/helpers/RedstoneWireTurbo.javax +++ b/src/main/java/carpet/helpers/RedstoneWireTurbo.java @@ -7,11 +7,17 @@ import java.util.Map; import java.util.HashMap; import java.util.concurrent.ThreadLocalRandom; +import carpet.fakes.RedstoneWireBlockInterface; import net.minecraft.block.Block; import net.minecraft.block.RedstoneWireBlock; import net.minecraft.block.BlockState; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.loot.context.LootContext; +import net.minecraft.world.loot.context.LootContextParameter; +import net.minecraft.world.loot.context.LootContextParameters; public class RedstoneWireTurbo { @@ -319,10 +325,19 @@ public class RedstoneWireTurbo // others are processed internally by the breadth first search // algorithm. To preserve this game behavior, this check must // be replicated here. - if (!oldState.isValidPosition(worldIn, pos)) { + if (!oldState.canPlaceAt(worldIn, pos)) { // Pop off the redstone dust - oldState.dropBlockAsItem(worldIn, pos, 0); - worldIn.removeBlock(pos); + // aurieh: there must be a better way to do this + LootContext.Builder ctx = new LootContext + .Builder(worldIn.getServer().getWorld(worldIn.dimension.getType())) + .put(LootContextParameters.POSITION, pos) + .put(LootContextParameters.TOOL, ItemStack.EMPTY); + List stacks = oldState.getDroppedStacks(ctx); + for (ItemStack stack : stacks) { + ItemEntity itemEntity = new ItemEntity(worldIn, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + worldIn.spawnEntity(itemEntity); + } + worldIn.clearBlockState(pos, false); // Mark this position as not being redstone wire upd1.type = UpdateNode.Type.OTHER; @@ -436,7 +451,7 @@ public class RedstoneWireTurbo // UpdateNode object. BlockState newState; if (old_current_change) { - newState = wire.func_212568_b(worldIn, pos, oldState); + newState = ((RedstoneWireBlockInterface)wire).updateLogicPublic(worldIn, pos, oldState); } else { // Looking up block state is slow. This accelerator includes a version of // calculateCurrentChanges that uses cahed wire values for a @@ -661,7 +676,7 @@ 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.updateNeighbor(upd.self, wire, upd.parent); } } @@ -765,7 +780,7 @@ public class RedstoneWireTurbo // Check this block's neighbors and see if its power level needs to change // Use the calculateCurrentChanges method in RedstoneWireBlock since we have no // cached block states at this point. - final BlockState newState = wire.func_212568_b(worldIn, pos, state); + final BlockState newState = ((RedstoneWireBlockInterface)wire).updateLogicPublic(worldIn, pos, state); // If no change, exit if (newState == state) { @@ -835,17 +850,17 @@ public class RedstoneWireTurbo BlockState state = upd.currentState; final int i = state.get(RedstoneWireBlock.POWER); int j = 0; - j = this.getMaxCurrentStrength(upd, j); + j = getMaxCurrentStrength(upd, j); int l = 0; - wire.setCanProvidePower(false); + ((RedstoneWireBlockInterface)wire).setWiresGivePower(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.getRedstonePowerFromNeighbors(upd.self); - wire.setCanProvidePower(true); + final int k = worldIn.getReceivedRedstonePower(upd.self); + ((RedstoneWireBlockInterface)wire).setWiresGivePower(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 @@ -863,7 +878,7 @@ public class RedstoneWireTurbo // 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.isNormalCube(); + boolean center_up_is_cube = center_up.currentState.isSimpleFullBlock(worldIn, center_up.self); for (int m=0; m<4; m++) { // Get the neighbor array index of each of the four cardinal @@ -873,18 +888,18 @@ public class RedstoneWireTurbo // Get the max redstone power level of each of the cardinal // neighbors UpdateNode neighbor = upd.neighbor_nodes[n]; - l = this.getMaxCurrentStrength(neighbor, l); + l = getMaxCurrentStrength(neighbor, l); // Also check the positions above and below the cardinal // neighbors - boolean neighbor_is_cube = neighbor.currentState.isNormalCube(); + boolean neighbor_is_cube = neighbor.currentState.isSimpleFullBlock(worldIn, neighbor.self); if (!neighbor_is_cube) { UpdateNode neighbor_down = upd.neighbor_nodes[rs_neighbors_dn[m]]; - l = this.getMaxCurrentStrength(neighbor_down, l); + l = getMaxCurrentStrength(neighbor_down, l); } else if (!center_up_is_cube) { UpdateNode neighbor_up = upd.neighbor_nodes[rs_neighbors_up[m]]; - l = this.getMaxCurrentStrength(neighbor_up, l); + l = getMaxCurrentStrength(neighbor_up, l); } } } diff --git a/src/main/java/carpet/mixins/RedstoneWireBlockMixin.java b/src/main/java/carpet/mixins/RedstoneWireBlockMixin.java new file mode 100644 index 00000000..a956d6bf --- /dev/null +++ b/src/main/java/carpet/mixins/RedstoneWireBlockMixin.java @@ -0,0 +1,187 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import carpet.fakes.RedstoneWireBlockInterface; +import carpet.helpers.RedstoneWireTurbo; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Iterator; +import java.util.Set; + +import static net.minecraft.block.RedstoneWireBlock.POWER; + +@Mixin(RedstoneWireBlock.class) +public abstract class RedstoneWireBlockMixin implements RedstoneWireBlockInterface { + // = + + @Shadow + private boolean wiresGivePower; + + @Shadow + @Final + private Set affectedNeighbors; + + @Shadow + private int increasePower(int int_1, BlockState blockState_1) { return 0; }; + + @Shadow + private BlockState update(World world_1, BlockPos blockPos_1, BlockState blockState_1) { return null; }; + + // = + + @Override + public BlockState updateLogicPublic(World world_1, BlockPos blockPos_1, BlockState blockState_1) { + return updateLogic(world_1, blockPos_1, blockState_1); + } + + @Override + @Accessor("wiresGivePower") + public abstract void setWiresGivePower(boolean wiresGivePower); + + @Override + @Accessor("wiresGivePower") + public abstract boolean getWiresGivePower(); + + // = + + private RedstoneWireTurbo wireTurbo = null; + + @Inject(method = "", at = @At("RETURN")) + private void onRedstoneWireBlockCTOR(Block.Settings settings, CallbackInfo ci) { + //noinspection ConstantConditions + wireTurbo = new RedstoneWireTurbo((RedstoneWireBlock) (Object) this); + } + + // = + + public BlockState fastUpdate(World world, BlockPos pos, BlockState state, BlockPos source) { + // [CM] fastRedstoneDust -- update based on carpet rule + if (CarpetSettings.b_fastRedstoneDust) { + wireTurbo.updateSurroundingRedstone(world, pos, state, source); + } + return update(world, pos, state); + } + + @Overwrite + private BlockState updateLogic(World world_1, BlockPos blockPos_1, BlockState blockState_1) { + BlockState blockState_2 = blockState_1; + int int_1 = (Integer)blockState_1.get(POWER); // i + int int_4 = increasePower(0, blockState_2); // j + this.wiresGivePower = false; + int int_2 = world_1.getReceivedRedstonePower(blockPos_1); // k + this.wiresGivePower = true; + int int_3 = 0; // l + + // [CM] fastRedstoneDust -- if statement around unnecessary check + if (!CarpetSettings.b_fastRedstoneDust) { + if (int_2 > 0 && int_2 > int_4 - 1) { + int_4 = int_2; + } + } + + if (!CarpetSettings.b_fastRedstoneDust || int_2 < 15) { + Iterator var8 = Direction.Type.HORIZONTAL.iterator(); + + label43: + while(true) { + while(true) { + if (!var8.hasNext()) { + break label43; + } + + Direction direction_1 = (Direction)var8.next(); + BlockPos blockPos_2 = blockPos_1.offset(direction_1); + BlockState blockState_3 = world_1.getBlockState(blockPos_2); + int_3 = this.increasePower(int_3, blockState_3); + BlockPos blockPos_3 = blockPos_1.up(); + if (blockState_3.isSimpleFullBlock(world_1, blockPos_2) && !world_1.getBlockState(blockPos_3).isSimpleFullBlock(world_1, blockPos_3)) { + int_3 = this.increasePower(int_3, world_1.getBlockState(blockPos_2.up())); + } else if (!blockState_3.isSimpleFullBlock(world_1, blockPos_2)) { + int_3 = this.increasePower(int_3, world_1.getBlockState(blockPos_2.down())); + } + } + } + } + + // [CM] fastRedstoneDust -- if statement around unnecessary check + if (!CarpetSettings.b_fastRedstoneDust) { + if (int_3 > int_4) { + int_4 = int_3 - 1; + } else if (int_4 > 0) { + --int_4; + } else { + int_4 = 0; + } + + if (int_2 > int_4 - 1) { + int_4 = int_2; + } + } else { + int_4 = int_3 - 1; + if (int_2 > int_4) int_4 = int_2; + } + + if (int_1 != int_4) { + blockState_1 = (BlockState)blockState_1.with(POWER, int_4); + if (world_1.getBlockState(blockPos_1) == blockState_2) { + world_1.setBlockState(blockPos_1, blockState_1, 2); + } + + if (!CarpetSettings.b_fastRedstoneDust) { + this.affectedNeighbors.add(blockPos_1); + Direction[] var14 = Direction.values(); + int var15 = var14.length; + + for (int var16 = 0; var16 < var15; ++var16) { + Direction direction_2 = var14[var16]; + this.affectedNeighbors.add(blockPos_1.offset(direction_2)); + } + } + } + + return blockState_1; + } + + // = + + private static final String updateTarget = "Lnet/minecraft/block/RedstoneWireBlock;update(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;"; + + @Redirect(method = "onBlockAdded", at = @At(value = "INVOKE", target = updateTarget)) + private BlockState redirectOnBlockAddedUpdate(RedstoneWireBlock self, World world_1, BlockPos blockPos_1, BlockState blockState_1) { + return fastUpdate(world_1, blockPos_1, blockState_1, null); + } + + @Redirect(method = "onBlockRemoved", at = @At(value = "INVOKE", target = updateTarget)) + private BlockState redirectOnBlockRemovedUpdate(RedstoneWireBlock self, World world_1, BlockPos blockPos_1, BlockState blockState_1) { + return fastUpdate(world_1, blockPos_1, blockState_1, null); + } + + @Redirect(method = "neighborUpdate", at = @At(value = "INVOKE", target = updateTarget)) + private BlockState redirectNeighborUpdateUpdate( + RedstoneWireBlock self, + World world_1, + BlockPos blockPos_1, + BlockState blockState_1, + BlockState blockState_2, + World world_2, + BlockPos blockPos_2, + Block block_1, + BlockPos blockPos_3, + boolean boolean_1) { + return fastUpdate(world_1, blockPos_1, blockState_1, blockPos_3); + } +} diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index fb04757a..7c322d6c 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -32,6 +32,7 @@ "PlayerActionC2SPacketMixin", "ServerPlayerEntityMixin", "PlayerManagerMixin", + "RedstoneWireBlockMixin", "CarpetBlockMixin", "SummonCommandMixin", "PistonHandler_pushLimitMixin",