diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index ce47c63e..13a49e68 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -1,41 +1,32 @@ package carpet; +import carpet.fakes.MinecraftServer_motdInterface; +import carpet.fakes.PortalForcerInterface; +import carpet.utils.Messenger; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.network.ServerPlayerEntity; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.io.File; -import java.io.FileWriter; -import java.io.FileReader; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.FileNotFoundException; - //import carpet.helpers.SpawnChunks; -import carpet.fakes.MinecraftServer_motdInterface; -import carpet.utils.Messenger; -import net.minecraft.server.command.CommandSource; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.world.dimension.DimensionType; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.server.MinecraftServer; public class CarpetSettings { @@ -136,7 +127,9 @@ public class CarpetSettings rule("commandPlayer", "commands", "Enables /player command to control/spawn players").isACommand().wip(), rule("carpets", "survival", "Placing carpets may issue carpet commands for non-op players"), rule("missingTools", "survival", "Pistons, Glass and Sponge can be broken faster with their appropriate tools").wip(), - rule("portalCaching", "survival experimental", "Alternative, persistent caching strategy for nether portals").wip(), + rule("portalCaching", "survival experimental", "Alternative, persistent caching strategy for nether portals").validate( + (s, n) -> s.getMinecraftServer().getWorlds().forEach(w -> ((PortalForcerInterface)w.getPortalForcer()).invalidateCache()) + ), rule("calmNetherFires", "experimental", "Permanent fires don't schedule random updates").wip(), rule("fillUpdates", "creative", "fill/clone/setblock and structure blocks cause block updates").defaultTrue().boolAccelerate(), rule("pushLimit", "creative","Customizable piston push limit") diff --git a/src/main/java/carpet/fakes/PortalForcerInterface.java b/src/main/java/carpet/fakes/PortalForcerInterface.java new file mode 100644 index 00000000..07d8725f --- /dev/null +++ b/src/main/java/carpet/fakes/PortalForcerInterface.java @@ -0,0 +1,6 @@ +package carpet.fakes; + +public interface PortalForcerInterface +{ + void invalidateCache(); +} diff --git a/src/main/java/carpet/mixins/PortalBlock_portalCachingMixin.java b/src/main/java/carpet/mixins/PortalBlock_portalCachingMixin.java new file mode 100644 index 00000000..a3e94ad0 --- /dev/null +++ b/src/main/java/carpet/mixins/PortalBlock_portalCachingMixin.java @@ -0,0 +1,43 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import carpet.fakes.PortalForcerInterface; +import net.minecraft.block.BlockState; +import net.minecraft.block.PortalBlock; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.IWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(PortalBlock.class) +public class PortalBlock_portalCachingMixin +{ + @Inject(method = "createPortalAt", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/block/PortalBlock$AreaHelper;createPortal()V" + )) + private void onCreatePortal(IWorld iWorld_1, BlockPos blockPos_1, CallbackInfoReturnable cir) + { + if (!iWorld_1.isClient() && CarpetSettings.getBool("portalCaching")) + { + ((PortalForcerInterface)((ServerWorld)iWorld_1).getPortalForcer()).invalidateCache(); + } + } + + @Inject(method = "getStateForNeighborUpdate", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/block/Block;getDefaultState()Lnet/minecraft/block/BlockState;" + )) + private void getAirBlockState(BlockState blockState_1, Direction direction_1, BlockState blockState_2, IWorld iWorld_1, BlockPos blockPos_1, BlockPos blockPos_2, CallbackInfoReturnable cir) + { + if (!iWorld_1.isClient() && CarpetSettings.getBool("portalCaching")) + { + ((PortalForcerInterface)((ServerWorld)iWorld_1).getPortalForcer()).invalidateCache(); + } + } + +} diff --git a/src/main/java/carpet/mixins/PortalForcer_portalCachingMixin.java b/src/main/java/carpet/mixins/PortalForcer_portalCachingMixin.java new file mode 100644 index 00000000..bedda2ca --- /dev/null +++ b/src/main/java/carpet/mixins/PortalForcer_portalCachingMixin.java @@ -0,0 +1,78 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import carpet.fakes.PortalForcerInterface; +import net.minecraft.entity.Entity; +import net.minecraft.server.world.ChunkTicketType; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.ColumnPos; +import net.minecraft.world.PortalForcer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfoReturnable; + +import java.util.HashMap; +import java.util.Map; + +@Mixin(PortalForcer.class) +public class PortalForcer_portalCachingMixin implements PortalForcerInterface +{ + @Shadow @Final private ServerWorld world; + private Map storedTicketInfos = new HashMap<>(); + + @Override + public void invalidateCache() + { + storedTicketInfos.clear(); + } + + @Inject(method = "createPortal", at = @At("HEAD")) + private void portalSpawnedByTheGame(Entity entity_1, CallbackInfoReturnable cir) + { + invalidateCache(); + } + + @Redirect(method = "getPortal", at = @At( + value = "INVOKE", + target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;" + )) + private Object /* private TicketInfo */ getTicketInfo(Map map, Object /* ColumnPos */ key) + { + //Do the dance with ticketinfos. If vanilla has one, we gonna borrow, if vanilla is missing, we supply + if (!CarpetSettings.getBool("portalCaching")) + return map.get(key); + Object ticketInfo = map.get(key); + if (ticketInfo != null) + { + storedTicketInfos.put((ColumnPos) key, ticketInfo); + return ticketInfo; + } + ticketInfo = storedTicketInfos.get(key); + if (ticketInfo != null) + { + // vanilla got removed, but we stored it meaning we not only need to add it but also let it chunkload + map.put(key, ticketInfo); + ColumnPos cpos = (ColumnPos)key; + BlockPos fakePos = new BlockPos(((ColumnPos) key).x, 0, ((ColumnPos) key).z); + world.method_14178().addTicket(ChunkTicketType.PORTAL, new ChunkPos(fakePos), 3, (ColumnPos) key); + } + return ticketInfo; + } + + @Redirect(method = "getPortal", at = @At( + value = "INVOKE", + target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + )) + private Object /* TicketInfo */ putNewTicket(Map map, Object /*ColumnPos */ key, Object /*TicketInfo */ value) + { + if (CarpetSettings.getBool("portalCaching")) + storedTicketInfos.put((ColumnPos) key, value); + return map.put(key, value); + } +} diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 5fc17beb..675b4e56 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -64,6 +64,9 @@ "ItemUsageContext_cactusMixin", "DispenserBehaviour_cactusMixin", + "PortalForcer_portalCachingMixin", + "PortalBlock_portalCachingMixin", + "HopperBlockEntityMixin", "ContainerMixin", "ClientConnectionMixin",