250 patches...

This commit is contained in:
granny
2024-10-26 01:00:13 -07:00
parent bc370d5521
commit b7daf30869
50 changed files with 637 additions and 637 deletions

View File

@@ -0,0 +1,277 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: YouHaveTrouble <youhavetrouble@youhavetrouble.me>
Date: Sun, 22 Aug 2021 05:12:05 +0200
Subject: [PATCH] Extended OfflinePlayer API
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index 94ca0407303c4493ab4928b12ec6ecc75aaca549..a138e1b6b66d99f2035de054137a607aa6b7f0b9 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -363,14 +363,26 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
@Override
public Location getLocation() {
+ // Purpur start
+ if (this.isOnline()) {
+ return this.getPlayer().getLocation();
+ }
+ // Purpur end
+
CompoundTag data = this.getData();
if (data == null) {
return null;
}
- if (data.contains("Pos") && data.contains("Rotation")) {
- ListTag position = (ListTag) data.get("Pos");
- ListTag rotation = (ListTag) data.get("Rotation");
+ // Purpur start - OfflinePlayer API
+ //if (data.contains("Pos") && data.contains("Rotation")) {
+ ListTag position = data.getList("Pos", net.minecraft.nbt.Tag.TAG_DOUBLE);
+ ListTag rotation = data.getList("Rotation", net.minecraft.nbt.Tag.TAG_FLOAT);
+
+ if (position.isEmpty() && rotation.isEmpty()) {
+ return null;
+ }
+ // Purpur end - OfflinePlayer API
UUID uuid = new UUID(data.getLong("WorldUUIDMost"), data.getLong("WorldUUIDLeast"));
@@ -381,9 +393,9 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
rotation.getFloat(0),
rotation.getFloat(1)
);
- }
+ //} // Purpur - OfflinePlayer API
- return null;
+ //return null; // Purpur - OfflinePlayer API
}
@Override
@@ -626,4 +638,191 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
manager.save();
}
}
+
+ // Purpur start - OfflinePlayer API
+ @Override
+ public boolean getAllowFlight() {
+ if (this.isOnline()) {
+ return this.getPlayer().getAllowFlight();
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return false;
+ if (!data.contains("abilities")) return false;
+ CompoundTag abilities = data.getCompound("abilities");
+ return abilities.getByte("mayfly") == (byte) 1;
+ }
+ }
+
+ @Override
+ public void setAllowFlight(boolean flight) {
+ if (this.isOnline()) {
+ this.getPlayer().setAllowFlight(flight);
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return;
+ if (!data.contains("abilities")) return;
+ CompoundTag abilities = data.getCompound("abilities");
+ abilities.putByte("mayfly", (byte) (flight ? 1 : 0));
+ data.put("abilities", abilities);
+ save(data);
+ }
+ }
+
+ @Override
+ public boolean isFlying() {
+ if (this.isOnline()) {
+ return this.isFlying();
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return false;
+ if (!data.contains("abilities")) return false;
+ CompoundTag abilities = data.getCompound("abilities");
+ return abilities.getByte("flying") == (byte) 1;
+ }
+ }
+
+ @Override
+ public void setFlying(boolean value) {
+ if (this.isOnline()) {
+ this.getPlayer().setFlying(value);
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return;
+ if (!data.contains("abilities")) return;
+ CompoundTag abilities = data.getCompound("abilities");
+ abilities.putByte("mayfly", (byte) (value ? 1 : 0));
+ data.put("abilities", abilities);
+ save(data);
+ }
+ }
+
+ @Override
+ public void setFlySpeed(float value) throws IllegalArgumentException {
+ if (value < -1f || value > 1f) throw new IllegalArgumentException("FlySpeed needs to be between -1 and 1");
+ if (this.isOnline()) {
+ this.getPlayer().setFlySpeed(value);
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return;
+ if (!data.contains("abilities")) return;
+ CompoundTag abilities = data.getCompound("abilities");
+ abilities.putFloat("flySpeed", value);
+ data.put("abilities", abilities);
+ save(data);
+ }
+ }
+
+ @Override
+ public float getFlySpeed() {
+ if (this.isOnline()) {
+ return this.getPlayer().getFlySpeed();
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return 0;
+ if (!data.contains("abilities")) return 0;
+ CompoundTag abilities = data.getCompound("abilities");
+ return abilities.getFloat("flySpeed");
+ }
+ }
+
+ @Override
+ public void setWalkSpeed(float value) throws IllegalArgumentException {
+ if (value < -1f || value > 1f) throw new IllegalArgumentException("WalkSpeed needs to be between -1 and 1");
+ if (this.isOnline()) {
+ this.getPlayer().setWalkSpeed(value);
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return;
+ if (!data.contains("abilities")) return;
+ CompoundTag abilities = data.getCompound("abilities");
+ abilities.putFloat("walkSpeed", value);
+ data.put("abilities", abilities);
+ save(data);
+ }
+ }
+
+ @Override
+ public float getWalkSpeed() {
+ if (this.isOnline()) {
+ return this.getPlayer().getWalkSpeed();
+ } else {
+ CompoundTag data = this.getData();
+ if (data == null) return 0;
+ if (!data.contains("abilities")) return 0;
+ CompoundTag abilities = data.getCompound("abilities");
+ return abilities.getFloat("walkSpeed");
+ }
+ }
+
+ @Override
+ public boolean teleportOffline(Location destination) {
+ if (this.isOnline()) {
+ return this.getPlayer().teleport(destination);
+ } else {
+ return setLocation(destination);
+ }
+ }
+
+ @Override
+ public boolean teleportOffline(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause){
+ if (this.isOnline()) {
+ return this.getPlayer().teleport(destination, cause);
+ } else {
+ return setLocation(destination);
+ }
+ }
+
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination) {
+ if (this.isOnline()) {
+ return this.getPlayer().teleportAsync(destination);
+ } else {
+ return java.util.concurrent.CompletableFuture.completedFuture(setLocation(destination));
+ }
+ }
+
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(Location destination, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
+ if (this.isOnline()) {
+ return this.getPlayer().teleportAsync(destination, cause);
+ } else {
+ return java.util.concurrent.CompletableFuture.completedFuture(setLocation(destination));
+ }
+ }
+
+ private boolean setLocation(Location location) {
+ CompoundTag data = this.getData();
+ if (data == null) return false;
+ data.putLong("WorldUUIDMost", location.getWorld().getUID().getMostSignificantBits());
+ data.putLong("WorldUUIDLeast", location.getWorld().getUID().getLeastSignificantBits());
+ net.minecraft.nbt.ListTag position = new net.minecraft.nbt.ListTag();
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getX()));
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getY()));
+ position.add(net.minecraft.nbt.DoubleTag.valueOf(location.getZ()));
+ data.put("Pos", position);
+ net.minecraft.nbt.ListTag rotation = new net.minecraft.nbt.ListTag();
+ rotation.add(net.minecraft.nbt.FloatTag.valueOf(location.getYaw()));
+ rotation.add(net.minecraft.nbt.FloatTag.valueOf(location.getPitch()));
+ data.put("Rotation", rotation);
+ save(data);
+ return true;
+ }
+
+ /**
+ * Safely replaces player's .dat file with provided CompoundTag
+ * @param compoundTag
+ */
+ private void save(CompoundTag compoundTag) {
+ File playerDir = server.console.playerDataStorage.getPlayerDir();
+ try {
+ File tempFile = File.createTempFile(this.getUniqueId()+"-", ".dat", playerDir);
+ net.minecraft.nbt.NbtIo.writeCompressed(compoundTag, tempFile.toPath());
+ File playerDataFile = new File(playerDir, this.getUniqueId()+".dat");
+ File playerDataFileOld = new File(playerDir, this.getUniqueId()+".dat_old");
+ net.minecraft.Util.safeReplaceFile(playerDataFile.toPath(), tempFile.toPath(), playerDataFileOld.toPath());
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ }
+ // Purpur end - OfflinePlayer API
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 32f0aa352a4809573784451bccd70ae8c02590f4..0d7e460cc73d7e236883e71ab77d51c7ef5e72ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2793,6 +2793,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return this.getHandle().getAbilities().walkingSpeed * 2f;
}
+ // Purpur start - OfflinePlayer API
+ @Override
+ public boolean teleportOffline(@NotNull Location destination) {
+ return this.teleport(destination);
+ }
+
+ @Override
+ public boolean teleportOffline(Location destination, PlayerTeleportEvent.TeleportCause cause) {
+ return this.teleport(destination, cause);
+ }
+
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(@NotNull Location destination) {
+ return this.teleportAsync(destination);
+ }
+
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportOfflineAsync(@NotNull Location destination, PlayerTeleportEvent.TeleportCause cause) {
+ return this.teleportAsync(destination, cause);
+ }
+ // Purpur end - OfflinePlayer API
+
private void validateSpeed(float value) {
Preconditions.checkArgument(value <= 1f && value >= -1f, "Speed value (%s) need to be between -1f and 1f", value);
}

View File

@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: DoctaEnkoda <bierquejason@gmail.com>
Date: Mon, 9 Aug 2021 13:22:20 +0200
Subject: [PATCH] Added the ability to add combustible items
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
index 1240df9368855f836412b06cf564926a18bfe90d..e559eabed82d2f402908e5b80d1505076ccc53a2 100644
--- a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java
@@ -114,7 +114,13 @@ public abstract class AbstractFurnaceMenu extends RecipeBookMenu {
} else if (slot != 1 && slot != 0) {
if (this.canSmelt(itemstack1)) {
if (!this.moveItemStackTo(itemstack1, 0, 1, false)) {
- return ItemStack.EMPTY;
+ // Purpur start - fix #625
+ if (this.isFuel(itemstack1)) {
+ if (!this.moveItemStackTo(itemstack1, 1, 2, false)) {
+ return ItemStack.EMPTY;
+ }
+ }
+ // Purpur end
}
} else if (this.isFuel(itemstack1)) {
if (!this.moveItemStackTo(itemstack1, 1, 2, false)) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 91a158ed90b7ce3eac7277fd962682a0226c08ed..658893b06a994c7b927ae40db2c1284d606c35c2 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -131,6 +131,22 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
this.recipeType = recipeType; // Paper - cook speed multiplier API
}
+ // Purpur start
+ public static void addFuel(ItemStack itemStack, Integer burnTime) {
+ Map<Item, Integer> map = Maps.newLinkedHashMap();
+ map.putAll(getFuel());
+ map.put(itemStack.getItem(), burnTime);
+ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map);
+ }
+
+ public static void removeFuel(ItemStack itemStack) {
+ Map<Item, Integer> map = Maps.newLinkedHashMap();
+ map.putAll(getFuel());
+ map.remove(itemStack.getItem());
+ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map);
+ }
+ // Purpur End
+
// CraftBukkit start - add fields and methods
private int maxStack = MAX_STACK;
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index ac0dd26ecaa3d6a4ef0ebd271ec5c328f5320399..4eb332ed95fd0ca196f3712037deb7637bfa4d8b 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1590,6 +1590,19 @@ public final class CraftServer implements Server {
return true;
}
+ // Purpur Start
+ @Override
+ public void addFuel(org.bukkit.Material material, int burnTime) {
+ Preconditions.checkArgument(burnTime > 0, "BurnTime must be greater than 0");
+ net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity.addFuel(net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material)), burnTime);
+ }
+
+ @Override
+ public void removeFuel(org.bukkit.Material material) {
+ net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity.removeFuel(net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material)));
+ }
+ // Purpur End
+
@Override
public List<Recipe> getRecipesFor(ItemStack result) {
Preconditions.checkArgument(result != null, "ItemStack cannot be null");

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 12emin34 <macanovic.emin@gmail.com>
Date: Mon, 23 Aug 2021 17:59:29 +0200
Subject: [PATCH] Option for if rain and thunder should stop on sleep
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index c70a1ca4ed978df1b54363e966a8344a2fe6f277..de24307e48e7bc6cc39234fae55ddb404df243b3 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1278,6 +1278,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@VisibleForTesting
public void resetWeatherCycle() {
// CraftBukkit start
+ if (this.purpurConfig.rainStopsAfterSleep) // Purpur
this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents
// If we stop due to everyone sleeping we should reset the weather duration to some other random value.
// Not that everyone ever manages to get the whole server to sleep at the same time....
@@ -1285,6 +1286,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.serverLevelData.setRainTime(0);
}
// CraftBukkit end
+ if (this.purpurConfig.thunderStopsAfterSleep) // Purpur
this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents
// CraftBukkit start
// If we stop due to everyone sleeping we should reset the weather duration to some other random value.
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index cce5813f0624fabf8a9e38d2eb9d1d1d63f15b70..91debf506c8f1ece992586a1d0328304e358d88a 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -139,6 +139,8 @@ public class PurpurWorldConfig {
public boolean tickFluids = true;
public double mobsBlindnessMultiplier = 1;
public boolean mobsIgnoreRails = false;
+ public boolean rainStopsAfterSleep = true;
+ public boolean thunderStopsAfterSleep = true;
private void miscGameplayMechanicsSettings() {
useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative);
@@ -160,6 +162,8 @@ public class PurpurWorldConfig {
tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids);
mobsBlindnessMultiplier = getDouble("gameplay-mechanics.entity-blindness-multiplier", mobsBlindnessMultiplier);
mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails);
+ rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep);
+ thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep);
}
public int daytimeTicks = 12000;

View File

