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 48991b885c7cad9c201887b222acad7d700bd03b..86ef1073c47ce430cd94befa8119dcac6a9a72b9 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -129,6 +129,12 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - rewrite chunk system + // 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); @@ -417,6 +423,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon List list = Lists.newArrayListWithCapacity(this.chunkMap.size()); Iterator iterator = this.chunkMap.getChunks().iterator(); + // 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 + while (iterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) iterator.next(); LevelChunk chunk = playerchunk.getTickingChunk(); @@ -457,6 +478,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 + Util.shuffle(list, this.level.random); // Paper start - PlayerNaturallySpawnCreaturesEvent int chunkRange = level.spigotConfig.mobSpawnRange; @@ -479,7 +509,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) { 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 (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index 5184df047c329323dfd1ebbf122963b4add098c3..3140d20aff7b1c518330bae088574e7163793eaf 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 74f4938c88b547c326c335aac09ab47fed3ea588..f7f65f3b7c0298e1e4fee4692ee6cce3bae707b6 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2372,6 +2372,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/org/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java index e964f05c5c0f2d1d9b4c0a3459076e4b95f0f4e8..b28ca267a841f33ba18fff5587a6b0e677dc1ea1 100644 --- a/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java +++ b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java @@ -34,6 +34,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..4c7895c94f7adaf0a7fb7c31327786b14768632e --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java @@ -0,0 +1,87 @@ +package org.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 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 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(); + } +}