From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:21:47 +0800 Subject: [PATCH] Force peaceful mode switch diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index 8a3e55b3a79a174a2a55f38d39ed4b8ba29b8763..d1a32a9e5267c27d1983abfb4812a6063964291f 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -74,6 +74,12 @@ public class ServerChunkCache extends ChunkSource { private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; + // Leaves start - peaceful mode switch + public int peacefulModeSwitchTick = -1; + public int peacefulModeSwitchCount = -1; + private final List> peacefulModeSwitchEntityTypes = List.of(net.minecraft.world.entity.boss.wither.WitherBoss.class, net.minecraft.world.entity.monster.Shulker.class, net.minecraft.world.entity.monster.warden.Warden.class); + // Leaves end - peaceful mode switch + private static int getChunkCacheKey(int x, int z) { return x & 3 | ((z & 3) << 2); } @@ -510,6 +516,21 @@ public class ServerChunkCache extends ChunkSource { // Leaves end - reset ice & snow tick random gameprofilerfiller.push("filteringLoadedChunks"); + // Leaves start - peaceful mode switch + if (peacefulModeSwitchTick > 0) { + if (this.level.getLevelData().getGameTime() % peacefulModeSwitchTick == 0) { + peacefulModeSwitchCount = 0; + this.level.getAllEntities().forEach(entity -> { + if (peacefulModeSwitchEntityTypes.contains(entity.getClass())) { + peacefulModeSwitchCount++; + } + }); + } + } else { + peacefulModeSwitchCount = -1; + } + // Leaves end - peaceful mode switch + // Paper start - optimise chunk tick iteration ChunkMap playerChunkMap = this.chunkMap; for (ServerPlayer player : this.level.players) { @@ -628,10 +649,20 @@ public class ServerChunkCache extends ChunkSource { } Util.shuffle(shuffled, this.level.random); chunkIterator = shuffled.iterator(); + } + + // Leaves start - peaceful mode switch + boolean peacefulModeSwitch = false; + if (lastSpawnState != null && peacefulModeSwitchCount != -1) { + if (peacefulModeSwitchCount >= NaturalSpawner.globalLimitForCategory(level, net.minecraft.world.entity.MobCategory.MONSTER, lastSpawnState.getSpawnableChunkCount())) { + peacefulModeSwitch = true; } - try { - // Paper end - optimise chunk tick iteration - while (chunkIterator.hasNext()) { + } + // Leaves end - peaceful mode switch + + try { + // Paper end - optimise chunk tick iteration + while (chunkIterator.hasNext()) { LevelChunk chunk1 = chunkIterator.next(); // Paper - optimise chunk tick iteration ChunkPos chunkcoordintpair = chunk1.getPos(); @@ -662,7 +693,7 @@ public class ServerChunkCache extends ChunkSource { // Paper end - optimise chunk tick iteration chunk1.incrementInhabitedTime(j); if (spawn && flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration - NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); + NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1, peacefulModeSwitch); // Leaves - peaceful mode switch } if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - optimise chunk tick iteration diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index 7eec9dc8237ff04c53b573c3cc87e6cdbfdda7ed..2aafb872578d266f2826e5bddebc9b4ab9b5050b 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -133,6 +133,12 @@ public final class NaturalSpawner { } public static void spawnForChunk(ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rareSpawn) { + // Leaves start - peaceful mode switch + spawnForChunk(world, chunk, info, spawnAnimals, spawnMonsters, rareSpawn, false); + } + + public static void spawnForChunk(ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rareSpawn, boolean peacefulModeSwitch) { + // Leaves end - peaceful mode switch world.getProfiler().push("spawner"); MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES; int i = aenumcreaturetype.length; @@ -141,6 +147,11 @@ public final class NaturalSpawner { for (int j = 0; j < i; ++j) { MobCategory enumcreaturetype = aenumcreaturetype[j]; + // Leaves start - peaceful mode switch + if (enumcreaturetype == MobCategory.MONSTER && peacefulModeSwitch) { + continue; + } + // Leaves end - peaceful mode switch // CraftBukkit start - Use per-world spawn limits boolean spawnThisTick = true; int limit = enumcreaturetype.getMaxInstancesPerChunk(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index e1fad381b861471a17529c246bb8a4a9c7646420..306c61c5d37bfda23fecde572ec6acd6d6d91e1e 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2370,6 +2370,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { return CraftFeatureFlag.getFromNMS(this.getHandle().enabledFeatures()).stream().map(FeatureFlag.class::cast).collect(Collectors.toUnmodifiableSet()); } + // Leaves start - unsupported settings + @Override + public void setPeacefulModeSwitchTick(int tick) { + this.getHandle().chunkSource.peacefulModeSwitchTick = tick; + } + + @Override + public int getPeacefulModeSwitchTick() { + return this.getHandle().chunkSource.peacefulModeSwitchTick; + } + // Leaves end - unsupported settings + public void storeBukkitValues(CompoundTag c) { if (!this.persistentDataContainer.isEmpty()) { c.put("BukkitValues", this.persistentDataContainer.toTagCompound()); diff --git a/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java index 8027a27b253db02570c2f28ebb200001b76a1fc3..da1f7ce2db23c509c70f673c8bb1c46af2ed7279 100644 --- a/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java +++ b/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java @@ -12,6 +12,7 @@ import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; +import top.leavesmc.leaves.command.subcommands.PeacefulModeSwitchCommand; import top.leavesmc.leaves.command.subcommands.UpdateCommand; import java.util.ArrayList; @@ -33,6 +34,7 @@ public final class LeavesCommand extends Command { private static final Map SUBCOMMANDS = Util.make(() -> { final Map, LeavesSubcommand> commands = new HashMap<>(); commands.put(Set.of("update"), new UpdateCommand()); + commands.put(Set.of("peaceful"), new PeacefulModeSwitchCommand()); return commands.entrySet().stream() .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) diff --git a/src/main/java/top/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java b/src/main/java/top/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..417689ab712ce21ee05fa05ffec35b9ff163e324 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java @@ -0,0 +1,87 @@ +package top.leavesmc.leaves.command.subcommands; + +import io.papermc.paper.command.CommandUtil; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.NaturalSpawner; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; +import top.leavesmc.leaves.command.LeavesSubcommand; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class PeacefulModeSwitchCommand implements LeavesSubcommand { + + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + World world; + if (args.length == 0) { + if (sender instanceof Player player) { + world = player.getWorld(); + } else { + sender.sendMessage(Component.text("Must specify a world! ex: '/leaves peaceful world'", NamedTextColor.RED)); + return true; + } + } else { + final String input = args[0]; + final World inputWorld = Bukkit.getWorld(input); + if (inputWorld == null) { + sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED)); + return true; + } else { + world = inputWorld; + } + } + + final ServerLevel level = ((CraftWorld) world).getHandle(); + int chunks = 0; + if (level.chunkSource.getLastSpawnState() != null) { + chunks = level.chunkSource.getLastSpawnState().getSpawnableChunkCount(); + } + + sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), + Component.text("Peaceful Mode Switch for world: "), + Component.text(world.getName(), NamedTextColor.AQUA) + )); + + sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), + Component.text("Refuses per "), + Component.text(level.chunkSource.peacefulModeSwitchTick, level.chunkSource.peacefulModeSwitchTick > 0 ? NamedTextColor.AQUA : NamedTextColor.GRAY), + Component.text(" tick") + )); + + int count = level.chunkSource.peacefulModeSwitchCount; + int limit = NaturalSpawner.globalLimitForCategory(level, MobCategory.MONSTER, chunks); + NamedTextColor color = count >= limit ? NamedTextColor.AQUA : NamedTextColor.GRAY; + + sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), + Component.text("Now count "), + Component.text(count, color), + Component.text("/", color), + Component.text(limit, color) + )); + + return true; + } + + @Override + public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { + return CommandUtil.getListMatchingLast(sender, args, this.suggestPeacefulModeSwitch(args)); + } + + private List suggestPeacefulModeSwitch(final String[] args) { + if (args.length == 1) { + return new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList()); + } + + return Collections.emptyList(); + } +}