@@ -0,0 +1,79 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 23 Aug 2021 20:57:04 -0500
Subject: [PATCH] Chance for azalea blocks to grow into trees naturally
diff --git a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
index affbbf6abc6bc09ecb652c1dee92aa297458bc39..febc05dc39741807127cba4a2a55aaad62b0800c 100644
--- a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java
@@ -50,6 +50,20 @@ public class AzaleaBlock extends BushBlock implements BonemealableBlock {
@Override
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
+ // Purpur start
+ growTree(world, random, pos, state);
+ }
+
+ @Override
+ public void randomTick(net.minecraft.world.level.block.state.BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ double chance = state.getBlock() == Blocks.FLOWERING_AZALEA ? world.purpurConfig.floweringAzaleaGrowthChance : world.purpurConfig.azaleaGrowthChance;
+ if (chance > 0.0D && world.getMaxLocalRawBrightness(pos.above()) > 9 && random.nextDouble() < chance) {
+ growTree(world, random, pos, state);
+ }
+ }
+
+ private void growTree(ServerLevel world, RandomSource random, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) {
+ // Purpur end
TreeGrower.AZALEA.growTree(world, world.getChunkSource().getGenerator(), pos, state, random);
}
diff --git a/src/main/java/net/minecraft/world/level/block/Blocks.java b/src/main/java/net/minecraft/world/level/block/Blocks.java
index 66a07f7cbf1c1d6ecbe055cbf4f63eb07d93e90c..63d67d46d30ed8ed57cdc0e59b6cb6b75ab22c1f 100644
--- a/src/main/java/net/minecraft/world/level/block/Blocks.java
+++ b/src/main/java/net/minecraft/world/level/block/Blocks.java
@@ -6465,6 +6465,7 @@ public class Blocks {
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.forceSolidOff()
+ .randomTicks() // Purpur
.instabreak()
.sound(SoundType.AZALEA)
.noOcclusion()
@@ -6476,6 +6477,7 @@ public class Blocks {
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.forceSolidOff()
+ .randomTicks() // Purpur
.instabreak()
.sound(SoundType.FLOWERING_AZALEA)
.noOcclusion()
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 91debf506c8f1ece992586a1d0328304e358d88a..0a4626ea59c854d072972e78f06df3808797503f 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -763,6 +763,11 @@ public class PurpurWorldConfig {
anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage);
}
+ public double azaleaGrowthChance = 0.0D;
+ private void azaleaSettings() {
+ azaleaGrowthChance = getDouble("blocks.azalea.growth-chance", azaleaGrowthChance);
+ }
+
public int beaconLevelOne = 20;
public int beaconLevelTwo = 30;
public int beaconLevelThree = 40;
@@ -900,6 +905,11 @@ public class PurpurWorldConfig {
farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling);
}
+ public double floweringAzaleaGrowthChance = 0.0D;
+ private void floweringAzaleaSettings() {
+ floweringAzaleaGrowthChance = getDouble("blocks.flowering_azalea.growth-chance", floweringAzaleaGrowthChance);
+ }
+
public boolean furnaceUseLavaFromUnderneath = false;
private void furnaceSettings() {
if (PurpurConfig.version < 17) {

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Tue, 24 Aug 2021 16:48:35 -0500
Subject: [PATCH] Shift right click to use exp for mending
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 8ad07b6939831f57469bb6ad7c78b2c7e3b17fea..0f3dbe848ad923733e356c344a00667c6da0ab83 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -524,6 +524,7 @@ public class ServerPlayerGameMode {
public InteractionHand interactHand;
public ItemStack interactItemStack;
public InteractionResult useItemOn(ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) {
+ if (shiftClickMended(stack)) return InteractionResult.SUCCESS; // Purpur
BlockPos blockposition = hitResult.getBlockPos();
BlockState iblockdata = world.getBlockState(blockposition);
boolean cancelledBlock = false;
@@ -632,4 +633,18 @@ public class ServerPlayerGameMode {
public void setLevel(ServerLevel world) {
this.level = world;
}
+
+ // Purpur start
+ public boolean shiftClickMended(ItemStack itemstack) {
+ if (this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints > 0 && this.player.isShiftKeyDown() && this.player.getBukkitEntity().hasPermission("purpur.mending_shift_click")) {
+ int points = Math.min(this.player.totalExperience, this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints);
+ if (points > 0 && itemstack.isDamaged() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MENDING, itemstack) > 0) {
+ this.player.giveExperiencePoints(-points);
+ this.player.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.player.level(), this.player.getX(), this.player.getY(), this.player.getZ(), points, org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN, this.player, this.player));
+ return true;
+ }
+ }
+ return false;
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index c3fd22396eaf85ac4d7a0aeba67b5c26a748be4c..8da850ab34e576caf89681171124f617f57d00a7 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2020,6 +2020,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
boolean cancelled;
if (movingobjectposition == null || movingobjectposition.getType() != HitResult.Type.BLOCK) {
+ if (this.player.gameMode.shiftClickMended(itemstack)) return; // Purpur
org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack, enumhand);
cancelled = event.useItemInHand() == Event.Result.DENY;
} else {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 0a4626ea59c854d072972e78f06df3808797503f..025982aac35116320ff41203645e606504640940 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -402,6 +402,7 @@ public class PurpurWorldConfig {
public boolean playerBurpWhenFull = false;
public boolean playerRidableInWater = false;
public boolean playerRemoveBindingWithWeakness = false;
+ public int shiftRightClickRepairsMendingPoints = 0;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -426,6 +427,7 @@ public class PurpurWorldConfig {
playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull);
playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater);
playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness);
+ shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 30 Aug 2021 22:14:39 -0500
Subject: [PATCH] Dolphins naturally aggressive to players chance
diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
index bcc6435c177189aa59a3fbe67795ae5092685133..515fa6120554d9b2aad32257c48577e6458cd2ff 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
@@ -85,6 +85,7 @@ public class Dolphin extends AgeableWaterCreature {
return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater();
};
public static final float BABY_SCALE = 0.65F;
+ private boolean isNaturallyAggressiveToPlayers; // Purpur
private int spitCooldown; // Purpur
public Dolphin(EntityType<? extends Dolphin> type, Level world) {
@@ -180,6 +181,7 @@ public class Dolphin extends AgeableWaterCreature {
SpawnGroupData groupdataentity1 = (SpawnGroupData) Objects.requireNonNullElseGet(entityData, () -> {
return new AgeableMob.AgeableMobGroupData(0.1F);
});
+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance; // Purpur
return super.finalizeSpawn(world, difficulty, spawnReason, groupdataentity1);
}
@@ -256,6 +258,7 @@ public class Dolphin extends AgeableWaterCreature {
protected void registerGoals() {
this.goalSelector.addGoal(0, new BreathAirGoal(this));
this.goalSelector.addGoal(0, new TryFindWaterGoal(this));
+ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this));
this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D));
@@ -263,12 +266,13 @@ public class Dolphin extends AgeableWaterCreature {
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(5, new DolphinJumpGoal(this, 10));
- this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true));
+ //this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - moved up
this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal());
this.goalSelector.addGoal(8, new FollowBoatGoal(this));
this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D));
this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers());
+ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, target -> isNaturallyAggressiveToPlayers)); // Purpur
}
public static AttributeSupplier.Builder createAttributes() {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 025982aac35116320ff41203645e606504640940..3f10fe595960a69ed372f80c1b28acd9e956516b 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1343,6 +1343,7 @@ public class PurpurWorldConfig {
public double dolphinScale = 1.0D;
public boolean dolphinDisableTreasureSearching = false;
public boolean dolphinTakeDamageFromWater = false;
+ public double dolphinNaturallyAggressiveToPlayersChance = 0.0D;
private void dolphinSettings() {
dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable);
dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable);
@@ -1358,6 +1359,7 @@ public class PurpurWorldConfig {
dolphinScale = Mth.clamp(getDouble("mobs.dolphin.attributes.scale", dolphinScale), 0.0625D, 16.0D);
dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching);
dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater);
+ dolphinNaturallyAggressiveToPlayersChance = getDouble("mobs.dolphin.naturally-aggressive-to-players-chance", dolphinNaturallyAggressiveToPlayersChance);
}
public boolean donkeyRidableInWater = false;

View File

@@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Mon, 30 Aug 2021 22:49:53 -0500
Subject: [PATCH] Cows naturally aggressive to players chance
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java
index 9c3bdf70c70328df4bfc13cb09aeef4b190cd77e..234785a387f445b3e40978978a647140b3490072 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cow.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java
@@ -37,6 +37,7 @@ import org.bukkit.event.player.PlayerBucketFillEvent;
// CraftBukkit end
public class Cow extends Animal {
+ private boolean isNaturallyAggressiveToPlayers; // Purpur
private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F);
@@ -64,6 +65,7 @@ public class Cow extends Animal {
public void initAttributes() {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth);
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale);
+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.cowNaturallyAggressiveToPlayersDamage); // Purpur
}
// Purpur end
@@ -77,11 +79,18 @@ public class Cow extends Animal {
return this.level().purpurConfig.cowTakeDamageFromWater;
}
+ @Override
+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData entityData) {
+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance;
+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
+ }
+
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur
this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D));
+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur
this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> {
return level().purpurConfig.cowFeedMushrooms > 0 && (itemstack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemstack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemstack.is(ItemTags.COW_FOOD); // Purpur
@@ -90,6 +99,7 @@ public class Cow extends Animal {
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
+ this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, target -> isNaturallyAggressiveToPlayers)); // Purpur
}
@Override
@@ -98,7 +108,7 @@ public class Cow extends Animal {
}
public static AttributeSupplier.Builder createAttributes() {
- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D);
+ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur
}
@Override
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 3f10fe595960a69ed372f80c1b28acd9e956516b..09465c479f1074d76be88713f727c648be61bf06 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1288,7 +1288,14 @@ public class PurpurWorldConfig {
public int cowFeedMushrooms = 0;
public int cowBreedingTicks = 6000;
public boolean cowTakeDamageFromWater = false;
+ public double cowNaturallyAggressiveToPlayersChance = 0.0D;
+ public double cowNaturallyAggressiveToPlayersDamage = 2.0D;
private void cowSettings() {
+ if (PurpurConfig.version < 22) {
+ double oldValue = getDouble("mobs.cow.naturally-aggressive-to-players-chance", cowNaturallyAggressiveToPlayersChance);
+ set("mobs.cow.naturally-aggressive-to-players-chance", null);
+ set("mobs.cow.naturally-aggressive-to-players.chance", oldValue);
+ }
cowRidable = getBoolean("mobs.cow.ridable", cowRidable);
cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater);
cowControllable = getBoolean("mobs.cow.controllable", cowControllable);
@@ -1302,6 +1309,8 @@ public class PurpurWorldConfig {
cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms);
cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks);
cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater);
+ cowNaturallyAggressiveToPlayersChance = getDouble("mobs.cow.naturally-aggressive-to-players.chance", cowNaturallyAggressiveToPlayersChance);
+ cowNaturallyAggressiveToPlayersDamage = getDouble("mobs.cow.naturally-aggressive-to-players.damage", cowNaturallyAggressiveToPlayersDamage);
}
public boolean creeperRidable = false;

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 12emin34 <macanovic.emin@gmail.com>
Date: Tue, 31 Aug 2021 16:48:29 +0200
Subject: [PATCH] Option for beds to explode on villager sleep
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 3b17133289f95e5420f1c0a73b34b953470df533..cd57f70a20f3b6b1eb1fd5d336be6297268c9605 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -1072,6 +1072,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
@Override
public void startSleeping(BlockPos pos) {
+ // Purpur start
+ if (level().purpurConfig.bedExplodeOnVillagerSleep && this.level().getBlockState(pos).getBlock() instanceof net.minecraft.world.level.block.BedBlock) {
+ this.level().explode(null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (float) this.level().purpurConfig.bedExplosionPower, this.level().purpurConfig.bedExplosionFire, this.level().purpurConfig.bedExplosionEffect);
+ return;
+ }
+ // Purpur end
super.startSleeping(pos);
this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level().getGameTime()); // CraftBukkit - decompile error
this.brain.eraseMemory(MemoryModuleType.WALK_TARGET);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 09465c479f1074d76be88713f727c648be61bf06..e869e2d3511991f8a88349c4db4328d68b4c234d 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -782,6 +782,7 @@ public class PurpurWorldConfig {
}
public boolean bedExplode = true;
+ public boolean bedExplodeOnVillagerSleep = false;
public double bedExplosionPower = 5.0D;
public boolean bedExplosionFire = true;
public net.minecraft.world.level.Level.ExplosionInteraction bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK;
@@ -792,6 +793,7 @@ public class PurpurWorldConfig {
}
}
bedExplode = getBoolean("blocks.bed.explode", bedExplode);
+ bedExplodeOnVillagerSleep = getBoolean("blocks.bed.explode-on-villager-sleep", bedExplodeOnVillagerSleep);
bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower);
bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire);
try {

View File

@@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: DoctaEnkoda <bierquejason@gmail.com>
Date: Mon, 13 Sep 2021 04:48:21 +0200
Subject: [PATCH] Halloween options and optimizations
diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
index a65286044be79e351bd5c80114a2f9fc5dacc11b..25c877481f3006afcdeb3634739e8f37accd27cd 100644
--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java
+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
@@ -305,7 +305,7 @@ public class Bat extends AmbientCreature {
int i = world.getMaxLocalRawBrightness(pos);
byte b0 = 4;
- if (Bat.isHalloween()) {
+ if (Bat.isHalloweenSeason(world.getMinecraftWorld())) { // Purpur
b0 = 7;
} else if (random.nextBoolean()) {
return false;
@@ -315,6 +315,11 @@ public class Bat extends AmbientCreature {
}
}
+ // Pufferfish start - only check for spooky season once an hour
+ private static boolean isSpookySeason = false;
+ private static final int ONE_HOUR = 20 * 60 * 60;
+ private static int lastSpookyCheck = -ONE_HOUR;
+ public static boolean isHalloweenSeason(Level level) { return level.purpurConfig.forceHalloweenSeason || isHalloween(); } // Purpur
private static boolean isHalloween() {
LocalDate localdate = LocalDate.now();
int i = localdate.get(ChronoField.DAY_OF_MONTH);
diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
index bbe4c1cb4244ab813ef7d56c46c3ae62701c4824..2cadbc0d56908ca978e1735eff07f5e634548606 100644
--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
@@ -138,11 +138,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
this.reassessWeaponGoal();
this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
- LocalDate localdate = LocalDate.now();
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
-
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index b34dec421adc3ce56c0720a839a43ce42faeefaf..98e7b57a45ae3cae704c65ec6db5f715f9af99a4 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -595,11 +595,7 @@ public class Zombie extends Monster {
}
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
- LocalDate localdate = LocalDate.now();
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
-
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index e869e2d3511991f8a88349c4db4328d68b4c234d..8f2ec3a415ef8dd5e9c9f45e5135702ed5e34a96 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1706,6 +1706,13 @@ public class PurpurWorldConfig {
guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater);
}
+ public boolean forceHalloweenSeason = false;
+ public float chanceHeadHalloweenOnEntity = 0.25F;
+ private void halloweenSetting() {
+ forceHalloweenSeason = getBoolean("gameplay-mechanics.halloween.force", forceHalloweenSeason);
+ chanceHeadHalloweenOnEntity = (float) getDouble("gameplay-mechanics.halloween.head-chance", chanceHeadHalloweenOnEntity);
+ }
+
public boolean hoglinRidable = false;
public boolean hoglinRidableInWater = true;
public boolean hoglinControllable = true;

View File

@@ -0,0 +1,160 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
Date: Wed, 29 Sep 2021 13:37:57 -0400
Subject: [PATCH] Config for grindstones
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 5687f492fc76f699e2a388790ca5380d9b8c8d0a..cc229f3e1e9527cbedf929e326731943bb513dae 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -135,7 +135,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
Holder<Enchantment> holder = (Holder) entry.getKey();
int k = entry.getIntValue();
- if (!holder.is(EnchantmentTags.CURSE)) {
+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value())) { // Purpur
j += ((Enchantment) holder.value()).getMinCost(k);
}
}
@@ -222,7 +222,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
Entry<Holder<Enchantment>> entry = (Entry) iterator.next();
Holder<Enchantment> holder = (Holder) entry.getKey();
- if (!holder.is(EnchantmentTags.CURSE) || itemenchantments_a.getLevel(holder) == 0) {
+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()) || itemenchantments_a.getLevel(holder) == 0) { // Purpur
itemenchantments_a.upgrade(holder, entry.getIntValue());
}
}
@@ -230,10 +230,70 @@ public class GrindstoneMenu extends AbstractContainerMenu {
});
}
+ // Purpur start
+ private java.util.List<net.minecraft.core.component.DataComponentType<?>> GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST = java.util.List.of(
+ // DataComponents.MAX_STACK_SIZE,
+ // DataComponents.DAMAGE,
+ // DataComponents.BLOCK_STATE,
+ DataComponents.CUSTOM_DATA,
+ // DataComponents.MAX_DAMAGE,
+ // DataComponents.UNBREAKABLE,
+ // DataComponents.CUSTOM_NAME,
+ // DataComponents.ITEM_NAME,
+ // DataComponents.LORE,
+ // DataComponents.RARITY,
+ // DataComponents.ENCHANTMENTS,
+ // DataComponents.CAN_PLACE_ON,
+ // DataComponents.CAN_BREAK,
+ DataComponents.ATTRIBUTE_MODIFIERS,
+ DataComponents.CUSTOM_MODEL_DATA,
+ // DataComponents.HIDE_ADDITIONAL_TOOLTIP,
+ // DataComponents.HIDE_TOOLTIP,
+ // DataComponents.REPAIR_COST,
+ // DataComponents.CREATIVE_SLOT_LOCK,
+ // DataComponents.ENCHANTMENT_GLINT_OVERRIDE,
+ // DataComponents.INTANGIBLE_PROJECTILE,
+ // DataComponents.FOOD,
+ // DataComponents.FIRE_RESISTANT,
+ // DataComponents.TOOL,
+ // DataComponents.STORED_ENCHANTMENTS,
+ DataComponents.DYED_COLOR,
+ // DataComponents.MAP_COLOR,
+ // DataComponents.MAP_ID,
+ // DataComponents.MAP_DECORATIONS,
+ // DataComponents.MAP_POST_PROCESSING,
+ // DataComponents.CHARGED_PROJECTILES,
+ // DataComponents.BUNDLE_CONTENTS,
+ // DataComponents.POTION_CONTENTS,
+ DataComponents.SUSPICIOUS_STEW_EFFECTS
+ // DataComponents.WRITABLE_BOOK_CONTENT,
+ // DataComponents.WRITTEN_BOOK_CONTENT,
+ // DataComponents.TRIM,
+ // DataComponents.DEBUG_STICK_STATE,
+ // DataComponents.ENTITY_DATA,
+ // DataComponents.BUCKET_ENTITY_DATA,
+ // DataComponents.BLOCK_ENTITY_DATA,
+ // DataComponents.INSTRUMENT,
+ // DataComponents.OMINOUS_BOTTLE_AMPLIFIER,
+ // DataComponents.RECIPES,
+ // DataComponents.LODESTONE_TRACKER,
+ // DataComponents.FIREWORK_EXPLOSION,
+ // DataComponents.FIREWORKS,
+ // DataComponents.PROFILE,
+ // DataComponents.NOTE_BLOCK_SOUND,
+ // DataComponents.BANNER_PATTERNS,
+ // DataComponents.BASE_COLOR,
+ // DataComponents.POT_DECORATIONS,
+ // DataComponents.CONTAINER,
+ // DataComponents.BEES,
+ // DataComponents.LOCK,
+ // DataComponents.CONTAINER_LOOT,
+ );
+ // Purpur end
private ItemStack removeNonCursesFrom(ItemStack item) {
ItemEnchantments itemenchantments = EnchantmentHelper.updateEnchantments(item, (itemenchantments_a) -> {
itemenchantments_a.removeIf((holder) -> {
- return !holder.is(EnchantmentTags.CURSE);
+ return !org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()); // Purpur
});
});
@@ -248,6 +308,23 @@ public class GrindstoneMenu extends AbstractContainerMenu {
}
item.set(DataComponents.REPAIR_COST, i);
+
+ // Purpur start
+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder();
+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes) {
+ item.getComponents().forEach(typedDataComponent -> {
+ if (GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST.contains(typedDataComponent.type())) {
+ builder.remove(typedDataComponent.type());
+ }
+ });
+ }
+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay) {
+ builder.remove(DataComponents.CUSTOM_NAME);
+ builder.remove(DataComponents.LORE);
+ }
+ item.applyComponents(builder.build());
+ // Purpur end
+
return item;
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 275078b6b4940fbc771fb1aad0990135d37b51f3..9c5348fd18c2943ce39346dd19fa194d9c31d7ea 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -311,6 +311,9 @@ public class PurpurConfig {
public static int beeInsideBeeHive = 3;
public static boolean anvilCumulativeCost = true;
public static int lightningRodRange = 128;
+ public static Set<Enchantment> grindstoneIgnoredEnchants = new HashSet<>();
+ public static boolean grindstoneRemoveAttributes = false;
+ public static boolean grindstoneRemoveDisplay = false;
private static void blockSettings() {
if (version < 3) {
boolean oldValue = getBoolean("settings.barrel.packed-barrels", true);
@@ -345,6 +348,21 @@ public class PurpurConfig {
beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive);
anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost);
lightningRodRange = getInt("settings.blocks.lightning_rod.range", lightningRodRange);
+ ArrayList<String> defaultCurses = new ArrayList<>(){{
+ add("minecraft:binding_curse");
+ add("minecraft:vanishing_curse");
+ }};
+ if (version < 24 && !getBoolean("settings.blocks.grindstone.ignore-curses", true)) {
+ defaultCurses.clear();
+ }
+ getList("settings.blocks.grindstone.ignored-enchants", defaultCurses).forEach(key -> {
+ Registry<Enchantment> registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.ENCHANTMENT);
+ Enchantment enchantment = registry.get(ResourceLocation.parse(key.toString()));
+ if (enchantment == null) return;
+ grindstoneIgnoredEnchants.add(enchantment);
+ });
+ grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes);
+ grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay);
}
public static boolean allowInapplicableEnchants = false;

