Skip to content

Commit

Permalink
Force peaceful mode switch (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
s-yh-china committed Aug 3, 2023
1 parent 66b078c commit 710267d
Show file tree
Hide file tree
Showing 2 changed files with 261 additions and 0 deletions.
23 changes: 23 additions & 0 deletions patches/api/0008-Force-peaceful-mode-switch.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <[email protected]>
Date: Thu, 3 Aug 2023 14:21:55 +0800
Subject: [PATCH] Force peaceful mode switch


diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index 6917931966377c51db88a3364997a110dd987970..ff145aba03c3ba20cb1d905705ff350d77dbc336 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -4000,6 +4000,12 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@NotNull
public Set<FeatureFlag> getFeatureFlags();

+ // Leaves start - unsupported settings
+ public void setPeacefulModeSwitchTick(int tick);
+
+ public int getPeacefulModeSwitchTick(int tick);
+ // Leaves end - unsupported settings
+
/**
* Represents various map environment types that a world may be
*/
238 changes: 238 additions & 0 deletions patches/server/0116-Force-peaceful-mode-switch.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <[email protected]>
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 47787f1f86b99cfcae6e1bb3dcf7648e9f04c936..d9da306d2675201beedddd43dcef18b31a2fa0e0 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -82,6 +82,12 @@ public class ServerChunkCache extends ChunkSource {
public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false);
// Leaves end - optimize mob spawning

+ // Leaves start - peaceful mode switch
+ public int peacefulModeSwitchTick = -1;
+ public int peacefulModeSwitchCount = -1;
+ private final List<Class<? extends Entity>> 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);
}
@@ -563,6 +569,22 @@ public class ServerChunkCache extends ChunkSource {
this.level.resetIceAndSnowTick();
}
// Leaves end - reset ice & snow tick random
+
+ // 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
+
int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
boolean flag1 = level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit

@@ -624,6 +646,15 @@ public class ServerChunkCache extends ChunkSource {
iterator1 = 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;
+ }
+ }
+ // Leaves end - peaceful mode switch
+
int chunksTicked = 0; // Paper
try {
while (iterator1.hasNext()) {
@@ -638,7 +669,7 @@ public class ServerChunkCache extends ChunkSource {
chunk1.incrementInhabitedTime(j);
// Leaves start - optimize mob spawning
if ((top.leavesmc.leaves.LeavesConfig.skipUnnecessaryMobSpawningComputations ? flag2AndHasNaturalSpawn : flag2) && (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning || spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration // Leaves -skip unnecessary mob spawning computations
- NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1);
+ NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1, peacefulModeSwitch); // Leaves - peaceful mode switch
}
// Leaves end - optimize mob spawning

diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 9a5b31a3a8614ca2ff2d5bdb64dddccd70b22c3f..64fdfb3c124f8574fc0313b8fd764a5cd254b151 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");
world.timings.mobSpawn.startTiming(); // Spigot
MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES;
@@ -142,6 +148,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 550dcb7d595221b221e4710890d8a3cad789fc07..7b576936c5a29f3714b2fc16c24e8cdec0d43f9e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -2300,6 +2300,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(int tick) {
+ 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 78d3df6a15057d42466c266226f308a070f560ac..06f5859cd04fe2147e37d61ab18e8fc0ff30769b 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<String, LeavesSubcommand> SUBCOMMANDS = Util.make(() -> {
final Map<Set<String>, 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..50c883ba689a51c1383e26ead3eb183c79b9a543
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java
@@ -0,0 +1,89 @@
+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<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ return CommandUtil.getListMatchingLast(sender, args, this.suggestPeacefulModeSwitch(args));
+ }
+
+ private List<String> suggestPeacefulModeSwitch(final String[] args) {
+ if (args.length == 1) {
+ final List<String> worlds = new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList());
+ worlds.add("*");
+ return worlds;
+ }
+
+ return Collections.emptyList();
+ }
+}

0 comments on commit 710267d

Please sign in to comment.