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 68e445c21e0acbdf6bb74d50ddd32e0ef2c0e9ad..021a9e557a186cb4439ef46b6cb9d014256c3f9e 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -128,6 +128,12 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon // Paper end - rewrite chunk system private ServerChunkCache.ChunkAndHolder[] iterationCopy; // Paper - chunk tick iteration optimisations + // Leaves start - peaceful mode switch + public int peacefulModeSwitchTick = org.leavesmc.leaves.LeavesConfig.forcePeacefulMode; + 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 + public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory) { this.level = world; this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(world); @@ -421,6 +427,22 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon gameprofilerfiller.push("pollingChunks"); 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 - chunk tick iteration optimisations List list; { @@ -475,6 +497,15 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon gameprofilerfiller.popPush("spawnAndTick"); boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + // 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; + } + } + // Leaves end - peaceful mode switch + if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.level.random); // Paper - per player mob spawns - do not need this when per-player is enabled // Paper start - PlayerNaturallySpawnCreaturesEvent int chunkRange = level.spigotConfig.mobSpawnRange; @@ -497,7 +528,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if (true && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) { // Paper - rewrite chunk system chunk1.incrementInhabitedTime(j); if (flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot - 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); } if (true) { // Paper - rewrite chunk system diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index 7cb97b7623b603aa5469c92f5a6816673c994540..adc3169fb375f03c532d0abdaf336bab8079c559 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -127,6 +127,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; @@ -135,6 +141,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 db2c1139f8471d12d6b80aab630b1426a084e47c..e08019b2191bf648a0a95ba0ef78d484ee4ff4ad 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2417,6 +2417,18 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper - replace feature flag API + // 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/org/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java index 41f4245f558f1c41ea84891b920f1d03dcb07066..92a8c3e4fc400988b3d984e7632a8149a2ce152e 100644 --- a/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java +++ b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java @@ -33,6 +33,7 @@ public final class LeavesCommand extends Command { final Map, LeavesSubcommand> commands = new HashMap<>(); commands.put(Set.of("config"), new ConfigCommand()); 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/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java b/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..1fe1d08cfb6caefc67cea27ac8fc188b8d6675c5 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java @@ -0,0 +1,87 @@ +package org.leavesmc.leaves.command.subcommands; + +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 org.leavesmc.leaves.command.LeavesCommandUtil; +import org.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 LeavesCommandUtil.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(); + } +}