View File

@@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Wed, 22 Jan 2020 20:13:40 -0600
Subject: [PATCH] UPnP Port Forwarding
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 76f31bf31f77c8347b9436779c3701f8a87045e6..781eb66ada5fd2bf821453be3b14c59026217999 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -331,6 +331,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
public boolean lagging = false; // Purpur
+ protected boolean upnp = false; // Purpur
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
AtomicReference<S> atomicreference = new AtomicReference();
@@ -1045,6 +1046,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
MinecraftServer.LOGGER.info("Stopping server");
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
MinecraftTimings.stopServer(); // Paper
+ // Purpur start
+ if (upnp) {
+ if (dev.omega24.upnp4j.UPnP4J.close(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
+ LOGGER.info("[UPnP] Port {} closed", this.getPort());
+ } else {
+ LOGGER.error("[UPnP] Failed to close port {}", this.getPort());
+ }
+ }
+ // Purpur end
// CraftBukkit start
if (this.server != null) {
this.server.disablePlugins();
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 86c25c52e4c42074866975884ec15dc099a77591..dfb502be415eb0e8750b0307d908bc42f11a2988 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -292,6 +292,30 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
if (true) throw new IllegalStateException("Failed to bind to port", ioexception); // Paper - Propagate failed to bind to port error
return false;
}
+ // Purpur start
+ if (org.purpurmc.purpur.PurpurConfig.useUPnP) {
+ LOGGER.info("[UPnP] Attempting to start UPnP port forwarding service...");
+ if (dev.omega24.upnp4j.UPnP4J.isUPnPAvailable()) {
+ if (dev.omega24.upnp4j.UPnP4J.isOpen(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
+ this.upnp = false;
+ LOGGER.info("[UPnP] Port {} is already open", this.getPort());
+ } else if (dev.omega24.upnp4j.UPnP4J.open(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) {
+ this.upnp = true;
+ LOGGER.info("[UPnP] Successfully opened port {}", this.getPort());
+ } else {
+ this.upnp = false;
+ LOGGER.info("[UPnP] Failed to open port {}", this.getPort());
+ }
+
+ if (upnp) {
+ LOGGER.info("[UPnP] {}:{}", dev.omega24.upnp4j.UPnP4J.getExternalIP(), this.getPort());
+ }
+ } else {
+ this.upnp = false;
+ LOGGER.error("[UPnP] Service is unavailable");
+ }
+ }
+ // Purpur end
// CraftBukkit start
// this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 9c5348fd18c2943ce39346dd19fa194d9c31d7ea..ce8181b0527406a54569779d453b227f6b693f0d 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -421,4 +421,9 @@ public class PurpurConfig {
private static void tpsCatchup() {
tpsCatchup = getBoolean("settings.tps-catchup", tpsCatchup);
}
+
+ public static boolean useUPnP = false;
+ private static void networkSettings() {
+ useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP);
+ }
}

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: granny <granny@purpurmc.org>
Date: Thu, 14 Oct 2021 01:53:20 -0700
Subject: [PATCH] Campfire option for lit when placed
diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
index 18d4020017d76303d3179fad8974574777ea6305..2ee2b1485f848ac5270bc3f7e1e5b1bc3029b0bb 100644
--- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java
@@ -140,7 +140,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB
BlockPos blockposition = ctx.getClickedPos();
boolean flag = world.getFluidState(blockposition).getType() == Fluids.WATER;
- return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, !flag)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection());
+ return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, world.purpurConfig.campFireLitWhenPlaced ? !flag : world.purpurConfig.campFireLitWhenPlaced)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection()); // Purpur
}
@Override
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 8f2ec3a415ef8dd5e9c9f45e5135702ed5e34a96..8bfaf9f1cfaea1366f1a726e74f325569889d612 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -825,6 +825,11 @@ public class PurpurWorldConfig {
cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors);
}
+ public boolean campFireLitWhenPlaced = true;
+ private void campFireSettings() {
+ campFireLitWhenPlaced = getBoolean("blocks.campfire.lit-when-placed", campFireLitWhenPlaced);
+ }
+
public boolean chestOpenWithBlockOnTop = false;
private void chestSettings() {
chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop);

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: granny <granny@purpurmc.org>
Date: Thu, 14 Oct 2021 02:05:52 -0700
Subject: [PATCH] options to extinguish fire blocks with snowballs
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
index 8c853b6fbbc966ee6ba9ad3770d4e2e2a50ef388..0db58e7d63a5c1b43a2224c247979f23a1d3f899 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
@@ -63,6 +63,36 @@ public class Snowball extends ThrowableItemProjectile {
entity.hurt(this.damageSources().thrown(this, this.getOwner()), (float) i);
}
+ // Purpur start - borrowed and modified code from ThrownPotion#onHitBlock and ThrownPotion#dowseFire
+ @Override
+ protected void onHitBlock(net.minecraft.world.phys.BlockHitResult blockHitResult) {
+ super.onHitBlock(blockHitResult);
+
+ if (!this.level().isClientSide) {
+ net.minecraft.core.BlockPos blockposition = blockHitResult.getBlockPos();
+ net.minecraft.core.BlockPos blockposition1 = blockposition.relative(blockHitResult.getDirection());
+
+ net.minecraft.world.level.block.state.BlockState iblockdata = this.level().getBlockState(blockposition);
+
+ if (this.level().purpurConfig.snowballExtinguishesFire && this.level().getBlockState(blockposition1).is(net.minecraft.world.level.block.Blocks.FIRE)) {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) {
+ this.level().removeBlock(blockposition1, false);
+ }
+ } else if (this.level().purpurConfig.snowballExtinguishesCandles && net.minecraft.world.level.block.AbstractCandleBlock.isLit(iblockdata)) {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.AbstractCandleBlock.LIT, false))) {
+ net.minecraft.world.level.block.AbstractCandleBlock.extinguish(null, iblockdata, this.level(), blockposition);
+ }
+ } else if (this.level().purpurConfig.snowballExtinguishesCampfires && net.minecraft.world.level.block.CampfireBlock.isLitCampfire(iblockdata)) {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false))) {
+ this.level().levelEvent(null, 1009, blockposition, 0);
+ net.minecraft.world.level.block.CampfireBlock.dowse(this.getOwner(), this.level(), blockposition, iblockdata);
+ this.level().setBlockAndUpdate(blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false));
+ }
+ }
+ }
+ }
+ // Purpur end
+
@Override
protected void onHit(HitResult hitResult) {
super.onHit(hitResult);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 8bfaf9f1cfaea1366f1a726e74f325569889d612..ce6cbfc763cc617952c9e64dc50847254a310a7f 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -222,6 +222,9 @@ public class PurpurWorldConfig {
public int glowBerriesEatGlowDuration = 0;
public boolean shulkerBoxItemDropContentsWhenDestroyed = true;
public boolean compassItemShowsBossBar = false;
+ public boolean snowballExtinguishesFire = false;
+ public boolean snowballExtinguishesCandles = false;
+ public boolean snowballExtinguishesCampfires = false;
private void itemSettings() {
itemImmuneToCactus.clear();
getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> {
@@ -270,6 +273,9 @@ public class PurpurWorldConfig {
glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration);
shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed);
compassItemShowsBossBar = getBoolean("gameplay-mechanics.item.compass.holding-shows-bossbar", compassItemShowsBossBar);
+ snowballExtinguishesFire = getBoolean("gameplay-mechanics.item.snowball.extinguish.fire", snowballExtinguishesFire);
+ snowballExtinguishesCandles = getBoolean("gameplay-mechanics.item.snowball.extinguish.candles", snowballExtinguishesCandles);
+ snowballExtinguishesCampfires = getBoolean("gameplay-mechanics.item.snowball.extinguish.campfires", snowballExtinguishesCampfires);
}
public double minecartMaxSpeed = 0.4D;

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: rafael59r2 <12960698+rafael59r2@users.noreply.github.com>
Date: Tue, 19 Oct 2021 13:10:44 +0100
Subject: [PATCH] Add option to disable zombie villagers cure
diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
index 623e8ef53d6336b3e3c83fd37eda13244a3b4ab6..3759f28c7f516a94ca8fe1b8f82230b9e8cfb9cb 100644
--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java
@@ -224,7 +224,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
ItemStack itemstack = player.getItemInHand(hand);
if (itemstack.is(Items.GOLDEN_APPLE)) {
- if (this.hasEffect(MobEffects.WEAKNESS)) {
+ if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur
itemstack.consume(1, player);
if (!this.level().isClientSide) {
this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index ce6cbfc763cc617952c9e64dc50847254a310a7f..4bd07e6ef30f6ff3e026492f36b0b3e8de363088 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -3008,6 +3008,7 @@ public class PurpurWorldConfig {
public boolean zombieVillagerTakeDamageFromWater = false;
public int zombieVillagerCuringTimeMin = 3600;
public int zombieVillagerCuringTimeMax = 6000;
+ public boolean zombieVillagerCureEnabled = true;
private void zombieVillagerSettings() {
zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable);
zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater);
@@ -3026,6 +3027,7 @@ public class PurpurWorldConfig {
zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater);
zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin);
zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax);
+ zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled);
}
public boolean zombifiedPiglinRidable = false;

View File

@@ -0,0 +1,164 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Wed, 30 Sep 2020 14:32:46 -0700
Subject: [PATCH] Persistent BlockEntity Lore and DisplayName
Makes it so that when a BlockEntity is placed in the world and then broken,
the dropped ItemStack retains any original custom display name/lore.
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
index 33d9b5fb6897fefb0f7b9009df7339341cb42317..d58619d1d63a03598b8740dd789d4b6f2c93f8d0 100644
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
@@ -151,7 +151,16 @@ public class BlockItem extends Item {
}
protected boolean updateCustomBlockEntityTag(BlockPos pos, Level world, @Nullable Player player, ItemStack stack, BlockState state) {
- return BlockItem.updateCustomBlockEntityTag(world, player, pos, stack);
+ // Purpur start
+ boolean handled = updateCustomBlockEntityTag(world, player, pos, stack);
+ if (world.purpurConfig.persistentTileEntityLore) {
+ BlockEntity blockEntity1 = world.getBlockEntity(pos);
+ if (blockEntity1 != null) {
+ blockEntity1.setPersistentLore(stack.getOrDefault(DataComponents.LORE, net.minecraft.world.item.component.ItemLore.EMPTY));
+ }
+ }
+ return handled;
+ // Purpur end
}
@Nullable
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index 135e59e549cbcb3806574f964947b6ff3ea517d1..e8c649d1db3dd82bb544aa6e96b6a19e96559b09 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -310,7 +310,7 @@ public class Block extends BlockBehaviour implements ItemLike {
public static void dropResources(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockEntity blockEntity) {
if (world instanceof ServerLevel) {
Block.getDrops(state, (ServerLevel) world, pos, blockEntity).forEach((itemstack) -> {
- Block.popResource((ServerLevel) world, pos, itemstack);
+ Block.popResource((ServerLevel) world, pos, applyLoreFromTile(itemstack, blockEntity)); // Purpur
});
state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true);
}
@@ -329,7 +329,7 @@ public class Block extends BlockBehaviour implements ItemLike {
event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping
event.callEvent();
for (org.bukkit.inventory.ItemStack drop : event.getDrops()) {
- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop));
+ popResource(serverLevel, pos, applyLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur
}
state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping
block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping
@@ -346,13 +346,32 @@ public class Block extends BlockBehaviour implements ItemLike {
// Paper end - Properly handle xp dropping
if (world instanceof ServerLevel) {
Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> {
- Block.popResource(world, pos, itemstack1);
+ Block.popResource(world, pos, applyLoreFromTile(itemstack1, blockEntity)); // Purpur
});
state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping
}
}
+ // Purpur start
+ private static ItemStack applyLoreFromTile(ItemStack stack, @Nullable BlockEntity blockEntity) {
+ if (stack.getItem() instanceof BlockItem) {
+ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel) {
+ net.minecraft.world.item.component.ItemLore lore = blockEntity.getPersistentLore();
+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder();
+ if (blockEntity.getLevel().purpurConfig.persistentTileEntityLore && lore != null) {
+ builder.set(net.minecraft.core.component.DataComponents.LORE, lore);
+ }
+ if (!blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayName) {
+ builder.remove(net.minecraft.core.component.DataComponents.CUSTOM_NAME);
+ }
+ stack.applyComponents(builder.build());
+ }
+ }
+ return stack;
+ }
+ // Purpur end
+
public static void popResource(Level world, BlockPos pos, ItemStack stack) {
double d0 = (double) EntityType.ITEM.getHeight() / 2.0D;
double d1 = (double) pos.getX() + 0.5D + Mth.nextDouble(world.random, -0.25D, 0.25D);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index fb00e5a02bb8c64e27d6d009068ba041098951d6..62b9e41cc35714428d7701d019b45c6ee429400c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -100,6 +100,12 @@ public abstract class BlockEntity {
if (persistentDataTag instanceof CompoundTag) {
this.persistentDataContainer.putAll((CompoundTag) persistentDataTag);
}
+ // Purpur start
+ if (nbt.contains("Purpur.persistentLore")) {
+ net.minecraft.world.item.component.ItemLore.CODEC.decode(net.minecraft.nbt.NbtOps.INSTANCE, nbt.getCompound("Purpur.persistentLore")).result()
+ .ifPresent(tag -> this.persistentLore = tag.getFirst());
+ }
+ // Purpur end
}
// CraftBukkit end
@@ -116,6 +122,15 @@ public abstract class BlockEntity {
this.loadAdditional(nbt, registries);
}
+ // Purpur start
+ protected void saveAdditional(CompoundTag nbt) {
+ if (this.persistentLore != null) {
+ net.minecraft.world.item.component.ItemLore.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, this.persistentLore).result()
+ .ifPresent(tag -> nbt.put("Purpur.persistentLore", tag));
+ }
+ }
+ // Purpur end
+
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {}
public final CompoundTag saveWithFullMetadata(HolderLookup.Provider registries) {
@@ -424,4 +439,16 @@ public abstract class BlockEntity {
<T> T getOrDefault(DataComponentType<? extends T> type, T fallback);
}
+ // Purpur start
+ @Nullable
+ private net.minecraft.world.item.component.ItemLore persistentLore = null;
+
+ public void setPersistentLore(net.minecraft.world.item.component.ItemLore lore) {
+ this.persistentLore = lore;
+ }
+
+ public @org.jetbrains.annotations.Nullable net.minecraft.world.item.component.ItemLore getPersistentLore() {
+ return this.persistentLore;
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 4bd07e6ef30f6ff3e026492f36b0b3e8de363088..420b086c27f4c0d977f2fdaead4e45fc989bc9f8 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -141,6 +141,8 @@ public class PurpurWorldConfig {
public boolean mobsIgnoreRails = false;
public boolean rainStopsAfterSleep = true;
public boolean thunderStopsAfterSleep = true;
+ public boolean persistentTileEntityLore = false;
+ public boolean persistentTileEntityDisplayName = true;
private void miscGameplayMechanicsSettings() {
useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative);
@@ -164,6 +166,14 @@ public class PurpurWorldConfig {
mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails);
rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep);
thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep);
+ if (PurpurConfig.version < 35) {
+ boolean oldVal = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityLore);
+ set("gameplay-mechanics.persistent-tileentity-display-names-and-lore", null);
+ set("gameplay-mechanics.persistent-tileentity-lore", oldVal);
+ set("gameplay-mechanics.persistent-tileentity-display-name", !oldVal);
+ }
+ persistentTileEntityLore = getBoolean("gameplay-mechanics.persistent-tileentity-lore", persistentTileEntityLore);
+ persistentTileEntityDisplayName = getBoolean("gameplay-mechanics.persistent-tileentity-display-name", persistentTileEntityDisplayName);
}
public int daytimeTicks = 12000;

