diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index fce45f26..3229911e 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -54,7 +54,6 @@ public class CarpetSettings public static boolean chainStoneStickToAll = false; public static Block structureBlockIgnoredBlock = Blocks.STRUCTURE_VOID; public static final int vanillaStructureBlockLimit = 48; - public static int updateSuppressionBlockSetting = -1; private static class LanguageValidator extends Validator { @Override public String validate(CommandSourceStack source, ParsedRule currentRule, String newValue, String string) { @@ -1035,57 +1034,34 @@ public class CarpetSettings @Rule( desc = "Lightning kills the items that drop when lightning kills an entity", extra = {"Setting to true will prevent lightning from killing drops", "Fixes [MC-206922](https://bugs.mojang.com/browse/MC-206922)."}, - category = {BUGFIX} + category = BUGFIX ) public static boolean lightningKillsDropsFix = false; @Rule( - desc = "Placing an activator rail on top of a barrier block will update suppress when the rail turns off.", - extra = {"Entering an integer will make the update suppression block auto-reset","Integer entered is the delay in ticks for it to reset"}, - category = {CREATIVE, "extras"}, - options = {"false","true","1","6"}, + desc = "Placing an activator rail on top of a barrier block will fill the neighbor updater stack when the rail turns off.", + extra = {"The integer entered is the amount of updates that should be left in the stack", "-1 turns it off"}, + category = CREATIVE, + options = {"-1","0","10","50"}, strict = false, - validate = updateSuppressionBlockModes.class + validate = UpdateSuppressionBlockModes.class ) - public static String updateSuppressionBlock = "false"; + public static int updateSuppressionBlock = -1; @Rule( desc = "Fixes update suppression causing server crashes.", - category = {BUGFIX} + category = BUGFIX ) public static boolean updateSuppressionCrashFix = false; - public static int getInteger(String s) { - try { - return Integer.parseInt(s); - } catch(NumberFormatException e) { - return -1; - } - } - - private static class updateSuppressionBlockModes extends Validator { + private static class UpdateSuppressionBlockModes extends Validator { @Override - public String validate(CommandSourceStack source, ParsedRule currentRule, String newValue, String string) { - if (!currentRule.get().equals(newValue)) { - if (newValue.equalsIgnoreCase("false")) { - updateSuppressionBlockSetting = -1; - } else if (newValue.equalsIgnoreCase("true")) { - updateSuppressionBlockSetting = 0; - } else { - int parsedInt = getInteger(newValue); - if (parsedInt <= 0) { - updateSuppressionBlockSetting = -1; - return "false"; - } else { - updateSuppressionBlockSetting = parsedInt; - } - } - } - return newValue; + public Integer validate(CommandSourceStack source, ParsedRule currentRule, Integer newValue, String string) { + return newValue < -1 ? null : newValue; } @Override public String description() { - return "Cannot be negative, can be true, false, or # > 0"; + return "This value represents the amount of updates required before the logger logs them. Must be -1 or larger"; } } diff --git a/src/main/java/carpet/fakes/WorldInterface.java b/src/main/java/carpet/fakes/LevelInterface.java similarity index 84% rename from src/main/java/carpet/fakes/WorldInterface.java rename to src/main/java/carpet/fakes/LevelInterface.java index b631f282..583da757 100644 --- a/src/main/java/carpet/fakes/WorldInterface.java +++ b/src/main/java/carpet/fakes/LevelInterface.java @@ -1,5 +1,6 @@ package carpet.fakes; +import net.minecraft.world.level.redstone.NeighborUpdater; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -12,11 +13,13 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; -public interface WorldInterface +public interface LevelInterface { Map, Entity> getPrecookedMobs(); boolean setBlockStateWithBlockEntity(BlockPos blockPos, BlockState blockState, BlockEntity newBlockEntity, int int1); List getOtherEntitiesLimited(@Nullable Entity except, AABB box, Predicate predicate, int limit); + + NeighborUpdater getNeighborUpdater(); } diff --git a/src/main/java/carpet/mixins/BarrierBlock_updateSuppressionBlockMixin.java b/src/main/java/carpet/mixins/BarrierBlock_updateSuppressionBlockMixin.java index c2e44843..a4f2cc52 100644 --- a/src/main/java/carpet/mixins/BarrierBlock_updateSuppressionBlockMixin.java +++ b/src/main/java/carpet/mixins/BarrierBlock_updateSuppressionBlockMixin.java @@ -1,10 +1,11 @@ package carpet.mixins; import carpet.CarpetSettings; +import carpet.fakes.LevelInterface; +import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.util.RandomSource; import org.spongepowered.asm.mixin.Mixin; -import java.util.Random; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -23,33 +24,33 @@ public class BarrierBlock_updateSuppressionBlockMixin extends Block { public BarrierBlock_updateSuppressionBlockMixin(Properties settings) { super(settings); } @Override - public int getSignal(BlockState state, BlockGetter world, BlockPos pos, Direction direction) { + public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) { return (shouldPower && direction == Direction.DOWN) ? 15 : 0; } @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { - if (CarpetSettings.updateSuppressionBlockSetting != -1) { + public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { + if (CarpetSettings.updateSuppressionBlock != -1) { if (fromPos.equals(pos.above())) { - BlockState stateAbove = world.getBlockState(fromPos); + BlockState stateAbove = level.getBlockState(fromPos); if (stateAbove.is(Blocks.ACTIVATOR_RAIL) && !stateAbove.getValue(PoweredRailBlock.POWERED)) { - if (CarpetSettings.updateSuppressionBlockSetting > 0) { - world.scheduleTick(pos, this, CarpetSettings.updateSuppressionBlockSetting); - } - throw new StackOverflowError("updateSuppressionBlock"); + level.scheduleTick(pos, this, 1); + NeighborUpdater updater = ((LevelInterface)level).getNeighborUpdater(); + if (updater instanceof CollectingNeighborUpdaterAccessor cnua) + cnua.setCount(cnua.getMaxChainedNeighborUpdates()-CarpetSettings.updateSuppressionBlock); } } } - super.neighborChanged(state, world, pos, block, fromPos, notify); + super.neighborChanged(state, level, pos, block, fromPos, notify); } @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { + public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { BlockPos posAbove = pos.above(); - BlockState stateAbove = world.getBlockState(posAbove); + BlockState stateAbove = level.getBlockState(posAbove); if (stateAbove.is(Blocks.ACTIVATOR_RAIL) && !stateAbove.getValue(PoweredRailBlock.POWERED)) { shouldPower = true; - world.setBlock(posAbove, stateAbove.setValue(PoweredRailBlock.POWERED, true), 3); + level.setBlock(posAbove, stateAbove.setValue(PoweredRailBlock.POWERED, true), Block.UPDATE_CLIENTS | Block.UPDATE_NONE); shouldPower = false; } } diff --git a/src/main/java/carpet/mixins/CollectingNeighborUpdaterAccessor.java b/src/main/java/carpet/mixins/CollectingNeighborUpdaterAccessor.java new file mode 100644 index 00000000..8e262186 --- /dev/null +++ b/src/main/java/carpet/mixins/CollectingNeighborUpdaterAccessor.java @@ -0,0 +1,13 @@ +package carpet.mixins; + +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CollectingNeighborUpdater.class) +public interface CollectingNeighborUpdaterAccessor { + @Accessor("count") + void setCount(int count); + @Accessor("maxChainedNeighborUpdates") + int getMaxChainedNeighborUpdates(); +} diff --git a/src/main/java/carpet/mixins/Level_getOtherEntitiesLimited.java b/src/main/java/carpet/mixins/Level_getOtherEntitiesLimited.java index dbe06add..4a6b4a75 100644 --- a/src/main/java/carpet/mixins/Level_getOtherEntitiesLimited.java +++ b/src/main/java/carpet/mixins/Level_getOtherEntitiesLimited.java @@ -1,6 +1,6 @@ package carpet.mixins; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import com.google.common.collect.Lists; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -18,7 +18,7 @@ import net.minecraft.world.level.entity.LevelEntityGetter; import net.minecraft.world.phys.AABB; @Mixin(Level.class) -public abstract class Level_getOtherEntitiesLimited implements WorldInterface { +public abstract class Level_getOtherEntitiesLimited implements LevelInterface { private static final RuntimeException CONTROL_FLOW_EXCEPTION = new RuntimeException("Should be caught for control flow in World_getOtherEntitiesLimited!"); diff --git a/src/main/java/carpet/mixins/Level_movableBEMixin.java b/src/main/java/carpet/mixins/Level_movableBEMixin.java index 770caefd..151f215f 100644 --- a/src/main/java/carpet/mixins/Level_movableBEMixin.java +++ b/src/main/java/carpet/mixins/Level_movableBEMixin.java @@ -1,7 +1,7 @@ package carpet.mixins; import carpet.fakes.WorldChunkInterface; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ChunkHolder; import net.minecraft.util.profiling.ProfilerFiller; @@ -19,7 +19,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(Level.class) -public abstract class Level_movableBEMixin implements WorldInterface, LevelAccessor +public abstract class Level_movableBEMixin implements LevelInterface, LevelAccessor { @Shadow @Final diff --git a/src/main/java/carpet/mixins/Level_tickMixin.java b/src/main/java/carpet/mixins/Level_tickMixin.java index ea1ecb86..cde0cdc1 100644 --- a/src/main/java/carpet/mixins/Level_tickMixin.java +++ b/src/main/java/carpet/mixins/Level_tickMixin.java @@ -1,11 +1,13 @@ package carpet.mixins; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import carpet.helpers.TickSpeed; import carpet.utils.CarpetProfiler; +import net.minecraft.world.level.redstone.NeighborUpdater; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -19,14 +21,21 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @Mixin(Level.class) -public abstract class Level_tickMixin implements WorldInterface +public abstract class Level_tickMixin implements LevelInterface { @Shadow @Final public boolean isClientSide; + @Shadow @Final protected NeighborUpdater neighborUpdater; CarpetProfiler.ProfilerToken currentSection; CarpetProfiler.ProfilerToken entitySection; Map, Entity> precookedMobs = new HashMap<>(); + @Override + @Unique + public NeighborUpdater getNeighborUpdater() { + return this.neighborUpdater; + } + public Map, Entity> getPrecookedMobs() { return precookedMobs; diff --git a/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java b/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java index 9c07ebf1..4a65060c 100644 --- a/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java +++ b/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java @@ -1,7 +1,7 @@ package carpet.mixins; import carpet.CarpetSettings; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -39,7 +39,7 @@ public abstract class LivingEntity_maxCollisionsMixin extends Entity if (CarpetSettings.maxEntityCollisions > 0) { maxEntityCramming = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); - entities = ((WorldInterface) this.level).getOtherEntitiesLimited( + entities = ((LevelInterface) this.level).getOtherEntitiesLimited( this, this.getBoundingBox(), EntitySelector.pushableBy(this), diff --git a/src/main/java/carpet/mixins/NaturalSpawnerMixin.java b/src/main/java/carpet/mixins/NaturalSpawnerMixin.java index d59c5ab8..4f9eb3dd 100644 --- a/src/main/java/carpet/mixins/NaturalSpawnerMixin.java +++ b/src/main/java/carpet/mixins/NaturalSpawnerMixin.java @@ -1,7 +1,7 @@ package carpet.mixins; import carpet.CarpetSettings; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import carpet.utils.SpawnReporter; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.asm.mixin.Final; @@ -139,7 +139,7 @@ public class NaturalSpawnerMixin { if (CarpetSettings.lagFreeSpawning) { - Map, Entity> precookedMobs = ((WorldInterface)world_1).getPrecookedMobs(); + Map, Entity> precookedMobs = ((LevelInterface)world_1).getPrecookedMobs(); if (precookedMobs.containsKey(entityType)) //this mob has been 's but not used yet return precookedMobs.get(entityType); @@ -159,7 +159,7 @@ public class NaturalSpawnerMixin { if (CarpetSettings.lagFreeSpawning) // we used the mob - next time we will create a new one when needed - ((WorldInterface) world).getPrecookedMobs().remove(entity_1.getType()); + ((LevelInterface) world).getPrecookedMobs().remove(entity_1.getType()); if (SpawnReporter.track_spawns > 0L && SpawnReporter.local_spawns != null) { diff --git a/src/main/java/carpet/mixins/PistonMovingBlockEntity_movableBEMixin.java b/src/main/java/carpet/mixins/PistonMovingBlockEntity_movableBEMixin.java index 76d11166..9fee32a5 100644 --- a/src/main/java/carpet/mixins/PistonMovingBlockEntity_movableBEMixin.java +++ b/src/main/java/carpet/mixins/PistonMovingBlockEntity_movableBEMixin.java @@ -3,7 +3,7 @@ package carpet.mixins; import carpet.CarpetSettings; import carpet.fakes.BlockEntityInterface; import carpet.fakes.PistonBlockEntityInterface; -import carpet.fakes.WorldInterface; +import carpet.fakes.LevelInterface; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.Level; @@ -92,7 +92,7 @@ public abstract class PistonMovingBlockEntity_movableBEMixin extends BlockEntity if (!CarpetSettings.movableBlockEntities) return world.setBlock(blockPos_1, blockAState_2, int_1); else - return ((WorldInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockAState_2, ((PistonBlockEntityInterface)pistonBlockEntity).getCarriedBlockEntity(), int_1); + return ((LevelInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockAState_2, ((PistonBlockEntityInterface)pistonBlockEntity).getCarriedBlockEntity(), int_1); } @Redirect(method = "finalTick", at = @At(value = "INVOKE", @@ -103,7 +103,7 @@ public abstract class PistonMovingBlockEntity_movableBEMixin extends BlockEntity return world.setBlock(blockPos_1, blockState_2, int_1); else { - boolean ret = ((WorldInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockState_2, this.carriedBlockEntity, int_1); + boolean ret = ((LevelInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockState_2, this.carriedBlockEntity, int_1); this.carriedBlockEntity = null; //this will cancel the finishHandleBroken return ret; } @@ -122,7 +122,7 @@ public abstract class PistonMovingBlockEntity_movableBEMixin extends BlockEntity blockState_2 = Blocks.AIR.defaultBlockState(); else blockState_2 = Block.updateFromNeighbourShapes(this.movedState, this.level, this.worldPosition); - ((WorldInterface) (this.level)).setBlockStateWithBlockEntity(this.worldPosition, blockState_2, this.carriedBlockEntity, 3); + ((LevelInterface) (this.level)).setBlockStateWithBlockEntity(this.worldPosition, blockState_2, this.carriedBlockEntity, 3); this.level.destroyBlock(this.worldPosition, false, null); } } diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 5ceda88d..36efc249 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -186,7 +186,8 @@ "MinecraftServer_updateSuppressionCrashFixMixin", "ServerPlayer_updateSuppressionCrashFixMixin", "ChunkMap_creativePlayersLoadChunksMixin", - "SculkSensorBlock_rangeMixin" + "SculkSensorBlock_rangeMixin", + "CollectingNeighborUpdaterAccessor" ], "client": [ "Timer_tickSpeedMixin",