diff --git a/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch b/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch deleted file mode 100644 index 3809e8c0b..000000000 --- a/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 22 Aug 2020 20:47:11 -0700 -Subject: [PATCH] Allow toggling special MobSpawners per world - -In vanilla, these are all hardcoded on for world type 0 (overworld) and hardcoded off for every other world type. Default config behaviour matches this. - -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 7ab130afddb0893016fb558ed624198316ca191d..3442ace00904b73f4384760d42c9385697132bc9 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -606,7 +606,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // CraftBukkit end - this.tickTime = flag1; - this.server = minecraftserver; -- this.customSpawners = list; -+ // Purpur start - enable/disable MobSpawners per world -+ this.customSpawners = Lists.newArrayList(); -+ if (purpurConfig.phantomSpawning) { -+ customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner()); -+ } -+ if (purpurConfig.patrolSpawning) { -+ customSpawners.add(new net.minecraft.world.level.levelgen.PatrolSpawner()); -+ } -+ if (purpurConfig.catSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.npc.CatSpawner()); -+ } -+ if (purpurConfig.villageSiegeSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege()); -+ } -+ if (purpurConfig.villagerTraderSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(iworlddataserver)); -+ } -+ // Purpur end - this.serverLevelData = iworlddataserver; - ChunkGenerator chunkgenerator = worlddimension.generator(); - // CraftBukkit start -diff --git a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -index a728dcbf956f108f01c966c7531449a506a14a87..4c1378132201c1e5d1bc01f8c0cbba91629bcffa 100644 ---- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -+++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -160,7 +160,17 @@ public class WanderingTraderSpawner implements CustomSpawner { - int k = pos.getX() + this.random.nextInt(range * 2) - range; - int l = pos.getZ() + this.random.nextInt(range * 2) - range; - int i1 = world.getHeight(Heightmap.Types.WORLD_SURFACE, k, l); -- BlockPos blockposition2 = new BlockPos(k, i1, l); -+ // Purpur start - allow traders to spawn below nether roof -+ BlockPos.MutableBlockPos blockposition2 = new BlockPos.MutableBlockPos(k, i1, l); -+ if (world.dimensionType().hasCeiling()) { -+ do { -+ blockposition2.relative(net.minecraft.core.Direction.DOWN); -+ } while (!world.getBlockState(blockposition2).isAir()); -+ do { -+ blockposition2.relative(net.minecraft.core.Direction.DOWN); -+ } while (world.getBlockState(blockposition2).isAir() && blockposition2.getY() > 0); -+ } -+ // Purpur end - - if (spawnplacementtype.isSpawnPositionOk(world, blockposition2, EntityType.WANDERING_TRADER)) { - blockposition1 = blockposition2; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e323914f8694043e7b08a2518169695f582bc1a8..9072bdd2fdb1c15ea1dbc599cb96fd82750ddcc6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -70,6 +70,12 @@ public class PurpurWorldConfig { - return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); - } - -+ private boolean getBoolean(String path, Predicate predicate) { -+ String val = getString(path, "default").toLowerCase(); -+ Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default"); -+ return predicate.test(bool); -+ } -+ - private double getDouble(String path, double def) { - PurpurConfig.config.addDefault("world-settings.default." + path, def); - return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); -@@ -232,6 +238,21 @@ public class PurpurWorldConfig { - } - } - -+ public boolean catSpawning; -+ public boolean patrolSpawning; -+ public boolean phantomSpawning; -+ public boolean villagerTraderSpawning; -+ public boolean villageSiegeSpawning; -+ private void mobSpawnerSettings() { -+ // values of "default" or null will default to true only if the world environment is normal (aka overworld) -+ Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); -+ catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate); -+ patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate); -+ phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); -+ villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); -+ villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); -+ } -+ - public boolean idleTimeoutKick = true; - public boolean idleTimeoutTickNearbyEntities = true; - public boolean idleTimeoutCountAsSleeping = false; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 49e8be572..7c43b4595 100644 --- a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -1,5 +1,31 @@ --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java +@@ -595,7 +_,24 @@ + // CraftBukkit end + this.tickTime = tickTime; + this.server = server; +- this.customSpawners = customSpawners; ++ // Purpur start - Allow toggling special MobSpawners per world ++ this.customSpawners = Lists.newArrayList(); ++ if (purpurConfig.phantomSpawning) { ++ customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner()); ++ } ++ if (purpurConfig.patrolSpawning) { ++ customSpawners.add(new net.minecraft.world.level.levelgen.PatrolSpawner()); ++ } ++ if (purpurConfig.catSpawning) { ++ customSpawners.add(new net.minecraft.world.entity.npc.CatSpawner()); ++ } ++ if (purpurConfig.villageSiegeSpawning) { ++ customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege()); ++ } ++ if (purpurConfig.villagerTraderSpawning) { ++ customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(serverLevelData)); ++ } ++ // Purpur end - Allow toggling special MobSpawners per world + this.serverLevelData = serverLevelData; + ChunkGenerator chunkGenerator = levelStem.generator(); + // CraftBukkit start @@ -934,9 +_,18 @@ && this.random.nextDouble() < currentDifficultyAt.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01) // Paper - Configurable spawn chances for skeleton horses && !this.getBlockState(blockPos.below()).is(Blocks.LIGHTNING_ROD); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index 06b6df21f..78a75e14c 100644 --- a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -6,7 +6,7 @@ - if (this.tickCount % 20 == 0) { - this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit -+ // Purpur start - Customizable wither health and healing ++ // Purpur start - Customizable wither health and healing - customizable heal rate and amount + if (this.tickCount % level().purpurConfig.witherHealthRegenDelay == 0) { + this.heal(level().purpurConfig.witherHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + // Purpur end - Customizable wither health and healing diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch new file mode 100644 index 000000000..f1ac7fc15 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -147,7 +_,17 @@ + int i1 = pos.getX() + this.random.nextInt(maxDistance * 2) - maxDistance; + int i2 = pos.getZ() + this.random.nextInt(maxDistance * 2) - maxDistance; + int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i1, i2); +- BlockPos blockPos1 = new BlockPos(i1, height, i2); ++ // Purpur start - Allow toggling special MobSpawners per world - allow traders to spawn below nether roof ++ BlockPos.MutableBlockPos blockPos1 = new BlockPos.MutableBlockPos(i1, height, i2); ++ if (level.dimensionType().hasCeiling()) { ++ do { ++ blockPos1.relative(net.minecraft.core.Direction.DOWN); ++ } while (!level.getBlockState(blockPos1).isAir()); ++ do { ++ blockPos1.relative(net.minecraft.core.Direction.DOWN); ++ } while (level.getBlockState(blockPos1).isAir() && blockPos1.getY() > 0); ++ } ++ // Purpur end - Allow toggling special MobSpawners per world + if (placementType.isSpawnPositionOk(level, blockPos1, EntityType.WANDERING_TRADER)) { + blockPos = blockPos1; + break; diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java index e8eab4631..9acbe5dc4 100644 --- a/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +++ b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java @@ -2,6 +2,7 @@ package org.purpurmc.purpur; import java.util.ArrayList; import java.util.HashMap; +import java.util.function.Predicate; import java.util.logging.Level; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -11,6 +12,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import org.apache.commons.lang.BooleanUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; @@ -59,6 +61,12 @@ public class PurpurWorldConfig { return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); } + private boolean getBoolean(String path, Predicate predicate) { + String val = getString(path, "default").toLowerCase(); + Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default"); + return predicate.test(bool); + } + private double getDouble(String path, double def) { PurpurConfig.config.addDefault("world-settings.default." + path, def); return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); @@ -221,6 +229,21 @@ public class PurpurWorldConfig { } } + public boolean catSpawning; + public boolean patrolSpawning; + public boolean phantomSpawning; + public boolean villagerTraderSpawning; + public boolean villageSiegeSpawning; + private void mobSpawnerSettings() { + // values of "default" or null will default to true only if the world environment is normal (aka overworld) + Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); + catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate); + patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate); + phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); + villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); + villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); + } + public boolean idleTimeoutKick = true; public boolean idleTimeoutTickNearbyEntities = true; public boolean idleTimeoutCountAsSleeping = false;