View File

@@ -0,0 +1,101 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 6 Jun 2019 17:40:30 -0500
Subject: [PATCH] Signs allow color codes
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 101f2db7d6e7eec85b21c576768224d6c3bba7e7..3f804ddb25aa03bdd964d390a1a1aab4d09abfde 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1969,6 +1969,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
@Override
public void openTextEdit(SignBlockEntity sign, boolean front) {
+ if (level().purpurConfig.signAllowColors) this.connection.send(sign.getTranslatedUpdatePacket(textFilteringEnabled, front)); // Purpur
this.connection.send(new ClientboundBlockUpdatePacket(this.level(), sign.getBlockPos()));
this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front));
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
index 8ac19e1e052e73ff3fd09089bb8e3fd687390ee4..6da1eec98c08e4909ecbd48fe90b3fd62011e284 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
@@ -201,16 +201,31 @@ public class SignBlockEntity extends BlockEntity {
return this.setText((SignText) textChanger.apply(signtext), front);
}
+ // Purpur start
+ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) {
+ if (level.purpurConfig.signAllowColors) {
+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1");
+
+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line));
+ } else {
+ return Component.literal(line).setStyle(style);
+ }
+ }
+ // Purpur end
+
private SignText setMessages(net.minecraft.world.entity.player.Player entityhuman, List<FilteredText> list, SignText signtext, boolean front) { // CraftBukkit
SignText originalText = signtext; // CraftBukkit
for (int i = 0; i < list.size(); ++i) {
FilteredText filteredtext = (FilteredText) list.get(i);
Style chatmodifier = signtext.getMessage(i, entityhuman.isTextFilteringEnabled()).getStyle();
+ org.bukkit.entity.Player player = (org.bukkit.craftbukkit.entity.CraftPlayer) entityhuman.getBukkitEntity(); // Purpur
if (entityhuman.isTextFilteringEnabled()) {
- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur
} else {
- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.raw())).setStyle(chatmodifier), Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only
+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.raw()), chatmodifier), translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur
}
}
@@ -348,6 +363,28 @@ public class SignBlockEntity extends BlockEntity {
return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events
}
+ // Purpur start
+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) {
+ final CompoundTag nbt = new CompoundTag();
+ this.saveAdditional(nbt, this.getLevel().registryAccess());
+ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered);
+ final String side = front ? "front_text" : "back_text";
+ for (int i = 0; i < 4; i++) {
+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]);
+ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component);
+ final var text = net.kyori.adventure.text.Component.text(line);
+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text);
+ if (!nbt.contains(side)) nbt.put(side, new CompoundTag());
+ final CompoundTag sideNbt = nbt.getCompound(side);
+ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag());
+ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING);
+ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json));
+ }
+ nbt.putString("PurpurEditor", "true");
+ return ClientboundBlockEntityDataPacket.create(this, (blockEntity, registryAccess) -> nbt);
+ }
+ // Purpur end
+
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 420b086c27f4c0d977f2fdaead4e45fc989bc9f8..9cfee77da2b368c2be4a91902df8e9085d07974b 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -998,6 +998,11 @@ public class PurpurWorldConfig {
}
}
+ public boolean signAllowColors = false;
+ private void signSettings() {
+ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors);
+ }
+
public boolean slabHalfBreak = false;
private void slabSettings() {
slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak);

View File

@@ -0,0 +1,182 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 22 Nov 2020 20:13:27 -0600
Subject: [PATCH] Kelp, cave, weeping, and twisting vines configurable max
growth age
diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
index c4473c2a778116d48bc3e4796afd901f455070e6..e62217c0bfa6cc426c7d41154f3ccc34d8f242ca 100644
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
@@ -94,4 +94,11 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements CaveVines {
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
world.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2);
}
+
+ // Purpur start
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.caveVinesMaxGrowthAge;
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
index 9b424d7661fedf8ee1eb9f3167c62e563f04d4d1..2af311847a085a8073e9bcb26c762d1bbe1eae2c 100644
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -34,12 +34,12 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
@Override
public BlockState getStateForPlacement(RandomSource random) {
- return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, random.nextInt(25));
+ return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, random.nextInt(getMaxGrowthAge())); // Purpur
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25;
+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge(); // Purpur
}
@Override
@@ -55,7 +55,7 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
} else {
modifier = world.spigotConfig.caveVinesModifier;
}
- if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution
+ if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge() && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution // Purpur
// Spigot end
BlockPos blockposition1 = pos.relative(this.growthDirection);
@@ -77,11 +77,11 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
}
public BlockState getMaxAgeState(BlockState state) {
- return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, 25);
+ return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, getMaxGrowthAge()); // Purpur
}
public boolean isMaxAge(BlockState state) {
- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) == 25;
+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) >= getMaxGrowthAge(); // Purpur
}
protected BlockState updateBodyAfterConvertedFromHead(BlockState from, BlockState to) {
@@ -123,13 +123,13 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
@Override
public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
BlockPos blockposition1 = pos.relative(this.growthDirection);
- int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, 25);
+ int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, getMaxGrowthAge()); // Purpur
int j = this.getBlocksToGrowWhenBonemealed(random);
for (int k = 0; k < j && this.canGrowInto(world.getBlockState(blockposition1)); ++k) {
world.setBlockAndUpdate(blockposition1, (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, i));
blockposition1 = blockposition1.relative(this.growthDirection);
- i = Math.min(i + 1, 25);
+ i = Math.min(i + 1, getMaxGrowthAge()); // Purpur
}
}
@@ -142,4 +142,6 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
protected GrowingPlantHeadBlock getHeadBlock() {
return this;
}
+
+ public abstract int getMaxGrowthAge(); // Purpur
}
diff --git a/src/main/java/net/minecraft/world/level/block/KelpBlock.java b/src/main/java/net/minecraft/world/level/block/KelpBlock.java
index 784b19bc78c8ad9476b6dac37b6778a409a7c675..d49dd8b20d3785cc9482ed2a34fbd7aed4c9e537 100644
--- a/src/main/java/net/minecraft/world/level/block/KelpBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/KelpBlock.java
@@ -72,4 +72,11 @@ public class KelpBlock extends GrowingPlantHeadBlock implements LiquidBlockConta
protected FluidState getFluidState(BlockState state) {
return Fluids.WATER.getSource(false);
}
+
+ // Purpur start
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.kelpMaxGrowthAge;
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
index 6342bb11a162b9e6d9475c5989b1670d77e8f0fb..f8be92512446d3f0e5f0f21222bbefd04ab2838a 100644
--- a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java
@@ -34,4 +34,11 @@ public class TwistingVinesBlock extends GrowingPlantHeadBlock {
protected boolean canGrowInto(BlockState state) {
return NetherVines.isValidGrowthState(state);
}
+
+ // Purpur start
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.twistingVinesMaxGrowthAge;
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
index 3dec5a082606ee35a8c8d7f746480262d6a189c5..b2f6ccae9576c176263e51a232e17a08d54543b3 100644
--- a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java
@@ -34,4 +34,11 @@ public class WeepingVinesBlock extends GrowingPlantHeadBlock {
protected boolean canGrowInto(BlockState state) {
return NetherVines.isValidGrowthState(state);
}
+
+ // Purpur start
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.weepingVinesMaxGrowthAge;
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index ce8181b0527406a54569779d453b227f6b693f0d..0d899125bd89b23d6b5f1fa6bdb25d3b76a62783 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -314,6 +314,10 @@ public class PurpurConfig {
public static Set<Enchantment> grindstoneIgnoredEnchants = new HashSet<>();
public static boolean grindstoneRemoveAttributes = false;
public static boolean grindstoneRemoveDisplay = false;
+ public static int caveVinesMaxGrowthAge = 25;
+ public static int kelpMaxGrowthAge = 25;
+ public static int twistingVinesMaxGrowthAge = 25;
+ public static int weepingVinesMaxGrowthAge = 25;
private static void blockSettings() {
if (version < 3) {
boolean oldValue = getBoolean("settings.barrel.packed-barrels", true);
@@ -363,6 +367,30 @@ public class PurpurConfig {
});
grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes);
grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay);
+ caveVinesMaxGrowthAge = getInt("settings.blocks.cave_vines.max-growth-age", caveVinesMaxGrowthAge);
+ if (caveVinesMaxGrowthAge > 25) {
+ caveVinesMaxGrowthAge = 25;
+ log(Level.WARNING, "blocks.cave_vines.max-growth-age is set to above maximum allowed value of 25");
+ log(Level.WARNING, "Using value of 25 to prevent issues");
+ }
+ kelpMaxGrowthAge = getInt("settings.blocks.kelp.max-growth-age", kelpMaxGrowthAge);
+ if (kelpMaxGrowthAge > 25) {
+ kelpMaxGrowthAge = 25;
+ log(Level.WARNING, "blocks.kelp.max-growth-age is set to above maximum allowed value of 25");
+ log(Level.WARNING, "Using value of 25 to prevent issues");
+ }
+ twistingVinesMaxGrowthAge = getInt("settings.blocks.twisting_vines.max-growth-age", twistingVinesMaxGrowthAge);
+ if (twistingVinesMaxGrowthAge > 25) {
+ twistingVinesMaxGrowthAge = 25;
+ log(Level.WARNING, "blocks.twisting_vines.max-growth-age is set to above maximum allowed value of 25");
+ log(Level.WARNING, "Using value of 25 to prevent issues");
+ }
+ weepingVinesMaxGrowthAge = getInt("settings.blocks.weeping_vines.max-growth-age", weepingVinesMaxGrowthAge);
+ if (weepingVinesMaxGrowthAge > 25) {
+ weepingVinesMaxGrowthAge = 25;
+ log(Level.WARNING, "blocks.weeping_vines.max-growth-age is set to above maximum allowed value of 25");
+ log(Level.WARNING, "Using value of 25 to prevent issues");
+ }
}
public static boolean allowInapplicableEnchants = false;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Mon, 27 Dec 2021 08:11:00 -0600
Subject: [PATCH] Grindstone API
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index cc229f3e1e9527cbedf929e326731943bb513dae..111da7435f0abb5a57bd2c5fecead2380ac4347a 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -96,12 +96,14 @@ public class GrindstoneMenu extends AbstractContainerMenu {
@Override
public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
+ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur
context.execute((world, blockposition) -> {
if (world instanceof ServerLevel) {
// Paper start - Fire BlockExpEvent on grindstone use
org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition), this.getExperienceAmount(world));
event.callEvent();
- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player);
+ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), event.getExpToDrop()); grindstoneTakeResultEvent.callEvent(); // Purpur
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Purpur
// Paper end - Fire BlockExpEvent on grindstone use
}
@@ -386,7 +388,9 @@ public class GrindstoneMenu extends AbstractContainerMenu {
return ItemStack.EMPTY;
}
+ this.activeQuickItem = itemstack; // Purpur
slot1.onTake(player, itemstack1);
+ this.activeQuickItem = null; // Purpur
}
return itemstack;

View File

@@ -0,0 +1,97 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Tue, 28 Dec 2021 16:22:20 -0600
Subject: [PATCH] Ability for hoe to replant crops and nether warts
diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java
index eb324fda54ada3ed7941713a784ed2d686ec8c4b..09cc76f3fee4a767c9ec3fa592f2c3c6146344ec 100644
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
@@ -55,4 +55,24 @@ public abstract class BushBlock extends Block {
protected boolean isPathfindable(BlockState state, PathComputationType type) {
return type == PathComputationType.AIR && !this.hasCollision ? true : super.isPathfindable(state, type);
}
+
+ // Purpur start
+ public void playerDestroyAndReplant(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, net.minecraft.world.item.ItemStack itemInHand, net.minecraft.world.level.ItemLike itemToReplant) {
+ player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(this));
+ player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED);
+ java.util.List<net.minecraft.world.item.ItemStack> dropList = Block.getDrops(state, (net.minecraft.server.level.ServerLevel) world, pos, blockEntity, player, itemInHand);
+
+ boolean planted = false;
+ for (net.minecraft.world.item.ItemStack itemToDrop : dropList) {
+ if (!planted && itemToDrop.getItem() == itemToReplant) {
+ world.setBlock(pos, defaultBlockState(), 3);
+ itemToDrop.setCount(itemToDrop.getCount() - 1);
+ planted = true;
+ }
+ Block.popResource(world, pos, itemToDrop);
+ }
+
+ state.spawnAfterBreak((net.minecraft.server.level.ServerLevel) world, pos, itemInHand, true);
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
index ab58c4dbe9deb8807478a8e66e01f81a30221532..4f64011262eef6a24a8e8595ace1e4d1d82923e5 100644
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
@@ -216,4 +216,15 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(CropBlock.AGE);
}
+
+ // Purpur start
+ @Override
+ public void playerDestroy(Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
+ if (world.purpurConfig.hoeReplantsCrops && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, getBaseSeedId());
+ } else {
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
+ }
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
index acbd60a2f162fe0e254e36d0e8e7face3fc8a7b3..da1c7999ca64199387054de46489d3ff4a299289 100644
--- a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java
@@ -68,4 +68,15 @@ public class NetherWartBlock extends BushBlock {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(NetherWartBlock.AGE);
}
+
+ // Purpur start
+ @Override
+ public void playerDestroy(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
+ if (world.purpurConfig.hoeReplantsNetherWarts && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, Items.NETHER_WART);
+ } else {
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
+ }
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 27b6b2c8dfa709229f709c1a030e7c680a1813e4..e49ddabb865e88782990024253d646cb0e8b32b4 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -505,6 +505,8 @@ public class PurpurWorldConfig {
public Map<Block, Weatherable> axeWeatherables = new HashMap<>();
public Map<Block, Tillable> hoeTillables = new HashMap<>();
public Map<Block, Flattenable> shovelFlattenables = new HashMap<>();
+ public boolean hoeReplantsCrops = false;
+ public boolean hoeReplantsNetherWarts = false;
private void toolSettings() {
axeStrippables.clear();
axeWaxables.clear();
@@ -772,6 +774,8 @@ public class PurpurWorldConfig {
});
shovelFlattenables.put(block, new Flattenable(into, drops));
});
+ hoeReplantsCrops = getBoolean("tools.hoe.replant-crops", hoeReplantsCrops);
+ hoeReplantsNetherWarts = getBoolean("tools.hoe.replant-nether-warts", hoeReplantsNetherWarts);
}
public boolean anvilAllowColors = false;

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Fri, 31 Dec 2021 06:18:54 -0600
Subject: [PATCH] Turtle eggs random tick crack chance
diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
index 4eb0f7a9cf6b12c02d0bd42980ae302dd56c1b8a..e1c984ec64565584c78fe0a6c7db3537108bac59 100644
--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
@@ -171,7 +171,7 @@ public class TurtleEggBlock extends Block {
private boolean shouldUpdateHatchLevel(Level world) {
float f = world.getTimeOfDay(1.0F);
- return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(500) == 0;
+ return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(world.purpurConfig.turtleEggsRandomTickCrackChance) == 0;
}
@Override
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index e49ddabb865e88782990024253d646cb0e8b32b4..16fecadf20523f2a2bf72082bd558e59805e02ca 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1032,11 +1032,13 @@ public class PurpurWorldConfig {
public boolean turtleEggsBreakFromItems = false;
public boolean turtleEggsBreakFromMinecarts = false;
public boolean turtleEggsBypassMobGriefing = false;
+ public int turtleEggsRandomTickCrackChance = 500;
private void turtleEggSettings() {
turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs);
turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems);
turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts);
turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing);
+ turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance);
}
public int waterInfiniteRequiredSources = 2;

