diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index e1fb609b..cb9a3598 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -5,13 +5,11 @@ import carpet.settings.Rule; import carpet.settings.SettingsManager; import carpet.settings.Validator; import carpet.utils.Messenger; +import carpet.utils.SpawnChunks; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.world.ChunkTicketType; -import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.Unit; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.ChunkPos; @@ -236,13 +234,6 @@ public class CarpetSettings @Rule( desc = "Pistons can push block entities, like hoppers, chests etc.", category = {EXPERIMENTAL, FEATURE} ) public static boolean movableBlockEntities = false; - /*@Rule( - desc = "Orange stained glass behaves like slime, but doesn't stick to it", - extra = "Only available for 1.14. in 1.15 use honey instead", - category = {EXPERIMENTAL, FEATURE} - ) - public static boolean honeySlime = false;*/ - @Rule( desc = "Saplings turn into dead shrubs in hot climates and no water access", category = FEATURE ) public static boolean desertShrubs = false; @@ -356,9 +347,6 @@ public class CarpetSettings @Rule(desc = "Pistons, Glass and Sponge can be broken faster with their appropriate tools", category = SURVIVAL) public static boolean missingTools = false; - //@Rule(desc = "Alternative, persistent caching strategy for nether portals", category = {SURVIVAL, CREATIVE}) - //public static boolean portalCaching = false; // ineffective in 1.15 - @Rule(desc = "fill/clone/setblock and structure blocks cause block updates", category = CREATIVE) public static boolean fillUpdates = true; @@ -509,13 +497,9 @@ public class CarpetSettings ) public static int viewDistance = 0; - private static class DisableSpawnChunksValidator extends Validator { - @Override public Boolean validate(ServerCommandSource source, ParsedRule currentRule, Boolean newValue, String string) { - if (currentRule.get().booleanValue() == newValue.booleanValue()) - { - //must been some startup thing - return newValue; - } + public static class ChangeSpawnChunksValidator extends Validator { + public static void changeSpawnSize(int size) + { ServerWorld overworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD); if (overworld != null) { ChunkPos centerChunk = new ChunkPos(new BlockPos( @@ -523,40 +507,37 @@ public class CarpetSettings overworld.getLevelProperties().getSpawnY(), overworld.getLevelProperties().getSpawnZ() )); - ServerChunkManager chunkManager = (ServerChunkManager) overworld.getChunkManager(); - - chunkManager.removeTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE); - if (!newValue) - { - chunkManager.addTicket(ChunkTicketType.START, centerChunk, 11, Unit.INSTANCE); - } + SpawnChunks.changeSpawnChunks(overworld.getChunkManager(), centerChunk, size); + } + } + @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) { + if (newValue < 0 || newValue > 32) + { + Messenger.m(source, "r spawn chunk size has to be between 0 and 32"); + return null; + } + if (currentRule.get().intValue() == newValue.intValue()) + { + //must been some startup thing + return newValue; + } + ServerWorld currentOverworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD); + if (currentOverworld != null) + { + changeSpawnSize(newValue); } return newValue; } } @Rule( - desc = "Allows spawn chunks to unload", + desc = "Changes size of spawn chunks", + extra = {"Defines new radius", "setting it to 0 - disables spawn chunks"}, category = CREATIVE, - validate = DisableSpawnChunksValidator.class - ) - public static boolean disableSpawnChunks = false; - - /*private static class KelpLimit extends Validator - { - @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) { - return (newValue>=0 && newValue <=25)?newValue:null; - } - @Override - public String description() { return "You must choose a value from 0 to 25. 25 and all natural kelp can grow 25 blocks, choose 0 to make all generated kelp not to grow";} - } - @Rule( - desc = "limits growth limit of newly naturally generated kelp to this amount of blocks", - options = {"0", "2", "25"}, - category = FEATURE, strict = false, - validate = KelpLimit.class + options = {"0", "11"}, + validate = ChangeSpawnChunksValidator.class ) - public static int kelpGenerationGrowthLimit = 25;*/ + public static int spawnChunksSize = 11; @Rule(desc = "Coral structures will grow with bonemeal from coral plants", category = FEATURE) public static boolean renewableCoral = false; @@ -573,13 +554,6 @@ public class CarpetSettings @Rule(desc = "Spawning requires much less CPU and Memory", category = OPTIMIZATION) public static boolean lagFreeSpawning = false; - - //@Rule( - // desc = "Prevents horses and other mobs to wander into the distance after dismounting", - // extra = "Fixes issues with various Joergens wandering off and disappearing client-side", - // category = BUGFIX - //) - //public static boolean horseWanderingFix = false; @Rule( desc = "Allows structure mobs to spawn in flat worlds", diff --git a/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java b/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java new file mode 100644 index 00000000..37c4ec65 --- /dev/null +++ b/src/main/java/carpet/fakes/ChunkTicketManagerInterface.java @@ -0,0 +1,12 @@ +package carpet.fakes; + +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.server.world.ChunkTicket; +import net.minecraft.util.SortedArraySet; +import net.minecraft.util.math.ChunkPos; + +public interface ChunkTicketManagerInterface +{ + void changeSpawnChunks(ChunkPos pos, int distance); + Long2ObjectOpenHashMap>> getTicketsByPosition(); +} diff --git a/src/main/java/carpet/fakes/ServerChunkManagerInterface.java b/src/main/java/carpet/fakes/ServerChunkManagerInterface.java new file mode 100644 index 00000000..9f7daddc --- /dev/null +++ b/src/main/java/carpet/fakes/ServerChunkManagerInterface.java @@ -0,0 +1,8 @@ +package carpet.fakes; + +import net.minecraft.server.world.ChunkTicketManager; + +public interface ServerChunkManagerInterface +{ + ChunkTicketManager getTicketManager(); +} diff --git a/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java b/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java index 6d52eebd..72621cdd 100644 --- a/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java +++ b/src/main/java/carpet/mixins/ChunkTicketManager_scarpetMixin.java @@ -1,15 +1,23 @@ package carpet.mixins; +import carpet.fakes.ChunkTicketManagerInterface; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ChunkTicketManager; import net.minecraft.util.SortedArraySet; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.Shadow; @Mixin(ChunkTicketManager.class) -public interface ChunkTicketManager_scarpetMixin +public abstract class ChunkTicketManager_scarpetMixin implements ChunkTicketManagerInterface { - @Accessor - Long2ObjectOpenHashMap>> getTicketsByPosition(); + @Shadow @Final private Long2ObjectOpenHashMap>> ticketsByPosition; + + @Override + public Long2ObjectOpenHashMap>> getTicketsByPosition() + { + return ticketsByPosition; + } + } diff --git a/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java b/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java new file mode 100644 index 00000000..53987e95 --- /dev/null +++ b/src/main/java/carpet/mixins/ChunkTicketManager_spawnChunksMixin.java @@ -0,0 +1,60 @@ +package carpet.mixins; + +import carpet.fakes.ChunkTicketManagerInterface; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.server.world.ChunkTicket; +import net.minecraft.server.world.ChunkTicketManager; +import net.minecraft.server.world.ChunkTicketType; +import net.minecraft.util.SortedArraySet; +import net.minecraft.util.Unit; +import net.minecraft.util.math.ChunkPos; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Iterator; + +@Mixin(ChunkTicketManager.class) +public abstract class ChunkTicketManager_spawnChunksMixin implements ChunkTicketManagerInterface +{ + + @Shadow protected abstract SortedArraySet> getTicketSet(long position); + + @Shadow @Final private Long2ObjectOpenHashMap>> ticketsByPosition; + + @Shadow public abstract void removeTicket(ChunkTicketType type, ChunkPos pos, int radius, T argument); + + @Shadow protected abstract void removeTicket(long pos, ChunkTicket ticket); + + @Shadow public abstract void addTicket(ChunkTicketType type, ChunkPos pos, int radius, T argument); + + @Override + public void changeSpawnChunks(ChunkPos chunkPos, int distance) + { + long pos = chunkPos.toLong(); + SortedArraySet> set = ticketsByPosition.get(pos); + ChunkTicket existingTicket = null; + if (set != null) + { + Iterator> iter = set.iterator(); + while(iter.hasNext()) + { + ChunkTicket ticket = iter.next(); + if (ticket.getType() == ChunkTicketType.START) + { + existingTicket = ticket; + iter.remove(); + } + } + set.add(existingTicket); + } + // the reason we are removing the ticket this way is that there are sideeffects of removal + if (existingTicket != null) + { + removeTicket(pos, existingTicket); + } + // set optionally new spawn ticket + if (distance > 0) + addTicket(ChunkTicketType.START, chunkPos, distance, Unit.INSTANCE); + } +} diff --git a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java index 5d5e330e..b11f9d8c 100644 --- a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java +++ b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java @@ -1,8 +1,10 @@ package carpet.mixins; import carpet.CarpetServer; +import carpet.CarpetSettings; import com.google.gson.JsonElement; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.WorldGenerationProgressListener; import net.minecraft.world.level.LevelGeneratorType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -41,4 +43,11 @@ public abstract class MinecraftServer_coreMixin { CarpetServer.onServerClosed((MinecraftServer) (Object) this); } + + @Inject(method = "prepareStartRegion", at = @At("RETURN")) + private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci) + { + if (CarpetSettings.spawnChunksSize != 11) + CarpetSettings.ChangeSpawnChunksValidator.changeSpawnSize(CarpetSettings.spawnChunksSize); + } } diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java index 109c9bb5..ce4b9132 100644 --- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java @@ -1,8 +1,10 @@ package carpet.mixins; +import carpet.fakes.ServerChunkManagerInterface; import carpet.utils.SpawnReporter; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.entity.EntityCategory; +import net.minecraft.server.world.ChunkTicketManager; import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; @@ -24,12 +26,20 @@ import java.util.HashMap; import java.util.HashSet; @Mixin(ServerChunkManager.class) -public abstract class ServerChunkManagerMixin +public abstract class ServerChunkManagerMixin implements ServerChunkManagerInterface { @Shadow @Final private ServerWorld world; @Shadow @Final private static int CHUNKS_ELIGIBLE_FOR_SPAWNING; + @Shadow @Final private ChunkTicketManager ticketManager; + + @Override // shared between scarpet and spawnChunks setting + public ChunkTicketManager getTicketManager() + { + return ticketManager; + } + @Inject( method = "tickChunks", locals = LocalCapture.CAPTURE_FAILHARD, diff --git a/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java b/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java deleted file mode 100644 index 9cec83e8..00000000 --- a/src/main/java/carpet/mixins/ServerChunkManager_scarpetMixin.java +++ /dev/null @@ -1,13 +0,0 @@ -package carpet.mixins; - -import net.minecraft.server.world.ChunkTicketManager; -import net.minecraft.server.world.ServerChunkManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(ServerChunkManager.class) -public interface ServerChunkManager_scarpetMixin -{ - @Accessor - ChunkTicketManager getTicketManager(); -} diff --git a/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java b/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java new file mode 100644 index 00000000..a462a6f6 --- /dev/null +++ b/src/main/java/carpet/mixins/ServerWorld_spawnChunksMixin.java @@ -0,0 +1,17 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(ServerWorld.class) +public class ServerWorld_spawnChunksMixin +{ + @ModifyConstant(method = "setSpawnPos", constant = @Constant(intValue = 11), expect = 2) + private int pushLimit(int original) + { + return CarpetSettings.spawnChunksSize; + } +} diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 63615671..f246d4fb 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -1,14 +1,14 @@ package carpet.script; import carpet.CarpetServer; +import carpet.fakes.ChunkTicketManagerInterface; import carpet.fakes.MinecraftServerInterface; import carpet.fakes.BiomeArrayInterface; +import carpet.fakes.ServerChunkManagerInterface; import carpet.fakes.StatTypeInterface; import carpet.fakes.ThreadedAnvilChunkStorageInterface; import carpet.helpers.FeatureGenerator; -import carpet.mixins.ChunkTicketManager_scarpetMixin; import carpet.mixins.PointOfInterest_scarpetMixin; -import carpet.mixins.ServerChunkManager_scarpetMixin; import carpet.script.Fluff.TriFunction; import carpet.script.bundled.Module; import carpet.CarpetSettings; @@ -708,7 +708,7 @@ public class CarpetExpression { ServerWorld world = ((CarpetContext) c).s.getWorld(); Long2ObjectOpenHashMap>> levelTickets = ( - (ChunkTicketManager_scarpetMixin) ((ServerChunkManager_scarpetMixin) world.getChunkManager()) + (ChunkTicketManagerInterface) ((ServerChunkManagerInterface) world.getChunkManager()) .getTicketManager() ).getTicketsByPosition(); List res = new ArrayList<>(); diff --git a/src/main/java/carpet/utils/SpawnChunks.java b/src/main/java/carpet/utils/SpawnChunks.java new file mode 100644 index 00000000..e97cb531 --- /dev/null +++ b/src/main/java/carpet/utils/SpawnChunks.java @@ -0,0 +1,16 @@ +package carpet.utils; + +import carpet.fakes.ChunkTicketManagerInterface; +import carpet.fakes.ServerChunkManagerInterface; +import net.minecraft.server.world.ChunkTicketManager; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.util.math.ChunkPos; + +public class SpawnChunks +{ + public static void changeSpawnChunks(ServerChunkManager chunkManager, ChunkPos pos, int size) + { + ChunkTicketManager ticketManager = ((ServerChunkManagerInterface)chunkManager).getTicketManager(); + ((ChunkTicketManagerInterface)ticketManager).changeSpawnChunks(pos, size); + } +} diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 1fc02972..ea11cc6d 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -29,6 +29,9 @@ "ThreadedAnvilChunkStorage_scarpetChunkCreationMixin", "ChunkHolder_scarpetChunkCreationMixin", + "ChunkTicketManager_spawnChunksMixin", + "ServerWorld_spawnChunksMixin", + "MobEntityMixin", "ServerWorld_unloadedEntityMixin", "EntityTrackerEntry_leashFixMixin", @@ -143,7 +146,6 @@ "PlayerManager_scarpetEventsMixin", "ChunkTicketManager_scarpetMixin", - "ServerChunkManager_scarpetMixin", "StatType_scarpetMixin", "PointOfInterest_scarpetMixin", "ServerWorld_scarpetEventMixin",