View File

@@ -0,0 +1,101 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Fri, 31 Dec 2021 06:40:19 -0600
Subject: [PATCH] Mob head visibility percent
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index fcb024cc70c750887e6d6ce19692385ab5ac9d01..090f259115573f0ed2fb7ed79d191b3f09ac27cd 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1071,9 +1071,20 @@ public abstract class LivingEntity extends Entity implements Attackable {
ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
EntityType<?> entitytypes = entity.getType();
- if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytypes == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
- d0 *= 0.5D;
+ // Purpur start
+ if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL)) {
+ d0 *= entity.level().purpurConfig.skeletonHeadVisibilityPercent;
+ }
+ else if (entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD)) {
+ d0 *= entity.level().purpurConfig.zombieHeadVisibilityPercent;
+ }
+ else if (entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
+ d0 *= entity.level().purpurConfig.creeperHeadVisibilityPercent;
}
+ else if ((entitytypes == EntityType.PIGLIN || entitytypes == EntityType.PIGLIN_BRUTE) && itemstack.is(Items.PIGLIN_HEAD)) {
+ d0 *= entity.level().purpurConfig.piglinHeadVisibilityPercent;
+ }
+ // Purpur end
// Purpur start
if (entity instanceof LivingEntity entityliving) {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 16fecadf20523f2a2bf72082bd558e59805e02ca..8e9c7d1d913e3ed5015f4016c96e56942ce07f5e 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1377,6 +1377,7 @@ public class PurpurWorldConfig {
public boolean creeperExplodeWhenKilled = false;
public boolean creeperHealthRadius = false;
public boolean creeperAlwaysDropExp = false;
+ public double creeperHeadVisibilityPercent = 0.5D;
private void creeperSettings() {
creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable);
creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater);
@@ -1395,6 +1396,7 @@ public class PurpurWorldConfig {
creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled);
creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius);
creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp);
+ creeperHeadVisibilityPercent = getDouble("mobs.creeper.head-visibility-percent", creeperHeadVisibilityPercent);
}
public boolean dolphinRidable = false;
@@ -2222,6 +2224,7 @@ public class PurpurWorldConfig {
public boolean piglinTakeDamageFromWater = false;
public int piglinPortalSpawnModifier = 2000;
public boolean piglinAlwaysDropExp = false;
+ public double piglinHeadVisibilityPercent = 0.5D;
private void piglinSettings() {
piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable);
piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater);
@@ -2237,6 +2240,7 @@ public class PurpurWorldConfig {
piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater);
piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier);
piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp);
+ piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent);
}
public boolean piglinBruteRidable = false;
@@ -2521,6 +2525,7 @@ public class PurpurWorldConfig {
public double skeletonScale = 1.0D;
public boolean skeletonTakeDamageFromWater = false;
public boolean skeletonAlwaysDropExp = false;
+ public double skeletonHeadVisibilityPercent = 0.5D;
private void skeletonSettings() {
skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable);
skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater);
@@ -2534,6 +2539,7 @@ public class PurpurWorldConfig {
skeletonScale = Mth.clamp(getDouble("mobs.skeleton.attributes.scale", skeletonScale), 0.0625D, 16.0D);
skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater);
skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp);
+ skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent);
}
public boolean skeletonHorseRidable = false;
@@ -3103,6 +3109,7 @@ public class PurpurWorldConfig {
public boolean zombieBypassMobGriefing = false;
public boolean zombieTakeDamageFromWater = false;
public boolean zombieAlwaysDropExp = false;
+ public double zombieHeadVisibilityPercent = 0.5D;
private void zombieSettings() {
zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable);
zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater);
@@ -3122,6 +3129,7 @@ public class PurpurWorldConfig {
zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing);
zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater);
zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp);
+ zombieHeadVisibilityPercent = getDouble("mobs.zombie.head-visibility-percent", zombieHeadVisibilityPercent);
}
public boolean zombieHorseRidable = false;

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Sat, 1 Jan 2022 18:38:58 -0600
Subject: [PATCH] Configurable valid characters for usernames
diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java
index 6c33002dc8bbb3759c3156302ab7d1f26ce5e8ee..c89fc375aff548a2b03eaf4da3b6a075012df012 100644
--- a/src/main/java/net/minecraft/util/StringUtil.java
+++ b/src/main/java/net/minecraft/util/StringUtil.java
@@ -69,6 +69,7 @@ public class StringUtil {
// Paper start - Username validation
public static boolean isReasonablePlayerName(final String name) {
+ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur
if (name.isEmpty() || name.length() > 16) {
return false;
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 0d899125bd89b23d6b5f1fa6bdb25d3b76a62783..7ad309e81ec61a6f2553e9ffeb9a986f4d569b37 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -454,4 +454,11 @@ public class PurpurConfig {
private static void networkSettings() {
useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP);
}
+
+ public static java.util.regex.Pattern usernameValidCharactersPattern;
+ private static void usernameValidationSettings() {
+ String defaultPattern = "^[a-zA-Z0-9_.]*$";
+ String setPattern = getString("settings.username-valid-characters", defaultPattern);
+ usernameValidCharactersPattern = java.util.regex.Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern);
+ }
}

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Mon, 3 Jan 2022 01:19:46 -0600
Subject: [PATCH] Stop bees from dying after stinging
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
index db382cf32d215f1b98b960e0c1a8dfaf6e19422f..4b32a783cabf05f5bae0dba22eea8ac7ba2cd285 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
@@ -461,6 +461,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
this.hurtServer(world, this.damageSources().drown(), 1.0F);
}
+ if (flag && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur
if (flag) {
++this.timeSinceSting;
if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 8e9c7d1d913e3ed5015f4016c96e56942ce07f5e..ad407f1b3b343244e5323d022702cc075b910b48 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1151,6 +1151,7 @@ public class PurpurWorldConfig {
public boolean beeCanWorkAtNight = false;
public boolean beeCanWorkInRain = false;
public boolean beeAlwaysDropExp = false;
+ public boolean beeDiesAfterSting = true;
private void beeSettings() {
beeRidable = getBoolean("mobs.bee.ridable", beeRidable);
beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater);
@@ -1168,6 +1169,7 @@ public class PurpurWorldConfig {
beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight);
beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain);
beeAlwaysDropExp = getBoolean("mobs.bee.always-drop-exp", beeAlwaysDropExp);
+ beeDiesAfterSting = getBoolean("mobs.bee.dies-after-sting", beeDiesAfterSting);
}
public boolean blazeRidable = false;

View File

@@ -0,0 +1,184 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 30 Dec 2021 09:56:43 -0600
Subject: [PATCH] Give bee counts in beehives to Purpur clients
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 781eb66ada5fd2bf821453be3b14c59026217999..c3c5d392f1295e7edc0e96881f90f96cace5486f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1148,6 +1148,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
org.purpurmc.purpur.task.BossBarTask.stopAll(); // Purpur
+ org.purpurmc.purpur.task.BeehiveTask.instance().unregister(); // Purpur
this.isRestarting = isRestarting;
this.hasLoggedStop = true; // Paper - Debugging
if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index dfb502be415eb0e8750b0307d908bc42f11a2988..136ac58eef2c243650ffb390459d6959b90d5202 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -390,6 +390,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur
+ if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur
return true;
}
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 7ad309e81ec61a6f2553e9ffeb9a986f4d569b37..357b5080b6d3651c8f913081de283576a0a17cec 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -434,6 +434,11 @@ public class PurpurConfig {
allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd);
}
+ public static boolean beeCountPayload = false;
+ private static void beeCountPayload() {
+ beeCountPayload = getBoolean("settings.bee-count-payload", beeCountPayload);
+ }
+
public static boolean loggerSuppressInitLegacyMaterialError = false;
public static boolean loggerSuppressIgnoredAdvancementWarnings = false;
public static boolean loggerSuppressUnrecognizedRecipeErrors = false;
diff --git a/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java
new file mode 100644
index 0000000000000000000000000000000000000000..793a3ea45fe04e84725926f17615c26e008b0ce4
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java
@@ -0,0 +1,27 @@
+package org.purpurmc.purpur.network;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.NotNull;
+
+public record ClientboundBeehivePayload(BlockPos pos, int numOfBees) implements CustomPacketPayload {
+ public static final StreamCodec<FriendlyByteBuf, ClientboundBeehivePayload> STREAM_CODEC = CustomPacketPayload.codec(ClientboundBeehivePayload::write, ClientboundBeehivePayload::new);
+ public static final Type<ClientboundBeehivePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_s2c"));
+
+ public ClientboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readBlockPos(), friendlyByteBuf.readInt());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeBlockPos(this.pos);
+ friendlyByteBuf.writeInt(this.numOfBees);
+ }
+
+ @Override
+ public @NotNull Type<? extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa72769e06061609e1e658a0250e99c8cb026c0e
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java
@@ -0,0 +1,26 @@
+package org.purpurmc.purpur.network;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.NotNull;
+
+public record ServerboundBeehivePayload(BlockPos pos) implements CustomPacketPayload {
+ public static final StreamCodec<FriendlyByteBuf, ServerboundBeehivePayload> STREAM_CODEC = CustomPacketPayload.codec(ServerboundBeehivePayload::write, ServerboundBeehivePayload::new);
+ public static final Type<ServerboundBeehivePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_c2s"));
+
+ public ServerboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readBlockPos());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeBlockPos(this.pos);
+ }
+
+ @Override
+ public @NotNull Type<? extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..664f9d5e1ce5e2787bf699bd11758b9e3aa8ed3a
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java
@@ -0,0 +1,67 @@
+package org.purpurmc.purpur.task;
+
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.PluginBase;
+import org.bukkit.plugin.messaging.PluginMessageListener;
+import org.jetbrains.annotations.NotNull;
+import org.purpurmc.purpur.network.ClientboundBeehivePayload;
+import org.purpurmc.purpur.network.ServerboundBeehivePayload;
+import org.purpurmc.purpur.util.MinecraftInternalPlugin;
+
+public class BeehiveTask implements PluginMessageListener {
+
+ private static BeehiveTask instance;
+
+ public static BeehiveTask instance() {
+ if (instance == null) {
+ instance = new BeehiveTask();
+ }
+ return instance;
+ }
+
+ private final PluginBase plugin = new MinecraftInternalPlugin();
+
+ private BeehiveTask() {
+ }
+
+ public void register() {
+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString());
+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString(), this);
+ }
+
+ public void unregister() {
+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString());
+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString());
+ }
+
+ @Override
+ public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] bytes) {
+ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes));
+ ServerboundBeehivePayload payload = ServerboundBeehivePayload.STREAM_CODEC.decode(byteBuf);
+
+ ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+
+ // targeted block info max range specified in client at net.minecraft.client.gui.hud.DebugHud#render
+ if (!payload.pos().getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20
+ if (serverPlayer.level().getChunkIfLoaded(payload.pos()) == null) return;
+
+ BlockEntity blockEntity = serverPlayer.level().getBlockEntity(payload.pos());
+ if (!(blockEntity instanceof BeehiveBlockEntity beehive)) {
+ return;
+ }
+
+ ClientboundBeehivePayload customPacketPayload = new ClientboundBeehivePayload(payload.pos(), beehive.getOccupantCount());
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
+ ClientboundBeehivePayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload);
+ byte[] byteArray = new byte[friendlyByteBuf.readableBytes()];
+ friendlyByteBuf.readBytes(byteArray);
+ player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray);
+ }
+}

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Tue, 4 Jan 2022 11:56:48 -0600
Subject: [PATCH] Configurable farmland trample height
This is _not_ in block height or an exact science.
During my testing I found very inconsistent values
for the fallDistance variable. Here are the results
of those tests (https://imgur.com/BojltJF):
Value set -> Actual fall distance needed to trample
1.0 -> 1.25
1.5 -> 1.75
2.0 -> 2.25
2.5 -> 2.87
3.0 -> 3.5
3.5 -> 4.25
4.0 -> 4.25
4.5 -> 5.0
5.0 -> 5.87
5.5 -> 5.87
6.0 -> 6.75
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
index bc149eb17695ac727aa8db08db6209497f7d20bf..6db97982972bfc67c828f574fb86391e1cdcd4a5 100644
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
@@ -112,7 +112,7 @@ public class FarmBlock extends Block {
public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage.
if (world instanceof ServerLevel worldserver) {
- if (world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || worldserver.purpurConfig.farmlandBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur
+ if ((worldserver.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= worldserver.purpurConfig.farmlandTrampleHeight : world.random.nextFloat() < fallDistance - 0.5F) && entity instanceof LivingEntity && (entity instanceof Player || worldserver.purpurConfig.farmlandBypassMobGriefing || worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur
// CraftBukkit start - Interact soil
org.bukkit.event.Cancellable cancellable;
if (entity instanceof Player) {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index ad407f1b3b343244e5323d022702cc075b910b48..b3382f2383f546ef53b4dd4c2187f39d8f027c01 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -925,6 +925,7 @@ public class PurpurWorldConfig {
public boolean farmlandTramplingDisabled = false;
public boolean farmlandTramplingOnlyPlayers = false;
public boolean farmlandTramplingFeatherFalling = false;
+ public double farmlandTrampleHeight = -1D;
private void farmlandSettings() {
farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing);
farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow);
@@ -932,6 +933,7 @@ public class PurpurWorldConfig {
farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled);
farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers);
farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling);
+ farmlandTrampleHeight = getDouble("blocks.farmland.trample-height", farmlandTrampleHeight);
}
public double floweringAzaleaGrowthChance = 0.0D;

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Mon, 10 Jan 2022 10:04:31 -0600
Subject: [PATCH] Configurable player pickup exp delay
Default vanilla value is to delay 2 ticks between picking up exp orbs.
Players only pick up 1 orb at a time, so even with setting this to 0
players still only pick up one orb every tick. However, setting this
to any negative number will pick up all orbs instantly.
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index 6db9a3ea4c0dc1f0629bc8bf6466aeab00c498f6..32a0db7e8f974712bd8a05f16f3bd48ac66142d5 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -333,7 +333,7 @@ public class ExperienceOrb extends Entity {
public void playerTouch(Player player) {
if (player instanceof ServerPlayer entityplayer) {
if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(entityplayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
- player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2;
+ player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur
player.take(this, 1);
int i = this.repairPlayerItems(entityplayer, this.value);
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 90998ee1671dc115428102e67a3b07c377133e6e..05d30d2ba3ea7daebe40ddfaa9ce38d99f943038 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -661,7 +661,7 @@ public abstract class Player extends LivingEntity {
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
- if (entity.getType() == EntityType.EXPERIENCE_ORB) {
+ if (entity.getType() == EntityType.EXPERIENCE_ORB && entity.level().purpurConfig.playerExpPickupDelay >= 0) { // Purpur
list1.add(entity);
} else if (!entity.isRemoved()) {
this.touch(entity);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index b3382f2383f546ef53b4dd4c2187f39d8f027c01..74b5d04cf6880f30f8f36ea0414e0ae5542c34b7 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -419,6 +419,7 @@ public class PurpurWorldConfig {
public boolean playerRidableInWater = false;
public boolean playerRemoveBindingWithWeakness = false;
public int shiftRightClickRepairsMendingPoints = 0;
+ public int playerExpPickupDelay = 2;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -444,6 +445,7 @@ public class PurpurWorldConfig {
playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater);
playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness);
shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints);
+ playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Sat, 15 Jan 2022 03:27:29 -0600
Subject: [PATCH] Allow void trading
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index de24307e48e7bc6cc39234fae55ddb404df243b3..f2bf1a9856fb1200f750b06b64e83b1b12e4068d 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2770,7 +2770,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Spigot Start
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
// Paper start - Fix merchant inventory not closing on entity removal
- if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
+ if (!entity.level().purpurConfig.playerVoidTrading && entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { // Purpur
merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
}
// Paper end - Fix merchant inventory not closing on entity removal
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 74b5d04cf6880f30f8f36ea0414e0ae5542c34b7..17f43806df5c8c14a7c90f02e8519e6786700859 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -420,6 +420,7 @@ public class PurpurWorldConfig {
public boolean playerRemoveBindingWithWeakness = false;
public int shiftRightClickRepairsMendingPoints = 0;
public int playerExpPickupDelay = 2;
+ public boolean playerVoidTrading = false;
private void playerSettings() {
if (PurpurConfig.version < 19) {
boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
@@ -446,6 +447,7 @@ public class PurpurWorldConfig {
playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness);
shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints);
playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay);
+ playerVoidTrading = getBoolean("gameplay-mechanics.player.allow-void-trading", playerVoidTrading);
}
public boolean silkTouchEnabled = false;

View File

@@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Mon, 17 Jan 2022 21:28:49 -0600
Subject: [PATCH] Configurable phantom size
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
index bd5dedf875014b4d75e381f613e708addeb154cc..ead5d7d58bbd66f05fd2178ca9c350105aa4008c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
@@ -261,7 +261,11 @@ public class Phantom extends FlyingMob implements Enemy {
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) {
this.anchorPoint = this.blockPosition().above(5);
- this.setPhantomSize(0);
+ // Purpur start
+ int min = world.getLevel().purpurConfig.phantomMinSize;
+ int max = world.getLevel().purpurConfig.phantomMaxSize;
+ this.setPhantomSize(min == max ? min : world.getRandom().nextInt(max + 1 - min) + min);
+ // Purpur end
return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 17f43806df5c8c14a7c90f02e8519e6786700859..6c9d1b53e1c4cc96620d3605c4fdd2d816cb5bf7 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2159,6 +2159,8 @@ public class PurpurWorldConfig {
public boolean phantomFlamesOnSwoop = false;
public boolean phantomTakeDamageFromWater = false;
public boolean phantomAlwaysDropExp = false;
+ public int phantomMinSize = 0;
+ public int phantomMaxSize = 0;
private void phantomSettings() {
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
@@ -2195,6 +2197,13 @@ public class PurpurWorldConfig {
phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop);
phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater);
phantomAlwaysDropExp = getBoolean("mobs.phantom.always-drop-exp", phantomAlwaysDropExp);
+ phantomMinSize = Mth.clamp(getInt("mobs.phantom.size.min", phantomMinSize), 0, 64);
+ phantomMaxSize = Mth.clamp(getInt("mobs.phantom.size.max", phantomMaxSize), 0, 64);
+ if (phantomMinSize > phantomMaxSize) {
+ phantomMinSize = phantomMinSize ^ phantomMaxSize;
+ phantomMaxSize = phantomMinSize ^ phantomMaxSize;
+ phantomMinSize = phantomMinSize ^ phantomMaxSize;
+ }
}
public boolean pigRidable = false;

View File

@@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Tue, 18 Jan 2022 06:35:54 -0600
Subject: [PATCH] Max joins per second
When this option is set to true the `max-joins-per-tick` setting in paper.yml will be used per second instead of per tick
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index fff8d15d44613a075b9793c2a41520212166eb3b..4b0e41b5e26ecf632dff512aac6660fff5264072 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -617,11 +617,20 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
private static int currTick; // Paper - Buffer joins to world
+ private static int tickSecond; // Purpur
public void tick() {
this.flushQueue();
// Paper start - Buffer joins to world
if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) {
Connection.currTick = net.minecraft.server.MinecraftServer.currentTick;
+ // Purpur start
+ if (org.purpurmc.purpur.PurpurConfig.maxJoinsPerSecond) {
+ if (++Connection.tickSecond > 20) {
+ Connection.tickSecond = 0;
+ Connection.joinAttemptsThisTick = 0;
+ }
+ } else
+ // Purpur end
Connection.joinAttemptsThisTick = 0;
}
// Paper end - Buffer joins to world
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 357b5080b6d3651c8f913081de283576a0a17cec..f8179f8b7a57a66705d51f30ab528307e3a84b32 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -456,8 +456,10 @@ public class PurpurConfig {
}
public static boolean useUPnP = false;
+ public static boolean maxJoinsPerSecond = false;
private static void networkSettings() {
useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP);
+ maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond);
}
public static java.util.regex.Pattern usernameValidCharactersPattern;

View File

@@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Totorewa <76272501+totorewa@users.noreply.github.com>
Date: Fri, 7 Jan 2022 21:34:57 +1300
Subject: [PATCH] Configurable minimum demand for trades
Addresses MC-163962 where villager demand decreases indefinitely. Paper
adds a patch to fix this by preventing demand from going below zero.
This patch adds a config option to allow the minimum demand to instead
be configurable.
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 8e519706b025579aad1b74be3b8c6c49146a64a2..b1a0a11f8443a797146dbaf46b9830133f3a51e0 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -539,7 +539,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
while (iterator.hasNext()) {
MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
- merchantrecipe.updateDemand();
+ merchantrecipe.updateDemand(this.level().purpurConfig.villagerMinimumDemand); // Purpur
}
}
diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
index 0efc8d997b34302c3e0a5d7ec73a11a940dbeefe..af157881d440b34cfe79fbc9b03cc9ef28515eb8 100644
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
@@ -131,7 +131,12 @@ public class MerchantOffer {
}
public void updateDemand() {
- this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
+ // Purpur start
+ this.updateDemand(0);
+ }
+ public void updateDemand(int minimumDemand) {
+ this.demand = Math.max(minimumDemand, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962
+ // Purpur end
}
public ItemStack assemble() {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 6c9d1b53e1c4cc96620d3605c4fdd2d816cb5bf7..e11ff40921da76c9d42b6a478fe7bd3e4417140b 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2889,6 +2889,7 @@ public class PurpurWorldConfig {
public boolean villagerTakeDamageFromWater = false;
public boolean villagerAllowTrading = true;
public boolean villagerAlwaysDropExp = false;
+ public int villagerMinimumDemand = 0;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -2910,6 +2911,7 @@ public class PurpurWorldConfig {
villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater);
villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading);
villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp);
+ villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Thu, 3 Dec 2020 17:56:18 -0600
Subject: [PATCH] Lobotomize stuck villagers
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index b1a0a11f8443a797146dbaf46b9830133f3a51e0..052a131d7222ac490b5c40e65c1f801a4299b4e9 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -141,6 +141,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}, MemoryModuleType.MEETING_POINT, (entityvillager, holder) -> {
return holder.is(PoiTypes.MEETING);
});
+ private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur
+ private int notLobotomizedCount = 0; // Purpur
public Villager(EntityType<? extends Villager> entityType, Level world) {
this(entityType, world, VillagerType.PLAINS);
@@ -200,6 +202,48 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
return this.level().purpurConfig.villagerAlwaysDropExp;
}
+ private boolean checkLobotomized() {
+ int interval = this.level().purpurConfig.villagerLobotomizeCheckInterval;
+ boolean shouldCheckForTradeLocked = this.level().purpurConfig.villagerLobotomizeWaitUntilTradeLocked;
+ if (this.notLobotomizedCount > 3) {
+ // check half as often if not lobotomized for the last 3+ consecutive checks
+ interval *= 2;
+ }
+ if (this.level().getGameTime() % interval == 0) {
+ // offset Y for short blocks like dirt_path/farmland
+ this.isLobotomized = !(shouldCheckForTradeLocked && this.getVillagerXp() == 0) && !canTravelFrom(BlockPos.containing(this.position().x, this.getBoundingBox().minY + 0.0625D, this.position().z));
+
+ if (this.isLobotomized) {
+ this.notLobotomizedCount = 0;
+ } else {
+ this.notLobotomizedCount++;
+ }
+ }
+ return this.isLobotomized;
+ }
+
+ private boolean canTravelFrom(BlockPos pos) {
+ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south());
+ }
+
+ private boolean canTravelTo(BlockPos pos) {
+ net.minecraft.world.level.block.state.BlockState state = this.level().getBlockStateIfLoaded(pos);
+ if (state == null) {
+ // chunk not loaded
+ return false;
+ }
+ net.minecraft.world.level.block.Block bottom = state.getBlock();
+ if (bottom instanceof net.minecraft.world.level.block.FenceBlock ||
+ bottom instanceof net.minecraft.world.level.block.FenceGateBlock ||
+ bottom instanceof net.minecraft.world.level.block.WallBlock) {
+ // bottom block is too tall to get over
+ return false;
+ }
+ net.minecraft.world.level.block.Block top = level().getBlockState(pos.above()).getBlock();
+ // only if both blocks have no collision
+ return !bottom.hasCollision && !top.hasCollision;
+ }
+
@Override
public Brain<Villager> getBrain() {
return (Brain<Villager>) super.getBrain(); // CraftBukkit - decompile error
@@ -294,11 +338,19 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
// Paper start - EAR 2
this.customServerAiStep(world, false);
}
- protected void customServerAiStep(ServerLevel world, final boolean inactive) {
+ protected void customServerAiStep(ServerLevel world, boolean inactive) { // Purpur - not final
// Paper end - EAR 2
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("villagerBrain");
+ // Purpur start
+ if (this.level().purpurConfig.villagerLobotomizeEnabled) {
+ // treat as inactive if lobotomized
+ inactive = inactive || checkLobotomized();
+ } else {
+ this.isLobotomized = false;
+ }
+ // Purpur end
if (!inactive && (getRider() == null || !this.isControllable())) this.getBrain().tick(world, this); // Purpur
gameprofilerfiller.pop();
if (this.assignProfessionWhenSpawned) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
index 8e895d6f84f7d84b219f2424909dd42e5f08dec4..53dcce0701d713c5dd097340a91b8be4806de4b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
@@ -375,4 +375,11 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
getHandle().getGossips().gossips.clear();
}
// Paper end
+
+ // Purpur start
+ @Override
+ public boolean isLobotomized() {
+ return getHandle().isLobotomized();
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index e11ff40921da76c9d42b6a478fe7bd3e4417140b..f43b835c9a7af1e19b9dd5de40fb2267c153595f 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2890,6 +2890,9 @@ public class PurpurWorldConfig {
public boolean villagerAllowTrading = true;
public boolean villagerAlwaysDropExp = false;
public int villagerMinimumDemand = 0;
+ public boolean villagerLobotomizeEnabled = false;
+ public int villagerLobotomizeCheckInterval = 100;
+ public boolean villagerLobotomizeWaitUntilTradeLocked = false;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -2912,6 +2915,18 @@ public class PurpurWorldConfig {
villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading);
villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp);
villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand);
+ if (PurpurConfig.version < 9) {
+ boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled);
+ set("mobs.villager.lobotomize.enabled", oldValue);
+ set("mobs.villager.lobotomize-1x1", null);
+ }
+ if (PurpurConfig.version < 27) {
+ int oldValue = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
+ set("mobs.villager.lobotomize.check-interval", oldValue == 60 ? 100 : oldValue);
+ }
+ villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled);
+ villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
+ villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Tue, 25 Jan 2022 15:03:48 -0600
Subject: [PATCH] Option for villager display trade item
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
index 18dad0825616c4167a0a7555689ee64910a87e09..6945992491027d43eca4f1ca697ad45ce06ded55 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java
@@ -46,6 +46,7 @@ public class ShowTradesToPlayer extends Behavior<Villager> {
@Override
public boolean canStillUse(ServerLevel world, Villager entity, long time) {
+ if (!entity.level().purpurConfig.villagerDisplayTradeItem) return false; // Purpur
return this.checkExtraStartConditions(world, entity)
&& this.lookTime > 0
&& entity.getBrain().getMemory(MemoryModuleType.INTERACTION_TARGET).isPresent();
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index f43b835c9a7af1e19b9dd5de40fb2267c153595f..ac3042705a8ef4154b6feac9115bac19f7fdead3 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2893,6 +2893,7 @@ public class PurpurWorldConfig {
public boolean villagerLobotomizeEnabled = false;
public int villagerLobotomizeCheckInterval = 100;
public boolean villagerLobotomizeWaitUntilTradeLocked = false;
+ public boolean villagerDisplayTradeItem = true;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -2927,6 +2928,7 @@ public class PurpurWorldConfig {
villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled);
villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked);
+ villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Sun, 30 Jan 2022 02:03:34 -0600
Subject: [PATCH] MC-238526 - Fix spawner not spawning water animals correctly
diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
index 8c4532a250f8679d729a35c17e9b5bd339264450..16518ade3b0c355e6002801d88eb92cc82dc7b56 100644
--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
@@ -74,6 +74,6 @@ public abstract class WaterAnimal extends PathfinderMob {
i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
// Paper end - Make water animal spawn height configurable
- return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
+ return ((reason == MobSpawnType.SPAWNER && world.getMinecraftWorld().purpurConfig.spawnerFixMC238526) || (pos.getY() >= j && pos.getY() <= i)) && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); // Purpur
}
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index ac3042705a8ef4154b6feac9115bac19f7fdead3..1426f0f6246c4e57a66e25365609c36991a72059 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1019,8 +1019,10 @@ public class PurpurWorldConfig {
}
public boolean spawnerDeactivateByRedstone = false;
+ public boolean spawnerFixMC238526 = false;
private void spawnerSettings() {
spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone);
+ spawnerFixMC238526 = getBoolean("blocks.spawner.fix-mc-238526", spawnerFixMC238526);
}
public int spongeAbsorptionArea = 65;

View File

@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@Gmail.com>
Date: Tue, 8 Feb 2022 13:35:48 -0600
Subject: [PATCH] Config for mob last hurt by player time
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 090f259115573f0ed2fb7ed79d191b3f09ac27cd..60b0cf7cd5e4bcbe882590b79a70dafb23e6772f 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1603,13 +1603,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
if (entity1 instanceof net.minecraft.world.entity.player.Player) {
net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity1;
- this.lastHurtByPlayerTime = 100;
+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur
this.lastHurtByPlayer = entityhuman;
} else if (entity1 instanceof Wolf) {
Wolf entitywolf = (Wolf) entity1;
if (entitywolf.isTame()) {
- this.lastHurtByPlayerTime = 100;
+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur
LivingEntity entityliving2 = entitywolf.getOwner();
if (entityliving2 instanceof net.minecraft.world.entity.player.Player) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index bf84c9664ca6d6c3d862e592c39bcc59374b63fe..051ffc663317fe5a4fafe0750c89fafdece4d316 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -523,7 +523,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
net.minecraft.server.level.ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle();
getHandle().lastHurtByPlayer = entityPlayer;
getHandle().lastHurtByMob = entityPlayer;
- getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : 100; // 100 value taken from EntityLiving#damageEntity
+ getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : getHandle().level().purpurConfig.mobLastHurtByPlayerTime; // 100 value taken from EntityLiving#damageEntity // Purpur
}
// Paper end
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 1426f0f6246c4e57a66e25365609c36991a72059..bd48ba4acf41ec77f542ca7e8dfe6280bb2fbed1 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -143,6 +143,7 @@ public class PurpurWorldConfig {
public boolean thunderStopsAfterSleep = true;
public boolean persistentTileEntityLore = false;
public boolean persistentTileEntityDisplayName = true;
+ public int mobLastHurtByPlayerTime = 100;
private void miscGameplayMechanicsSettings() {
useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending);
alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative);
@@ -174,6 +175,7 @@ public class PurpurWorldConfig {
}
persistentTileEntityLore = getBoolean("gameplay-mechanics.persistent-tileentity-lore", persistentTileEntityLore);
persistentTileEntityDisplayName = getBoolean("gameplay-mechanics.persistent-tileentity-display-name", persistentTileEntityDisplayName);
+ mobLastHurtByPlayerTime = getInt("gameplay-mechanics.mob-last-hurt-by-player-time", mobLastHurtByPlayerTime);
}
public int daytimeTicks = 12000;

View File

@@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 12emin34 <macanovic.emin@gmail.com>
Date: Sat, 12 Feb 2022 01:08:18 +0100
Subject: [PATCH] Anvil repair/damage options
diff --git a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
index 50c907c962f936d2035bb7550750cdbd220b29c2..7f07a38553325056ab4ae65895c8c5c12cb41a1f 100644
--- a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java
@@ -59,6 +59,53 @@ public class AnvilBlock extends FallingBlock {
return this.defaultBlockState().setValue(FACING, ctx.getHorizontalDirection().getClockWise());
}
+ // Purpur start - repairable/damageable anvils
+ @Override
+ protected net.minecraft.world.ItemInteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) {
+ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) {
+ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) {
+ // not enough iron ingots, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.ItemInteractionResult.CONSUME;
+ }
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
+ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.ANVIL)) {
+ // anvil is already fully repaired, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.ItemInteractionResult.CONSUME;
+ }
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount);
+ }
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.ItemInteractionResult.CONSUME;
+ }
+ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) {
+ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) {
+ // not enough obsidian, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.ItemInteractionResult.CONSUME;
+ }
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
+ world.destroyBlock(pos, false);
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
+ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.ANVIL)) {
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ }
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount);
+ }
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.ItemInteractionResult.CONSUME;
+ }
+ return net.minecraft.world.ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+ }
+ // Purpur end
+
@Override
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
if (!world.isClientSide) {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index bd48ba4acf41ec77f542ca7e8dfe6280bb2fbed1..9f4f3d94e6790b29cfda030780d95caf48eee0e5 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -786,9 +786,13 @@ public class PurpurWorldConfig {
public boolean anvilAllowColors = false;
public boolean anvilColorsUseMiniMessage;
+ public int anvilRepairIngotsAmount = 0;
+ public int anvilDamageObsidianAmount = 0;
private void anvilSettings() {
anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors);
anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage);
+ anvilRepairIngotsAmount = getInt("blocks.anvil.iron-ingots-used-for-repair", anvilRepairIngotsAmount);
+ anvilDamageObsidianAmount = getInt("blocks.anvil.obsidian-used-for-damage", anvilDamageObsidianAmount);
}
public double azaleaGrowthChance = 0.0D;

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 12emin34 <macanovic.emin@gmail.com>
Date: Mon, 9 May 2022 23:18:09 +0200
Subject: [PATCH] Option to disable turtle egg trampling with feather falling
diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
index e1c984ec64565584c78fe0a6c7db3537108bac59..3829dbae8542396f8360eae54f0ed18fbde4cd8c 100644
--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
@@ -220,7 +220,13 @@ public class TurtleEggBlock extends Block {
if (!(entity instanceof LivingEntity)) {
return false;
}
- if (entity instanceof Player) return true;
+ if (world.purpurConfig.turtleEggsTramplingFeatherFalling) {
+ java.util.Iterator<ItemStack> armor = ((LivingEntity) entity).getArmorSlots().iterator();
+ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance;
+ }
+ if (entity instanceof Player) {
+ return true;
+ }
return world.purpurConfig.turtleEggsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
// Purpur end
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index 9f4f3d94e6790b29cfda030780d95caf48eee0e5..d5b19afb053ff01962939d1584b2d00db3f9cea3 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1047,12 +1047,14 @@ public class PurpurWorldConfig {
public boolean turtleEggsBreakFromMinecarts = false;
public boolean turtleEggsBypassMobGriefing = false;
public int turtleEggsRandomTickCrackChance = 500;
+ public boolean turtleEggsTramplingFeatherFalling = false;
private void turtleEggSettings() {
turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs);
turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems);
turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts);
turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing);
turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance);
+ turtleEggsTramplingFeatherFalling = getBoolean("blocks.turtle_egg.feather-fall-distance-affects-trampling", turtleEggsTramplingFeatherFalling);
}
public int waterInfiniteRequiredSources = 2;

View File

@@ -0,0 +1,80 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 12emin34 <macanovic.emin@gmail.com>
Date: Sat, 30 Apr 2022 10:32:40 +0200
Subject: [PATCH] Add toggle for enchant level clamping
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index e114e687f2f4503546687fd6792226a643af8793..cccdf61ff0b08531ec0f2165588abe5dd4d488eb 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -119,6 +119,11 @@ public class Main {
JvmProfiler.INSTANCE.start(Environment.SERVER);
}
+ // Purpur start - load config files early
+ org.bukkit.configuration.file.YamlConfiguration purpurConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("purpur-settings"));
+ org.purpurmc.purpur.PurpurConfig.clampEnchantLevels = purpurConfiguration.getBoolean("settings.enchantment.clamp-levels");
+ // Purpur end - load config files early
+
io.papermc.paper.plugin.PluginInitializerManager.load(optionset); // Paper
Bootstrap.bootStrap();
Bootstrap.validate();
diff --git a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
index cfc6a657cae92c68868a76c1b7b1febe2a16e9f4..a12c08da793139e39dc11c213c94796b83bd8240 100644
--- a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
+++ b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java
@@ -35,7 +35,7 @@ public class ItemEnchantments implements TooltipProvider {
private static final java.util.Comparator<Holder<Enchantment>> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName);
public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true);
// Paper end
- private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, 255);
+ private static final Codec<Integer> LEVEL_CODEC = Codec.intRange(1, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur
private static final Codec<Object2IntAVLTreeMap<Holder<Enchantment>>> LEVELS_CODEC = Codec.unboundedMap(
Enchantment.CODEC, LEVEL_CODEC
)// Paper start - sort enchantments
@@ -69,7 +69,7 @@ public class ItemEnchantments implements TooltipProvider {
for (Entry<Holder<Enchantment>> entry : enchantments.object2IntEntrySet()) {
int i = entry.getIntValue();
- if (i < 0 || i > 255) {
+ if (i < 0 || i > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur
throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + i);
}
}
@@ -164,13 +164,13 @@ public class ItemEnchantments implements TooltipProvider {
if (level <= 0) {
this.enchantments.removeInt(enchantment);
} else {
- this.enchantments.put(enchantment, Math.min(level, 255));
+ this.enchantments.put(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); // Purpur
}
}
public void upgrade(Holder<Enchantment> enchantment, int level) {
if (level > 0) {
- this.enchantments.merge(enchantment, Math.min(level, 255), Integer::max);
+ this.enchantments.merge(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); // Purpur
}
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index f8179f8b7a57a66705d51f30ab528307e3a84b32..5b509058cda0e0b5f923f669b5dd3d9e67e3e148 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -398,6 +398,7 @@ public class PurpurConfig {
public static boolean allowHigherEnchantsLevels = false;
public static boolean allowUnsafeEnchantCommand = false;
public static boolean replaceIncompatibleEnchants = false;
+ public static boolean clampEnchantLevels = true;
private static void enchantmentSettings() {
if (version < 30) {
boolean oldValue = getBoolean("settings.enchantment.allow-unsafe-enchants", false);
@@ -421,6 +422,7 @@ public class PurpurConfig {
allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels);
allowUnsafeEnchantCommand = getBoolean("settings.enchantment.allow-unsafe-enchant-command", allowUnsafeEnchantCommand);
replaceIncompatibleEnchants = getBoolean("settings.enchantment.anvil.replace-incompatible-enchants", replaceIncompatibleEnchants);
+ clampEnchantLevels = getBoolean("settings.enchantment.clamp-levels", clampEnchantLevels);
}
public static boolean endermanShortHeight = false;

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 8 Dec 2022 19:13:26 -0600
Subject: [PATCH] Skip junit tests for purpur commands
diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
index 75ed5050f72c001d6eab117a2c0b352a413548bd..180c0a532bbac10a8280b63eb7aa783a1bfbb237 100644
--- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
+++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
@@ -46,6 +46,7 @@ public class MinecraftCommandPermissionsTest {
Set<String> foundPerms = new HashSet<>();
for (CommandNode<CommandSourceStack> child : root.getChildren()) {
final String vanillaPerm = VanillaCommandWrapper.getPermission(child);
+ if (TO_SKIP.contains(vanillaPerm)) continue; // Purpur
if (!perms.contains(vanillaPerm)) {
missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command");
} else {
@@ -58,6 +59,25 @@ public class MinecraftCommandPermissionsTest {
}
private static final List<String> TO_SKIP = List.of(
+ // Purpur start
+ "minecraft.command.compass",
+ "minecraft.command.credits",
+ "minecraft.command.demo",
+ "minecraft.command.ping",
+ "minecraft.command.ram",
+ "minecraft.command.rambar",
+ "minecraft.command.tpsbar",
+ "minecraft.command.uptime",
+ "minecraft.command.debug",
+ "minecraft.command.gamemode.adventure",
+ "minecraft.command.gamemode.adventure.other",
+ "minecraft.command.gamemode.creative",
+ "minecraft.command.gamemode.creative.other",
+ "minecraft.command.gamemode.spectator",
+ "minecraft.command.gamemode.spectator.other",
+ "minecraft.command.gamemode.survival",
+ "minecraft.command.gamemode.survival.other",
+ // Purpur end
"minecraft.command.selector"
);

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Wed, 8 Jun 2022 14:13:39 -0400
Subject: [PATCH] Implement configurable search radius for villagers to spawn
iron golems
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 052a131d7222ac490b5c40e65c1f801a4299b4e9..c885b214f4d7d91627e98d8779aab8515f205636 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -1065,6 +1065,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
public void spawnGolemIfNeeded(ServerLevel world, long time, int requiredCount) {
+ if (world.purpurConfig.villagerSpawnIronGolemRadius > 0 && world.getEntitiesOfClass(net.minecraft.world.entity.animal.IronGolem.class, getBoundingBox().inflate(world.purpurConfig.villagerSpawnIronGolemRadius)).size() > world.purpurConfig.villagerSpawnIronGolemLimit) return; // Purpur
if (this.wantsToSpawnGolem(time)) {
AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
List<Villager> list = world.getEntitiesOfClass(Villager.class, axisalignedbb);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index d5b19afb053ff01962939d1584b2d00db3f9cea3..cc6b3d249cd63a4cf9f1888f21f251199cdccde4 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2904,6 +2904,8 @@ public class PurpurWorldConfig {
public int villagerLobotomizeCheckInterval = 100;
public boolean villagerLobotomizeWaitUntilTradeLocked = false;
public boolean villagerDisplayTradeItem = true;
+ public int villagerSpawnIronGolemRadius = 0;
+ public int villagerSpawnIronGolemLimit = 0;
private void villagerSettings() {
villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -2939,6 +2941,8 @@ public class PurpurWorldConfig {
villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval);
villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked);
villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem);
+ villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius);
+ villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit);
}
public boolean vindicatorRidable = false;

View File

@@ -0,0 +1,160 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Wed, 8 Jun 2022 14:19:35 -0400
Subject: [PATCH] Stonecutter damage
diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
index a375d40ec6365ba8704ba3ece22dd5b2de9857b5..357a79d72a2de02a019595e457fe432bf409e516 100644
--- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java
@@ -101,6 +101,8 @@ public class CombatTracker {
// Purpur start
if (damageSource.isScissors()) {
return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgRunWithScissors, this.mob);
+ } else if (damageSource.isStonecutter()) {
+ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgStonecutter, this.mob);
}
// Purpur end
return damageSource.getLocalizedDeathMessage(this.mob);
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
index aa65f4bf60172a2629daf6e15f7f48d29b250ee0..d95d122601dd47a27e8d82a13b071919c360fe68 100644
--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java
@@ -30,6 +30,7 @@ public class DamageSource {
private boolean melting = false;
private boolean poison = false;
private boolean scissors = false; // Purpur
+ private boolean stonecutter = false; // Purpur
@Nullable
private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API
@@ -69,6 +70,15 @@ public class DamageSource {
public boolean isScissors() {
return this.scissors;
}
+
+ public DamageSource stonecutter() {
+ this.stonecutter = true;
+ return this;
+ }
+
+ public boolean isStonecutter() {
+ return this.stonecutter;
+ }
// Purpur end
// Paper start - fix DamageSource API
@@ -130,6 +140,7 @@ public class DamageSource {
damageSource.poison = this.isPoison();
damageSource.melting = this.isMelting();
damageSource.scissors = this.isScissors(); // Purpur
+ damageSource.stonecutter = this.isStonecutter(); // Purpur
return damageSource;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
index 61e906fb47b242e86789dca1a210473c76863166..d343fd5c9f31073f1b3a0f91b8ea61a67077cc12 100644
--- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java
+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java
@@ -47,12 +47,14 @@ public class DamageSources {
private final DamageSource melting;
private final DamageSource poison;
private final DamageSource scissors; // Purpur
+ private final DamageSource stonecutter; // Purpur
public DamageSources(RegistryAccess registryManager) {
this.damageTypes = registryManager.lookupOrThrow(Registries.DAMAGE_TYPE);
this.melting = this.source(DamageTypes.ON_FIRE).melting();
this.poison = this.source(DamageTypes.MAGIC).poison();
this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur
+ this.stonecutter = this.source(DamageTypes.MAGIC).stonecutter(); // Purpur
// CraftBukkit end
this.inFire = this.source(DamageTypes.IN_FIRE);
this.campfire = this.source(DamageTypes.CAMPFIRE);
@@ -107,6 +109,9 @@ public class DamageSources {
public DamageSource scissors() {
return this.scissors;
}
+ public DamageSource stonecutter() {
+ return this.stonecutter;
+ }
// Purpur end
public DamageSource inFire() {
diff --git a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
index e61644241f24b42bb4f702d3eef5b590b4d107c8..0bf6503819b02e5ba2c346d9d563a93f2946d89b 100644
--- a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java
@@ -98,4 +98,14 @@ public class StonecutterBlock extends Block {
protected boolean isPathfindable(BlockState state, PathComputationType type) {
return false;
}
+
+ // Purpur start
+ @Override
+ public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) {
+ if (level.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.LivingEntity) {
+ entity.hurt(entity.damageSources().stonecutter().directBlock(level, pos), level.purpurConfig.stonecutterDamage);
+ }
+ super.stepOn(level, pos, state, entity);
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
index f6291ff377b38cb84692a9fd564b4b1a9780cf4f..224896124706764412033c8726c822e116f2c0f1 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -491,7 +491,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
return PathType.TRAPDOOR;
} else if (blockState.is(Blocks.POWDER_SNOW)) {
return PathType.POWDER_SNOW;
- } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) {
+ } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur
return PathType.DAMAGE_OTHER;
} else if (blockState.is(Blocks.HONEY_BLOCK)) {
return PathType.STICKY_HONEY;
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index c9f5047bfa48c12a9090cb8da4bb9045e38e8f89..483b2fa71df29e064e35694a6017286bf30f1568 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1140,7 +1140,7 @@ public class CraftEventFactory {
return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.LAVA, bukkitDamageSource, modifiers, modifierFunctions, cancelled);
} else if (source.getDirectBlock() != null) {
DamageCause cause;
- if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL)) {
+ if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL) || source.isStonecutter()) { // Purpur
cause = DamageCause.CONTACT;
} else if (source.is(DamageTypes.HOT_FLOOR)) {
cause = DamageCause.HOT_FLOOR;
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 5b509058cda0e0b5f923f669b5dd3d9e67e3e148..5475a8c622c4090e994f87f6a28febdccecbf973 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -211,8 +211,10 @@ public class PurpurConfig {
}
public static String deathMsgRunWithScissors = "<player> slipped and fell on their shears";
+ public static String deathMsgStonecutter = "<player> has sawed themself in half";
private static void deathMessages() {
deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors);
+ deathMsgStonecutter = getString("settings.messages.death-message.stonecutter", deathMsgStonecutter);
}
public static boolean advancementOnlyBroadcastToAffectedPlayer = false;
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index cc6b3d249cd63a4cf9f1888f21f251199cdccde4..c1b269ebd90be16888f7fcace9efc0e0c08a4448 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1042,6 +1042,11 @@ public class PurpurWorldConfig {
spongeAbsorbsWaterFromMud = getBoolean("blocks.sponge.absorbs-water-from-mud", spongeAbsorbsWaterFromMud);
}
+ public float stonecutterDamage = 0.0F;
+ private void stonecutterSettings() {
+ stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage);
+ }
+
public boolean turtleEggsBreakFromExpOrbs = false;
public boolean turtleEggsBreakFromItems = false;
public boolean turtleEggsBreakFromMinecarts = false;

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kerllenevich <ben@omega24.dev>
Date: Wed, 8 Jun 2022 14:32:55 -0400
Subject: [PATCH] Configurable damage settings for magma blocks
diff --git a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
index 7ffdcf18bf4bd8b5325c76945b2d80ca3fe52958..dfa931316fde0b2e80068a0edd1427ffd096b15b 100644
--- a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java
@@ -29,7 +29,7 @@ public class MagmaBlock extends Block {
@Override
public void stepOn(Level world, BlockPos pos, BlockState state, Entity entity) {
- if (!entity.isSteppingCarefully() && entity instanceof LivingEntity) {
+ if ((!entity.isSteppingCarefully() || world.purpurConfig.magmaBlockDamageWhenSneaking) && entity instanceof LivingEntity) { // Purpur
entity.hurt(world.damageSources().hotFloor().directBlock(world, pos), 1.0F); // CraftBukkit
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index c1b269ebd90be16888f7fcace9efc0e0c08a4448..f370e1e5132e5800114f8bd8700444d7892590ac 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -983,6 +983,11 @@ public class PurpurWorldConfig {
pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit);
}
+ public boolean magmaBlockDamageWhenSneaking = false;
+ private void magmaBlockSettings() {
+ magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking);
+ }
+
public boolean powderSnowBypassMobGriefing = false;
private void powderSnowSettings() {
powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing);

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Wed, 8 Jun 2022 15:19:41 -0400
Subject: [PATCH] Add config for snow on blue ice
diff --git a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
index 9908a0b5b1fec5f9de518a733f7abbbff7e1a9f9..0ad444cf7f798f63e9140a42c5d5d8cab0fcf14f 100644
--- a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java
@@ -88,6 +88,12 @@ public class SnowLayerBlock extends Block {
protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
BlockState iblockdata1 = world.getBlockState(pos.below());
+ // Purpur start
+ if (iblockdata1.is(Blocks.BLUE_ICE) && !world.getWorldBorder().world.purpurConfig.snowOnBlueIce) {
+ return false;
+ }
+ // Purpur end
+
return iblockdata1.is(BlockTags.SNOW_LAYER_CANNOT_SURVIVE_ON) ? false : (iblockdata1.is(BlockTags.SNOW_LAYER_CAN_SURVIVE_ON) ? true : Block.isFaceFull(iblockdata1.getCollisionShape(world, pos.below()), Direction.UP) || iblockdata1.is((Block) this) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 8);
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index f370e1e5132e5800114f8bd8700444d7892590ac..ac183cb85490adc2312f5ec674a515826e540ae4 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -964,9 +964,11 @@ public class PurpurWorldConfig {
public boolean mobsSpawnOnPackedIce = true;
public boolean mobsSpawnOnBlueIce = true;
+ public boolean snowOnBlueIce = true;
private void iceSettings() {
mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce);
mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce);
+ snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce);
}
public int lavaInfiniteRequiredSources = 2;

View File

@@ -0,0 +1,111 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kerllenevich <ben@omega24.dev>
Date: Sat, 25 Jun 2022 00:18:33 -0400
Subject: [PATCH] Skeletons eat wither roses
diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
index 61b5f27c1125ed1b183dd3b86b44a10b7098f91c..b1158967400815b90687dddcc482846c70e03658 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java
@@ -17,6 +17,16 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
+// Purpur start
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.Blocks;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import net.minecraft.world.InteractionHand;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.core.particles.ParticleTypes;
+// Purpur end
+
public class Skeleton extends AbstractSkeleton {
private static final int TOTAL_CONVERSION_TIME = 300;
@@ -181,4 +191,63 @@ public class Skeleton extends AbstractSkeleton {
}
}
+
+ // Purpur start
+ private int witherRosesFed = 0;
+
+ @Override
+ public InteractionResult mobInteract(Player player, InteractionHand hand) {
+ ItemStack stack = player.getItemInHand(hand);
+
+ if (level().purpurConfig.skeletonFeedWitherRoses > 0 && this.getType() != EntityType.WITHER_SKELETON && stack.getItem() == Blocks.WITHER_ROSE.asItem()) {
+ return this.feedWitherRose(player, stack);
+ }
+
+ return super.mobInteract(player, hand);
+ }
+
+ private InteractionResult feedWitherRose(Player player, ItemStack stack) {
+ if (++witherRosesFed < level().purpurConfig.skeletonFeedWitherRoses) {
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(1);
+ }
+ return InteractionResult.CONSUME;
+ }
+
+ WitherSkeleton skeleton = EntityType.WITHER_SKELETON.create(level());
+ if (skeleton == null) {
+ return InteractionResult.PASS;
+ }
+
+ skeleton.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ skeleton.setHealth(this.getHealth());
+ skeleton.setAggressive(this.isAggressive());
+ skeleton.copyPosition(this);
+ skeleton.setYBodyRot(this.yBodyRot);
+ skeleton.setYHeadRot(this.getYHeadRot());
+ skeleton.yRotO = this.yRotO;
+ skeleton.xRotO = this.xRotO;
+
+ if (this.hasCustomName()) {
+ skeleton.setCustomName(this.getCustomName());
+ }
+
+ if (CraftEventFactory.callEntityTransformEvent(this, skeleton, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) {
+ return InteractionResult.PASS;
+ }
+
+ this.level().addFreshEntity(skeleton);
+ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(1);
+ }
+
+ for (int i = 0; i < 15; ++i) {
+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER,
+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1,
+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
+ }
+ return InteractionResult.SUCCESS;
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index ac183cb85490adc2312f5ec674a515826e540ae4..a7f750506e03cae0e965dfd874e92d3157576fb0 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -2565,6 +2565,7 @@ public class PurpurWorldConfig {
public boolean skeletonTakeDamageFromWater = false;
public boolean skeletonAlwaysDropExp = false;
public double skeletonHeadVisibilityPercent = 0.5D;
+ public int skeletonFeedWitherRoses = 0;
private void skeletonSettings() {
skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable);
skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater);
@@ -2579,6 +2580,7 @@ public class PurpurWorldConfig {
skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater);
skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp);
skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent);
+ skeletonFeedWitherRoses = getInt("mobs.skeleton.feed-wither-roses", skeletonFeedWitherRoses);
}
public boolean skeletonHorseRidable = false;

View File

@@ -0,0 +1,153 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kerllenevich <ben@omega24.dev>
Date: Sat, 25 Jun 2022 08:04:06 -0400
Subject: [PATCH] Enchantment Table Persists Lapis
diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
index 50a735dd97daab4fb9579f922a4c63de60204f29..5b8ad051347f73553acb65c5ddc690d2b7eaa754 100644
--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
@@ -42,6 +42,12 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
import org.bukkit.entity.Player;
// CraftBukkit end
+// Purpur start
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+// Purpur end
+
public class EnchantmentMenu extends AbstractContainerMenu {
static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = ResourceLocation.withDefaultNamespace("item/empty_slot_lapis_lazuli");
@@ -76,6 +82,22 @@ public class EnchantmentMenu extends AbstractContainerMenu {
return context.getLocation();
}
// CraftBukkit end
+
+ // Purpur start
+ @Override
+ public void onClose(CraftHumanEntity who) {
+ super.onClose(who);
+
+ if (who.getHandle().level().purpurConfig.enchantmentTableLapisPersists) {
+ access.execute((level, pos) -> {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
+ enchantmentTable.setLapis(this.getItem(1).getCount());
+ }
+ });
+ }
+ }
+ // Purpur end
};
this.random = RandomSource.create();
this.enchantmentSeed = DataSlot.standalone();
@@ -100,6 +122,16 @@ public class EnchantmentMenu extends AbstractContainerMenu {
return Pair.of(InventoryMenu.BLOCK_ATLAS, EnchantmentMenu.EMPTY_SLOT_LAPIS_LAZULI);
}
});
+ // Purpur start
+ access.execute((level, pos) -> {
+ if (level.purpurConfig.enchantmentTableLapisPersists) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
+ this.getSlot(1).set(new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis()));
+ }
+ }
+ });
+ // Purpur end
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(DataSlot.shared(this.costs, 0));
this.addDataSlot(DataSlot.shared(this.costs, 1));
@@ -329,6 +361,7 @@ public class EnchantmentMenu extends AbstractContainerMenu {
public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.access.execute((world, blockposition) -> {
+ if (world.purpurConfig.enchantmentTableLapisPersists) this.getSlot(1).set(ItemStack.EMPTY); // Purpur
this.clearContainer(player, this.enchantSlots);
});
}
diff --git a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
index a7fb500d950687743d1fc0b3ad3e6d10dcc6e31a..ce6a9e15ae0114623e79b5d8c244c2c490a3f74e 100644
--- a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java
@@ -123,4 +123,18 @@ public class EnchantingTableBlock extends BaseEntityBlock {
protected boolean isPathfindable(BlockState state, PathComputationType type) {
return false;
}
+
+ // Purpur start
+ @Override
+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+
+ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
+ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis()));
+ level.updateNeighbourForOutputSignal(pos, this);
+ }
+
+ super.onRemove(state, level, pos, newState, moved);
+ }
+ // Purpur end
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
index 39aac959775afeaeea211f21d498cb0ddf0a3fcb..6349a342c023f378af431a73a62fb017882e257d 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
@@ -28,6 +28,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
private static final RandomSource RANDOM = RandomSource.create();
@Nullable
private Component name;
+ private int lapis = 0; // Purpur
public EnchantingTableBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.ENCHANTING_TABLE, pos, state);
@@ -39,6 +40,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
if (this.hasCustomName()) {
nbt.putString("CustomName", Component.Serializer.toJson(this.name, registries));
}
+ nbt.putInt("Purpur.Lapis", this.lapis); // Purpur
}
@Override
@@ -47,6 +49,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
if (nbt.contains("CustomName", 8)) {
this.name = parseCustomNameSafe(nbt.getString("CustomName"), registries);
}
+ this.lapis = nbt.getInt("Purpur.Lapis"); // Purpur
}
public static void bookAnimationTick(Level world, BlockPos pos, BlockState state, EnchantingTableBlockEntity blockEntity) {
@@ -138,4 +141,14 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
public void removeComponentsFromTag(CompoundTag nbt) {
nbt.remove("CustomName");
}
+
+ // Purpur start
+ public int getLapis() {
+ return this.lapis;
+ }
+
+ public void setLapis(int lapis) {
+ this.lapis = lapis;
+ }
+ // Purpur
}
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index a7f750506e03cae0e965dfd874e92d3157576fb0..b28282fc3a2715d77187fab816dce9b38adbe6c1 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1541,6 +1541,11 @@ public class PurpurWorldConfig {
elderGuardianAlwaysDropExp = getBoolean("mobs.elder_guardian.always-drop-exp", elderGuardianAlwaysDropExp);
}
+ public boolean enchantmentTableLapisPersists = false;
+ private void enchantmentTableSettings() {
+ enchantmentTableLapisPersists = getBoolean("blocks.enchantment-table.lapis-persists", enchantmentTableLapisPersists);
+ }
+
public boolean enderDragonRidable = false;
public boolean enderDragonRidableInWater = true;
public boolean enderDragonControllable = true;

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Sun, 3 Jul 2022 04:13:57 -0500
Subject: [PATCH] Option to disable kick for out of order chat
diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
index 300929a406905f5ff1ede664d5b99fb0938d4d2e..a4e9ac0e07f08e0b6aa682e8c1587d9c84fc3c6c 100644
--- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
@@ -45,7 +45,7 @@ public class SignedMessageChain {
SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink;
if (signedMessageLink == null) {
throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN);
- } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) {
+ } else if (org.purpurmc.purpur.PurpurConfig.kickForOutOfOrderChat && body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) {
this.setChainBroken();
throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes
} else {
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 5475a8c622c4090e994f87f6a28febdccecbf973..afb165af34f365210fdfa6542cf7a81435096738 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -461,9 +461,11 @@ public class PurpurConfig {
public static boolean useUPnP = false;
public static boolean maxJoinsPerSecond = false;
+ public static boolean kickForOutOfOrderChat = true;
private static void networkSettings() {
useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP);
maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond);
+ kickForOutOfOrderChat = getBoolean("settings.network.kick-for-out-of-order-chat", kickForOutOfOrderChat);
}
public static java.util.regex.Pattern usernameValidCharactersPattern;

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
Date: Mon, 4 Jul 2022 13:32:51 -0400
Subject: [PATCH] Config for sculk shrieker can_summon state
diff --git a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
index 0e05bfef55dcacb50766bba8328ffeb8a5394c31..e00fcea07e74de647c26ff9eb32bc682738c15b7 100644
--- a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java
@@ -135,7 +135,7 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
- return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER);
+ return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER).setValue(SculkShriekerBlock.CAN_SUMMON, ctx.getLevel().purpurConfig.sculkShriekerCanSummonDefault); // Purpur
}
@Override
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index b28282fc3a2715d77187fab816dce9b38adbe6c1..b6b0ebe3c96c4c8f4ce9ed454ec64a7f64e6b950 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -1021,6 +1021,11 @@ public class PurpurWorldConfig {
}
}
+ public boolean sculkShriekerCanSummonDefault = false;
+ private void sculkShriekerSettings() {
+ sculkShriekerCanSummonDefault = getBoolean("blocks.sculk_shrieker.can-summon-default", sculkShriekerCanSummonDefault);
+ }
+
public boolean signAllowColors = false;
private void signSettings() {
signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors);

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
Date: Mon, 4 Jul 2022 13:57:06 -0400
Subject: [PATCH] Config to not let coral die
diff --git a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
index d7ca7a43d2d5f8cad416156fd40588cdd6634f52..231338adda19f57bf1a95379cc2e14341d4068d0 100644
--- a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
@@ -39,6 +39,7 @@ public abstract class BaseCoralPlantTypeBlock extends Block implements SimpleWat
}
protected static boolean scanForWater(BlockState state, BlockGetter world, BlockPos pos) {
+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur
if (state.getValue(WATERLOGGED)) {
return true;
} else {
diff --git a/src/main/java/net/minecraft/world/level/block/CoralBlock.java b/src/main/java/net/minecraft/world/level/block/CoralBlock.java
index a59b23f4062fa896836dec72cbd5097411774ad1..c526ea13a726624adaa654f09ff84c899c13ab98 100644
--- a/src/main/java/net/minecraft/world/level/block/CoralBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CoralBlock.java
@@ -60,6 +60,7 @@ public class CoralBlock extends Block {
}
protected boolean scanForWater(BlockGetter world, BlockPos pos) {
+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur
Direction[] aenumdirection = Direction.values();
int i = aenumdirection.length;
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
index b6b0ebe3c96c4c8f4ce9ed454ec64a7f64e6b950..3853e9e894c19da5a0e74c30a5e248c3e8790160 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
@@ -870,6 +870,11 @@ public class PurpurWorldConfig {
composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess);
}
+ public boolean coralDieOutsideWater = true;
+ private void coralSettings() {
+ coralDieOutsideWater = getBoolean("blocks.coral.die-outside-water", coralDieOutsideWater);
+ }
+
public boolean dispenserApplyCursedArmor = true;
public boolean dispenserPlaceAnvils = false;
private void dispenserSettings() {

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Sat, 9 Jul 2022 00:57:32 -0500
Subject: [PATCH] Add local difficulty api
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index d41c81158c00931e6b11093cce141f6a3085ba05..3be5c25f8ce15e2f035c92e5fe90693e0236967d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -2399,6 +2399,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return (this.getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().getDragonFight());
}
+ // Purpur start
+ public float getLocalDifficultyAt(Location location) {
+ return getHandle().getCurrentDifficultyAt(io.papermc.paper.util.MCUtil.toBlockPosition(location)).getEffectiveDifficulty();
+ }
+ // Purpur end
+
@Override
public Collection<GeneratedStructure> getStructures(int x, int z) {
return this.getStructures(x, z, struct -> true);